bug hunting

This commit is contained in:
zzzzrrr 2009-08-10 16:30:37 -04:00
parent a6b338d88d
commit f06c23d4e8
5 changed files with 153 additions and 62 deletions

View File

@ -170,7 +170,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
}) })
if(drawCDT) { if(drawCDT) {
val draw = if(drawcdtMesh) slCDT.triangleMesh else slCDT.triangles //val draw = if(drawcdtMesh) slCDT.triangleMesh else slCDT.triangles
val draw = slCDT.testTri
draw.foreach( t => { draw.foreach( t => {
val triangle = new Polygon val triangle = new Polygon
triangle.addPoint(t.points(0).x, t.points(0).y) triangle.addPoint(t.points(0).x, t.points(0).y)

View File

@ -30,6 +30,8 @@
*/ */
package org.poly2tri.cdt package org.poly2tri.cdt
import scala.collection.mutable.ArrayBuffer
import shapes.{Point, Triangle} import shapes.{Point, Triangle}
// Advancing front // Advancing front
@ -87,7 +89,94 @@ class AFront(iTriangle: Triangle) {
node node
} }
def constrainedEdge() { // Update advancing front with constrained edge triangles
def constrainedEdge(sNode: Node, eNode: Node, T1: ArrayBuffer[Triangle],
T2: ArrayBuffer[Triangle]): Triangle = {
var node = sNode
var t1r, t2r = false
while(node != eNode) {
T2.foreach(t => {
if(t.contains(node.point, node.next.point)) {
node.triangle = t
t2r = true
}
})
if(!t2r)
T1.foreach(t => {
if(t.contains(node.point, node.next.point)) {
node.triangle = t
t1r = true
}
})
node = node.next
}
if(t1r && !t2r)
T1.first
else if(t2r && !t1r)
T2.first
else
throw new Exception("edge insertion error")
}
// Update advancing front with qNode
def constrainedEdge(qNode: Node, tList: ArrayBuffer[Triangle], T1: ArrayBuffer[Triangle],
T2: ArrayBuffer[Triangle]): Triangle = {
var t1r, t2r = false
for(t <- tList) {
if(qNode.triangle == t) {
val p1 = qNode.point
val p2 = qNode.next.point
T2.foreach(tri => if(tri.contains(p1, p2)) {
qNode.triangle = tri
t2r = true
})
if(!t2r)
T1.foreach(tri => if(tri.contains(p1, p2)) {
qNode.triangle = tri
t1r = true
})
} else if(qNode.prev.triangle == t) {
val p1 = qNode.prev.point
val p2 = qNode.point
T2.foreach(tri => if(tri.contains(p1, p2)) {
qNode.prev.triangle = tri
t2r = true
})
if(!t2r)
T1.foreach(tri => if(tri.contains(p1, p2)) {
qNode.prev.triangle = tri
t1r = true
})
} else if(qNode.next.triangle == t) {
throw new Exception("unanticipated edge event!")
}
}
if(t1r && !t2r)
T1.first
else if(t2r && !t1r)
T2.first
else
throw new Exception("edge insertion error")
} }
@ -98,6 +187,12 @@ class AFront(iTriangle: Triangle) {
node.triangle = triangle node.triangle = triangle
} }
def link(node1: Node, node2: Node, t: Triangle) {
node1.next = node2
node2.prev = node1
node1.triangle = t
}
def basin(node: Node) { def basin(node: Node) {
if(node.next != tail) { if(node.next != tail) {
val p1 = node.point val p1 = node.point

View File

@ -128,6 +128,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Finalize triangulation // Finalize triangulation
finalization finalization
val testTri = new ArrayBuffer[Triangle]
val p1 = Point(200, 300)
val p2 = Point(500, 300)
val p3 = Point(250, 500)
val p4 = Point(350, 400)
val p5 = Point(400, 350)
val pts = Array(p3, p4, p5)
triangulate(pts, List(p1, p2), testTri)
// Implement sweep-line // Implement sweep-line
private def sweep { private def sweep {
@ -136,7 +148,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Process Point event // Process Point event
var triangle = pointEvent(point) var triangle = pointEvent(point)
// Process edge events // Process edge events
//point.edges.foreach(e => triangle = edgeEvent(e, triangle)) point.edges.foreach(e => triangle = edgeEvent(e, triangle))
if(i == CDT.clearPoint) {cleanTri = triangle; mesh.debug += cleanTri} if(i == CDT.clearPoint) {cleanTri = triangle; mesh.debug += cleanTri}
} }
} }
@ -231,39 +243,15 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Update advancing front // Update advancing front
val qNode = aFront.locatePoint(edge.q) var first: Triangle = null
val pNode = aFront.locatePoint(edge.p) val sNode = aFront.locatePoint(point1)
val eNode = aFront.locatePoint(point2)
// TODO: Make this more robust....
for(t <- tList) {
if(qNode.triangle == t) {
val p1 = qNode.point
val p2 = qNode.next.point
T1.foreach(tri => if(tri.contains(p1, p2)) qNode.triangle = tri)
T2.foreach(tri => if(tri.contains(p1, p2)) qNode.triangle = tri)
} else if(qNode.prev.triangle == t) {
val p1 = qNode.prev.point
val p2 = qNode.point
T1.foreach(tri => if(tri.contains(p1, p2)) qNode.prev.triangle = tri)
T2.foreach(tri => if(tri.contains(p1, p2)) qNode.prev.triangle = tri)
}
if(pNode != null) {
if(pNode.triangle == t) {
val p1 = pNode.point
val p2 = pNode.next.point
T1.foreach(tri => if(tri.contains(p1, p2)) pNode.triangle = tri)
T2.foreach(tri => if(tri.contains(p1, p2)) pNode.triangle = tri)
} else if(pNode.prev.triangle == t) {
val p1 = pNode.point
val p2 = pNode.prev.point
T1.foreach(tri => if(tri.contains(p1, p2)) pNode.prev.triangle = tri)
T2.foreach(tri => if(tri.contains(p1, p2)) pNode.prev.triangle = tri)
}
}
if(sNode != null && eNode != null) {
first = aFront.constrainedEdge(sNode, eNode, T1, T2)
} else {
val qNode = if(sNode == null) eNode else sNode
first = aFront.constrainedEdge(qNode, tList, T1, T2)
} }
// Update neighbors // Update neighbors
@ -275,7 +263,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
T2.first.mark(point1, point2) T2.first.mark(point1, point2)
// Double check returning T2.first vs T1.first // Double check returning T2.first vs T1.first
T2.first first
} else if(firstTriangle == null) { } else if(firstTriangle == null) {
@ -283,6 +271,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Apply constraint; traverse the AFront, and build triangles // Apply constraint; traverse the AFront, and build triangles
val ahead = (edge.p.x > edge.q.x) val ahead = (edge.p.x > edge.q.x)
val point1 = if(ahead) edge.q else edge.p val point1 = if(ahead) edge.q else edge.p
val point2 = if(ahead) edge.p else edge.q val point2 = if(ahead) edge.p else edge.q
@ -310,7 +299,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
triangulate(points.toArray, endPoints, T) triangulate(points.toArray, endPoints, T)
// Update advancing front // Update advancing front
aFront -= (first, node.prev, T.first) aFront link (first, node, T.first)
// Update neighbors // Update neighbors
edgeNeighbors(nTriangles, T) edgeNeighbors(nTriangles, T)
@ -318,6 +307,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Mark constrained edge // Mark constrained edge
T.first mark(edge.p, edge.q) T.first mark(edge.p, edge.q)
// Return original triangle
triangle triangle
} else { } else {
@ -347,9 +337,9 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val a = ab.first val a = ab.first
val b = ab.last val b = ab.last
var c = if(!P.isEmpty) P.first else null
if(P.size > 1) { if(P.size > 1) {
var c = P.first
var i = 0 var i = 0
for(j <- 1 until P.size) { for(j <- 1 until P.size) {
if(illegal(a, c, b, P(j))) { if(illegal(a, c, b, P(j))) {
@ -358,13 +348,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
} }
} }
val PE = P.slice(0, i) val PE = P.slice(0, i)
val PD = P.slice(i, P.size-1) val PD = P.slice(i+1, P.size)
triangulate(PE, List(a, c), T) triangulate(PE, List(a, c), T)
triangulate(PD, List(c, b), T) triangulate(PD, List(c, b), T)
} }
if(!P.isEmpty) { if(!P.isEmpty) {
val points = Array(a, P.first, b) val left = if(Util.orient(a, b, c) > 0) true else false
val p2 = if(left) c else b
val p3 = if(left) b else c
val points = Array(a, p2, p3)
T += new Triangle(points) T += new Triangle(points)
mesh.map += T.last mesh.map += T.last
} }

View File

@ -49,28 +49,14 @@ class Triangle(val points: Array[Point]) {
var clean = false var clean = false
// Update neighbor pointers // Update neighbor pointers
// Debug version private def markNeighbor(p1: Point, p2: Point, t: Triangle) {
def markNeighbor(p1: Point, p2: Point, triangle: Triangle, debug: HashSet[Triangle]) { assert(t != this, "self-pointer error")
if((p1 == points(2) && p2 == points(1)) || (p1 == points(1) && p2 == points(2))) if((p1 == points(2) && p2 == points(1)) || (p1 == points(1) && p2 == points(2)))
neighbors(0) = triangle neighbors(0) = t
else if((p1 == points(0) && p2 == points(2)) || (p1 == points(2) && p2 == points(0))) else if((p1 == points(0) && p2 == points(2)) || (p1 == points(2) && p2 == points(0)))
neighbors(1) = triangle neighbors(1) = t
else if((p1 == points(0) && p2 == points(1)) || (p1 == points(1) && p2 == points(0))) else if((p1 == points(0) && p2 == points(1)) || (p1 == points(1) && p2 == points(0)))
neighbors(2) = triangle neighbors(2) = t
else {
debug += triangle
println("Neighbor pointer ERROR!")
}
}
// Update neighbor pointers
private def markNeighbor(p1: Point, p2: Point, triangle: Triangle) {
if((p1 == points(2) && p2 == points(1)) || (p1 == points(1) && p2 == points(2)))
neighbors(0) = triangle
else if((p1 == points(0) && p2 == points(2)) || (p1 == points(2) && p2 == points(0)))
neighbors(1) = triangle
else if((p1 == points(0) && p2 == points(1)) || (p1 == points(1) && p2 == points(0)))
neighbors(2) = triangle
else { else {
throw new Exception("Neighbor pointer error, please report!") throw new Exception("Neighbor pointer error, please report!")
} }
@ -78,6 +64,7 @@ class Triangle(val points: Array[Point]) {
/* Exhaustive search to update neighbor pointers */ /* Exhaustive search to update neighbor pointers */
def markNeighbor(t: Triangle) { def markNeighbor(t: Triangle) {
assert(t != this, "self-pointer error")
if (t.contains(points(1), points(2))) { if (t.contains(points(1), points(2))) {
neighbors(0) = t neighbors(0) = t
t.markNeighbor(points(1), points(2), this) t.markNeighbor(points(1), points(2), this)
@ -95,13 +82,16 @@ class Triangle(val points: Array[Point]) {
} }
def oppositePoint(t: Triangle): Point = { def oppositePoint(t: Triangle): Point = {
assert(t != this, "self-pointer error")
if(points(0) == t.points(1)) if(points(0) == t.points(1))
points(1) points(1)
else if(points(0) == t.points(2)) else if(points(0) == t.points(2))
points(2) points(2)
else if((points(2) == t.points(1) && points(1) == t.points(2)) || (points(1) == t.points(1) && points(2) == t.points(2))) else if(contains(t.points(1), t.points(2)))
points(0) points(0)
else { else {
t.printDebug
printDebug
throw new Exception("Point location error, please report") throw new Exception("Point location error, please report")
} }

View File

@ -49,6 +49,18 @@ object Util {
} }
// Return: positive if point p is left of ab
// negative if point p is right of ab
// zero if points are colinear
// See: http://www-2.cs.cmu.edu/~quake/robust.html
def orient(b: Point, a: Point, p: Point): Float = {
val acx = a.x - p.x
val bcx = b.x - p.x
val acy = a.y - p.y
val bcy = b.y - p.y
acx * bcy - acy * bcx
}
} }
/** The object <code>Random</code> offers a default implementation /** The object <code>Random</code> offers a default implementation