diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index a87a37b..80d5cbd 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -75,7 +75,6 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { var drawSegs = true var hiLighter = 0 var drawEarClip = false - var hertelMehlhorn = false var drawCDT = false val nazcaMonkey = "data/nazca_monkey.dat" @@ -201,7 +200,6 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { if(c == '6') selectModel(i18) if(c == 's') drawSegs = !drawSegs if(c == 'e') {drawEarClip = !drawEarClip; selectModel(currentModel)} - if(c == 'h') {hertelMehlhorn = !hertelMehlhorn; selectModel(currentModel)} } def selectModel(model: String) { @@ -262,7 +260,6 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { // Sediel triangulation seidel = new Triangulator(segments) - seidel.buildTriangles = hertelMehlhorn val t1 = System.nanoTime seidel.process diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index 1f4d05b..d8a4001 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -122,13 +122,13 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Implement sweep-line private def sweep { - for(i <- 1 until 9 /*points.size*/) { + for(i <- 1 until points.size) { val point = points(i) - println(point) // 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)) } } @@ -164,12 +164,40 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // EdgeEvent private def edgeEvent(edge: Segment, triangle: Triangle) { + // STEP 1: Locate the first intersected triangle - val first = triangle.locateFirst(edge) - println(first) - if(first != null && first != triangle && !first.contains(edge)) - mesh.map -= first + 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 + while(!triangles.last.contains(edge.p)) + triangles += triangles.last.findNeighbor(edge.p - edge.q) + // Remove from the mesh + triangles.foreach(t => mesh.map -= t) + } else if(firstTriangle == null) { + + // Traverse the AFront, and build triangle list + + var node = aFront.locate(edge.q) + + if(edge.p.x > edge.q.x) { + // Search right + while(node.point != edge.p) { + // Collect points + node = node.next + } + } else { + // Search left + while(node.point != edge.p) { + // Collect points + node = node.prev + } + } + + } + // STEP 3: Triangulate empty areas. } diff --git a/src/org/poly2tri/seidel/MonotoneMountain.scala b/src/org/poly2tri/seidel/MonotoneMountain.scala index 422c251..00b09ff 100644 --- a/src/org/poly2tri/seidel/MonotoneMountain.scala +++ b/src/org/poly2tri/seidel/MonotoneMountain.scala @@ -35,7 +35,7 @@ import scala.collection.mutable.{ArrayBuffer, Queue} import shapes.Point // Doubly linked list -class MonotoneMountain(buildTriangles: Boolean) { +class MonotoneMountain { var tail, head: Point = null var size = 0 @@ -108,10 +108,7 @@ class MonotoneMountain(buildTriangles: Boolean) { p = p.next } - if(buildTriangles) - triangulate - else - hertelMehlhorn + triangulate } @@ -135,30 +132,7 @@ class MonotoneMountain(buildTriangles: Boolean) { assert(size <= 3, "Triangulation bug, please report") } - - private def hertelMehlhorn { - - while(!convexPoints.isEmpty) { - val ear = convexPoints.remove(0) - val a = ear.prev - val b = ear - val c = ear.next - val triangle = Array(a, b, c) - convexPolies += triangle - // Remove ear, update angles and convex list - remove(ear) - } - - val polygon = new Array[Point](size) - - var p = head - for(i <- 0 until size) { - polygon(i) = p - p = p.next - } - convexPolies += polygon - } - + private def valid(p: Point) = (p != head && p != tail && convex(p)) // Create the monotone polygon diff --git a/src/org/poly2tri/seidel/Triangulator.scala b/src/org/poly2tri/seidel/Triangulator.scala index b054f41..466dc45 100644 --- a/src/org/poly2tri/seidel/Triangulator.scala +++ b/src/org/poly2tri/seidel/Triangulator.scala @@ -43,9 +43,6 @@ class Triangulator(segments: ArrayBuffer[Segment]) { // Convex polygon list var polygons = new ArrayBuffer[Array[Point]] - // Generate triangles vs non-convex polygons - // On by default - var buildTriangles = true // Order and randomize the segments val segmentList = orderSegments @@ -149,7 +146,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) { if(s.mPoints.size > 0) { - val mountain = new MonotoneMountain(buildTriangles) + val mountain = new MonotoneMountain var k: List[Point] = null // Sorting is a perfromance hit. Literature says this can be accomplised in @@ -173,20 +170,11 @@ class Triangulator(segments: ArrayBuffer[Segment]) { // Triangulate monotone mountain mountain process - if(buildTriangles) { - // Extract the triangles into a single list - j = 0 - while(j < mountain.triangles.size) { - polygons += mountain.triangles(j) - j += 1 - } - } else { - // Extract the convex polygons into a single list - j = 0 - while(j < mountain.convexPolies.size) { - polygons += mountain.convexPolies(j) - j += 1 - } + // Extract the triangles into a single list + j = 0 + while(j < mountain.triangles.size) { + polygons += mountain.triangles(j) + j += 1 } xMonoPoly += mountain diff --git a/src/org/poly2tri/shapes/Segment.scala b/src/org/poly2tri/shapes/Segment.scala index de563d8..d14e44f 100644 --- a/src/org/poly2tri/shapes/Segment.scala +++ b/src/org/poly2tri/shapes/Segment.scala @@ -53,13 +53,14 @@ class Segment(var p: Point, var q: Point) { // Update point edge list for CDT def updateEdge { - if(p.y > q.y) { + if(q.y > p.y) { // For CDT we want q to be the point with > y - val tmp = p - p = q - q = tmp + // val tmp = p + //p = q + //q = tmp + q.edges += this } - q.edges += this + } } diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index 25dc8c9..5307ed3 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -30,6 +30,8 @@ */ package org.poly2tri.shapes +import scala.collection.mutable.ArrayBuffer + // Triangle-based data structures are know to have better performance than quad-edge structures // See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator" // "Triangulations in CGAL" @@ -65,7 +67,7 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { } def contains(p: Point): Boolean = (p == points(0) || p == points(1) || p == points(2)) - def contains(e: Segment): Boolean = (contains(e.p) || contains(e.q)) + def contains(e: Segment): Boolean = (contains(e.p) && contains(e.q)) // Fast point in triangle test def pointIn(point: Point): Boolean = { @@ -86,7 +88,7 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { val p = edge.p if(contains(p)) return this val q = edge.q - val e = q - p + val e = p - q if(q == points(0)) { val sameSign = Math.signum(ik cross e) == Math.signum(ij cross e) if(!sameSign) return this @@ -105,4 +107,15 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { } throw new Exception("location error") } + + def findNeighbor(e: Point): Triangle = { + var sameSign = Math.signum(ik cross e) == Math.signum(ij cross e) + if(!sameSign) return neighbors(0) + sameSign = Math.signum(jk cross e) == Math.signum(ji cross e) + if(!sameSign) return neighbors(1) + sameSign = Math.signum(kj cross e) == Math.signum(ki cross e) + if(!sameSign) return neighbors(2) + this + } + }