From b31d115774a6c694dfeee3cad61720b4bb27299a Mon Sep 17 00:00:00 2001 From: zzzzrrr Date: Wed, 29 Jul 2009 12:15:09 -0400 Subject: [PATCH] refactored Triangle --- src/org/poly2tri/Poly2Tri.scala | 18 +++--- src/org/poly2tri/cdt/CDT.scala | 29 +++++++-- src/org/poly2tri/cdt/Mesh.scala | 4 +- src/org/poly2tri/cdt/Triangle.scala | 40 ------------ src/org/poly2tri/earClip/EarClip.scala | 55 +++++++++++++++- src/org/poly2tri/shapes/Triangle.scala | 89 +++++++++++--------------- 6 files changed, 126 insertions(+), 109 deletions(-) delete mode 100644 src/org/poly2tri/cdt/Triangle.scala diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index 86b598b..5a8a41a 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -58,7 +58,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { var segments: ArrayBuffer[Segment] = null val earClip = new EarClip - var earClipResults: Array[Triangle] = null + var earClipResults: Array[poly2tri.earClip.Triangle] = null var polyX: ArrayBuffer[Float] = null var polyY: ArrayBuffer[Float] = null @@ -376,9 +376,9 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { // Earclip - earClipResults = new Array[Triangle](maxTriangles) + earClipResults = new Array[poly2tri.earClip.Triangle](maxTriangles) - for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle + for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle val xVerts = polyX.toArray.reverse val yVerts = polyY.toArray.reverse @@ -397,8 +397,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { val polyX = Array(400f, 500f, 520f, 460f, 580f, 480f, 360f, 360f, 300f, 200f, 120f, 200f, 340f, 208f, 180f, 300f) val polyY = Array(472f, 392f, 272f, 232f, 212f, 152f, 172f, 52f, 112f, 32f, 92f, 72f, 272f, 212f, 352f, 312f) - val earClipResults = new Array[Triangle](14) - for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle + val earClipResults = new Array[poly2tri.earClip.Triangle](14) + for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle val t1 = System.nanoTime earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) val t2 = System.nanoTime @@ -410,8 +410,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { val polyX = Array(200f, 300f, 400f, 500f, 600f, 600f, 500f, 400f, 300f, 200f, 110f, 110f) val polyY = Array(110f, 200f, 110f, 200f, 110f, 200f, 300f, 200f, 300f, 200f, 300f, 200f) - val earClipResults = new Array[Triangle](14) - for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle + val earClipResults = new Array[poly2tri.earClip.Triangle](14) + for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle val t1 = System.nanoTime earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) val t2 = System.nanoTime @@ -434,8 +434,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { val polyX = Array(350f, 379f, 469f, 397f, 423f, 350f, 277f, 303f, 231f, 321f) val polyY = Array(75f, 161f, 161f, 215f, 301f, 250f, 301f,215f, 161f, 161f) - val earClipResults = new Array[Triangle](14) - for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle + val earClipResults = new Array[poly2tri.earClip.Triangle](14) + for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle val t1 = System.nanoTime earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) val t2 = System.nanoTime diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index dbeaaa7..83f6a70 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -32,7 +32,7 @@ package org.poly2tri.cdt import scala.collection.mutable.ArrayBuffer -import shapes.{Segment, Point} +import shapes.{Segment, Point, Triangle} import utils.Util /** @@ -42,10 +42,15 @@ import utils.Util */ class CDT(segments: ArrayBuffer[Segment]) { + // The initial triangle + var initialTriangle: Triangle = null // The point list val points = init // The triangle mesh - val mesh = new Mesh + val mesh = new Mesh(initialTriangle) + + // Used to compute inital triangle + private val ALPHA = 0.3f // Sweep points; build mesh sweep @@ -55,8 +60,8 @@ class CDT(segments: ArrayBuffer[Segment]) { // Initialize and sort point list private def init: List[Point] = { - var xmax, xmin = 0f - var ymax, ymin = 0f + var xmax, xmin = segments(0).p.x + var ymax, ymin = segments(0).p.y val pts = new ArrayBuffer[Point] for(i <- 0 until segments.size) { @@ -74,18 +79,28 @@ class CDT(segments: ArrayBuffer[Segment]) { if(p.y < ymin) ymin = p.x if(q.y < ymin) ymin = q.x - pts += shearTransform(p) pts += shearTransform(q) } + var points: List[Point] = null + if(pts.size < 10) // Insertion sort is one of the fastest algorithms for sorting arrays containing // fewer than ten elements, or for lists that are already mostly sorted. - Util.insertSort((p1: Point, p2: Point) => p1 > p2)(pts).toList + points = Util.insertSort((p1: Point, p2: Point) => p1 > p2)(pts).toList else // Merge sort: O(n log n) - Util.msort((p1: Point, p2: Point) => p1 > p2)(pts.toList) + points = Util.msort((p1: Point, p2: Point) => p1 > p2)(pts.toList) + + val deltaX = ALPHA * (xmax - xmin) + val deltaY = ALPHA * (ymax - ymin) + + val p1 = Point(xmin - deltaX, ymin - deltaY) + val p2 = Point(xmax - deltaX, ymin - deltaY) + + initialTriangle = new Triangle(Array(p2, points(0), p1), null) + points } // Implement sweep-line paradigm diff --git a/src/org/poly2tri/cdt/Mesh.scala b/src/org/poly2tri/cdt/Mesh.scala index 0b929e0..9bfd389 100644 --- a/src/org/poly2tri/cdt/Mesh.scala +++ b/src/org/poly2tri/cdt/Mesh.scala @@ -34,8 +34,8 @@ import scala.collection.mutable.HashSet import shapes.Point -class Mesh { +class Mesh(initialTriangle: Triangle) { - val map = HashSet.empty[Triangle] + val map = HashSet(initialTriangle) } diff --git a/src/org/poly2tri/cdt/Triangle.scala b/src/org/poly2tri/cdt/Triangle.scala deleted file mode 100644 index 19b3f6f..0000000 --- a/src/org/poly2tri/cdt/Triangle.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* Poly2Tri - * Copyright (c) 2009, Mason Green - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.poly2tri.cdt - -import shapes.Point - -// Triangle-based data structures have better performance than quad-edge structures -// See: Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator" -// "Triangulations in CGAL" -class Triangle(points: Array[Point], neighbors: Array[Triangle]) { - -} diff --git a/src/org/poly2tri/earClip/EarClip.scala b/src/org/poly2tri/earClip/EarClip.scala index 55a7f6e..86f19fc 100644 --- a/src/org/poly2tri/earClip/EarClip.scala +++ b/src/org/poly2tri/earClip/EarClip.scala @@ -25,7 +25,7 @@ */ package org.poly2tri.earClip -import shapes.{Point, Triangle} +import shapes.Point class EarClip { @@ -313,3 +313,56 @@ class Poly(var x: Array[Float], var y: Array[Float], var nVertices: Int) { areaIsSet = false } } + +class Triangle(var x1: Float, var y1: Float, var x2: Float, var y2: Float, var x3: Float, var y3: Float) { + + def this() = this(0,0,0,0,0,0) + + val x = new Array[Float](3) + val y = new Array[Float](3) + + // Automatically fixes orientation to ccw + + val dx1 = x2-x1 + val dx2 = x3-x1 + val dy1 = y2-y1 + val dy2 = y3-y1 + val cross = dx1*dy2-dx2*dy1 + val ccw = (cross>0) + if (ccw){ + x(0) = x1; x(1) = x2; x(2) = x3; + y(0) = y1; y(1) = y2; y(2) = y3; + } else{ + x(0) = x1; x(1) = x3; x(2) = x2; + y(0) = y1; y(1) = y3; y(2) = y2; + } + + def set(t: Triangle) { + x(0) = t.x(0) + x(1) = t.x(1) + x(2) = t.x(2) + y(0) = t.y(0) + y(1) = t.y(1) + y(2) = t.y(2) + } + + + def containsPoint(_x: Float, _y: Float): Boolean = { + + val vx2 = _x-x(0); val vy2 = _y-y(0); + val vx1 = x(1)-x(0); val vy1 = y(1)-y(0); + val vx0 = x(2)-x(0); val vy0 = y(2)-y(0); + + val dot00 = vx0*vx0+vy0*vy0; + val dot01 = vx0*vx1+vy0*vy1; + val dot02 = vx0*vx2+vy0*vy2; + val dot11 = vx1*vx1+vy1*vy1; + val dot12 = vx1*vx2+vy1*vy2; + val invDenom = 1.0f / (dot00*dot11 - dot01*dot01); + val u = (dot11*dot02 - dot01*dot12)*invDenom; + val v = (dot00*dot12 - dot01*dot02)*invDenom; + + return ((u>=0)&&(v>=0)&&(u+v<=1)); + } + + } \ No newline at end of file diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index 6200883..0570d91 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -1,54 +1,43 @@ +/* Poly2Tri + * Copyright (c) 2009, Mason Green + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package org.poly2tri.shapes -class Triangle(var x1: Float, var y1: Float, var x2: Float, var y2: Float, var x3: Float, var y3: Float) { - - def this() = this(0,0,0,0,0,0) - - val x = new Array[Float](3) - val y = new Array[Float](3) - - // Automatically fixes orientation to ccw +import shapes.Point - val dx1 = x2-x1 - val dx2 = x3-x1 - val dy1 = y2-y1 - val dy2 = y3-y1 - val cross = dx1*dy2-dx2*dy1 - val ccw = (cross>0) - if (ccw){ - x(0) = x1; x(1) = x2; x(2) = x3; - y(0) = y1; y(1) = y2; y(2) = y3; - } else{ - x(0) = x1; x(1) = x3; x(2) = x2; - y(0) = y1; y(1) = y3; y(2) = y2; - } +// 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" +class Triangle(points: Array[Point], neighbors: Array[Triangle]) { - def set(t: Triangle) { - x(0) = t.x(0) - x(1) = t.x(1) - x(2) = t.x(2) - y(0) = t.y(0) - y(1) = t.y(1) - y(2) = t.y(2) - } - - - def containsPoint(_x: Float, _y: Float): Boolean = { - - val vx2 = _x-x(0); val vy2 = _y-y(0); - val vx1 = x(1)-x(0); val vy1 = y(1)-y(0); - val vx0 = x(2)-x(0); val vy0 = y(2)-y(0); - - val dot00 = vx0*vx0+vy0*vy0; - val dot01 = vx0*vx1+vy0*vy1; - val dot02 = vx0*vx2+vy0*vy2; - val dot11 = vx1*vx1+vy1*vy1; - val dot12 = vx1*vx2+vy1*vy2; - val invDenom = 1.0f / (dot00*dot11 - dot01*dot01); - val u = (dot11*dot02 - dot01*dot12)*invDenom; - val v = (dot00*dot12 - dot01*dot02)*invDenom; - - return ((u>=0)&&(v>=0)&&(u+v<=1)); - } - - } + // Flags to determine if an edge is the final Delauney edge + val edges = new Array[Boolean](3) + +}