This commit is contained in:
zzzzrrr 2009-07-28 21:01:41 -04:00
parent f75a0a2974
commit 3ededbd3d0
6 changed files with 115 additions and 16 deletions

View File

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

View File

@ -31,7 +31,9 @@
package org.poly2tri.cdt
import scala.collection.mutable.HashSet
import shapes.Point
class Mesh {
val map = HashSet.empty[Triangle]

View File

@ -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)

View File

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

View File

@ -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
}
}

View File

@ -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
}
}