bug fixes and optimizations

This commit is contained in:
zzzzrrr 2009-08-11 22:40:56 -04:00
parent 5fa8c4501e
commit 14980edabe
6 changed files with 94 additions and 137 deletions

View File

@ -87,7 +87,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
val i18 = "data/i.18" val i18 = "data/i.18"
val tank = "data/tank.dat" val tank = "data/tank.dat"
var currentModel = tank var currentModel = strange
var doCDT = true var doCDT = true
var mouseButton = 0 var mouseButton = 0
@ -112,7 +112,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
def render(container: GameContainer, g: Graphics) { def render(container: GameContainer, g: Graphics) {
g.drawString("'1-7' to cycle models, mouse to pan & zoom", 10, 520) g.drawString("'1-8' to cycle models, mouse to pan & zoom", 10, 520)
g.drawString("'SPACE' to show Seidel debug info", 10, 532) g.drawString("'SPACE' to show Seidel debug info", 10, 532)
g.drawString("'m' to show trapezoidal map (Seidel debug mode)", 10, 544) g.drawString("'m' to show trapezoidal map (Seidel debug mode)", 10, 544)
g.drawString("'e' to switch Seidel / EarClip", 10, 556) g.drawString("'e' to switch Seidel / EarClip", 10, 556)
@ -305,13 +305,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
CDT.clearPoint = 7 CDT.clearPoint = 7
loadModel(i18, 20f, Point(600f, 500f), 20) loadModel(i18, 20f, Point(600f, 500f), 20)
case "data/nazca_heron.dat" => case "data/nazca_heron.dat" =>
doCDT = false; drawCDT = false; drawcdtMesh = false
CDT.clearPoint = 7 CDT.clearPoint = 7
loadModel(nazcaHeron, 4.5f, Point(400f, 300f), 1500) loadModel(nazcaHeron, 4.2f, Point(400f, 300f), 1500)
case "data/tank.dat" => case "data/tank.dat" =>
//doCDT = false; drawCDT = false; drawcdtMesh = false //doCDT = false; drawCDT = false; drawcdtMesh = false
doCDT = true; drawCDT = true doCDT = true; drawCDT = true
CDT.clearPoint = 50 CDT.clearPoint = 38
loadModel(tank, -1f, Point(0f, 0f), 10) loadModel(tank, -1f, Point(100f, 0f), 10)
case _ => case _ =>
assert(false) assert(false)
} }
@ -361,7 +362,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
} }
if(!drawEarClip) { if(!drawEarClip) {
// Sediel triangulation // Sediel triangulation
seidel = new Triangulator(segments) seidel = new Triangulator(segments)

View File

@ -32,7 +32,7 @@ package org.poly2tri.cdt
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import shapes.{Point, Triangle} import shapes.{Point, Triangle, Segment}
// Advancing front // Advancing front
class AFront(iTriangle: Triangle) { class AFront(iTriangle: Triangle) {
@ -91,11 +91,13 @@ class AFront(iTriangle: Triangle) {
// Update advancing front with constrained edge triangles // Update advancing front with constrained edge triangles
def constrainedEdge(sNode: Node, eNode: Node, T1: ArrayBuffer[Triangle], def constrainedEdge(sNode: Node, eNode: Node, T1: ArrayBuffer[Triangle],
T2: ArrayBuffer[Triangle]): Triangle = { T2: ArrayBuffer[Triangle], edge: Segment): Triangle = {
var node = sNode var node = sNode
var t1r, t2r = false var t1r, t2r = false
// Scan the advancing front and update Node triangle pointers
// Either T1 OR T2
while(node != eNode) { while(node != eNode) {
T2.foreach(t => { T2.foreach(t => {
@ -115,68 +117,44 @@ class AFront(iTriangle: Triangle) {
node = node.next node = node.next
} }
if(t1r && !t2r)
T1.first
else if(t2r && !t1r)
T2.first
else
throw new Exception("edge insertion error")
} val point1 = edge.q
val point2 = edge.p
// Update advancing front with qNode
def constrainedEdge(qNode: Node, tList: ArrayBuffer[Triangle], T1: ArrayBuffer[Triangle],
T2: ArrayBuffer[Triangle]): Triangle = {
var t1r, t2r = false // Select edge triangles
for(t <- tList) { var edgeTri1: Triangle = null
var i = 0
if(qNode.triangle == t) { while(edgeTri1 == null) {
if(T1(i).contains(point1, point2))
val p1 = qNode.point edgeTri1 = T1(i)
val p2 = qNode.next.point i += 1
}
T2.foreach(tri => if(tri.contains(p1, p2)) {
qNode.triangle = tri // Mark constrained edge
t2r = true edgeTri1 markEdge(point1, point2)
})
var edgeTri2: Triangle = null
if(!t2r) i = 0
T1.foreach(tri => if(tri.contains(p1, p2)) { while(edgeTri2 == null) {
qNode.triangle = tri if(T2(i).contains(point1, point2))
t1r = true edgeTri2 = T2(i)
}) i += 1
}
} else if(qNode.prev.triangle == t) {
// Mark constrained edge
val p1 = qNode.prev.point edgeTri2 markEdge(point1, point2)
val p2 = qNode.point
// Update neighbor pointer
T2.foreach(tri => if(tri.contains(p1, p2)) { edgeTri1.markNeighbor(edgeTri2)
qNode.prev.triangle = tri
t2r = true
})
if(!t2r)
T1.foreach(tri => if(tri.contains(p1, p2)) {
qNode.prev.triangle = tri
t1r = true
})
} else if(qNode.next.triangle == t) {
throw new Exception("unanticipated edge event!")
}
}
if(t1r && !t2r) if(t1r && !t2r)
T1.first edgeTri1
else if(t2r && !t1r) else if(t2r && !t1r) {
T2.first edgeTri2
else } else {
throw new Exception("edge insertion error") throw new Exception("edge insertion error")
}
} }
@ -193,6 +171,7 @@ class AFront(iTriangle: Triangle) {
node1.triangle = t node1.triangle = t
} }
// NOT IMPLEMENTED
def basin(node: Node) { def basin(node: Node) {
if(node.next != tail) { if(node.next != tail) {
val p1 = node.point val p1 = node.point

View File

@ -30,7 +30,7 @@
*/ */
package org.poly2tri.cdt package org.poly2tri.cdt
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.{ArrayBuffer, Set}
import shapes.{Segment, Point, Triangle} import shapes.{Segment, Point, Triangle}
import utils.Util import utils.Util
@ -44,7 +44,7 @@ object CDT {
// Inital triangle factor // Inital triangle factor
val ALPHA = 0.3f val ALPHA = 0.3f
val SHEER = 0.001f val SHEER = 0.0001
var clearPoint = 0 var clearPoint = 0
@ -101,7 +101,7 @@ object CDT {
// Prevents any two distinct endpoints from lying on a common horizontal line, and avoiding // 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 // the degenerate case. See Mark de Berg et al, Chapter 6.3
private def shearTransform(point: Point) = Point(point.x, point.y + point.x * SHEER) private def shearTransform(point: Point) = Point(point.x, point.y + point.x * 0.001f)
} }
@ -144,7 +144,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
} catch { } catch {
case e: Exception => case e: Exception =>
throw new Exception("Systect point = " + i) //throw new Exception("Suspect point = " + i)
} }
} }
@ -154,9 +154,9 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Clean exterior triangles // Clean exterior triangles
private def finalization { private def finalization {
mesh.map.foreach(m => m.markEdges) mesh.map.foreach(m => m.markNeighborEdges)
mesh clean cleanTri mesh clean cleanTri
} }
// Point event // Point event
@ -191,17 +191,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val tList = new ArrayBuffer[Triangle] val tList = new ArrayBuffer[Triangle]
tList += firstTriangle tList += firstTriangle
while(tList.last != null && !tList.last.contains(edge.p)) while(!tList.last.contains(edge.p))
tList += tList.last.findNeighbor(edge.p - edge.q) tList += tList.last.findNeighbor(edge.p - edge.q)
// TODO: fix tList.last == null bug!
// Not sure why this happens in bird & nazca monkey demo...
if(tList.last == null) tList -= tList.last
// Neighbor triangles // Neighbor triangles
val nTriangles = new ArrayBuffer[Triangle] val nTriangles = new ArrayBuffer[Triangle]
// Remove old triangles; collect neighbor triangles // Remove old triangles; collect neighbor triangles
// Keep duplicates out
tList.foreach(t => { tList.foreach(t => {
t.neighbors.foreach(n => if(n != null && !tList.contains(n)) nTriangles += n) t.neighbors.foreach(n => if(n != null && !tList.contains(n)) nTriangles += n)
mesh.map -= t mesh.map -= t
@ -240,47 +237,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val point1 = if(ahead) edge.q else edge.p val point1 = if(ahead) edge.q else edge.p
val point2 = if(ahead) edge.p else edge.q val point2 = if(ahead) edge.p else edge.q
var first: Triangle = null val sNode = aFront.locate(point1)
val sNode = aFront.locatePoint(point1) val eNode = aFront.locate(point2)
val eNode = aFront.locatePoint(point2)
val first = aFront.constrainedEdge(sNode, eNode, T1, T2, edge)
if(sNode != null && eNode != null) {
first = aFront.constrainedEdge(sNode, eNode, T1, T2)
} else {
val qNode = if(sNode == null) eNode else sNode
first = aFront.constrainedEdge(qNode, tList, T1, T2)
}
// Update neighbors // Update neighbors
edgeNeighbors(nTriangles, T1) edgeNeighbors(nTriangles, T1)
edgeNeighbors(nTriangles, T2) edgeNeighbors(nTriangles, T2)
// Select edge triangle first
var edgeTri1: Triangle = null
var i = 0
while(edgeTri1 == null) {
if(T1(i).contains(point1, point2))
edgeTri1 = T1(i)
i += 1
}
// Select edge triangle
var edgeTri2: Triangle = null
i = 0
while(edgeTri2 == null) {
if(T2(i).contains(point1, point2))
edgeTri2 = T2(i)
i += 1
}
edgeTri1.markNeighbor(edgeTri2)
// Mark constrained edge
edgeTri1 mark(point1, point2)
edgeTri2 mark(point1, point2)
// Double check returning T2.first vs T1.first
first
} else if(firstTriangle == null) { } else if(firstTriangle == null) {
@ -330,17 +296,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
edgeNeighbors(nTriangles, T) edgeNeighbors(nTriangles, T)
// Mark constrained edge // Mark constrained edge
edgeTri mark(edge.p, edge.q) edgeTri markEdge(point1, point2)
// Return original triangle // Return original triangle
triangle triangle
} else if(firstTriangle.contains(edge.p, edge.q)) { } else if(firstTriangle.contains(edge.p, edge.q)) {
// Mark constrained edge // Mark constrained edge
firstTriangle mark(edge.p, edge.q) firstTriangle markEdge(edge.p, edge.q)
triangle triangle
} else { } else {
throw new Exception("Triangulation error") throw new Exception("Triangulation error")
//null
} }
} }

View File

@ -42,17 +42,25 @@ class Mesh(initialTriangle: Triangle) {
val debug = HashSet.empty[Triangle] val debug = HashSet.empty[Triangle]
val triangles = new ArrayBuffer[Triangle] val triangles = new ArrayBuffer[Triangle]
def test(triangle: Triangle) {
if(triangle != null && !triangle.test){
triangle.test = true
debug += triangle
for(i <- 0 until 3) {
test(triangle.neighbors(i))
}
}
}
// Recursively collect triangles // Recursively collect triangles
def clean(triangle: Triangle) { def clean(triangle: Triangle) {
if(triangle != null && !triangle.clean) { if(triangle != null && !triangle.interior) {
triangle.clean = true triangle.interior = true
triangles += triangle triangles += triangle
if(!triangle.edges(0)) for(i <- 0 until 3) {
clean(triangle.neighbors(0)) if(!triangle.edges(i))
if(!triangle.edges(1)) clean(triangle.neighbors(i))
clean(triangle.neighbors(1)) }
if(!triangle.edges(2))
clean(triangle.neighbors(2))
} }
} }

View File

@ -46,10 +46,12 @@ class Triangle(val points: Array[Point]) {
val edges = Array(false, false, false) val edges = Array(false, false, false)
// Finalization flag // Finalization flag
var clean = false var interior = false
var finalized = false var finalized = false
var test = false
// Update neighbor pointers // Update neighbor pointers
private def markNeighbor(p1: Point, p2: Point, t: Triangle) { private def markNeighbor(p1: Point, p2: Point, t: Triangle) {
@ -284,15 +286,9 @@ class Triangle(val points: Array[Point]) {
} }
def printDebug = println(points(0) + "," + points(1) + "," + points(2)) def printDebug = println(points(0) + "," + points(1) + "," + points(2))
// Initial mark edges sweep
def mark(p: Point, q: Point) {
markEdge(p, q)
markNeighborEdge(p, q)
}
// Finalize edge marking // Finalize edge marking
def markEdges { def markNeighborEdges {
for(i <- 0 to 2) for(i <- 0 to 2)
if(edges(i)) if(edges(i))
i match { i match {
@ -302,18 +298,24 @@ class Triangle(val points: Array[Point]) {
} }
} }
// Mark neighbor's edge def markEdge(triangle: Triangle) {
private def markNeighborEdge(p: Point, q: Point) = for(i <- 0 to 2)
neighbors.foreach(n => if(n != null) n.markEdge(p, q)) if(edges(i))
i match {
case 0 => triangle.markEdge(points(1), points(2))
case 1 => triangle.markEdge(points(0), points(2))
case _ => triangle.markEdge(points(0), points(1))
}
}
// Mark edge as constrained // Mark edge as constrained
private def markEdge(p: Point, q: Point) { def markEdge(p: Point, q: Point) {
if((q == points(0) && p == points(1)) || (q == points(1) && p == points(0))) { if((q == points(0) && p == points(1)) || (q == points(1) && p == points(0))) {
finalized = true finalized = true
edges(2) = true edges(2) = true
} else if ((q == points(0) && p == points(2)) || (q == points(2) && p == points(0))) { } else if ((q == points(0) && p == points(2)) || (q == points(2) && p == points(0))) {
finalized = true
edges(1) = true edges(1) = true
finalized = true
} else if ((q == points(1) && p == points(2)) || (q == points(2) && p == points(1))){ } else if ((q == points(1) && p == points(2)) || (q == points(2) && p == points(1))){
finalized = true finalized = true
edges(0) = true edges(0) = true

View File

@ -8,7 +8,7 @@ import shapes.Point
object Util { object Util {
// Almost zero // Almost zero
val COLLINEAR_SLOP = 0.01f val COLLINEAR_SLOP = 0.1f
val epsilon = exactinit val epsilon = exactinit
val ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon val ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon