From 08264e50d0547adc66c81e7ec02f98f5e8feca83 Mon Sep 17 00:00:00 2001 From: masongreen Date: Sat, 18 Jul 2009 15:52:58 -0400 Subject: [PATCH] bug hunting --- src/org/poly2tri/MonoToneMountain.scala | 26 +++------- src/org/poly2tri/Point.scala | 1 + src/org/poly2tri/Poly2Tri.scala | 16 +++---- src/org/poly2tri/QueryGraph.scala | 2 +- src/org/poly2tri/Trapezoid.scala | 28 ++++------- src/org/poly2tri/TrapezoidalMap.scala | 64 +++++++++++-------------- src/org/poly2tri/Triangulator.scala | 6 +-- 7 files changed, 55 insertions(+), 88 deletions(-) diff --git a/src/org/poly2tri/MonoToneMountain.scala b/src/org/poly2tri/MonoToneMountain.scala index 148ccb5..5eb38fd 100644 --- a/src/org/poly2tri/MonoToneMountain.scala +++ b/src/org/poly2tri/MonoToneMountain.scala @@ -39,9 +39,9 @@ class MonotoneMountain { var size = 0 val convexPoints = new Queue[Point] - // Monotone mountain points + // Monotone mountain points val monoPoly = new ArrayBuffer[Point] - // Triangles that constitute the mountain + // Triangles that constitute the mountain val triangles = new ArrayBuffer[Array[Point]] // Used to track which side of the line we are on var positive = false @@ -83,9 +83,6 @@ class MonotoneMountain { // create monotone polygon - for dubug purposes genMonoPoly - if(size == 3) { - lastTriangle - } else { // Initialize internal angles at each nonbase vertex // Link strictly convex vertices into a list, ignore reflex vertices var p = head.next @@ -115,17 +112,17 @@ class MonotoneMountain { if(valid(c)) convexPoints.enqueue(c) } assert(size <= 3, "Triangulation bug") - } + } def valid(p: Point) = (p.prev != null && p.next != null && convex(p)) // Create the monotone polygon private def genMonoPoly { - var p = head + var p = head while(p != null) { - monoPoly += p - p = p.next + monoPoly += p + p = p.next } } @@ -147,15 +144,4 @@ class MonotoneMountain { else true } - private def lastTriangle { - val triangle = new Array[Point](3) - var i = 0 - var p = head - while(p != null) { - triangle(i) = p - p = p.next - i += 1 - } - triangles += triangle - } } diff --git a/src/org/poly2tri/Point.scala b/src/org/poly2tri/Point.scala index 9eadc58..e329163 100644 --- a/src/org/poly2tri/Point.scala +++ b/src/org/poly2tri/Point.scala @@ -45,6 +45,7 @@ case class Point(val x: Float, val y: Float) { def dot(p: Point) = x * p.x + y * p.y def length = Math.sqrt(x * x + y * y).toFloat def normalize = this / length + def !(p: Point) = !(p.x == x && p.y == y) def <(p: Point) = { if(p.x == x) diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index 9c81229..ac2b23f 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -60,7 +60,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { var quit = false var debug = false var drawMap = false - var drawSegs = false + var drawSegs = true var hiLighter = 0 def init(container: GameContainer) { @@ -104,10 +104,10 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { g.setColor(red) g.draw(triangle) } - val triangle = new Polygon - tesselator.triangles(hiLighter).foreach(p => triangle.addPoint(p.x, p.y)) - g.setColor(blue) - g.draw(triangle) + //val triangle = new Polygon + //tesselator.triangles(hiLighter).foreach(p => triangle.addPoint(p.x, p.y)) + //g.setColor(blue) + //g.draw(triangle) } else if (debug && drawMap){ for(mp <- tesselator.monoPolies) { val poly = new Polygon @@ -189,7 +189,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p16, p1) tesselator = new Triangulator(segments) - tesselator.process + tesselator process } def star { @@ -217,7 +217,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p9, p10) segments += new Segment(p10, p1) tesselator = new Triangulator(segments) - tesselator.process + tesselator process } // Test #2 @@ -252,7 +252,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p11, p12) segments += new Segment(p12, p1) tesselator = new Triangulator(segments) - tesselator.process + tesselator process } diff --git a/src/org/poly2tri/QueryGraph.scala b/src/org/poly2tri/QueryGraph.scala index 002f7e9..2b02ed7 100644 --- a/src/org/poly2tri/QueryGraph.scala +++ b/src/org/poly2tri/QueryGraph.scala @@ -40,7 +40,7 @@ class QueryGraph(var head: Node) { def locate(s: Segment) = head.locate(s).trapezoid def followSegment(s: Segment) = { - assert(s.p.x < s.q.x) + val trapezoids = new ArrayBuffer[Trapezoid] trapezoids += locate(s) var j = 0 diff --git a/src/org/poly2tri/Trapezoid.scala b/src/org/poly2tri/Trapezoid.scala index 71e7794..1851ad1 100644 --- a/src/org/poly2tri/Trapezoid.scala +++ b/src/org/poly2tri/Trapezoid.scala @@ -41,16 +41,6 @@ class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, v var upperRight: Trapezoid = null var lowerRight: Trapezoid = null - def updateLeftNeighbors(ul: Trapezoid, ll: Trapezoid) { - if(upperLeft != null && upperLeft.top == top) upperLeft.upperRight = ul - if(lowerLeft != null && lowerLeft.bottom == bottom) lowerLeft.lowerRight = ll - } - - def updateRightNeighbors(ur: Trapezoid, lr: Trapezoid) { - if(upperRight != null && upperRight.top == top) upperRight.upperLeft = ur - if(lowerRight != null && lowerRight.bottom == bottom) lowerRight.lowerLeft = lr - } - def update(ul: Trapezoid, ll: Trapezoid, ur: Trapezoid, lr: Trapezoid) { upperLeft = ul; if(ul != null) ul.upperRight = this lowerLeft = ll; if(ll != null) ll.lowerRight = this @@ -62,10 +52,10 @@ class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, v def trimNeighbors { if(inside) { inside = false - if(upperLeft != null) {upperLeft.trimNeighbors} - if(lowerLeft != null) {lowerLeft.trimNeighbors} - if(upperRight != null) {upperRight.trimNeighbors} - if(lowerRight != null) {lowerRight.trimNeighbors} + if(upperLeft != null) upperLeft.trimNeighbors + if(lowerLeft != null) lowerLeft.trimNeighbors + if(upperRight != null) upperRight.trimNeighbors + if(lowerRight != null) lowerRight.trimNeighbors } } @@ -85,14 +75,14 @@ class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, v def lineIntersect(s: Segment, x: Float) = { val y = s.slope * x + s.b - new Point(x, y) + Point(x, y) } // Add points to monotone mountain def addPoints { - if(leftPoint != bottom.p) bottom.mPoints += leftPoint - if(rightPoint != bottom.q) bottom.mPoints += rightPoint - if(leftPoint != top.p) top.mPoints += leftPoint - if(rightPoint != top.q) top.mPoints += rightPoint + if(leftPoint ! bottom.p) bottom.mPoints += leftPoint.clone + if(rightPoint ! bottom.q) bottom.mPoints += rightPoint.clone + if(leftPoint ! top.p) top.mPoints += leftPoint.clone + if(rightPoint ! top.q) top.mPoints += rightPoint.clone } } diff --git a/src/org/poly2tri/TrapezoidalMap.scala b/src/org/poly2tri/TrapezoidalMap.scala index dc8e661..a19540f 100644 --- a/src/org/poly2tri/TrapezoidalMap.scala +++ b/src/org/poly2tri/TrapezoidalMap.scala @@ -67,14 +67,11 @@ class TrapezoidalMap { // break trapezoid into 4 smaller trapezoids def case1(t: Trapezoid, s: Segment) = { - assert(s.p.x != s.q.x) - assert(s.p.x < s.q.x) - val trapezoids = new Array[Trapezoid](4) - trapezoids(0) = new Trapezoid(t.leftPoint, s.p, t.top, t.bottom) - trapezoids(1) = new Trapezoid(s.p, s.q, t.top, s) - trapezoids(2) = new Trapezoid(s.p, s.q, s, t.bottom) - trapezoids(3) = new Trapezoid(s.q, t.rightPoint, t.top, t.bottom) + trapezoids(0) = new Trapezoid(t.leftPoint.clone, s.p.clone, t.top, t.bottom) + trapezoids(1) = new Trapezoid(s.p.clone, s.q.clone, t.top, s) + trapezoids(2) = new Trapezoid(s.p.clone, s.q.clone, s, t.bottom) + trapezoids(3) = new Trapezoid(s.q.clone, t.rightPoint.clone, t.top, t.bottom) trapezoids(0).update(t.upperLeft, t.lowerLeft, trapezoids(1), trapezoids(2)) trapezoids(1).update(trapezoids(0), null, trapezoids(3), null) @@ -94,9 +91,9 @@ class TrapezoidalMap { assert(s.p.x < s.q.x) val trapezoids = new Array[Trapezoid](3) - trapezoids(0) = new Trapezoid(t.leftPoint, s.p, t.top, t.bottom) - trapezoids(1) = new Trapezoid(s.p, t.rightPoint, t.top, s) - trapezoids(2) = new Trapezoid(s.p, t.rightPoint, s, t.bottom) + trapezoids(0) = new Trapezoid(t.leftPoint.clone, s.p.clone, t.top, t.bottom) + trapezoids(1) = new Trapezoid(s.p.clone, t.rightPoint.clone, t.top, s) + trapezoids(2) = new Trapezoid(s.p.clone, t.rightPoint.clone, s, t.bottom) trapezoids(0).update(t.upperLeft, t.lowerLeft, trapezoids(1), trapezoids(2)) trapezoids(1).update(trapezoids(0), null, t.upperRight, null) @@ -113,20 +110,17 @@ class TrapezoidalMap { // Case 3: Trapezoid is bisected def case3(t: Trapezoid, s: Segment) = { - assert(s.p.x != s.q.x) - assert(s.p.x < s.q.x) - val topCross = (tCross == t.top) val bottomCross = (bCross == t.bottom) val trapezoids = new Array[Trapezoid](2) - trapezoids(0) = if(topCross) t.upperLeft else new Trapezoid(t.leftPoint, t.rightPoint, t.top, s) - trapezoids(1) = if(bottomCross) t.lowerLeft else new Trapezoid(t.leftPoint, t.rightPoint, s, t.bottom) + trapezoids(0) = if(topCross) t.upperLeft else new Trapezoid(t.leftPoint.clone, t.rightPoint.clone, t.top, s) + trapezoids(1) = if(bottomCross) t.lowerLeft else new Trapezoid(t.leftPoint.clone, t.rightPoint.clone, s, t.bottom) if(topCross) { trapezoids(0).upperRight = t.upperRight if(t.upperRight != null) t.upperRight.upperLeft = trapezoids(0) - trapezoids(0).rightPoint = t.rightPoint + trapezoids(0).rightPoint = t.rightPoint.clone } else { trapezoids(0).update(t.upperLeft, s.above, t.upperRight, null) } @@ -134,7 +128,7 @@ class TrapezoidalMap { if(bottomCross) { trapezoids(1).lowerRight = t.lowerRight if(t.lowerRight != null) t.lowerRight.lowerLeft = trapezoids(1) - trapezoids(1).rightPoint = t.rightPoint + trapezoids(1).rightPoint = t.rightPoint.clone } else { trapezoids(1).update(s.below, t.lowerLeft, null, t.lowerRight) } @@ -150,27 +144,25 @@ class TrapezoidalMap { // Case 4: Trapezoid contains point q, p lies outside // break trapezoid into 3 smaller trapezoids def case4(t: Trapezoid, s: Segment) = { - - assert(s.p.x < s.q.x) val topCross = (tCross == t.top) val bottomCross = (bCross == t.bottom) val trapezoids = new Array[Trapezoid](3) - trapezoids(0) = if(topCross) t.upperLeft else new Trapezoid(t.leftPoint, s.q, t.top, s) - trapezoids(1) = if(bottomCross) t.lowerLeft else new Trapezoid(t.leftPoint, s.q, s, t.bottom) - trapezoids(2) = new Trapezoid(s.q, t.rightPoint, t.top, t.bottom) + trapezoids(0) = if(topCross) t.upperLeft else new Trapezoid(t.leftPoint.clone, s.q.clone, t.top, s) + trapezoids(1) = if(bottomCross) t.lowerLeft else new Trapezoid(t.leftPoint.clone, s.q.clone, s, t.bottom) + trapezoids(2) = new Trapezoid(s.q.clone, t.rightPoint.clone, t.top, t.bottom) if(topCross) { trapezoids(0).upperRight = trapezoids(2) - trapezoids(0).rightPoint = s.q + trapezoids(0).rightPoint = s.q.clone } else { trapezoids(0).update(t.upperLeft, s.above, trapezoids(2), null) } if(bottomCross) { trapezoids(1).lowerRight = trapezoids(2) - trapezoids(1).rightPoint = s.q + trapezoids(1).rightPoint = s.q.clone } else { trapezoids(1).update(s.below, t.lowerLeft, null, trapezoids(2)) } @@ -186,24 +178,24 @@ class TrapezoidalMap { // Create an AABB around segments def boundingBox(segments: ArrayBuffer[Segment]): Trapezoid = { - var max = segments(0).p + margin - var min = segments(0).q - margin + var max = segments(0).p.clone + margin + var min = segments(0).q.clone - margin for(s <- segments) { - if(s.p.x > max.x) max = Point(s.p.x + margin, max.y) - if(s.p.y > max.y) max = Point(max.x, s.p.y + margin) - if(s.q.x > max.x) max = Point(s.q.x+margin, max.y) - if(s.q.y > max.y) max = Point(max.x, s.q.y+margin) - if(s.p.x < min.x) min = Point(s.p.x-margin, min.y) - if(s.p.y < min.y) min = Point(min.x, s.p.y-margin) - if(s.q.x < min.x) min = Point(s.q.x-margin, min.y) - if(s.q.y < min.y) min = Point(min.x, s.q.y-margin) + if(s.p.clone.x > max.x) max = Point(s.p.x + margin, max.y) + if(s.p.clone.y > max.y) max = Point(max.x, s.p.y + margin) + if(s.q.clone.x > max.x) max = Point(s.q.x+margin, max.y) + if(s.q.clone.y > max.y) max = Point(max.x, s.q.y+margin) + if(s.p.clone.x < min.x) min = Point(s.p.x-margin, min.y) + if(s.p.clone.y < min.y) min = Point(min.x, s.p.y-margin) + if(s.q.clone.x < min.x) min = Point(s.q.x-margin, min.y) + if(s.q.clone.y < min.y) min = Point(min.x, s.q.y-margin) } val top = new Segment(Point(min.x, max.y), Point(max.x, max.y)) val bottom = new Segment(Point(min.x, min.y), Point(max.x, min.y)) - val left = bottom.p - val right = bottom.q + val left = bottom.p.clone + val right = bottom.q.clone return new Trapezoid(left, right, top, bottom) } diff --git a/src/org/poly2tri/Triangulator.scala b/src/org/poly2tri/Triangulator.scala index 6134c4e..b4b0353 100644 --- a/src/org/poly2tri/Triangulator.scala +++ b/src/org/poly2tri/Triangulator.scala @@ -122,7 +122,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) { val mountain = new MonotoneMountain val k = Util.msort((p1: Point, p2: Point) => p1 < p2)(s.mPoints.toList) val points = s.p :: k ::: List(s.q) - points.foreach(p => mountain += p.clone) + points.foreach(p => mountain += p) mountain.triangulate xMonoPoly += mountain } @@ -147,9 +147,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) { segs += new Segment(s.p.clone, s.q.clone) // Randomized triangulation improves performance // See Seidel's paper, or O'Rourke's book, p. 57 - // Turn this off for now because of pointer bug somewhere in DAG? - // The solution to this bug may be more apparent with a better Trapezoidal Map - // data structure... Maybe a modified doubly connected edge list? + // Turn this off for now because of pointer bug somewhere in DAG / trapezoidal map //Random.shuffle(segs) segs }