diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index 845851e..a2b28d5 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -209,6 +209,13 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { g.setColor(blue) g.draw(triangle) }) + + //slCDT.cList.foreach(c => { + for(i <- 0 until 7) { + val circ = new Circle(slCDT.cList(i).x, slCDT.cList(i).y, 0.5f) + g.setColor(blue); g.draw(circ); g.fill(circ) + } + //}) } @@ -243,6 +250,11 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { mousePressed = true mousePosOld = mousePos mousePos = Point(x, y) + /* + val point = mousePos/scaleFactor + Point(deltaX, deltaY) + slCDT.addPoint(point) + slCDT.triangulate + */ } /** @@ -424,6 +436,15 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { slCDT triangulate val runTime = System.nanoTime - t1 + if(slCDT.cList.size > 1) { + //slCDT.addPoint(slCDT.cList(0)) + //slCDT.addPoint(slCDT.cList(1)) + println(slCDT.cList.size) + for(i <- 0 until 7) + slCDT.addPoint(slCDT.cList(i)) + slCDT.triangulate + } + println("CDT average (ms) = " + runTime*1e-6) println("Number of triangles = " + slCDT.triangles.size) println diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index 01639ce..084660c 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -53,6 +53,9 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { def triangleMesh = mesh.map def debugTriangles = mesh.debug + val cList = new ArrayBuffer[Point] + var refine = false + // Initialize edges initEdges(polyLine) @@ -62,9 +65,20 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { points = points ++ holePolyLine.toList } + // Add an internal point + // Good for manually refining the mesh. Use this when you want to eliminate + // skinny triangles + def addPoint(point: Point) { + points = point :: points + } + // Triangulate simple polygon with holes def triangulate { + mesh.map.clear + mesh.triangles.clear + mesh.debug.clear + var xmax, xmin = points.first.x var ymax, ymin = points.first.y @@ -125,7 +139,6 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { if(p1.x > p2.x) { return List(p2, p1) } else if(p1.x == p2.x) { - println(p1 + "," + p2) throw new Exception("Duplicate point") } } @@ -139,8 +152,10 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { // Implement sweep-line private def sweep { + // 48 67 + val size = if(refine) 68 else points.size - for(i <- 1 until points.size) { + for(i <- 1 until size) { val point = points(i) // Process Point event @@ -167,6 +182,17 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { }) // Collect interior triangles constrained by edges mesh clean cleanTri + + mesh.triangles.foreach(t => { + if(t.thin) { + val center = Util.circumcenter(t.points(0), t.points(1), t.points(2)) + cList += center + refine = true + //addPoint(center) + //mesh.debug += t + } + }) + } // Point event @@ -286,12 +312,24 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { nTriangles += pNode.triangle pNode = pNode.next - while(pNode.point != point2 && edge > pNode.point) { + while(pNode.point != point2) { points += pNode.point nTriangles += pNode.triangle pNode = pNode.next } + val s = new Segment(first.point, first.next.point) + if(s > point1) { + mesh.map -= first.triangle + first.triangle = first.triangle.neighborCW(first.point) + val t = first.triangle.neighborAcross(first.point) + val n = new Node(point1, t) + first.next = n + n.prev = first + n.next = first.next.next + n.next.prev = n + } + // Triangulate empty areas. val T = new ArrayBuffer[Triangle] triangulate(points.toArray, List(point1, point2), T) @@ -305,6 +343,11 @@ class CDT(polyLine: Array[Point], clearPoint: Point) { // Mark constrained edge T.last markEdge(point1, point2) + if(pNode.point != edge.p) { + println("span") + //edgeEvent(edge, pNode) + } + } else if(firstTriangle.contains(edge.q, edge.p)) { // Constrained edge lies on the side of a triangle // Mark constrained edge diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index ccbeb49..b38a08a 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -353,7 +353,8 @@ class Triangle(val points: Array[Point]) { val b = points(0).x - points(1).x val h = points(2).y - points(1).y - (b*h*0.5f) + + Math.abs((b*h*0.5f)) } def centroid: Point = { @@ -363,4 +364,18 @@ class Triangle(val points: Array[Point]) { Point(cx, cy) } + def thin: Boolean = { + val a1 = (points(1) - points(0)) + val b1 = (points(2) - points(0)) + val a2 = (points(0) - points(1)) + val b2 = (points(2) - points(1)) + val angle1 = Math.abs(Math.atan2(a1 cross b1, a1 dot b1)) + val angle2 = Math.abs(Math.atan2(a2 cross b2, a2 dot b2)) + val angle3 = Math.Pi - angle1 - angle2 + // 30 degrees + val minAngle = Math.Pi/6 + //println(angle1 + "," + angle2 + "," + angle3) + (angle1 <= minAngle || angle2 <= minAngle || angle3 <= minAngle) + } + } diff --git a/src/org/poly2tri/utils/Util.scala b/src/org/poly2tri/utils/Util.scala index 6f29d65..4fa471f 100644 --- a/src/org/poly2tri/utils/Util.scala +++ b/src/org/poly2tri/utils/Util.scala @@ -133,6 +133,30 @@ object Util { } + // Original by Jonathan Shewchuk + // http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html + def circumcenter(a: Point, b: Point, c: Point): Point = { + + /* Use coordinates relative to point `a' of the triangle. */ + val xba = b.x - a.x + val yba = b.y - a.y + val xca = c.x - a.x + val yca = c.y - a.y + /* Squares of lengths of the edges incident to `a'. */ + val balength = xba * xba + yba * yba + val calength = xca * xca + yca * yca + + /* Calculate the denominator of the formulae. */ + val denominator = 0.5 / orient2d(b, c, a) + + /* Calculate offset (from `a') of circumcenter. */ + val xcirca = (yca * balength - yba * calength) * denominator + val ycirca = (xba * calength - xca * balength) * denominator + + a + Point(xcirca.toFloat, ycirca.toFloat) + + } + // Returns triangle circumcircle point and radius def circumCircle(a: Point, b: Point, c: Point): Tuple2[Point, Float] = {