edge event work

This commit is contained in:
zzzzrrr 2009-08-02 12:12:55 -04:00
parent be0112a0a3
commit 54b7fbd009
5 changed files with 87 additions and 56 deletions

View File

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

View File

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

View File

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

View File

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

View File

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