mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-26 15:26:12 +01:00
init CDT
This commit is contained in:
parent
f75a0a2974
commit
3ededbd3d0
@ -28,14 +28,75 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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
|
* Sweep-line, Constrained Delauney Triangulation
|
||||||
* See: Domiter, V. and Žalik, B.(2008)'Sweep-line algorithm for constrained Delaunay 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
|
* International Journal of Geographical Information Science,22:4,449 — 462
|
||||||
*/
|
*/
|
||||||
package org.poly2tri.cdt
|
class CDT(segments: ArrayBuffer[Segment]) {
|
||||||
|
|
||||||
class CDT {
|
// 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)
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ package org.poly2tri.cdt
|
|||||||
|
|
||||||
import scala.collection.mutable.HashSet
|
import scala.collection.mutable.HashSet
|
||||||
|
|
||||||
|
import shapes.Point
|
||||||
|
|
||||||
class Mesh {
|
class Mesh {
|
||||||
|
|
||||||
val map = HashSet.empty[Triangle]
|
val map = HashSet.empty[Triangle]
|
||||||
|
@ -158,7 +158,7 @@ class Triangulator(segments: ArrayBuffer[Segment]) {
|
|||||||
if(s.mPoints.size < 10)
|
if(s.mPoints.size < 10)
|
||||||
// Insertion sort is one of the fastest algorithms for sorting arrays containing
|
// Insertion sort is one of the fastest algorithms for sorting arrays containing
|
||||||
// fewer than ten elements, or for lists that are already mostly sorted.
|
// 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
|
else
|
||||||
k = Util.msort((p1: Point, p2: Point) => p1 < p2)(s.mPoints.toList)
|
k = Util.msort((p1: Point, p2: Point) => p1 < p2)(s.mPoints.toList)
|
||||||
|
|
||||||
|
@ -30,10 +30,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.poly2tri.shapes
|
package org.poly2tri.shapes
|
||||||
|
|
||||||
|
object Event extends Enumeration {
|
||||||
|
val point, edge = Value
|
||||||
|
}
|
||||||
|
|
||||||
case class Point(val x: Float, val y: Float) {
|
case class Point(val x: Float, val y: Float) {
|
||||||
|
|
||||||
// Pointers to next and previous points in Monontone Mountain
|
// Pointers to next and previous points in Monontone Mountain
|
||||||
var next, prev: Point = null
|
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)
|
||||||
@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 dot(p: Point) = x * p.x + y * p.y
|
||||||
@inline def length = Math.sqrt(x * x + y * y).toFloat
|
@inline def length = Math.sqrt(x * x + y * y).toFloat
|
||||||
@inline def normalize = this / length
|
@inline def normalize = this / length
|
||||||
|
// Sort along x axis
|
||||||
@inline def <(p: Point) = (x < p.x)
|
@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 def !(p: Point) = !(p.x == x && p.y == y)
|
||||||
@inline override def clone = Point(x, y)
|
@inline override def clone = Point(x, y)
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,13 @@ import scala.collection.mutable.{ArrayBuffer}
|
|||||||
// Represents a simple polygon's edge
|
// Represents a simple polygon's edge
|
||||||
class Segment(var p: Point, var q: Point) {
|
class Segment(var p: Point, var q: Point) {
|
||||||
|
|
||||||
|
p.segment = this
|
||||||
|
q.segment = this
|
||||||
|
|
||||||
// Pointers used for building trapezoidal map
|
// Pointers used for building trapezoidal map
|
||||||
var above, below: Trapezoid = null
|
var above, below: Trapezoid = null
|
||||||
// Montone mountain points
|
// Montone mountain points
|
||||||
val mPoints = new ArrayBuffer[Point]
|
val mPoints = new ArrayBuffer[Point]
|
||||||
|
|
||||||
// Equation of a line: y = m*x + b
|
// Equation of a line: y = m*x + b
|
||||||
// Slope of the line (m)
|
// Slope of the line (m)
|
||||||
val slope = (q.y - p.y)/(q.x - p.x)
|
val slope = (q.y - p.y)/(q.x - p.x)
|
||||||
@ -51,4 +53,27 @@ class Segment(var p: Point, var q: Point) {
|
|||||||
// Determines if this segment lies below the given point
|
// Determines if this segment lies below the given point
|
||||||
def < (point: Point) = (Math.floor(point.y) > Math.floor(slope * point.x + b))
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,19 +19,19 @@ object Util {
|
|||||||
else merge(msort(less)(xs take n), msort(less)(xs drop n))
|
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
|
var j = 1
|
||||||
while(j < list.size){
|
while(j < xs.size){
|
||||||
val key = list(j)
|
val key = xs(j)
|
||||||
var i = j-1
|
var i = j-1
|
||||||
while(i>=0 && list(i).x > key.x){
|
while(i >= 0 && less(key, xs(i)) ){
|
||||||
list(i+1) = list(i)
|
xs(i+1) = xs(i)
|
||||||
i=i-1
|
i -= 1
|
||||||
}
|
}
|
||||||
list(i+1)=key
|
xs(i+1)=key
|
||||||
j=j+1
|
j += 1
|
||||||
}
|
}
|
||||||
list
|
xs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user