From f75a0a29742fc1c61868dc235f8c4c3b6dbe2a9c Mon Sep 17 00:00:00 2001 From: zzzzrrr Date: Tue, 28 Jul 2009 11:09:19 -0400 Subject: [PATCH] setup triangle, mesh, and advancing front classes --- src/org/poly2tri/Poly2Tri.scala | 24 +++++++---- src/org/poly2tri/cdt/AFront.scala | 36 ++++++++++++++++ src/org/poly2tri/cdt/Mesh.scala | 39 +++++++++++++++++ src/org/poly2tri/cdt/Triangle.scala | 40 ++++++++++++++++++ .../poly2tri/seidel/MonotoneMountain.scala | 42 +++++++++++++++++-- src/org/poly2tri/seidel/TrapezoidalMap.scala | 2 +- src/org/poly2tri/seidel/Triangulator.scala | 31 +++++++++----- 7 files changed, 192 insertions(+), 22 deletions(-) create mode 100644 src/org/poly2tri/cdt/AFront.scala create mode 100644 src/org/poly2tri/cdt/Mesh.scala create mode 100644 src/org/poly2tri/cdt/Triangle.scala diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index a3f25fd..86b598b 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -69,6 +69,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { var drawSegs = true var hiLighter = 0 var drawEarClip = false + var hertelMehlhorn = false val nazcaMonkey = "data/nazca_monkey.dat" val bird = "data/bird.dat" @@ -114,11 +115,11 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { if(!debug && !drawEarClip) { var i = 0 - for(t <- tesselator.triangles) { - val triangle = new Polygon - t.foreach(p => triangle.addPoint(p.x, p.y)) + for(t <- tesselator.polygons) { + val poly = new Polygon + t.foreach(p => poly.addPoint(p.x, p.y)) g.setColor(red) - g.draw(triangle) + g.draw(poly) } } else if (debug && drawMap && !drawEarClip){ for(mp <- tesselator.monoPolies) { @@ -158,14 +159,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { // UP if(key == 200) { hiLighter += 1 - if (hiLighter == tesselator.triangles.size) + if (hiLighter == tesselator.polygons.size) hiLighter = 0 } // DOWN if(key == 208) { hiLighter -= 1 if (hiLighter == -1) - hiLighter = tesselator.triangles.size-1 + hiLighter = tesselator.polygons.size-1 } if(c == 'm') drawMap = !drawMap if(c == '1') {currentModel = nazcaMonkey; selectModel} @@ -175,6 +176,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { if(c == '5') star if(c == 's') drawSegs = !drawSegs if(c == 'e') {drawEarClip = !drawEarClip; selectModel} + if(c == 'h') {hertelMehlhorn = !hertelMehlhorn; selectModel} } def selectModel { @@ -227,6 +229,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p6, p7) tesselator = new Triangulator(segments) + tesselator.buildTriangles = hertelMehlhorn + val t1 = System.nanoTime tesselator process val t2 = System.nanoTime @@ -260,7 +264,9 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p8, p9) segments += new Segment(p9, p10) segments += new Segment(p10, p1) + tesselator = new Triangulator(segments) + tesselator.buildTriangles = hertelMehlhorn val t1 = System.nanoTime tesselator process @@ -301,7 +307,9 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { segments += new Segment(p10, p11) segments += new Segment(p11, p12) segments += new Segment(p12, p1) + tesselator = new Triangulator(segments) + tesselator.buildTriangles = hertelMehlhorn val t1 = System.nanoTime tesselator process @@ -355,12 +363,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { // Sediel triangulation tesselator = new Triangulator(segments) + tesselator.buildTriangles = hertelMehlhorn + val t1 = System.nanoTime tesselator.process val runTime = System.nanoTime - t1 println("Poly2Tri average (ms) = " + runTime*1e-6) - println("Number of triangles = " + tesselator.triangles.size) + println("Number of triangles = " + tesselator.polygons.size) } else { diff --git a/src/org/poly2tri/cdt/AFront.scala b/src/org/poly2tri/cdt/AFront.scala new file mode 100644 index 0000000..b03e165 --- /dev/null +++ b/src/org/poly2tri/cdt/AFront.scala @@ -0,0 +1,36 @@ +/* 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 + +// Advancing front +class AFront { + +} diff --git a/src/org/poly2tri/cdt/Mesh.scala b/src/org/poly2tri/cdt/Mesh.scala new file mode 100644 index 0000000..8f6da95 --- /dev/null +++ b/src/org/poly2tri/cdt/Mesh.scala @@ -0,0 +1,39 @@ +/* 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 scala.collection.mutable.HashSet + +class Mesh { + + val map = HashSet.empty[Triangle] + +} diff --git a/src/org/poly2tri/cdt/Triangle.scala b/src/org/poly2tri/cdt/Triangle.scala new file mode 100644 index 0000000..19b3f6f --- /dev/null +++ b/src/org/poly2tri/cdt/Triangle.scala @@ -0,0 +1,40 @@ +/* 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/seidel/MonotoneMountain.scala b/src/org/poly2tri/seidel/MonotoneMountain.scala index 7347bc1..422c251 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 { +class MonotoneMountain(buildTriangles: Boolean) { var tail, head: Point = null var size = 0 @@ -45,6 +45,8 @@ class MonotoneMountain { val monoPoly = new ArrayBuffer[Point] // Triangles that constitute the mountain val triangles = new ArrayBuffer[Array[Point]] + // Convex polygons that constitute the mountain + val convexPolies = new ArrayBuffer[Array[Point]] // Used to track which side of the line we are on private var positive = false // Almost Pi! @@ -86,7 +88,7 @@ class MonotoneMountain { // Partition a x-monotone mountain into triangles O(n) // See "Computational Geometry in C", 2nd edition, by Joseph O'Rourke, page 52 - def triangulate { + def process { // Establish the proper sign positive = angleSign @@ -105,7 +107,16 @@ class MonotoneMountain { if(convex(p)) convexPoints += p p = p.next } - + + if(buildTriangles) + triangulate + else + hertelMehlhorn + + } + + private def triangulate { + while(!convexPoints.isEmpty) { val ear = convexPoints.remove(0) @@ -123,7 +134,30 @@ class MonotoneMountain { } 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)) diff --git a/src/org/poly2tri/seidel/TrapezoidalMap.scala b/src/org/poly2tri/seidel/TrapezoidalMap.scala index ea907f7..b9e38fe 100644 --- a/src/org/poly2tri/seidel/TrapezoidalMap.scala +++ b/src/org/poly2tri/seidel/TrapezoidalMap.scala @@ -38,7 +38,7 @@ import shapes.{Point, Segment, Trapezoid} class TrapezoidalMap { - // Trapezoid associated array + // Trapezoid container val map = HashSet.empty[Trapezoid] // AABB margin var margin = 50f diff --git a/src/org/poly2tri/seidel/Triangulator.scala b/src/org/poly2tri/seidel/Triangulator.scala index 74deefd..fc34ca2 100644 --- a/src/org/poly2tri/seidel/Triangulator.scala +++ b/src/org/poly2tri/seidel/Triangulator.scala @@ -41,9 +41,11 @@ import shapes.{Point, Segment, Trapezoid} // "Computational Geometry in C", 2nd edition, by Joseph O'Rourke class Triangulator(segments: ArrayBuffer[Segment]) { - // Triangle decomposition list - var triangles = new ArrayBuffer[Array[Point]] - + // 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 @@ -147,7 +149,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) { if(s.mPoints.size > 0) { - val mountain = new MonotoneMountain + val mountain = new MonotoneMountain(buildTriangles) var k: List[Point] = null // Sorting is a perfromance hit. Literature says this can be accomplised in @@ -169,13 +171,22 @@ class Triangulator(segments: ArrayBuffer[Segment]) { } // Triangulate monotone mountain - mountain.triangulate + mountain process - // Extract the triangles into a single list - j = 0 - while(j < mountain.triangles.size) { - triangles += mountain.triangles(j) - j += 1 + 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 + } } xMonoPoly += mountain