mirror of
				https://github.com/jhasse/poly2tri.git
				synced 2025-10-31 04:27:09 +01:00 
			
		
		
		
	bug hunting
This commit is contained in:
		| @@ -232,7 +232,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { | ||||
|     | ||||
|   def loadModel(model: String, scale: Float, center: Point, maxTriangles: Int) { | ||||
|      | ||||
|     println("*** " + model + " ***") | ||||
|     println | ||||
|     println("************** " + model + " **************") | ||||
|      | ||||
|     polyX = new ArrayBuffer[Float] | ||||
|     polyY = new ArrayBuffer[Float] | ||||
| @@ -259,11 +260,16 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { | ||||
|       segments += new Segment(points(i), points(i+1)) | ||||
|     segments += new Segment(points.first, points.last) | ||||
|      | ||||
|     slCDT = CDT.init(points) | ||||
|      | ||||
|     println("Number of points = " + polyX.size) | ||||
|     println | ||||
|       | ||||
|      | ||||
|     val t1 = System.nanoTime | ||||
|     slCDT = CDT.init(points) | ||||
|     val runTime = System.nanoTime - t1 | ||||
|     println("CDT average (ms) =  " + runTime*1e-6) | ||||
| 	println("Number of triangles = " + slCDT.triangles.size) | ||||
|     println | ||||
|      | ||||
|     if(!drawEarClip) {   | ||||
|        | ||||
| 	    // Sediel triangulation | ||||
|   | ||||
| @@ -36,7 +36,6 @@ import shapes.{Point, Triangle} | ||||
| class AFront(iTriangle: Triangle) { | ||||
|  | ||||
|   // Doubly linked list | ||||
|   // TODO: Replace with a Red-Black Tree for better performance | ||||
|   var head = new Node(iTriangle.points(1), iTriangle) | ||||
|   head.next = new Node(iTriangle.points(0), iTriangle) | ||||
|   var tail = new Node(iTriangle.points(2), null) | ||||
| @@ -44,6 +43,7 @@ class AFront(iTriangle: Triangle) { | ||||
|   head.next.next = tail | ||||
|   tail.prev = head.next | ||||
|    | ||||
|   // TODO: Usea Red-Black Tree or interval tree for better search performance! | ||||
|   def locate(point: Point): Node = { | ||||
|     var node = head | ||||
|     while(node != tail) { | ||||
| @@ -76,14 +76,8 @@ class AFront(iTriangle: Triangle) { | ||||
|    | ||||
| } | ||||
|  | ||||
| // Advancing front node | ||||
| class Node(val point: Point, var triangle: Triangle) { | ||||
|  | ||||
|   var next: Node = null | ||||
|   var prev: Node = null | ||||
|    | ||||
|   def printDebug { | ||||
|     println("Point: " + point) | ||||
|     if(triangle != null) | ||||
|       println("Triangle points: " + triangle.points) | ||||
|   } | ||||
| } | ||||
| @@ -36,7 +36,7 @@ import shapes.{Segment, Point, Triangle} | ||||
| import utils.Util | ||||
|  | ||||
| /** | ||||
|  * Sweep-line, Constrained Delauney Triangulation | ||||
|  * Sweep-line, Constrained Delauney Triangulation (CDT) | ||||
|  * See: Domiter, V. and Žalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', | ||||
|  *      International Journal of Geographical Information Science,22:4,449 — 462 | ||||
|  */ | ||||
| @@ -124,7 +124,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|    | ||||
|   // Implement sweep-line  | ||||
|   private def sweep { | ||||
|     for(i <- 1 until 11 /*points.size*/) { | ||||
|     for(i <- 1 until points.size) { | ||||
|       val point = points(i) | ||||
|       // Process Point event | ||||
|       val triangle = pointEvent(point) | ||||
| @@ -137,9 +137,8 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|   private def pointEvent(point: Point): Triangle = { | ||||
|      | ||||
|     val node = aFront.locate(point) | ||||
|     var newNode: Node = null | ||||
|      | ||||
|     if(point.x == node.point.x) { | ||||
|          | ||||
|     if(point.x == node.point.x && node != aFront.head) { | ||||
|        | ||||
|         // Projected point coincides with existing point; create two triangles | ||||
|     	val rPts = Array(point, node.point, node.next.point) | ||||
| @@ -163,11 +162,15 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|         node.prev.triangle.updateNeighbors(node.point, node.prev.point, rTriangle) | ||||
|          | ||||
|         // Update advancing front | ||||
|         newNode = aFront.insert(point, rTriangle, node) | ||||
|         val newNode = aFront.insert(point, rTriangle, node) | ||||
|         aFront -= (node.prev, node, rTriangle) | ||||
|          | ||||
|         // Fill in adjacent triangles if required | ||||
| 	    scanAFront(newNode) | ||||
|       | ||||
| 	    newNode.triangle | ||||
|       | ||||
|     } else {  | ||||
|        | ||||
|       | ||||
|         // Projected point hits advancing front; create new triangle  | ||||
| 	    val cwPoint = node.next.point | ||||
| 	    val ccwPoint = node.point | ||||
| @@ -181,16 +184,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|         // Legalize | ||||
| 	    legalization(triangle, nTri) | ||||
|         // Update neighbor pointers | ||||
| 	    nTri.updateNeighbors(ccwPoint, cwPoint, triangle) | ||||
| 	    nTri.updateNeighbors(triangle.points(1), triangle.points(2), triangle) | ||||
|         // Update advancing front | ||||
|         newNode = aFront.insert(point, triangle, node) | ||||
|          | ||||
|         val newNode = aFront.insert(point, triangle, node) | ||||
|         // Fill in adjacent triangles if required | ||||
| 	    scanAFront(newNode) | ||||
|       | ||||
| 	    newNode.triangle | ||||
| 	} | ||||
|      | ||||
|     // Fill in adjacent triangles if required | ||||
|     scan(newNode) | ||||
|     newNode.triangle | ||||
|      | ||||
|   } | ||||
|    | ||||
|   // EdgeEvent | ||||
| @@ -198,49 +199,58 @@ 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 | ||||
|     // STEP 3: Triangulate empty areas. | ||||
|     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(e) | ||||
|        // Remove from the mesh | ||||
|         | ||||
|        // TODO: Implement this section | ||||
|        //triangles.foreach(t => mesh.map -= t) | ||||
|        | ||||
|     } else if(firstTriangle == null) { | ||||
|        | ||||
|       // Traverse the AFront, and build triangles | ||||
|       var node = aFront.locate(edge.q) | ||||
|       node = node.next | ||||
|       val points = new ArrayBuffer[Point] | ||||
|       // No triangles are intersected by the edge; edge must lie outside the mesh | ||||
|       // Apply constraint; traverse the AFront, and build triangles | ||||
|        | ||||
|       if(edge.p.x > edge.q.x) { | ||||
|         // Search right | ||||
|         while(node != null && node.point != edge.p) { | ||||
|           // Collect points | ||||
|           points += node.point | ||||
|           node = node.next | ||||
|         } | ||||
|       } else { | ||||
|         // Search left | ||||
|         while(node != null && node.point != edge.p) { | ||||
|           // Collect points | ||||
|           points += node.point | ||||
|           node = node.prev | ||||
|         } | ||||
|       } | ||||
|       val ahead = (edge.p.x > edge.q.x) | ||||
|       val point1 = if(ahead) edge.q else edge.p | ||||
|       val point2 = if(ahead) edge.p else edge.q | ||||
|        | ||||
|       val points = new ArrayBuffer[Point] | ||||
|       var node = aFront.locate(point1) | ||||
|       val node1 = node | ||||
|        | ||||
|       node = node.next | ||||
|        | ||||
| 	  while(node.point != point2) { | ||||
| 		points += node.point | ||||
| 		node = node.next | ||||
| 	  } | ||||
|        | ||||
|       val node2 = node | ||||
|        | ||||
|       val T = new ArrayBuffer[Triangle] | ||||
|       angladaTPD(points.toArray, List(edge.p, edge.q), T) | ||||
|       T.foreach(t => mesh.debug += t) | ||||
|       angladaTPD(points.toArray, List(point1, point2), T) | ||||
|        | ||||
|       node1.triangle = T.first | ||||
|       node1.next = node2 | ||||
|       node2.prev = node1 | ||||
|  | ||||
|       T.foreach(t => mesh.map += t) | ||||
|                  | ||||
|     } | ||||
|      | ||||
|     // STEP 3: Triangulate empty areas. | ||||
|      | ||||
|   } | ||||
|    | ||||
|   // Marc Vigo Anglada's triangulatePseudopolygonDelaunay algo  | ||||
|   // TODO: Bugy fix - works for a single triangle  | ||||
|   def angladaTPD(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) { | ||||
|      | ||||
|     val a = ab.first | ||||
| @@ -263,13 +273,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|     if(!P.isEmpty) { | ||||
|       c = P.first | ||||
|       val points = Array(a, b, c) | ||||
|       // TODO: Correctly update neighbor pointers | ||||
|       val neighbors = new Array[Triangle](3) | ||||
|       T += new Triangle(points, neighbors) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Scan left and right along AFront to fill holes | ||||
|   def scan(n: Node) { | ||||
|   def scanAFront(n: Node) { | ||||
|      | ||||
|     var node = n.next | ||||
|     // Update right | ||||
| @@ -294,6 +305,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|    | ||||
|   // Fill empty space with a triangle | ||||
|   def fill(node: Node): Double = { | ||||
|      | ||||
| 	  val a = (node.prev.point - node.point) | ||||
| 	  val b = (node.next.point - node.point) | ||||
| 	  val angle = Math.abs(Math.atan2(a cross b, a dot b)) | ||||
| @@ -312,6 +324,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|    | ||||
|   // Do edges need to be swapped? | ||||
|   private def illegal(p1: Point, p2: Point, p3: Point, p4:Point): Boolean = { | ||||
|      | ||||
| 	  val v1 = p3 - p2 | ||||
|       val v2 = p1 - p2 | ||||
|       val v3 = p1 - p4 | ||||
| @@ -322,28 +335,42 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian | ||||
|         false | ||||
|   } | ||||
|    | ||||
|   // Ensure new adjacent triangles are legal | ||||
|   // Ensure adjacent triangles are legal | ||||
|   // If illegal, flip edges and update triangle's pointers | ||||
|   private def legalization(t1: Triangle, t2: Triangle) { | ||||
|      | ||||
|     val oPoint = t2 oppositePoint t1 | ||||
|      | ||||
|     if(illegal(t1.points(1), oPoint, t1.points(2), t1.points(0))) { | ||||
|          | ||||
| 	    // Flip edges and rotate everything clockwise | ||||
| 	    val point = t1.points(0) | ||||
| 	    t1.points(1) = t1.points(0) | ||||
| 	    t1.points(0) = t1.points(2) | ||||
| 	    t1.points(2) = oPoint     | ||||
| 	    val tmp = t2.points(1) | ||||
| 	    t2.points(1) = point | ||||
| 	    t2.points(0) = t2.points(2) | ||||
| 	    t2.points(2) = tmp | ||||
| 	     | ||||
| 	    t1.updatePoints | ||||
| 	    t2.updatePoints | ||||
| 	    // TODO: Rotate neighbors | ||||
| 	    println("legalize") | ||||
|         val point = t1.points(0) | ||||
| 	    t1.legalize(oPoint)  | ||||
| 	    t2.legalize(oPoint, point) | ||||
| 	    | ||||
| 	    // TODO: Make sure this is correct | ||||
|         val cwNeighbor = t2.neighborCW(oPoint) | ||||
|         val ccwNeighbor = t2.neighborCCW(oPoint) | ||||
|          | ||||
|         t1.neighbors(0) = t2 | ||||
| 	    t1.neighbors(1) = cwNeighbor | ||||
|         t1.neighbors(2) = null | ||||
|          | ||||
| 	    if(t2.points(0) == oPoint) { | ||||
| 	      t2.neighbors(0) = null | ||||
|           t2.neighbors(1) = ccwNeighbor | ||||
|           t2.neighbors(2) = t1 | ||||
| 	    } else { | ||||
| 	      t2.neighbors(0) = ccwNeighbor | ||||
|           t2.neighbors(1) = t1 | ||||
|           t2.neighbors(2) = null | ||||
| 	    } | ||||
|     } | ||||
|   } | ||||
|   | ||||
|   // Final step in the sweep-line CDT algo | ||||
|   private def finalization { | ||||
|      | ||||
|   } | ||||
|    | ||||
| } | ||||
|   | ||||
| @@ -38,12 +38,14 @@ import scala.collection.mutable.ArrayBuffer | ||||
| class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { | ||||
|  | ||||
|   var ik, ij , jk, ji, kj, ki: Point = null | ||||
|   updatePoints | ||||
|   updateEdges | ||||
|    | ||||
|   // Flags to determine if an edge is the final Delauney edge | ||||
|   val edges = new Array[Boolean](3) | ||||
|    | ||||
|   def updatePoints { | ||||
|   // Update the edges that consitite this triangle | ||||
|   // May change during legalization | ||||
|   def updateEdges { | ||||
|     ik = points(2) - points(0) | ||||
|     ij = points(1) - points(0) | ||||
|     jk = points(2) - points(1) | ||||
| @@ -89,9 +91,10 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { | ||||
|     true | ||||
|   } | ||||
|  | ||||
|   // Locate first triangle crossed by constrained edge | ||||
|   def locateFirst(edge: Segment): Triangle = { | ||||
|     val p = edge.p | ||||
|     if(contains(p) || contains(edge)) return this | ||||
|     if(contains(p)) return this | ||||
|     val q = edge.q | ||||
|     val e = p - q | ||||
|     if(q == points(0)) { | ||||
| @@ -113,6 +116,7 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { | ||||
|     null | ||||
|   } | ||||
|    | ||||
|   // Locate next triangle crossed by constraied edge | ||||
|   def findNeighbor(e: Point): Triangle = { | ||||
|     var sameSign = Math.signum(ik cross e) == Math.signum(ij cross e) | ||||
|     if(!sameSign) return neighbors(0) | ||||
| @@ -123,6 +127,52 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { | ||||
|     this | ||||
|   } | ||||
|    | ||||
|   // The neighbor CW to given point | ||||
|   def neighborCW(point: Point): Triangle = { | ||||
|     if(point == points(0)) { | ||||
|       neighbors(2) | ||||
|     }else if(point == points(1)) { | ||||
|       neighbors(0) | ||||
|     } else  | ||||
|       neighbors(1) | ||||
|   } | ||||
|    | ||||
|   // The neighbor CW to given point | ||||
|   def neighborCCW(point: Point): Triangle = { | ||||
|     if(point == points(0)) { | ||||
|       neighbors(1) | ||||
|     }else if(point == points(1)) { | ||||
|       neighbors(2) | ||||
|     } else  | ||||
|       neighbors(0) | ||||
|   } | ||||
|    | ||||
|   // Legalized triangle by rotating clockwise around point(0) | ||||
|   def legalize(oPoint: Point) { | ||||
| 	points(1) = points(0) | ||||
| 	points(0) = points(2) | ||||
| 	points(2) = oPoint | ||||
|     updateEdges | ||||
|   } | ||||
|    | ||||
|   // Legalize triagnle by rotating clockwise around oPoint | ||||
|   def legalize(oPoint: Point, nPoint: Point) { | ||||
|     if(oPoint == points(0)) { | ||||
|       points(1) = points(0) | ||||
|       points(0) = points(2) | ||||
|       points(2) = nPoint  | ||||
|     } else if (oPoint == points(1)) { | ||||
|       points(2) = points(1) | ||||
|       points(1) = points(0) | ||||
|       points(0) = nPoint | ||||
|     } else { | ||||
|       points(0) = points(2) | ||||
|       points(2) = points(1) | ||||
|       points(1) = nPoint | ||||
|     } | ||||
|     updateEdges | ||||
|   } | ||||
|    | ||||
|   def printDebug { | ||||
|     println("**************") | ||||
|     println(points(0) + "," + points(1) + "," + points(2)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 zzzzrrr
					zzzzrrr