diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index f9243ae..7eba85c 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -87,7 +87,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { val i18 = "data/i.18" val tank = "data/tank.dat" - var currentModel = tank + var currentModel = strange var doCDT = true var mouseButton = 0 @@ -112,7 +112,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { def render(container: GameContainer, g: Graphics) { - g.drawString("'1-7' to cycle models, mouse to pan & zoom", 10, 520) + g.drawString("'1-8' to cycle models, mouse to pan & zoom", 10, 520) g.drawString("'SPACE' to show Seidel debug info", 10, 532) g.drawString("'m' to show trapezoidal map (Seidel debug mode)", 10, 544) g.drawString("'e' to switch Seidel / EarClip", 10, 556) @@ -305,13 +305,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { CDT.clearPoint = 7 loadModel(i18, 20f, Point(600f, 500f), 20) case "data/nazca_heron.dat" => + doCDT = false; drawCDT = false; drawcdtMesh = false CDT.clearPoint = 7 - loadModel(nazcaHeron, 4.5f, Point(400f, 300f), 1500) + loadModel(nazcaHeron, 4.2f, Point(400f, 300f), 1500) case "data/tank.dat" => //doCDT = false; drawCDT = false; drawcdtMesh = false doCDT = true; drawCDT = true - CDT.clearPoint = 50 - loadModel(tank, -1f, Point(0f, 0f), 10) + CDT.clearPoint = 38 + loadModel(tank, -1f, Point(100f, 0f), 10) case _ => assert(false) } @@ -361,7 +362,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { } if(!drawEarClip) { - + // Sediel triangulation seidel = new Triangulator(segments) diff --git a/src/org/poly2tri/cdt/AFront.scala b/src/org/poly2tri/cdt/AFront.scala index ef9a4af..8d82029 100644 --- a/src/org/poly2tri/cdt/AFront.scala +++ b/src/org/poly2tri/cdt/AFront.scala @@ -32,7 +32,7 @@ package org.poly2tri.cdt import scala.collection.mutable.ArrayBuffer -import shapes.{Point, Triangle} +import shapes.{Point, Triangle, Segment} // Advancing front class AFront(iTriangle: Triangle) { @@ -91,11 +91,13 @@ class AFront(iTriangle: Triangle) { // Update advancing front with constrained edge triangles def constrainedEdge(sNode: Node, eNode: Node, T1: ArrayBuffer[Triangle], - T2: ArrayBuffer[Triangle]): Triangle = { + T2: ArrayBuffer[Triangle], edge: Segment): Triangle = { var node = sNode var t1r, t2r = false + // Scan the advancing front and update Node triangle pointers + // Either T1 OR T2 while(node != eNode) { T2.foreach(t => { @@ -115,68 +117,44 @@ class AFront(iTriangle: Triangle) { 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 = { + val point1 = edge.q + val point2 = edge.p - var t1r, t2r = false + // Select edge triangles - 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!") - } - - } + var edgeTri1: Triangle = null + var i = 0 + while(edgeTri1 == null) { + if(T1(i).contains(point1, point2)) + edgeTri1 = T1(i) + i += 1 + } + + // Mark constrained edge + edgeTri1 markEdge(point1, point2) + + var edgeTri2: Triangle = null + i = 0 + while(edgeTri2 == null) { + if(T2(i).contains(point1, point2)) + edgeTri2 = T2(i) + i += 1 + } + + // Mark constrained edge + edgeTri2 markEdge(point1, point2) + + // Update neighbor pointer + edgeTri1.markNeighbor(edgeTri2) if(t1r && !t2r) - T1.first - else if(t2r && !t1r) - T2.first - else + edgeTri1 + else if(t2r && !t1r) { + edgeTri2 + } else { throw new Exception("edge insertion error") + } } @@ -193,6 +171,7 @@ class AFront(iTriangle: Triangle) { node1.triangle = t } + // NOT IMPLEMENTED def basin(node: Node) { if(node.next != tail) { val p1 = node.point diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index d1d52b8..0a2834b 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -30,7 +30,7 @@ */ package org.poly2tri.cdt -import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.{ArrayBuffer, Set} import shapes.{Segment, Point, Triangle} import utils.Util @@ -44,7 +44,7 @@ object CDT { // Inital triangle factor val ALPHA = 0.3f - val SHEER = 0.001f + val SHEER = 0.0001 var clearPoint = 0 @@ -101,7 +101,7 @@ object CDT { // Prevents any two distinct endpoints from lying on a common horizontal line, and avoiding // the degenerate case. See Mark de Berg et al, Chapter 6.3 - private def shearTransform(point: Point) = Point(point.x, point.y + point.x * SHEER) + private def shearTransform(point: Point) = Point(point.x, point.y + point.x * 0.001f) } @@ -144,7 +144,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian } catch { case e: Exception => - throw new Exception("Systect point = " + i) + //throw new Exception("Suspect point = " + i) } } @@ -154,9 +154,9 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Clean exterior triangles private def finalization { - mesh.map.foreach(m => m.markEdges) + mesh.map.foreach(m => m.markNeighborEdges) mesh clean cleanTri - + } // Point event @@ -191,17 +191,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian val tList = new ArrayBuffer[Triangle] tList += firstTriangle - while(tList.last != null && !tList.last.contains(edge.p)) + while(!tList.last.contains(edge.p)) tList += tList.last.findNeighbor(edge.p - edge.q) - // TODO: fix tList.last == null bug! - // Not sure why this happens in bird & nazca monkey demo... - if(tList.last == null) tList -= tList.last - // Neighbor triangles val nTriangles = new ArrayBuffer[Triangle] // Remove old triangles; collect neighbor triangles + // Keep duplicates out tList.foreach(t => { t.neighbors.foreach(n => if(n != null && !tList.contains(n)) nTriangles += n) mesh.map -= t @@ -240,47 +237,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian val point1 = if(ahead) edge.q else edge.p val point2 = if(ahead) edge.p else edge.q - var first: Triangle = null - val sNode = aFront.locatePoint(point1) - val eNode = aFront.locatePoint(point2) + val sNode = aFront.locate(point1) + val eNode = aFront.locate(point2) + + val first = aFront.constrainedEdge(sNode, eNode, T1, T2, edge) - 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 edgeNeighbors(nTriangles, T1) edgeNeighbors(nTriangles, T2) - - // Select edge triangle - var edgeTri1: Triangle = null - var i = 0 - while(edgeTri1 == null) { - if(T1(i).contains(point1, point2)) - edgeTri1 = T1(i) - i += 1 - } - - // Select edge triangle - var edgeTri2: Triangle = null - i = 0 - while(edgeTri2 == null) { - if(T2(i).contains(point1, point2)) - edgeTri2 = T2(i) - i += 1 - } - - edgeTri1.markNeighbor(edgeTri2) - - // Mark constrained edge - edgeTri1 mark(point1, point2) - edgeTri2 mark(point1, point2) - - // Double check returning T2.first vs T1.first - first + + first } else if(firstTriangle == null) { @@ -330,17 +296,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian edgeNeighbors(nTriangles, T) // Mark constrained edge - edgeTri mark(edge.p, edge.q) + edgeTri markEdge(point1, point2) // Return original triangle triangle } else if(firstTriangle.contains(edge.p, edge.q)) { // Mark constrained edge - firstTriangle mark(edge.p, edge.q) + firstTriangle markEdge(edge.p, edge.q) triangle } else { throw new Exception("Triangulation error") + //null } } diff --git a/src/org/poly2tri/cdt/Mesh.scala b/src/org/poly2tri/cdt/Mesh.scala index bb5f884..827b8d9 100644 --- a/src/org/poly2tri/cdt/Mesh.scala +++ b/src/org/poly2tri/cdt/Mesh.scala @@ -42,17 +42,25 @@ class Mesh(initialTriangle: Triangle) { val debug = HashSet.empty[Triangle] val triangles = new ArrayBuffer[Triangle] + def test(triangle: Triangle) { + if(triangle != null && !triangle.test){ + triangle.test = true + debug += triangle + for(i <- 0 until 3) { + test(triangle.neighbors(i)) + } + } + } + // Recursively collect triangles def clean(triangle: Triangle) { - if(triangle != null && !triangle.clean) { - triangle.clean = true + if(triangle != null && !triangle.interior) { + triangle.interior = true triangles += triangle - if(!triangle.edges(0)) - clean(triangle.neighbors(0)) - if(!triangle.edges(1)) - clean(triangle.neighbors(1)) - if(!triangle.edges(2)) - clean(triangle.neighbors(2)) + for(i <- 0 until 3) { + if(!triangle.edges(i)) + clean(triangle.neighbors(i)) + } } } diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index 122900a..2ec81ee 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -46,10 +46,12 @@ class Triangle(val points: Array[Point]) { val edges = Array(false, false, false) // Finalization flag - var clean = false + var interior = false var finalized = false + var test = false + // Update neighbor pointers private def markNeighbor(p1: Point, p2: Point, t: Triangle) { @@ -284,15 +286,9 @@ class Triangle(val points: Array[Point]) { } def printDebug = println(points(0) + "," + points(1) + "," + points(2)) - - // Initial mark edges sweep - def mark(p: Point, q: Point) { - markEdge(p, q) - markNeighborEdge(p, q) - } - + // Finalize edge marking - def markEdges { + def markNeighborEdges { for(i <- 0 to 2) if(edges(i)) i match { @@ -302,18 +298,24 @@ class Triangle(val points: Array[Point]) { } } - // Mark neighbor's edge - private def markNeighborEdge(p: Point, q: Point) = - neighbors.foreach(n => if(n != null) n.markEdge(p, q)) + def markEdge(triangle: Triangle) { + for(i <- 0 to 2) + if(edges(i)) + i match { + case 0 => triangle.markEdge(points(1), points(2)) + case 1 => triangle.markEdge(points(0), points(2)) + case _ => triangle.markEdge(points(0), points(1)) + } + } // Mark edge as constrained - private def markEdge(p: Point, q: Point) { + def markEdge(p: Point, q: Point) { if((q == points(0) && p == points(1)) || (q == points(1) && p == points(0))) { finalized = true edges(2) = true } else if ((q == points(0) && p == points(2)) || (q == points(2) && p == points(0))) { - finalized = true edges(1) = true + finalized = true } else if ((q == points(1) && p == points(2)) || (q == points(2) && p == points(1))){ finalized = true edges(0) = true diff --git a/src/org/poly2tri/utils/Util.scala b/src/org/poly2tri/utils/Util.scala index 06f691b..16e77ba 100644 --- a/src/org/poly2tri/utils/Util.scala +++ b/src/org/poly2tri/utils/Util.scala @@ -8,7 +8,7 @@ import shapes.Point object Util { // Almost zero - val COLLINEAR_SLOP = 0.01f + val COLLINEAR_SLOP = 0.1f val epsilon = exactinit val ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon