improve voxel side calculating

Less memory allocation, faster performance, better results. Still not perfect
This commit is contained in:
Bixilon 2023-05-31 15:13:50 +02:00
parent 199aab67d7
commit aca80648d3
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
6 changed files with 204 additions and 240 deletions

View File

@ -15,8 +15,8 @@ package de.bixilon.minosoft.data.registries.blocks.light
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.shapes.side.SideQuad
import de.bixilon.minosoft.data.registries.shapes.side.VoxelSide
import de.bixilon.minosoft.data.registries.shapes.side.VoxelSideSet
import de.bixilon.minosoft.data.registries.shapes.voxel.AbstractVoxelShape
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
@ -34,7 +34,8 @@ class DirectedProperty(
companion object {
private val TRUE = BooleanArray(Directions.SIZE) { true }
private val FALSE = BooleanArray(Directions.SIZE) { false }
private val FULL_SIDE = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
private val FULL_SIDE = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
private val REQUIRED_SURFACE_AREA = FULL_SIDE.surfaceArea() - 0.0001f // add some padding for floating point
private val BooleanArray.isSimple: Boolean?
get() {
@ -69,11 +70,13 @@ class DirectedProperty(
}
private fun AbstractVoxelShape.getSide(side: Directions): VoxelSideSet {
private fun AbstractVoxelShape.getSide(side: Directions): VoxelSide? {
// ToDo: This whole calculation is technically wrong, it could be that 2 different sides of 2 blocks are "free". That means that light can still not pass the blocks, but
// this algorithm does not cover it. Let's see it as performance hack
val sides: MutableSet<VoxelSide> = ObjectOpenHashSet()
if (this.aabbs == 0) return null
val sides: MutableSet<SideQuad> = ObjectOpenHashSet()
for (aabb in this) {
when (side.axis) {
@ -81,41 +84,60 @@ class DirectedProperty(
if ((side == Directions.DOWN && aabb.min.y != 0.0) || (side == Directions.UP && aabb.max.y != 1.0)) {
continue
}
sides += VoxelSide(aabb.min.x, aabb.min.z, aabb.max.x, aabb.max.z)
val side = SideQuad(aabb.min.x, aabb.min.z, aabb.max.x, aabb.max.z)
if (side.surfaceArea() > 0.0f) {
sides += side
}
}
Axes.X -> {
if ((side == Directions.WEST && aabb.min.x != 0.0) || (side == Directions.EAST && aabb.max.x != 1.0)) {
continue
}
sides += VoxelSide(aabb.min.y, aabb.min.z, aabb.max.y, aabb.max.z)
val side = SideQuad(aabb.min.y, aabb.min.z, aabb.max.y, aabb.max.z)
if (side.surfaceArea() > 0.0f) {
sides += side
}
}
Axes.Z -> {
if ((side == Directions.NORTH && aabb.min.z != 0.0) || (side == Directions.SOUTH && aabb.max.z != 1.0)) {
continue
}
sides += VoxelSide(aabb.min.x, aabb.min.y, aabb.max.x, aabb.max.y)
val side = SideQuad(aabb.min.x, aabb.min.y, aabb.max.x, aabb.max.y)
if (side.surfaceArea() > 0.0f) {
sides += side
}
}
}
}
return VoxelSideSet(sides)
if (sides.isEmpty()) return null
return VoxelSide(sides)
}
private fun VoxelSide.getSideArea(target: SideQuad): Float {
// overlapping is broken, see https://stackoverflow.com/questions/7342935/algorithm-to-compute-total-area-covered-by-a-set-of-overlapping-segments
var area = 0.0f
for (quad in this) {
val width = minOf(target.max.x, quad.max.x) - maxOf(quad.min.x, target.min.x)
val height = minOf(target.max.y, quad.max.y) - maxOf(quad.min.y, target.min.y)
area += width * height
}
return area
}
fun AbstractVoxelShape.isSideCovered(direction: Directions): Boolean {
val side = getSide(direction)
if (side.isEmpty()) {
return false
}
// this should be improved: https://stackoverflow.com/questions/76373725/check-if-a-quad-is-fully-covered-by-a-set-of-others
val side = getSide(direction) ?: return false
val rest = FULL_SIDE - side
var compacted = rest.compact()
if (rest != compacted) {
compacted = FULL_SIDE - compacted
}
val surface = side.getSideArea(FULL_SIDE)
return !FULL_SIDE.touches(compacted)
return surface >= REQUIRED_SURFACE_AREA
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.shapes.side
import com.google.common.base.Objects
import de.bixilon.kotlinglm.vec2.Vec2
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
data class SideQuad(
val min: Vec2,
val max: Vec2,
) {
private val hashCode = Objects.hashCode(min.hashCode(), max.hashCode())
constructor(minX: Float, minZ: Float, maxX: Float, maxZ: Float) : this(Vec2(minOf(minX, maxX), minOf(minZ, maxZ)), Vec2(maxOf(minX, maxX), maxOf(minZ, maxZ)))
constructor(minX: Double, minZ: Double, maxX: Double, maxZ: Double) : this(Vec2(minOf(minX, maxX).toFloat(), minOf(minZ, maxZ).toFloat()), Vec2(maxOf(minX, maxX).toFloat(), maxOf(minZ, maxZ).toFloat()))
fun touches(other: SideQuad): Boolean {
return !(this.min.x > other.max.x || other.min.x > this.max.x || this.min.y > other.max.y || other.min.y > this.max.y)
}
infix operator fun minus(set: VoxelSide): VoxelSide {
val result: MutableSet<SideQuad> = ObjectOpenHashSet()
for (side in set.sides) {
result += (this minus side).sides
}
return VoxelSide(result)
}
infix operator fun minus(other: SideQuad): VoxelSide {
val result: MutableSet<SideQuad> = ObjectOpenHashSet()
if (other.min.x > min.x && other.min.x < max.x) {
result += SideQuad(min.x, min.y, other.min.x, max.y)
}
if (other.min.y > min.y && other.min.y < max.y) {
result += SideQuad(min.x, min.y, max.x, other.min.y)
}
if (max.x > other.max.x) {
result += SideQuad(other.max.x, min.y, max.x, max.y)
}
if (max.y > other.max.y) {
result += SideQuad(min.x, other.max.y, max.x, max.y)
}
return VoxelSide(result)
}
override fun hashCode(): Int {
return hashCode
}
override fun equals(other: Any?): Boolean {
if (other !is SideQuad) return false
if (hashCode != other.hashCode) return false
return min == other.min && max == other.max
}
fun surfaceArea(): Float {
val surface = (max.x - min.x) * (max.y - min.y)
if (surface <= 0.0f) return 0.0f
return surface
}
}

View File

@ -13,105 +13,23 @@
package de.bixilon.minosoft.data.registries.shapes.side
import com.google.common.base.Objects
import de.bixilon.kotlinglm.vec2.Vec2
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
class VoxelSide(
val sides: Set<SideQuad>,
) : Iterable<SideQuad> {
data class VoxelSide(
val min: Vec2,
val max: Vec2,
) {
private val hashCode = Objects.hashCode(min.hashCode(), max.hashCode())
fun isEmpty(): Boolean = sides.isEmpty()
constructor(minX: Float, minZ: Float, maxX: Float, maxZ: Float) : this(Vec2(minOf(minX, maxX), minOf(minZ, maxZ)), Vec2(maxOf(minX, maxX), maxOf(minZ, maxZ)))
constructor(minX: Double, minZ: Double, maxX: Double, maxZ: Double) : this(Vec2(minOf(minX, maxX).toFloat(), minOf(minZ, maxZ).toFloat()), Vec2(maxOf(minX, maxX).toFloat(), maxOf(minZ, maxZ).toFloat()))
fun touches(set: VoxelSideSet): Boolean {
for (side in set) {
if (touches(side)) {
return true
}
}
return false
}
fun touches(other: VoxelSide): Boolean {
return !(this.min.x > other.max.x || other.min.x > this.max.x || this.min.y > other.max.y || other.min.y > this.max.y)
}
infix operator fun minus(set: VoxelSideSet): VoxelSideSet {
val result: MutableSet<VoxelSide> = ObjectOpenHashSet()
for (side in set.sides) {
result += (this minus side).sides
}
return VoxelSideSet(result)
}
infix operator fun minus(other: VoxelSide): VoxelSideSet {
val result: MutableSet<VoxelSide> = ObjectOpenHashSet()
if (other.min.x > min.x && other.min.x < max.x) {
result += VoxelSide(min.x, min.y, other.min.x, max.y)
}
if (other.min.y > min.y && other.min.y < max.y) {
result += VoxelSide(min.x, min.y, max.x, other.min.y)
}
if (max.x > other.max.x) {
result += VoxelSide(other.max.x, min.y, max.x, max.y)
}
if (max.y > other.max.y) {
result += VoxelSide(min.x, other.max.y, max.x, max.y)
}
return VoxelSideSet(result)
}
infix fun or(other: VoxelSide): VoxelSide {
TODO("Not yet implemented")
}
fun compact(side: VoxelSide): VoxelSideSet {
var minX = min.x
var minY = min.y
var maxX = max.x
var maxY = max.y
var changes = 0
if (side.min.y == minY && side.min.x < minX) {
minX = side.min.x; changes++
} else if (side.min.x == minX && side.min.y < minY) {
minY = side.min.y;changes++
}
if (side.max.y == maxY && side.max.x > maxX) {
maxX = side.max.x;changes++
} else if (side.max.x == maxX && side.min.y > maxY) {
maxY = side.max.y;changes++
}
if (changes == 0) {
val set: MutableSet<VoxelSide> = ObjectOpenHashSet(2)
set += this
set += side
return VoxelSideSet(set)
}
return VoxelSideSet(setOf(VoxelSide(minX, minY, maxX, maxY)))
override fun iterator(): Iterator<SideQuad> {
return sides.iterator()
}
override fun hashCode(): Int {
return hashCode
return sides.hashCode()
}
override fun equals(other: Any?): Boolean {
if (other !is VoxelSide) return false
if (hashCode != other.hashCode) return false
return min == other.min && max == other.max
if (hashCode() != other.hashCode()) return false
return sides == other.sides
}
}

View File

@ -1,57 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.registries.shapes.side
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
class VoxelSideSet(
val sides: Set<VoxelSide>,
) : Iterable<VoxelSide> {
fun isEmpty(): Boolean = sides.isEmpty()
override fun iterator(): Iterator<VoxelSide> {
return sides.iterator()
}
fun compact(): VoxelSideSet {
if (this.sides.size <= 1) {
return this
}
val next: MutableSet<VoxelSide> = ObjectOpenHashSet()
val array = this.sides.toTypedArray()
for (i in 1 until sides.size) {
next += array[i - 1].compact(array[i])
}
val set = VoxelSideSet(next)
if (next.size < this.sides.size) {
return set.compact()
}
return set
}
override fun hashCode(): Int {
return sides.hashCode()
}
override fun equals(other: Any?): Boolean {
if (other !is VoxelSideSet) return false
if (hashCode() != other.hashCode()) return false
return sides == other.sides
}
}

View File

@ -80,7 +80,7 @@ internal class DirectedPropertyTest {
assertTrue(shape.isSideCovered(Directions.EAST))
}
// @Test // TODO: This test is correct, isSideCovered is broken
@Test
fun testSideCovered6() {
val shape = VoxelShape(
AABB(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f),
@ -109,4 +109,35 @@ internal class DirectedPropertyTest {
assertFalse(shape.isSideCovered(Directions.WEST))
assertFalse(shape.isSideCovered(Directions.EAST))
}
@Test
fun testSideCovered8() { // overlapping
val shape = VoxelShape(
AABB(0.0f, 0.0f, 0.0f, 1.0f, 0.6f, 1.0f),
AABB(0.0f, 0.4f, 0.5f, 1.0f, 1.0f, 1.0f),
)
assertTrue(shape.isSideCovered(Directions.DOWN))
assertFalse(shape.isSideCovered(Directions.UP))
assertFalse(shape.isSideCovered(Directions.NORTH))
assertTrue(shape.isSideCovered(Directions.SOUTH))
assertFalse(shape.isSideCovered(Directions.WEST))
assertFalse(shape.isSideCovered(Directions.EAST))
}
// @Test // TODO: This test is correct, isSideCovered is broken
fun testSideCovered9() { // overlapping
val shape = VoxelShape(
AABB(0.0f, 0.0f, 0.0f, 1.0f, 0.6f, 1.0f),
AABB(0.1f, 0.0f, 0.0f, 0.9f, 0.8f, 1.0f),
AABB(0.0f, 0.4f, 0.5f, 1.0f, 0.9f, 1.0f),
)
assertTrue(shape.isSideCovered(Directions.DOWN))
assertFalse(shape.isSideCovered(Directions.UP))
assertFalse(shape.isSideCovered(Directions.NORTH))
assertTrue(shape.isSideCovered(Directions.SOUTH))
assertFalse(shape.isSideCovered(Directions.WEST))
assertFalse(shape.isSideCovered(Directions.EAST))
}
}

View File

@ -20,15 +20,15 @@ internal class VoxelSideTest {
@Test
fun testMinus1() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 0.0f, 0.5f, 0.5f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(0.0f, 0.0f, 0.5f, 0.5f)
val result = a - b
assertEquals(
setOf(
VoxelSide(0.0f, 0.5f, 1.0f, 1.0f),
VoxelSide(0.5f, 0.0f, 1.0f, 1.0f),
SideQuad(0.0f, 0.5f, 1.0f, 1.0f),
SideQuad(0.5f, 0.0f, 1.0f, 1.0f),
),
result.sides
)
@ -36,17 +36,17 @@ internal class VoxelSideTest {
@Test
fun testMinus2() {
val a = VoxelSide(1.0f, 1.0f, 4.0f, 4.0f)
val b = VoxelSide(2.0f, 2.0f, 3.0f, 3.0f)
val a = SideQuad(1.0f, 1.0f, 4.0f, 4.0f)
val b = SideQuad(2.0f, 2.0f, 3.0f, 3.0f)
val result = a - b
assertEquals(
setOf(
VoxelSide(1.0f, 1.0f, 4.0f, 2.0f),
VoxelSide(3.0f, 1.0f, 4.0f, 4.0f),
VoxelSide(1.0f, 3.0f, 4.0f, 4.0f),
VoxelSide(1.0f, 1.0f, 2.0f, 4.0f),
SideQuad(1.0f, 1.0f, 4.0f, 2.0f),
SideQuad(3.0f, 1.0f, 4.0f, 4.0f),
SideQuad(1.0f, 3.0f, 4.0f, 4.0f),
SideQuad(1.0f, 1.0f, 2.0f, 4.0f),
),
result.sides
)
@ -54,60 +54,29 @@ internal class VoxelSideTest {
@Test
fun testMinus3() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(1.0f, 1.0f, 2.0f, 2.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(1.0f, 1.0f, 2.0f, 2.0f)
val result = a - b
assertEquals(emptySet<VoxelSide>(), result.sides)
assertEquals(emptySet<SideQuad>(), result.sides)
}
@Test
fun testMinus4() {
val a = VoxelSide(0.0f, 0.0f, 0.5f, 0.5f)
val b = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val a = SideQuad(0.0f, 0.0f, 0.5f, 0.5f)
val b = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val result = a - b
assertEquals(emptySet<VoxelSide>(), result.sides)
assertEquals(emptySet<SideQuad>(), result.sides)
}
private fun testOr1() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 0.0f, 0.5f, 0.5f)
val or = a or b
assertEquals(or, b)
}
private fun testOr2() {
val a = VoxelSide(0.0f, 0.0f, 3.0f, 3.0f)
val b = VoxelSide(1.0f, 1.0f, 2.0f, 2.0f)
val or = a or b
assertEquals(or, b)
}
private fun testOr3() {
val a = VoxelSide(1.0f, 1.0f, 2.0f, 2.0f)
val b = VoxelSide(0.0f, 0.0f, 3.0f, 3.0f)
val or = a or b
assertEquals(or, a)
}
private fun testOr4() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 0.0f, 0.5f, 1.0f)
val or = a or b
assertEquals(or, b)
}
@Test
fun testTouches1() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -115,8 +84,8 @@ internal class VoxelSideTest {
@Test
fun testTouches2() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 0.0f, 0.5f, 0.5f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(0.0f, 0.0f, 0.5f, 0.5f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -124,8 +93,8 @@ internal class VoxelSideTest {
@Test
fun testTouches3() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(-1.0f, -1.0f, 0.5f, 0.5f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(-1.0f, -1.0f, 0.5f, 0.5f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -133,8 +102,8 @@ internal class VoxelSideTest {
@Test
fun testTouches4() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(-1.0f, -1.0f, 2.0f, 2.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(-1.0f, -1.0f, 2.0f, 2.0f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -142,8 +111,8 @@ internal class VoxelSideTest {
@Test
fun testTouches5() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.1f, -1.0f, 2.0f, 0.9f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(0.1f, -1.0f, 2.0f, 0.9f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -151,8 +120,8 @@ internal class VoxelSideTest {
@Test
fun testTouches6() {
val a = VoxelSide(0.0f, 0.0f, 3.0f, 3.0f)
val b = VoxelSide(1.0f, 1.0f, 2.0f, 2.0f)
val a = SideQuad(0.0f, 0.0f, 3.0f, 3.0f)
val b = SideQuad(1.0f, 1.0f, 2.0f, 2.0f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -160,8 +129,8 @@ internal class VoxelSideTest {
@Test
fun testTouches7() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(1.0f, 1.0f, 2.0f, 2.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(1.0f, 1.0f, 2.0f, 2.0f)
assertTrue(a.touches(b))
assertTrue(b.touches(a))
@ -169,8 +138,8 @@ internal class VoxelSideTest {
@Test
fun testTouches8() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(2.0f, 2.0f, 3.0f, 3.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(2.0f, 2.0f, 3.0f, 3.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))
@ -178,8 +147,8 @@ internal class VoxelSideTest {
@Test
fun testTouches9() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(0.0f, 2.0f, 3.0f, 3.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(0.0f, 2.0f, 3.0f, 3.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))
@ -187,8 +156,8 @@ internal class VoxelSideTest {
@Test
fun testTouches10() {
val a = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val b = VoxelSide(2.0f, 0.0f, 3.0f, 3.0f)
val a = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
val b = SideQuad(2.0f, 0.0f, 3.0f, 3.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))
@ -196,8 +165,8 @@ internal class VoxelSideTest {
@Test
fun testTouches11() {
val a = VoxelSide(2.0f, 0.0f, 3.0f, 3.0f)
val b = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val a = SideQuad(2.0f, 0.0f, 3.0f, 3.0f)
val b = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))
@ -205,8 +174,8 @@ internal class VoxelSideTest {
@Test
fun testTouches12() {
val a = VoxelSide(0.0f, 2.0f, 3.0f, 3.0f)
val b = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val a = SideQuad(0.0f, 2.0f, 3.0f, 3.0f)
val b = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))
@ -214,8 +183,8 @@ internal class VoxelSideTest {
@Test
fun testTouches13() {
val a = VoxelSide(2.0f, 2.0f, 3.0f, 3.0f)
val b = VoxelSide(0.0f, 0.0f, 1.0f, 1.0f)
val a = SideQuad(2.0f, 2.0f, 3.0f, 3.0f)
val b = SideQuad(0.0f, 0.0f, 1.0f, 1.0f)
assertFalse(a.touches(b))
assertFalse(b.touches(a))