diff --git a/src/org/poly2tri/cdt/CDT.scala b/src/org/poly2tri/cdt/CDT.scala index c6a74cb..dbeaaa7 100644 --- a/src/org/poly2tri/cdt/CDT.scala +++ b/src/org/poly2tri/cdt/CDT.scala @@ -28,14 +28,75 @@ * 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.ArrayBuffer + +import shapes.{Segment, Point} +import utils.Util /** * Sweep-line, Constrained Delauney Triangulation * See: Domiter, V. and Žalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science,22:4,449 — 462 */ -package org.poly2tri.cdt - -class CDT { +class CDT(segments: ArrayBuffer[Segment]) { + // The point list + val points = init + // The triangle mesh + val mesh = new Mesh + + // Sweep points; build mesh + sweep + // Finalize triangulation + finalization + + // Initialize and sort point list + private def init: List[Point] = { + + var xmax, xmin = 0f + var ymax, ymin = 0f + val pts = new ArrayBuffer[Point] + + for(i <- 0 until segments.size) { + + val p = segments(i).p + val q = segments(i).q + + if(p.x > xmax) xmax = p.x + if(q.x > xmax) xmax = q.x + if(p.x < xmin) xmin = p.x + if(q.x < xmin) xmin = q.x + + if(p.y > ymax) ymax = p.x + if(q.y > ymax) ymax = q.x + if(p.y < ymin) ymin = p.x + if(q.y < ymin) ymin = q.x + + + pts += shearTransform(p) + pts += shearTransform(q) + } + + 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 + else + // Merge sort: O(n log n) + Util.msort((p1: Point, p2: Point) => p1 > p2)(pts.toList) + } + + // Implement sweep-line paradigm + private def sweep { + } + + private def finalization { + } + + // 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 + def shearTransform(point: Point) = Point(point.x, point.y + point.x * 0.0001f) } diff --git a/src/org/poly2tri/cdt/Mesh.scala b/src/org/poly2tri/cdt/Mesh.scala index 8f6da95..0b929e0 100644 --- a/src/org/poly2tri/cdt/Mesh.scala +++ b/src/org/poly2tri/cdt/Mesh.scala @@ -31,7 +31,9 @@ package org.poly2tri.cdt import scala.collection.mutable.HashSet - + +import shapes.Point + class Mesh { val map = HashSet.empty[Triangle] diff --git a/src/org/poly2tri/seidel/Triangulator.scala b/src/org/poly2tri/seidel/Triangulator.scala index fc34ca2..b054f41 100644 --- a/src/org/poly2tri/seidel/Triangulator.scala +++ b/src/org/poly2tri/seidel/Triangulator.scala @@ -158,7 +158,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) { if(s.mPoints.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. - k = Util.insertSort(s.mPoints).toList + k = Util.insertSort((p1: Point, p2: Point) => p1 < p2)(s.mPoints).toList else k = Util.msort((p1: Point, p2: Point) => p1 < p2)(s.mPoints.toList) diff --git a/src/org/poly2tri/shapes/Point.scala b/src/org/poly2tri/shapes/Point.scala index 34c174a..b2111c9 100644 --- a/src/org/poly2tri/shapes/Point.scala +++ b/src/org/poly2tri/shapes/Point.scala @@ -30,10 +30,18 @@ */ package org.poly2tri.shapes +object Event extends Enumeration { + val point, edge = Value +} + case class Point(val x: Float, val y: Float) { // Pointers to next and previous points in Monontone Mountain var next, prev: Point = null + // The setment this point belongs to + var segment: Segment = null + // Point type for CDT + var eventType: Event.Value = _ @inline def -(p: Point) = Point(x - p.x, y - p.y) @inline def +(p: Point) = Point(x + p.x, y + p.y) @@ -45,7 +53,10 @@ case class Point(val x: Float, val y: Float) { @inline def dot(p: Point) = x * p.x + y * p.y @inline def length = Math.sqrt(x * x + y * y).toFloat @inline def normalize = this / length - @inline def <(p: Point) = (x < p.x) + // Sort along x axis + @inline def <(p: Point) = (x < p.x) + // Sort along y axis + @inline def >(p: Point) = (y < p.y) @inline def !(p: Point) = !(p.x == x && p.y == y) @inline override def clone = Point(x, y) } diff --git a/src/org/poly2tri/shapes/Segment.scala b/src/org/poly2tri/shapes/Segment.scala index 0d032d5..e23686a 100644 --- a/src/org/poly2tri/shapes/Segment.scala +++ b/src/org/poly2tri/shapes/Segment.scala @@ -35,11 +35,13 @@ import scala.collection.mutable.{ArrayBuffer} // Represents a simple polygon's edge class Segment(var p: Point, var q: Point) { + p.segment = this + q.segment = this + // Pointers used for building trapezoidal map var above, below: Trapezoid = null // Montone mountain points val mPoints = new ArrayBuffer[Point] - // Equation of a line: y = m*x + b // Slope of the line (m) val slope = (q.y - p.y)/(q.x - p.x) @@ -50,5 +52,28 @@ class Segment(var p: Point, var q: Point) { def > (point: Point) = (Math.floor(point.y) < Math.floor(slope * point.x + b)) // Determines if this segment lies below the given point def < (point: Point) = (Math.floor(point.y) > Math.floor(slope * point.x + b)) + + // Assign point type for CDT + if(p.y > q.y) + pEdge + else if (p.y < q.y) + pPoint + else + if(p.x < q.x) + pPoint + else if (p.x > q.x) + pEdge + else + throw new Exception("Invalid segment") + + private def pPoint { + p.eventType = Event.point + q.eventType = Event.edge + } + + private def pEdge { + p.eventType = Event.edge + q.eventType = Event.point + } } diff --git a/src/org/poly2tri/utils/Util.scala b/src/org/poly2tri/utils/Util.scala index c7c685e..b2048c5 100644 --- a/src/org/poly2tri/utils/Util.scala +++ b/src/org/poly2tri/utils/Util.scala @@ -19,19 +19,19 @@ object Util { else merge(msort(less)(xs take n), msort(less)(xs drop n)) } - def insertSort(list:ArrayBuffer[Point]) = { + def insertSort[A](less: (A, A) => Boolean)(xs: ArrayBuffer[A]): ArrayBuffer[A] = { var j = 1 - while(j < list.size){ - val key = list(j) + while(j < xs.size){ + val key = xs(j) var i = j-1 - while(i>=0 && list(i).x > key.x){ - list(i+1) = list(i) - i=i-1 + while(i >= 0 && less(key, xs(i)) ){ + xs(i+1) = xs(i) + i -= 1 } - list(i+1)=key - j=j+1 + xs(i+1)=key + j += 1 } - list + xs } }