diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index 80d5cbd..2981aa2 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -160,6 +160,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { g.setColor(red) g.draw(triangle) }) + slCDT.debugTriangles.foreach( t => { + val triangle = new Polygon + triangle.addPoint(t.points(0).x, t.points(0).y) + triangle.addPoint(t.points(1).x, t.points(1).y) + triangle.addPoint(t.points(2).x, t.points(2).y) + g.setColor(blue) + g.draw(triangle) + }) } if(drawSegs) { diff --git a/src/org/poly2tri/cdt/AFront.scala b/src/org/poly2tri/cdt/AFront.scala index 66509be..9f8ea67 100644 --- a/src/org/poly2tri/cdt/AFront.scala +++ b/src/org/poly2tri/cdt/AFront.scala @@ -47,11 +47,11 @@ class AFront(iTriangle: Triangle) { def locate(point: Point): Node = { var node = head while(node != tail) { - if(point.x >= node.point.x && point.x <= node.next.point.x) + if(point.x >= node.point.x && point.x < node.next.point.x) return node node = node.next } - throw new Exception("Advancing front error") + throw new Exception("Advancing front error: point not found") } def insert(tuple: Tuple3[Point, Triangle, Node]) = { diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index d8a4001..4f6a840 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -108,6 +108,8 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Triangle list def triangles = mesh.map + def debugTriangles = mesh.debug + // The triangle mesh private val mesh = new Mesh(iTriangle) // Advancing front @@ -122,13 +124,12 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Implement sweep-line private def sweep { - for(i <- 1 until points.size) { + for(i <- 1 until 10 /*points.size*/) { val point = points(i) // Process Point event - //val triangle = - pointEvent(point) + val triangle = pointEvent(point) // Process edge events - //point.edges.foreach(e => edgeEvent(e, triangle)) + point.edges.foreach(e => edgeEvent(e, triangle)) } } @@ -136,6 +137,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian private def pointEvent(point: Point): Triangle = { val node = aFront.locate(point) + // Neightbor points (ccw & cw) and triangle(i) val cwPoint = node.next.point val ccwPoint = node.point @@ -167,40 +169,76 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // STEP 1: Locate the first intersected triangle val firstTriangle = triangle.locateFirst(edge) + // STEP 2: Remove intersected triangles if(firstTriangle != null && !firstTriangle.contains(edge)) { // Collect intersected triangles val triangles = new ArrayBuffer[Triangle] triangles += firstTriangle + val e = edge.p - edge.q while(!triangles.last.contains(edge.p)) - triangles += triangles.last.findNeighbor(edge.p - edge.q) + triangles += triangles.last.findNeighbor(e) // Remove from the mesh - triangles.foreach(t => mesh.map -= t) + //triangles.foreach(t => mesh.map -= t) } else if(firstTriangle == null) { // Traverse the AFront, and build triangle list - var node = aFront.locate(edge.q) + node = node.next + val points = new ArrayBuffer[Point] if(edge.p.x > edge.q.x) { // Search right while(node.point != edge.p) { // Collect points + points += node.point node = node.next } } else { // Search left while(node.point != edge.p) { // Collect points + points += node.point node = node.prev } } + val T = new ArrayBuffer[Triangle] + angladaTPD(points.toArray, List(edge.p, edge.q), T) + T.foreach(t => mesh.debug += t) } // STEP 3: Triangulate empty areas. } + // Marc Vigo Anglada's triangulatePseudopolygonDelaunay algo + def angladaTPD(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) { + + val a = ab.first + val b = ab.last + var c: Point = null + if(P.size > 1) { + c = P.first + var i = 0 + for(j <- 1 until P.size) { + if(illegal(a, c, b, P(j))) { + c = P(j) + i = j + } + } + val PE = P.slice(0, i) + val PD = P.slice(i, P.size-1) + angladaTPD(PE, List(a, c), T) + angladaTPD(PD, List(c, b), T) + } + if(!P.isEmpty) { + c = P.first + val points = Array(a, b, c) + val neighbors = new Array[Triangle](3) + T += new Triangle(points, neighbors) + } + } + // Scan left and right along AFront to fill holes def scan(n: Node) { @@ -231,11 +269,11 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian val b = (node.next.point - node.point) val angle = Math.abs(Math.atan2(a cross b, a dot b)) if(angle <= PI_2) { - val points = Array(node.prev.point, node.next.point, node.point) - val neighbors = Array(node.prev.triangle, null, node.triangle) + val points = Array(node.prev.point, node.point, node.next.point) + val neighbors = Array(node.triangle, null, node.prev.triangle) val triangle = new Triangle(points, neighbors) // Update neighbor pointers - node.prev.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle) + node.prev.triangle.updateNeighbors(triangle.points(0), triangle.points(1), triangle) node.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle) mesh.map += triangle aFront -= (node.prev, node, triangle) @@ -250,7 +288,6 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian val v3 = p1 - p4 val v4 = p3 - p4 if((v1 dot v2) < 0 && (v3 dot v4) < 0) - // swap the edge true else false @@ -267,8 +304,11 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian t2.points(1) = point t2.points(0) = t2.points(2) t2.points(2) = tmp - // Rotate neighbors + t1.updatePoints + t2.updatePoints + // TODO: Rotate neighbors + println("legalize") } private def finalization { diff --git a/src/org/poly2tri/cdt/Mesh.scala b/src/org/poly2tri/cdt/Mesh.scala index 5914c47..c728850 100644 --- a/src/org/poly2tri/cdt/Mesh.scala +++ b/src/org/poly2tri/cdt/Mesh.scala @@ -38,6 +38,7 @@ class Mesh(initialTriangle: Triangle) { // Triangles that constitute the mesh val map = HashSet(initialTriangle) + val debug = HashSet.empty[Triangle] def addEdge(point:Point, triangle: Triangle) { /* diff --git a/src/org/poly2tri/shapes/Segment.scala b/src/org/poly2tri/shapes/Segment.scala index d14e44f..de563d8 100644 --- a/src/org/poly2tri/shapes/Segment.scala +++ b/src/org/poly2tri/shapes/Segment.scala @@ -53,14 +53,13 @@ class Segment(var p: Point, var q: Point) { // Update point edge list for CDT def updateEdge { - if(q.y > p.y) { + if(p.y > q.y) { // For CDT we want q to be the point with > y - // val tmp = p - //p = q - //q = tmp - q.edges += this + val tmp = p + p = q + q = tmp } - + q.edges += this } } diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index 5307ed3..284a87f 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -37,16 +37,21 @@ import scala.collection.mutable.ArrayBuffer // "Triangulations in CGAL" class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { - val ik = points(2) - points(0) - val ij = points(1) - points(0) - val jk = points(2) - points(1) - val ji = points(0) - points(1) - val kj = points(1) - points(2) - val ki = points(0) - points(2) - + var ik, ij , jk, ji, kj, ki: Point = null + updatePoints + // Flags to determine if an edge is the final Delauney edge val edges = new Array[Boolean](3) + def updatePoints { + ik = points(2) - points(0) + ij = points(1) - points(0) + jk = points(2) - points(1) + ji = points(0) - points(1) + kj = points(1) - points(2) + ki = points(0) - points(2) + } + // Update neighbor pointers def updateNeighbors(ccwPoint: Point, cwPoint: Point, triangle: Triangle) { if(ccwPoint == points(2) && cwPoint == points(1)) @@ -105,7 +110,7 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { if(neighbors(1) == null) return null return neighbors(1).locateFirst(edge) } - throw new Exception("location error") + null } def findNeighbor(e: Point): Triangle = { @@ -118,4 +123,9 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { this } + def printDebug { + println("**************") + println(points(0) + "," + points(1) + "," + points(2)) + } + }