From 54b7fbd0096532ee5d71f1f4beb974de3268b142 Mon Sep 17 00:00:00 2001 From: zzzzrrr Date: Sun, 2 Aug 2009 12:12:55 -0400 Subject: [PATCH] edge event work --- src/org/poly2tri/Poly2Tri.scala | 4 +- src/org/poly2tri/cdt/CDT.scala | 63 +++++++++++++++----------- src/org/poly2tri/shapes/Point.scala | 7 --- src/org/poly2tri/shapes/Segment.scala | 13 +++++- src/org/poly2tri/shapes/Triangle.scala | 56 +++++++++++++++-------- 5 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/org/poly2tri/Poly2Tri.scala b/src/org/poly2tri/Poly2Tri.scala index ff9006c..a87a37b 100644 --- a/src/org/poly2tri/Poly2Tri.scala +++ b/src/org/poly2tri/Poly2Tri.scala @@ -85,7 +85,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { val strange = "data/strange.dat" val i18 = "data/i.18" - var currentModel = nazcaMonkey + var currentModel = i18 def init(container: GameContainer) { selectModel(currentModel) @@ -153,7 +153,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") { }) if(drawCDT) { - slCDT.mesh.map.foreach( t => { + slCDT.triangles.foreach( t => { val triangle = new Polygon triangle.addPoint(t.points(0).x, t.points(0).y) triangle.addPoint(t.points(1).x, t.points(1).y) diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index 9622fdf..1f4d05b 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -44,6 +44,7 @@ object CDT { // Inital triangle factor val ALPHA = 0.3f + val SHEER = 0.00001f // Triangulate simple polygon def init(points: ArrayBuffer[Point]): CDT = { @@ -78,19 +79,15 @@ object CDT { // Create segments and connect end points; update edge event pointer private def initSegments(points: ArrayBuffer[Point]): List[Segment] = { var segments = List[Segment]() - for(i <- 0 until points.size-1) - segments = segment(points(i), points(i+1)) :: segments - segments = segment(points.first, points.last) :: segments + for(i <- 0 until points.size-1) { + segments = new Segment(points(i), points(i+1)) :: segments + segments.first.updateEdge + } + segments = new Segment(points.first, points.last) :: segments + segments.first.updateEdge segments } - // Create a new segment and updates edge pointer - private def segment(p1: Point, p2: Point): Segment = { - val seg = new Segment(p1, p2) - p1.updateEdges(p2, seg) - seg - } - // Insertion sort is one of the fastest algorithms for sorting arrays containing // fewer than ten elements, or for lists that are already mostly sorted. // Merge sort: O(n log n) @@ -103,19 +100,20 @@ object CDT { // Prevents any two distinct endpoints from lying on a common horizontal line, and avoiding // the degenerate case. See Mark de Berg et al, Chapter 6.3 - //val SHEER = 0.0001f - private def shearTransform(point: Point) = Point(point.x, point.y + point.x * 0.0001f) + private def shearTransform(point: Point) = Point(point.x, point.y + point.x * SHEER) } class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Triangle) { + // Triangle list + def triangles = mesh.map // The triangle mesh - val mesh = new Mesh(iTriangle) + private val mesh = new Mesh(iTriangle) // Advancing front - val aFront = new AFront(iTriangle) + private val aFront = new AFront(iTriangle) - val PI_2 = Math.Pi/2 + private val PI_2 = Math.Pi/2 // Sweep points; build mesh sweep @@ -124,13 +122,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Implement sweep-line private def sweep { - - for(i <- 1 until points.size) { + for(i <- 1 until 9 /*points.size*/) { val point = points(i) + println(point) + // Process Point event val triangle = pointEvent(point) - edgeEvent(point, triangle) + // Process edge events + point.edges.foreach(e => edgeEvent(e, triangle)) } - } // Point event @@ -159,17 +158,23 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian // Update advancing front val newNode = aFront.insert(point, triangle, node) // Fill in adjacent triangles if required - march(newNode) + scan(newNode) triangle } // EdgeEvent - private def edgeEvent(point: Point, triangle: Triangle) { - mesh.addEdge(point, triangle) + private def edgeEvent(edge: Segment, triangle: Triangle) { + // STEP 1: Locate the first intersected triangle + val first = triangle.locateFirst(edge) + println(first) + if(first != null && first != triangle && !first.contains(edge)) + mesh.map -= first + // STEP 2: Remove intersected triangles + // STEP 3: Triangulate empty areas. } - // Scan left and right to fill holes in the mesh - def march(n: Node) { + // Scan left and right along AFront to fill holes + def scan(n: Node) { var node = n.next // Update right @@ -192,14 +197,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian } } + // Fill empty space with a triangle def fill(node: Node): Double = { val a = (node.prev.point - node.point) val b = (node.next.point - node.point) val angle = Math.abs(Math.atan2(a cross b, a dot b)) if(angle <= PI_2) { - val points = Array(node.point, node.next.point, node.prev.point) - val neighbors = Array(null, node.prev.triangle, node.triangle) + val points = Array(node.prev.point, node.next.point, node.point) + val neighbors = Array(node.prev.triangle, null, node.triangle) val triangle = new Triangle(points, neighbors) + // Update neighbor pointers + node.prev.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle) + node.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle) mesh.map += triangle aFront -= (node.prev, node, triangle) } @@ -231,10 +240,10 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian t2.points(0) = t2.points(2) t2.points(2) = tmp // Rotate neighbors + } private def finalization { } - def triangles = mesh.map } diff --git a/src/org/poly2tri/shapes/Point.scala b/src/org/poly2tri/shapes/Point.scala index 49ca1ef..fba52e0 100644 --- a/src/org/poly2tri/shapes/Point.scala +++ b/src/org/poly2tri/shapes/Point.scala @@ -58,11 +58,4 @@ case class Point(val x: Float, val y: Float) { @inline def !(p: Point) = !(p.x == x && p.y == y) @inline override def clone = Point(x, y) - def updateEdges(point: Point, segment: Segment) { - if(point.y > y) - point.edges += segment - else - edges += segment - } - } diff --git a/src/org/poly2tri/shapes/Segment.scala b/src/org/poly2tri/shapes/Segment.scala index 22b95af..de563d8 100644 --- a/src/org/poly2tri/shapes/Segment.scala +++ b/src/org/poly2tri/shapes/Segment.scala @@ -30,7 +30,7 @@ */ package org.poly2tri.shapes -import scala.collection.mutable.{ArrayBuffer} +import scala.collection.mutable.ArrayBuffer // Represents a simple polygon's edge // TODO: Rename this class to Edge? @@ -51,4 +51,15 @@ class Segment(var p: Point, var q: Point) { // Determines if this segment lies below the given point def < (point: Point) = (Math.floor(point.y) > Math.floor(slope * point.x + b)) + // Update point edge list for CDT + def updateEdge { + if(p.y > q.y) { + // For CDT we want q to be the point with > y + val tmp = p + p = q + q = tmp + } + q.edges += this + } + } diff --git a/src/org/poly2tri/shapes/Triangle.scala b/src/org/poly2tri/shapes/Triangle.scala index d50b825..25dc8c9 100644 --- a/src/org/poly2tri/shapes/Triangle.scala +++ b/src/org/poly2tri/shapes/Triangle.scala @@ -35,20 +35,16 @@ package org.poly2tri.shapes // "Triangulations in CGAL" class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { + val ik = points(2) - points(0) + val ij = points(1) - points(0) + val jk = points(2) - points(1) + val ji = points(0) - points(1) + val kj = points(1) - points(2) + val ki = points(0) - points(2) + // Flags to determine if an edge is the final Delauney edge val edges = new Array[Boolean](3) - def contains(point: Point) = { - if(point == points(0) || point == points(1) || point == points(2)) - true - else - false - } - - def legalize { - - } - // Update neighbor pointers def updateNeighbors(ccwPoint: Point, cwPoint: Point, triangle: Triangle) { if(ccwPoint == points(2) && cwPoint == points(1)) @@ -68,23 +64,45 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) { points(0) } + def contains(p: Point): Boolean = (p == points(0) || p == points(1) || p == points(2)) + def contains(e: Segment): Boolean = (contains(e.p) || contains(e.q)) + // Fast point in triangle test def pointIn(point: Point): Boolean = { - - val ab = points(1) - points(0) - val bc = points(2) - points(1) - val ca = points(0) - points(2) - val pab = (point - points(0)).cross(ab) - val pbc = (point - points(1)).cross(bc) + val pab = (point - points(0)).cross(ij) + val pbc = (point - points(1)).cross(jk) var sameSign = Math.signum(pab) == Math.signum(pbc) if (!sameSign) return false - val pca = (point - points(2)).cross(ca) + val pca = (point - points(2)).cross(ki) sameSign = Math.signum(pab) == Math.signum(pca) if (!sameSign) return false true -} + } + def locateFirst(edge: Segment): Triangle = { + val p = edge.p + if(contains(p)) return this + val q = edge.q + val e = q - p + if(q == points(0)) { + val sameSign = Math.signum(ik cross e) == Math.signum(ij cross e) + if(!sameSign) return this + if(neighbors(2) == null) return null + return neighbors(2).locateFirst(edge) + } else if(q == points(1)) { + val sameSign = Math.signum(jk cross e) == Math.signum(ji cross e) + if(!sameSign) return this + if(neighbors(0) == null) return null + return neighbors(0).locateFirst(edge) + } else if(q == points(2)) { + val sameSign = Math.signum(kj cross e) == Math.signum(ki cross e) + if(!sameSign) return this + if(neighbors(1) == null) return null + return neighbors(1).locateFirst(edge) + } + throw new Exception("location error") + } }