Commit 1fc3a6cf authored by Kevin Turner's avatar Kevin Turner

optimize wholly overlapping (eclipsing) rectangles

parent 5cfa9cba
......@@ -69,6 +69,14 @@ data class Rect(val left: Int, val top: Int, val width: Int, val height: Int) {
inRight = this
}
// Special case for one rect being completely contained by the other.
if (inRight.top >= inLeft.top &&
inRight.bottom <= inLeft.bottom &&
inRight.right <= inLeft.right // and we already know inLeft.left <= inRight.left
) {
return setOf(inLeft)
}
val leftRect = Rect(inLeft.left, inLeft.top, inRight.left - inLeft.left, inLeft.height)
val collisionRect = Rect(
......@@ -156,25 +164,46 @@ fun unionRects(rects: List<Rect>): Set<Rect> {
var passCount = 0
do {
val leftToRight = oldGeneration.sortedBy { rect -> rect.left }
val leftToRight = oldGeneration.sortedBy { rect -> rect.left }.toMutableList()
val notCollidedYet = oldGeneration.toMutableSet()
val newGeneration = mutableSetOf<Rect>()
println("* Pass ${passCount}, ${notCollidedYet.size} inputs, ${collisionFree.size} cleared")
for ((currentIndex, rect) in leftToRight.withIndex()) {
bloop@ for (hazard in leftToRight.listIterator(currentIndex + 1)) {
while (leftToRight.isNotEmpty()) {
val rect = leftToRight.removeAt(0)
val forRemoval = mutableListOf<Rect>()
val forAddition = mutableSetOf<Rect>()
bloop@ for (hazard in leftToRight) {
if (hazard.left > rect.right) {
break@bloop
}
val results = rect.collided(hazard)
if (results != null) {
newGeneration.addAll(results)
notCollidedYet.remove(rect)
notCollidedYet.remove(hazard)
if (results.all { it == rect}) { // special case for eclipsing the other
forRemoval.add(hazard)
notCollidedYet.remove(hazard)
} else {
notCollidedYet.remove(rect)
notCollidedYet.remove(hazard)
forRemoval.add(hazard)
forAddition.addAll(results)
newGeneration.addAll(results)
notCollidedYet.addAll(results)
}
}
}
leftToRight.removeAll(forRemoval)
for (newRect in forAddition) {
var insertionPoint = leftToRight.binarySearchBy(newRect.left) { it.left }
if (insertionPoint < 0) {
insertionPoint = -insertionPoint - 1
}
leftToRight.add(insertionPoint, newRect)
}
}
collisionFree.addAll(notCollidedYet)
......@@ -185,6 +214,8 @@ fun unionRects(rects: List<Rect>): Set<Rect> {
oldGeneration = newGeneration
} while (newGeneration.isNotEmpty())
println("* * DONE * * ${collisionFree.size} cleared")
return collisionFree
}
......
......@@ -72,13 +72,13 @@ class ClaimTest {
class RectTest {
// @Test
// fun `union of wholly overlapping rectangles is one rectangle`() {
// val rect1 = Rect(1, 2, 30, 40)
// val rect2 = Rect(10, 20, 5, 6)
//
// assert(rect1.union(rect2)).containsStrictly(rect1)
// }
@Test
fun `union of wholly overlapping rectangles is one rectangle`() {
val rect1 = Rect(1, 2, 30, 40)
val rect2 = Rect(10, 20, 5, 6)
assert(rect1.collided(rect2)).notToBeNull { containsStrictly(rect1) }
}
/* 1
......@@ -162,10 +162,7 @@ class RectTest {
containsStrictly(collision)
}
}
}
class RectColliderTest {
@Test
fun `non-collision returns null`() {
val rect1 = Rect(1, 2, 3, 4)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment