bug hunting

This commit is contained in:
zzzzrrr 2009-08-04 16:23:07 -04:00
parent 324fb8207e
commit 660f5d752a
4 changed files with 147 additions and 70 deletions

View File

@ -232,7 +232,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
def loadModel(model: String, scale: Float, center: Point, maxTriangles: Int) {
println("*** " + model + " ***")
println
println("************** " + model + " **************")
polyX = new ArrayBuffer[Float]
polyY = new ArrayBuffer[Float]
@ -259,11 +260,16 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
segments += new Segment(points(i), points(i+1))
segments += new Segment(points.first, points.last)
slCDT = CDT.init(points)
println("Number of points = " + polyX.size)
println
val t1 = System.nanoTime
slCDT = CDT.init(points)
val runTime = System.nanoTime - t1
println("CDT average (ms) = " + runTime*1e-6)
println("Number of triangles = " + slCDT.triangles.size)
println
if(!drawEarClip) {
// Sediel triangulation

View File

@ -36,7 +36,6 @@ import shapes.{Point, Triangle}
class AFront(iTriangle: Triangle) {
// Doubly linked list
// TODO: Replace with a Red-Black Tree for better performance
var head = new Node(iTriangle.points(1), iTriangle)
head.next = new Node(iTriangle.points(0), iTriangle)
var tail = new Node(iTriangle.points(2), null)
@ -44,6 +43,7 @@ class AFront(iTriangle: Triangle) {
head.next.next = tail
tail.prev = head.next
// TODO: Usea Red-Black Tree or interval tree for better search performance!
def locate(point: Point): Node = {
var node = head
while(node != tail) {
@ -76,14 +76,8 @@ class AFront(iTriangle: Triangle) {
}
// Advancing front node
class Node(val point: Point, var triangle: Triangle) {
var next: Node = null
var prev: Node = null
def printDebug {
println("Point: " + point)
if(triangle != null)
println("Triangle points: " + triangle.points)
}
}

View File

@ -36,7 +36,7 @@ import shapes.{Segment, Point, Triangle}
import utils.Util
/**
* Sweep-line, Constrained Delauney Triangulation
* Sweep-line, Constrained Delauney Triangulation (CDT)
* See: Domiter, V. and Žalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',
* International Journal of Geographical Information Science,22:4,449 462
*/
@ -124,7 +124,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Implement sweep-line
private def sweep {
for(i <- 1 until 11 /*points.size*/) {
for(i <- 1 until points.size) {
val point = points(i)
// Process Point event
val triangle = pointEvent(point)
@ -137,9 +137,8 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
private def pointEvent(point: Point): Triangle = {
val node = aFront.locate(point)
var newNode: Node = null
if(point.x == node.point.x) {
if(point.x == node.point.x && node != aFront.head) {
// Projected point coincides with existing point; create two triangles
val rPts = Array(point, node.point, node.next.point)
@ -163,11 +162,15 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
node.prev.triangle.updateNeighbors(node.point, node.prev.point, rTriangle)
// Update advancing front
newNode = aFront.insert(point, rTriangle, node)
val newNode = aFront.insert(point, rTriangle, node)
aFront -= (node.prev, node, rTriangle)
// Fill in adjacent triangles if required
scanAFront(newNode)
newNode.triangle
} else {
// Projected point hits advancing front; create new triangle
val cwPoint = node.next.point
val ccwPoint = node.point
@ -181,16 +184,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Legalize
legalization(triangle, nTri)
// Update neighbor pointers
nTri.updateNeighbors(ccwPoint, cwPoint, triangle)
nTri.updateNeighbors(triangle.points(1), triangle.points(2), triangle)
// Update advancing front
newNode = aFront.insert(point, triangle, node)
val newNode = aFront.insert(point, triangle, node)
// Fill in adjacent triangles if required
scanAFront(newNode)
newNode.triangle
}
// Fill in adjacent triangles if required
scan(newNode)
newNode.triangle
}
// EdgeEvent
@ -198,49 +199,58 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// STEP 1: Locate the first intersected triangle
val firstTriangle = triangle.locateFirst(edge)
// STEP 2: Remove intersected triangles
// STEP 3: Triangulate empty areas.
if(firstTriangle != null && !firstTriangle.contains(edge)) {
// Collect intersected triangles
val triangles = new ArrayBuffer[Triangle]
triangles += firstTriangle
val e = edge.p - edge.q
while(!triangles.last.contains(edge.p))
triangles += triangles.last.findNeighbor(e)
// Remove from the mesh
// TODO: Implement this section
//triangles.foreach(t => mesh.map -= t)
} else if(firstTriangle == null) {
// Traverse the AFront, and build triangles
var node = aFront.locate(edge.q)
node = node.next
val points = new ArrayBuffer[Point]
// No triangles are intersected by the edge; edge must lie outside the mesh
// Apply constraint; traverse the AFront, and build triangles
if(edge.p.x > edge.q.x) {
// Search right
while(node != null && node.point != edge.p) {
// Collect points
points += node.point
node = node.next
}
} else {
// Search left
while(node != null && node.point != edge.p) {
// Collect points
points += node.point
node = node.prev
}
}
val ahead = (edge.p.x > edge.q.x)
val point1 = if(ahead) edge.q else edge.p
val point2 = if(ahead) edge.p else edge.q
val points = new ArrayBuffer[Point]
var node = aFront.locate(point1)
val node1 = node
node = node.next
while(node.point != point2) {
points += node.point
node = node.next
}
val node2 = node
val T = new ArrayBuffer[Triangle]
angladaTPD(points.toArray, List(edge.p, edge.q), T)
T.foreach(t => mesh.debug += t)
angladaTPD(points.toArray, List(point1, point2), T)
node1.triangle = T.first
node1.next = node2
node2.prev = node1
T.foreach(t => mesh.map += t)
}
// STEP 3: Triangulate empty areas.
}
// Marc Vigo Anglada's triangulatePseudopolygonDelaunay algo
// TODO: Bugy fix - works for a single triangle
def angladaTPD(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) {
val a = ab.first
@ -263,13 +273,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
if(!P.isEmpty) {
c = P.first
val points = Array(a, b, c)
// TODO: Correctly update neighbor pointers
val neighbors = new Array[Triangle](3)
T += new Triangle(points, neighbors)
}
}
// Scan left and right along AFront to fill holes
def scan(n: Node) {
def scanAFront(n: Node) {
var node = n.next
// Update right
@ -294,6 +305,7 @@ 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))
@ -312,6 +324,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Do edges need to be swapped?
private def illegal(p1: Point, p2: Point, p3: Point, p4:Point): Boolean = {
val v1 = p3 - p2
val v2 = p1 - p2
val v3 = p1 - p4
@ -322,28 +335,42 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
false
}
// Ensure new adjacent triangles are legal
// Ensure adjacent triangles are legal
// If illegal, flip edges and update triangle's pointers
private def legalization(t1: Triangle, t2: Triangle) {
val oPoint = t2 oppositePoint t1
if(illegal(t1.points(1), oPoint, t1.points(2), t1.points(0))) {
// Flip edges and rotate everything clockwise
val point = t1.points(0)
t1.points(1) = t1.points(0)
t1.points(0) = t1.points(2)
t1.points(2) = oPoint
val tmp = t2.points(1)
t2.points(1) = point
t2.points(0) = t2.points(2)
t2.points(2) = tmp
t1.updatePoints
t2.updatePoints
// TODO: Rotate neighbors
println("legalize")
val point = t1.points(0)
t1.legalize(oPoint)
t2.legalize(oPoint, point)
// TODO: Make sure this is correct
val cwNeighbor = t2.neighborCW(oPoint)
val ccwNeighbor = t2.neighborCCW(oPoint)
t1.neighbors(0) = t2
t1.neighbors(1) = cwNeighbor
t1.neighbors(2) = null
if(t2.points(0) == oPoint) {
t2.neighbors(0) = null
t2.neighbors(1) = ccwNeighbor
t2.neighbors(2) = t1
} else {
t2.neighbors(0) = ccwNeighbor
t2.neighbors(1) = t1
t2.neighbors(2) = null
}
}
}
// Final step in the sweep-line CDT algo
private def finalization {
}
}

View File

@ -38,12 +38,14 @@ import scala.collection.mutable.ArrayBuffer
class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
var ik, ij , jk, ji, kj, ki: Point = null
updatePoints
updateEdges
// Flags to determine if an edge is the final Delauney edge
val edges = new Array[Boolean](3)
def updatePoints {
// Update the edges that consitite this triangle
// May change during legalization
def updateEdges {
ik = points(2) - points(0)
ij = points(1) - points(0)
jk = points(2) - points(1)
@ -89,9 +91,10 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
true
}
// Locate first triangle crossed by constrained edge
def locateFirst(edge: Segment): Triangle = {
val p = edge.p
if(contains(p) || contains(edge)) return this
if(contains(p)) return this
val q = edge.q
val e = p - q
if(q == points(0)) {
@ -113,6 +116,7 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
null
}
// Locate next triangle crossed by constraied edge
def findNeighbor(e: Point): Triangle = {
var sameSign = Math.signum(ik cross e) == Math.signum(ij cross e)
if(!sameSign) return neighbors(0)
@ -123,6 +127,52 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
this
}
// The neighbor CW to given point
def neighborCW(point: Point): Triangle = {
if(point == points(0)) {
neighbors(2)
}else if(point == points(1)) {
neighbors(0)
} else
neighbors(1)
}
// The neighbor CW to given point
def neighborCCW(point: Point): Triangle = {
if(point == points(0)) {
neighbors(1)
}else if(point == points(1)) {
neighbors(2)
} else
neighbors(0)
}
// Legalized triangle by rotating clockwise around point(0)
def legalize(oPoint: Point) {
points(1) = points(0)
points(0) = points(2)
points(2) = oPoint
updateEdges
}
// Legalize triagnle by rotating clockwise around oPoint
def legalize(oPoint: Point, nPoint: Point) {
if(oPoint == points(0)) {
points(1) = points(0)
points(0) = points(2)
points(2) = nPoint
} else if (oPoint == points(1)) {
points(2) = points(1)
points(1) = points(0)
points(0) = nPoint
} else {
points(0) = points(2)
points(2) = points(1)
points(1) = nPoint
}
updateEdges
}
def printDebug {
println("**************")
println(points(0) + "," + points(1) + "," + points(2))