mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-05 13:59:53 +01:00
fixed angle init bug
This commit is contained in:
parent
5f651233d8
commit
9cdc372690
72
data/15Point.svg
Normal file
72
data/15Point.svg
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="15Point.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="375"
|
||||
inkscape:cy="829.15262"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="795"
|
||||
inkscape:window-height="711"
|
||||
inkscape:window-x="284"
|
||||
inkscape:window-y="20">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2383" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 400,472.36218 L 500,392.36218 L 520,272.36218 L 460,232.36218 L 580,212.36218 L 480,152.36218 L 360,172.36218 L 360,52.362183 L 300,112.36218 L 200,32.362183 L 120,92.362183 L 200,72.362183 L 340,272.36218 L 200,212.36218 L 180,352.36218 L 300,312.36218 L 400,472.36218 z"
|
||||
id="path2385" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
@ -46,7 +46,7 @@ class MonotoneMountain {
|
||||
// Used to track which side of the line we are on
|
||||
var positive = false
|
||||
// Almost Pi!
|
||||
val SLOP = 3.1
|
||||
val PI_SLOP = 3.1
|
||||
|
||||
// Append a point to the list
|
||||
def +=(point: Point) {
|
||||
@ -78,6 +78,8 @@ class MonotoneMountain {
|
||||
// See "Computational Geometry in C", 2nd edition, by Joseph O'Rourke, page 52
|
||||
def triangulate {
|
||||
|
||||
// Establish the proper sign
|
||||
positive = initAngle
|
||||
// create monotone polygon - for dubug purposes
|
||||
genMonoPoly
|
||||
|
||||
@ -90,7 +92,7 @@ class MonotoneMountain {
|
||||
while(p != tail) {
|
||||
val a = angle(p)
|
||||
// If the point is almost colinear with it's neighbor, remove it!
|
||||
if(a >= SLOP || a <= -SLOP)
|
||||
if(a >= PI_SLOP || a <= -PI_SLOP)
|
||||
remove(p)
|
||||
else
|
||||
if(convex(p)) convexPoints.enqueue(p)
|
||||
@ -100,17 +102,17 @@ class MonotoneMountain {
|
||||
while(!convexPoints.isEmpty) {
|
||||
|
||||
val ear = convexPoints.dequeue
|
||||
val a = ear.prev.clone
|
||||
val b = ear.clone
|
||||
val c = ear.next.clone
|
||||
val a = ear.prev
|
||||
val b = ear
|
||||
val c = ear.next
|
||||
val triangle = Array(a, b, c)
|
||||
|
||||
triangles += triangle
|
||||
|
||||
// Remove ear, update angles and convex list
|
||||
remove(ear)
|
||||
if(a.prev != null && convex(a)) convexPoints.enqueue(a);
|
||||
if(c.prev != null && convex(c)) convexPoints.enqueue(c)
|
||||
if(valid(a)) convexPoints.enqueue(a);
|
||||
if(valid(c)) convexPoints.enqueue(c)
|
||||
|
||||
}
|
||||
assert(size <= 3, "Triangulation bug")
|
||||
@ -118,6 +120,8 @@ class MonotoneMountain {
|
||||
}
|
||||
}
|
||||
|
||||
def valid(p: Point) = (p.prev != null && p.next != null && convex(p))
|
||||
|
||||
// Create the monotone polygon
|
||||
private def genMonoPoly {
|
||||
var p = head
|
||||
@ -133,12 +137,15 @@ class MonotoneMountain {
|
||||
Math.atan2(a cross b, a dot b)
|
||||
}
|
||||
|
||||
def initAngle = {
|
||||
val a = (head.next - head)
|
||||
val b = (tail - head)
|
||||
(Math.atan2(a cross b, a dot b) >= 0)
|
||||
}
|
||||
|
||||
// Determines if the inslide angle is convex or reflex
|
||||
private def convex(p: Point) = {
|
||||
val cvx = (angle(p) >= 0)
|
||||
if(p.prev == head)
|
||||
positive = cvx
|
||||
if(positive != cvx)
|
||||
if(positive != (angle(p) >= 0))
|
||||
false
|
||||
else
|
||||
true
|
||||
|
@ -30,21 +30,17 @@
|
||||
*/
|
||||
package org.poly2tri
|
||||
|
||||
class Point(val x: Float, val y: Float, var segment: Segment) {
|
||||
|
||||
def this(x: Float, y: Float) = this(x, y, null)
|
||||
case class Point(val x: Float, val y: Float) {
|
||||
|
||||
// Pointers to next and previous points in Monontone Mountain
|
||||
var next, prev: Point = null
|
||||
|
||||
/* Internal angle */
|
||||
var angle = 0f
|
||||
|
||||
def -(p: Point) = new Point(x - p.x, y - p.y)
|
||||
def +(p: Point) = new Point(x + p.x, y + p.y)
|
||||
def +(f: Float) = new Point(x + f, y + f)
|
||||
def *(f: Float) = new Point(x * f, y * f)
|
||||
def /(a: Float) = new Point(x / a, y / a)
|
||||
def -(p: Point) = Point(x - p.x, y - p.y)
|
||||
def +(p: Point) = Point(x + p.x, y + p.y)
|
||||
def +(f: Float) = Point(x + f, y + f)
|
||||
def -(f: Float) = Point(x - f, y - f)
|
||||
def *(f: Float) = Point(x * f, y * f)
|
||||
def /(a: Float) = Point(x / a, y / a)
|
||||
def cross(p: Point) = x * p.y - y * p.x
|
||||
def dot(p: Point) = x * p.x + y * p.y
|
||||
def length = Math.sqrt(x * x + y * y).toFloat
|
||||
@ -52,12 +48,11 @@ class Point(val x: Float, val y: Float, var segment: Segment) {
|
||||
|
||||
def <(p: Point) = {
|
||||
if(p.x == x)
|
||||
if(y > p.y) true
|
||||
if(y <= p.y) true
|
||||
else false
|
||||
else
|
||||
(x < p.x)
|
||||
}
|
||||
|
||||
|
||||
override def clone = new Point(x, y)
|
||||
override def clone = Point(x, y)
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
val lCirc = new Circle(t.leftPoint.x, t.leftPoint.y, 4)
|
||||
g.setColor(blue); g.draw(lCirc); g.fill(lCirc)
|
||||
val rCirc = new Circle(t.rightPoint.x, t.rightPoint.y, 4)
|
||||
g.setColor(yellow); g.draw(rCirc); g.fill(rCirc)
|
||||
//g.setColor(yellow); g.draw(rCirc); g.fill(rCirc)
|
||||
g.setColor(red)
|
||||
g.draw(polygon)
|
||||
}
|
||||
@ -140,22 +140,41 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
|
||||
// Test #1
|
||||
def poly {
|
||||
|
||||
val scale = 1.0f
|
||||
val p1 = new Point(100,300)*scale
|
||||
val p2 = new Point(400,500)*scale
|
||||
val p3 = new Point(260,200)*scale
|
||||
val p4 = new Point(600,175)*scale
|
||||
val p5 = new Point(400,300)*scale
|
||||
val p6 = new Point(650,250)*scale
|
||||
|
||||
val p1 = Point(400,472)
|
||||
val p2 = Point(500,392)
|
||||
val p3 = Point(520,272)
|
||||
val p4 = Point(460,232)
|
||||
val p5 = Point(580,212)
|
||||
val p6 = Point(480,152)
|
||||
val p7 = Point(360,172)
|
||||
val p8 = Point(360,52)
|
||||
val p9 = Point(300,112)
|
||||
val p10 = Point(200,32)
|
||||
val p11 = Point(120,92)
|
||||
val p12 = Point(200,72)
|
||||
val p13 = Point(340,272)
|
||||
val p14 = Point(208,212)
|
||||
val p15 = Point(180,352)
|
||||
val p16 = Point(300,312)
|
||||
|
||||
val segments = new ArrayBuffer[Segment]
|
||||
segments += new Segment(p1, p2)
|
||||
segments += new Segment(p2, p3)
|
||||
segments += new Segment(p3, p4)
|
||||
segments += new Segment(p1, p3)
|
||||
segments += new Segment(p5, p2)
|
||||
segments += new Segment(p4, p5)
|
||||
segments += new Segment(p5, p6)
|
||||
segments += new Segment(p4, p6)
|
||||
segments += new Segment(p6, p7)
|
||||
segments += new Segment(p7, p8)
|
||||
segments += new Segment(p8, p9)
|
||||
segments += new Segment(p9, p10)
|
||||
segments += new Segment(p10, p11)
|
||||
segments += new Segment(p11, p12)
|
||||
segments += new Segment(p12, p13)
|
||||
segments += new Segment(p13, p14)
|
||||
segments += new Segment(p14, p15)
|
||||
segments += new Segment(p15, p16)
|
||||
segments += new Segment(p16, p1)
|
||||
|
||||
tesselator = new Triangulator(segments)
|
||||
tesselator.process
|
||||
@ -163,16 +182,16 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
|
||||
def star {
|
||||
|
||||
val p1 = new Point(350,75)
|
||||
val p2 = new Point(379,161)
|
||||
val p3 = new Point(469,161)
|
||||
val p4 = new Point(397,215)
|
||||
val p5 = new Point(423,301)
|
||||
val p6 = new Point(350,250)
|
||||
val p7 = new Point(277,301)
|
||||
val p8 = new Point(303,215)
|
||||
val p9 = new Point(231,161)
|
||||
val p10 = new Point(321,161)
|
||||
val p1 = Point(350,75)
|
||||
val p2 = Point(379,161)
|
||||
val p3 = Point(469,161)
|
||||
val p4 = Point(397,215)
|
||||
val p5 = Point(423,301)
|
||||
val p6 = Point(350,250)
|
||||
val p7 = Point(277,301)
|
||||
val p8 = Point(303,215)
|
||||
val p9 = Point(231,161)
|
||||
val p10 = Point(321,161)
|
||||
|
||||
val segments = new ArrayBuffer[Segment]
|
||||
segments += new Segment(p1, p2)
|
||||
@ -194,18 +213,18 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
|
||||
val scale = 10.0f
|
||||
val displace = 100
|
||||
val p1 = new Point(10,1)*scale+displace
|
||||
val p2 = new Point(20,10)*scale+displace
|
||||
val p3 = new Point(30,1)*scale+displace
|
||||
val p4 = new Point(40,10)*scale+displace
|
||||
val p5 = new Point(50,1)*scale+displace
|
||||
val p6 = new Point(50,10)*scale+displace
|
||||
val p7 = new Point(40,20)*scale+displace
|
||||
val p8 = new Point(30,10)*scale+displace
|
||||
val p9 = new Point(20,20)*scale+displace
|
||||
val p10 = new Point(10,10)*scale+displace
|
||||
val p11 = new Point(1,20)*scale+displace
|
||||
val p12 = new Point(1,10)*scale+displace
|
||||
val p1 = Point(10,1)*scale+displace
|
||||
val p2 = Point(20,10)*scale+displace
|
||||
val p3 = Point(30,1)*scale+displace
|
||||
val p4 = Point(40,10)*scale+displace
|
||||
val p5 = Point(50,1)*scale+displace
|
||||
val p6 = Point(50,10)*scale+displace
|
||||
val p7 = Point(40,20)*scale+displace
|
||||
val p8 = Point(30,10)*scale+displace
|
||||
val p9 = Point(20,20)*scale+displace
|
||||
val p10 = Point(10,10)*scale+displace
|
||||
val p11 = Point(1,20)*scale+displace
|
||||
val p12 = Point(1,10)*scale+displace
|
||||
|
||||
val segments = new ArrayBuffer[Segment]
|
||||
segments += new Segment(p1, p2)
|
||||
|
@ -40,6 +40,7 @@ class QueryGraph(var head: Node) {
|
||||
def locate(s: Segment) = head.locate(s).trapezoid
|
||||
|
||||
def followSegment(s: Segment) = {
|
||||
assert(s.p.x < s.q.x)
|
||||
val trapezoids = new ArrayBuffer[Trapezoid]
|
||||
trapezoids += locate(s)
|
||||
var j = 0
|
||||
@ -68,14 +69,14 @@ class QueryGraph(var head: Node) {
|
||||
|
||||
def case1(sink: Sink, s: Segment, tList: ArrayBuffer[Trapezoid]) {
|
||||
val yNode = new YNode(s, Sink.init(tList(1)), Sink.init(tList(2)))
|
||||
val qNode = new XNode(new Point(s.q.x, s.q.y, s), yNode, Sink.init(tList(3)))
|
||||
val pNode = new XNode(new Point(s.p.x, s.p.y, s), Sink.init(tList(0)), qNode)
|
||||
val qNode = new XNode(s.q, yNode, Sink.init(tList(3)))
|
||||
val pNode = new XNode(s.p, Sink.init(tList(0)), qNode)
|
||||
replace(sink, pNode)
|
||||
}
|
||||
|
||||
def case2(sink: Sink, s: Segment, tList: ArrayBuffer[Trapezoid]) {
|
||||
val yNode = new YNode(s, Sink.init(tList(1)), Sink.init(tList(2)))
|
||||
val pNode = new XNode(new Point(s.p.x, s.p.y, s), Sink.init(tList(0)), yNode)
|
||||
val pNode = new XNode(s.p, Sink.init(tList(0)), yNode)
|
||||
replace(sink, pNode)
|
||||
}
|
||||
|
||||
@ -86,7 +87,7 @@ class QueryGraph(var head: Node) {
|
||||
|
||||
def case4(sink: Sink, s: Segment, tList: ArrayBuffer[Trapezoid]) {
|
||||
val yNode = new YNode(s, Sink.init(tList(0)), Sink.init(tList(1)))
|
||||
val qNode = new XNode(new Point(s.q.x, s.q.y, s), yNode, Sink.init(tList(2)))
|
||||
val qNode = new XNode(s.q, yNode, Sink.init(tList(2)))
|
||||
replace(sink, qNode)
|
||||
}
|
||||
}
|
||||
|
@ -30,14 +30,13 @@
|
||||
*/
|
||||
package org.poly2tri
|
||||
|
||||
import collection.jcl.ArrayList
|
||||
import scala.collection.mutable.HashSet
|
||||
|
||||
// Represents a simple polygon's edge
|
||||
class Segment(var p: Point, var q: Point) {
|
||||
|
||||
// Pointer used for building trapezoidal map
|
||||
var above, below, left: Trapezoid = null
|
||||
// Pointers used for building trapezoidal map
|
||||
var above, below: Trapezoid = null
|
||||
|
||||
// Montone mountain points
|
||||
// Use a HashSet to avoid repeats
|
||||
|
@ -33,7 +33,7 @@ package org.poly2tri
|
||||
class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, val bottom: Segment) {
|
||||
|
||||
var sink: Sink = null
|
||||
var outside = false
|
||||
var inside = true
|
||||
|
||||
// Neighbor pointers
|
||||
var upperLeft: Trapezoid = null
|
||||
@ -58,11 +58,15 @@ class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, v
|
||||
lowerRight = lr; if(lr != null) lr.lowerLeft = this
|
||||
}
|
||||
|
||||
def markNeighbors {
|
||||
if(upperLeft != null) upperLeft.outside = true
|
||||
if(lowerLeft != null) lowerLeft.outside = true
|
||||
if(upperRight != null) upperRight.outside = true
|
||||
if(lowerRight != null) lowerRight.outside = true
|
||||
// Recursively trim neightbors
|
||||
def trimNeighbors {
|
||||
if(inside) {
|
||||
inside = false
|
||||
if(upperLeft != null) {upperLeft.trimNeighbors}
|
||||
if(lowerLeft != null) {lowerLeft.trimNeighbors}
|
||||
if(upperRight != null) {upperRight.trimNeighbors}
|
||||
if(lowerRight != null) {lowerRight.trimNeighbors}
|
||||
}
|
||||
}
|
||||
|
||||
// Determines if this point lies inside the trapezoid
|
||||
@ -85,7 +89,7 @@ class Trapezoid(val leftPoint: Point, var rightPoint: Point, val top: Segment, v
|
||||
}
|
||||
|
||||
// Add points to monotone mountain
|
||||
def mark {
|
||||
def addPoints {
|
||||
if(leftPoint != bottom.p) bottom.mPoints += leftPoint
|
||||
if(rightPoint != bottom.q) bottom.mPoints += rightPoint
|
||||
if(leftPoint != top.p) top.mPoints += leftPoint
|
||||
|
@ -39,7 +39,7 @@ class TrapezoidalMap {
|
||||
// Trapezoid associated array
|
||||
val map = HashSet.empty[Trapezoid]
|
||||
// AABB margin
|
||||
var margin = 20f
|
||||
var margin = 50f
|
||||
|
||||
// Bottom segment that spans multiple trapezoids
|
||||
private var bCross: Segment = null
|
||||
@ -48,11 +48,13 @@ class TrapezoidalMap {
|
||||
|
||||
// Add a trapezoid to the map
|
||||
def add(t: Trapezoid) {
|
||||
assert(t != null)
|
||||
map += t
|
||||
}
|
||||
|
||||
// Remove a trapezoid from the map
|
||||
def remove(t: Trapezoid) {
|
||||
assert(t != null)
|
||||
map -=t
|
||||
}
|
||||
|
||||
@ -66,6 +68,7 @@ class TrapezoidalMap {
|
||||
def case1(t: Trapezoid, s: Segment) = {
|
||||
|
||||
assert(s.p.x != s.q.x)
|
||||
assert(s.p.x < s.q.x)
|
||||
|
||||
val trapezoids = new ArrayBuffer[Trapezoid]
|
||||
trapezoids += new Trapezoid(t.leftPoint, s.p, t.top, t.bottom)
|
||||
@ -88,6 +91,8 @@ class TrapezoidalMap {
|
||||
// break trapezoid into 3 smaller trapezoids
|
||||
def case2(t: Trapezoid, s: Segment) = {
|
||||
|
||||
assert(s.p.x < s.q.x)
|
||||
|
||||
val rp = if(s.q.x == t.rightPoint.x) s.q else t.rightPoint
|
||||
|
||||
val trapezoids = new ArrayBuffer[Trapezoid]
|
||||
@ -111,6 +116,7 @@ class TrapezoidalMap {
|
||||
def case3(t: Trapezoid, s: Segment) = {
|
||||
|
||||
assert(s.p.x != s.q.x)
|
||||
assert(s.p.x < s.q.x)
|
||||
|
||||
val lp = if(s.p.x == t.leftPoint.x) s.p else t.leftPoint
|
||||
val rp = if(s.q.x == t.rightPoint.x) s.q else t.rightPoint
|
||||
@ -150,6 +156,8 @@ class TrapezoidalMap {
|
||||
// break trapezoid into 3 smaller trapezoids
|
||||
def case4(t: Trapezoid, s: Segment) = {
|
||||
|
||||
assert(s.p.x < s.q.x)
|
||||
|
||||
val lp = if(s.p.x == t.leftPoint.x) s.p else t.leftPoint
|
||||
|
||||
val topCross = (tCross == t.top)
|
||||
@ -176,6 +184,9 @@ class TrapezoidalMap {
|
||||
|
||||
trapezoids(2).update(trapezoids(0), trapezoids(1), t.upperRight, t.lowerRight)
|
||||
|
||||
s.above = trapezoids(0)
|
||||
s.below = trapezoids(1)
|
||||
|
||||
trapezoids
|
||||
}
|
||||
|
||||
@ -183,21 +194,21 @@ class TrapezoidalMap {
|
||||
def boundingBox(segments: ArrayBuffer[Segment]): Trapezoid = {
|
||||
|
||||
var max = segments(0).p + margin
|
||||
var min = segments(0).q + margin
|
||||
var min = segments(0).q - margin
|
||||
|
||||
for(s <- segments) {
|
||||
if(s.p.x > max.x) max = new Point(s.p.x + margin, max.y)
|
||||
if(s.p.y > max.y) max = new Point(max.x, s.p.y + margin)
|
||||
if(s.q.x > max.x) max = new Point(s.q.x+margin, max.y)
|
||||
if(s.q.y > max.y) max = new Point(max.x, s.q.y+margin)
|
||||
if(s.p.x < min.x) min = new Point(s.p.x-margin, min.y)
|
||||
if(s.p.y < min.y) min = new Point(min.x, s.p.y-margin)
|
||||
if(s.q.x < min.x) min = new Point(s.q.x-margin, min.y)
|
||||
if(s.q.y < min.y) min = new Point(min.x, s.q.y-margin)
|
||||
if(s.p.x > max.x) max = Point(s.p.x + margin, max.y)
|
||||
if(s.p.y > max.y) max = Point(max.x, s.p.y + margin)
|
||||
if(s.q.x > max.x) max = Point(s.q.x+margin, max.y)
|
||||
if(s.q.y > max.y) max = Point(max.x, s.q.y+margin)
|
||||
if(s.p.x < min.x) min = Point(s.p.x-margin, min.y)
|
||||
if(s.p.y < min.y) min = Point(min.x, s.p.y-margin)
|
||||
if(s.q.x < min.x) min = Point(s.q.x-margin, min.y)
|
||||
if(s.q.y < min.y) min = Point(min.x, s.q.y-margin)
|
||||
}
|
||||
|
||||
val top = new Segment(new Point(min.x, max.y), new Point(max.x, max.y))
|
||||
val bottom = new Segment(new Point(min.x, min.y), new Point(max.x, min.y))
|
||||
val top = new Segment(Point(min.x, max.y), Point(max.x, max.y))
|
||||
val bottom = new Segment(Point(min.x, min.y), Point(max.x, min.y))
|
||||
val left = bottom.p
|
||||
val right = top.q
|
||||
|
||||
|
@ -70,12 +70,22 @@ class Triangulator(var segments: ArrayBuffer[Segment]) {
|
||||
tList = trapezoidalMap.case4(t, s)
|
||||
queryGraph.case4(t.sink, s, tList)
|
||||
}
|
||||
// Add new trapezoids to the trapezoidal map
|
||||
// Add new trapezoids to map
|
||||
tList.foreach(trapezoidalMap.add)
|
||||
}
|
||||
trapezoidalMap reset
|
||||
}
|
||||
trapezoids = trim
|
||||
|
||||
// Mark outside trapezoids
|
||||
trapezoidalMap.map.foreach(markOutside)
|
||||
|
||||
// Collect interior trapezoids
|
||||
for(t <- trapezoidalMap.map)
|
||||
if(t.inside) {
|
||||
trapezoids += t
|
||||
t addPoints
|
||||
}
|
||||
|
||||
createMountains
|
||||
|
||||
// Extract all the triangles into a single list
|
||||
@ -89,7 +99,7 @@ class Triangulator(var segments: ArrayBuffer[Segment]) {
|
||||
// The trapezoidal map
|
||||
def trapezoidMap = trapezoidalMap.map
|
||||
// Trapezoid decomposition list
|
||||
var trapezoids : ArrayBuffer[Trapezoid] = null
|
||||
var trapezoids = new ArrayBuffer[Trapezoid]
|
||||
// Monotone polygons - these are monotone mountains
|
||||
def monoPolies: ArrayBuffer[ArrayBuffer[Point]] = {
|
||||
val polies = new ArrayBuffer[ArrayBuffer[Point]]
|
||||
@ -101,14 +111,15 @@ class Triangulator(var segments: ArrayBuffer[Segment]) {
|
||||
// Initialize trapezoidal map and query structure
|
||||
private val trapezoidalMap = new TrapezoidalMap
|
||||
private val boundingBox = trapezoidalMap.boundingBox(segments)
|
||||
private val queryGraph = new QueryGraph(new Sink(boundingBox))
|
||||
trapezoidalMap add boundingBox
|
||||
private val queryGraph = new QueryGraph(Sink.init(boundingBox))
|
||||
private val xMonoPoly = new ArrayBuffer[MonotoneMountain]
|
||||
|
||||
// Build a list of x-monotone mountains
|
||||
private def createMountains {
|
||||
for(s <- segments) {
|
||||
val mountain = new MonotoneMountain
|
||||
val k = Util.msort((x: Point, y: Point) => x < y)(s.mPoints.toList)
|
||||
val k = Util.msort((p1: Point, p2: Point) => p1 < p2)(s.mPoints.toList)
|
||||
val points = s.p :: k ::: List(s.q)
|
||||
points.foreach(p => mountain += p.clone)
|
||||
if(mountain.size > 2) {
|
||||
@ -118,22 +129,11 @@ class Triangulator(var segments: ArrayBuffer[Segment]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Trim off the extraneous trapezoids surrounding the polygon
|
||||
private def trim = {
|
||||
val traps = new ArrayBuffer[Trapezoid]
|
||||
// Mark outside trapezoids
|
||||
for(t <- trapezoidalMap.map) {
|
||||
// Mark the outside trapezoids surrounding the polygon
|
||||
private def markOutside(t: Trapezoid) {
|
||||
if(t.top == boundingBox.top || t.bottom == boundingBox.bottom) {
|
||||
t.outside = true
|
||||
t.markNeighbors
|
||||
t trimNeighbors
|
||||
}
|
||||
}
|
||||
// Collect interior trapezoids
|
||||
for(t <- trapezoidalMap.map) if(!t.outside) {
|
||||
traps += t
|
||||
t.mark
|
||||
}
|
||||
traps
|
||||
}
|
||||
|
||||
private def orderSegments = {
|
||||
@ -142,14 +142,12 @@ class Triangulator(var segments: ArrayBuffer[Segment]) {
|
||||
for(s <- segments) {
|
||||
// Point p must be to the left of point q
|
||||
if(s.p.x > s.q.x) {
|
||||
val tmp = s.p
|
||||
s.p = s.q
|
||||
s.q = tmp
|
||||
segs += s
|
||||
segs += new Segment(s.q.clone, s.p.clone)
|
||||
} else if(s.p.x < s.q.x)
|
||||
segs += s
|
||||
segs += new Segment(s.p.clone, s.q.clone)
|
||||
}
|
||||
// This is actually important: See Seidel's paper
|
||||
Random.shuffle(segs)
|
||||
//Random.shuffle(segs)
|
||||
segs
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user