mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-12-02 10:13:29 +01:00
bug hunting
This commit is contained in:
parent
a6b338d88d
commit
f06c23d4e8
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user