refactored Triangle

This commit is contained in:
zzzzrrr 2009-07-29 12:15:09 -04:00
parent 3ededbd3d0
commit b31d115774
6 changed files with 126 additions and 109 deletions

View File

@ -58,7 +58,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
var segments: ArrayBuffer[Segment] = null var segments: ArrayBuffer[Segment] = null
val earClip = new EarClip val earClip = new EarClip
var earClipResults: Array[Triangle] = null var earClipResults: Array[poly2tri.earClip.Triangle] = null
var polyX: ArrayBuffer[Float] = null var polyX: ArrayBuffer[Float] = null
var polyY: ArrayBuffer[Float] = null var polyY: ArrayBuffer[Float] = null
@ -376,9 +376,9 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
// Earclip // 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 xVerts = polyX.toArray.reverse
val yVerts = polyY.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 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 polyY = Array(472f, 392f, 272f, 232f, 212f, 152f, 172f, 52f, 112f, 32f, 92f, 72f, 272f, 212f, 352f, 312f)
val earClipResults = new Array[Triangle](14) val earClipResults = new Array[poly2tri.earClip.Triangle](14)
for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle
val t1 = System.nanoTime val t1 = System.nanoTime
earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults)
val t2 = System.nanoTime 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 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 polyY = Array(110f, 200f, 110f, 200f, 110f, 200f, 300f, 200f, 300f, 200f, 300f, 200f)
val earClipResults = new Array[Triangle](14) val earClipResults = new Array[poly2tri.earClip.Triangle](14)
for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle
val t1 = System.nanoTime val t1 = System.nanoTime
earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults)
val t2 = System.nanoTime 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 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 polyY = Array(75f, 161f, 161f, 215f, 301f, 250f, 301f,215f, 161f, 161f)
val earClipResults = new Array[Triangle](14) val earClipResults = new Array[poly2tri.earClip.Triangle](14)
for(i <- 0 until earClipResults.size) earClipResults(i) = new Triangle for(i <- 0 until earClipResults.size) earClipResults(i) = new poly2tri.earClip.Triangle
val t1 = System.nanoTime val t1 = System.nanoTime
earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults) earClip.triangulatePolygon(polyX, polyY, polyX.size, earClipResults)
val t2 = System.nanoTime val t2 = System.nanoTime

View File

@ -32,7 +32,7 @@ package org.poly2tri.cdt
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import shapes.{Segment, Point} import shapes.{Segment, Point, Triangle}
import utils.Util import utils.Util
/** /**
@ -42,10 +42,15 @@ import utils.Util
*/ */
class CDT(segments: ArrayBuffer[Segment]) { class CDT(segments: ArrayBuffer[Segment]) {
// The initial triangle
var initialTriangle: Triangle = null
// The point list // The point list
val points = init val points = init
// The triangle mesh // 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 points; build mesh
sweep sweep
@ -55,8 +60,8 @@ class CDT(segments: ArrayBuffer[Segment]) {
// Initialize and sort point list // Initialize and sort point list
private def init: List[Point] = { private def init: List[Point] = {
var xmax, xmin = 0f var xmax, xmin = segments(0).p.x
var ymax, ymin = 0f var ymax, ymin = segments(0).p.y
val pts = new ArrayBuffer[Point] val pts = new ArrayBuffer[Point]
for(i <- 0 until segments.size) { for(i <- 0 until segments.size) {
@ -74,18 +79,28 @@ class CDT(segments: ArrayBuffer[Segment]) {
if(p.y < ymin) ymin = p.x if(p.y < ymin) ymin = p.x
if(q.y < ymin) ymin = q.x if(q.y < ymin) ymin = q.x
pts += shearTransform(p) pts += shearTransform(p)
pts += shearTransform(q) pts += shearTransform(q)
} }
var points: List[Point] = null
if(pts.size < 10) if(pts.size < 10)
// Insertion sort is one of the fastest algorithms for sorting arrays containing // Insertion sort is one of the fastest algorithms for sorting arrays containing
// fewer than ten elements, or for lists that are already mostly sorted. // 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 else
// Merge sort: O(n log n) // 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 // Implement sweep-line paradigm

View File

@ -34,8 +34,8 @@ import scala.collection.mutable.HashSet
import shapes.Point import shapes.Point
class Mesh { class Mesh(initialTriangle: Triangle) {
val map = HashSet.empty[Triangle] val map = HashSet(initialTriangle)
} }

View File

@ -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]) {
}

View File

@ -25,7 +25,7 @@
*/ */
package org.poly2tri.earClip package org.poly2tri.earClip
import shapes.{Point, Triangle} import shapes.Point
class EarClip { class EarClip {
@ -313,3 +313,56 @@ class Poly(var x: Array[Float], var y: Array[Float], var nVertices: Int) {
areaIsSet = false 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));
}
}

View File

@ -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 package org.poly2tri.shapes
class Triangle(var x1: Float, var y1: Float, var x2: Float, var y2: Float, var x3: Float, var y3: Float) { import shapes.Point
def this() = this(0,0,0,0,0,0) // 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]) {
val x = new Array[Float](3) // Flags to determine if an edge is the final Delauney edge
val y = new Array[Float](3) val edges = new Array[Boolean](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));
}
} }