updated comments

This commit is contained in:
zzzzrrr 2009-08-25 13:56:55 -04:00
parent ed89aea7c0
commit d2dd39686e
4 changed files with 67 additions and 46 deletions

View File

@ -42,7 +42,7 @@ import earClip.EarClip
import cdt.CDT import cdt.CDT
// TODO: Lots of documentation! // TODO: Lots of documentation!
// : Add Hertel-Mehlhorn algorithm
object Poly2Tri { object Poly2Tri {
def main(args: Array[String]) { def main(args: Array[String]) {
@ -250,11 +250,15 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
mousePressed = true mousePressed = true
mousePosOld = mousePos mousePosOld = mousePos
mousePos = Point(x, y) mousePos = Point(x, y)
/*
val point = mousePos/scaleFactor + Point(deltaX, deltaY) // Right click
slCDT.addPoint(point) // Correctly adjust for pan and zoom
slCDT.triangulate if(mouseButton == 1) {
*/ val point = mousePos/scaleFactor + Point(deltaX, deltaY)
slCDT.addPoint(point)
slCDT.triangulate
}
} }
/** /**
@ -306,6 +310,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
if (hiLighter == -1) if (hiLighter == -1)
hiLighter = seidel.polygons.size-1 hiLighter = seidel.polygons.size-1
} }
if(c == 'm') drawMap = !drawMap if(c == 'm') drawMap = !drawMap
if(c == 'd') drawCDT = !drawCDT if(c == 'd') drawCDT = !drawCDT
if(c == '1') selectModel(nazcaMonkey) if(c == '1') selectModel(nazcaMonkey)
@ -320,6 +325,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
if(c == 's') drawSegs = !drawSegs if(c == 's') drawSegs = !drawSegs
if(c == 'c') drawcdtMesh = !drawcdtMesh if(c == 'c') drawcdtMesh = !drawcdtMesh
if(c == 'e') {drawEarClip = !drawEarClip; drawCDT = false; selectModel(currentModel)} if(c == 'e') {drawEarClip = !drawEarClip; drawCDT = false; selectModel(currentModel)}
if(c == 'r') slCDT.refine
} }
def selectModel(model: String) { def selectModel(model: String) {
@ -434,12 +441,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
} }
slCDT triangulate slCDT triangulate
val runTime = System.nanoTime - t1 val runTime = System.nanoTime - t1
for(j <- 0 until 1) {
slCDT.refine
}
//slCDT.refine
println("CDT average (ms) = " + runTime*1e-6) println("CDT average (ms) = " + runTime*1e-6)
println("Number of triangles = " + slCDT.triangles.size) println("Number of triangles = " + slCDT.triangles.size)
println println

View File

@ -114,6 +114,23 @@ class AFront(iTriangle: Triangle) {
} }
// Transition from AFront traversal to interior mesh traversal
def aboveEdge(first: Node, pNode: Node, last: Triangle,
point2: Point, ahead:Boolean): Node =
if(ahead) {
val n = new Node(point2, pNode.prev.triangle)
link (first, n, last)
n.next = pNode
pNode.prev = n
n
} else {
val n = new Node(point2, last)
link (n, first, last)
pNode.next = n
n.prev = pNode
pNode
}
def -=(tuple: Tuple3[Node, Node, Triangle]) { def -=(tuple: Tuple3[Node, Node, Triangle]) {
val (node, kNode, triangle) = tuple val (node, kNode, triangle) = tuple
kNode.next.prev = node kNode.next.prev = node

View File

@ -41,10 +41,6 @@ import utils.Util
* International Journal of Geographical Information Science * International Journal of Geographical Information Science
*/ */
// NOTE: May need to implement edge insertion which combines advancing front (AF)
// and triangle traversal respectively. See figure 14(a) from Domiter et al.
// Although it may not be necessary for simple polygons....
// clearPoint is any interior point inside the polygon // clearPoint is any interior point inside the polygon
class CDT(polyLine: Array[Point], clearPoint: Point) { class CDT(polyLine: Array[Point], clearPoint: Point) {
@ -67,8 +63,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
} }
// Add an internal point // Add an internal point
// Good for manually refining the mesh. Use this when you want to eliminate // Good for manually refining the mesh
// skinny triangles
def addPoint(point: Point) { def addPoint(point: Point) {
points = point :: points points = point :: points
} }
@ -186,21 +181,25 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
} }
// Refine the mesh using Steiner points // Delauney Refinement: Refine triangules using Steiner points
// Probably overkill for 2D games, and will create a large number of
// triangles that are probably unoptimal for a physics engine like
// Box2D.... Better to manually enter interior points for mesh "smoothing"
// TODO: Finish implementation... Maybe!
def refine { def refine {
cList.clear cList.clear
mesh.triangles.foreach(t => { mesh.triangles.foreach(t => {
if(t.thin) { if(t.thin) {
val center = Util.circumcenter(t.points(0), t.points(1), t.points(2)) val center = Util.circumcenter(t.points(0), t.points(1), t.points(2))
cList += center cList += center
addPoint(center) addPoint(center)
} }
}) })
// Retriangulate // Retriangulate
if(cList.size > 0) if(cList.size > 0)
triangulate triangulate
} }
// Point event // Point event
private def pointEvent(point: Point): Node = { private def pointEvent(point: Point): Node = {
@ -231,6 +230,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
if(firstTriangle != null && !firstTriangle.contains(edge)) { if(firstTriangle != null && !firstTriangle.contains(edge)) {
// Interior mesh traversal - edge is "burried" in the mesh
// Constrained edge lies below the advancing front. Traverse through intersected triangles, // Constrained edge lies below the advancing front. Traverse through intersected triangles,
// form empty pseudo-polygons, and re-triangulate // form empty pseudo-polygons, and re-triangulate
@ -238,14 +238,23 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
val tList = new ArrayBuffer[Triangle] val tList = new ArrayBuffer[Triangle]
tList += firstTriangle tList += firstTriangle
while(!tList.last.contains(edge.p)) while(tList.last != null && !tList.last.contains(edge.p))
tList += tList.last.findNeighbor(edge.p) tList += tList.last.findNeighbor(edge.p)
// TODO: Finish implementing edge insertion which combines advancing front (AF)
// and triangle traversal respectively. See figure 14(a) from Domiter et al.
// Should only occur with complex patterns of interior points
// Already added provision for transitioning from AFront traversal to
// interior mesh traversal - may need to add the opposite case
if(tList.last == null)
throw new Exception("Not implemented yet - interior points too complex")
// Neighbor triangles // Neighbor triangles
// HashMap or set may improve performance
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 // 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
@ -304,6 +313,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
} else if(firstTriangle == null) { } else if(firstTriangle == null) {
// AFront traversal
// No triangles are intersected by the edge; edge must lie outside the mesh // No triangles are intersected by the edge; edge must lie outside the mesh
// Apply constraint; traverse the advancing front, and build triangles // Apply constraint; traverse the advancing front, and build triangles
@ -315,6 +325,9 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
nTriangles += pNode.triangle nTriangles += pNode.triangle
val ahead = (edge.p.x > edge.q.x) val ahead = (edge.p.x > edge.q.x)
// If this is true we transition from AFront traversal to
// interior mesh traversal
var aboveEdge = false var aboveEdge = false
if(ahead) { if(ahead) {
@ -327,7 +340,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
aboveEdge = edge < pNode.point aboveEdge = edge < pNode.point
} }
} else { } else {
// Scal left // Scan left
pNode = pNode.prev pNode = pNode.prev
while(pNode.point != edge.p && !aboveEdge) { while(pNode.point != edge.p && !aboveEdge) {
points += pNode.point points += pNode.point
@ -353,31 +366,19 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
// Update neighbors // Update neighbors
edgeNeighbors(nTriangles, T) edgeNeighbors(nTriangles, T)
// Update advancing front
if(ahead && !aboveEdge)
aFront link (first, pNode, T.last)
else if(!ahead && !aboveEdge)
aFront link (pNode, first, T.last)
// Mark constrained edge // Mark constrained edge
T.last markEdge(edge.q, point2) T.last markEdge(edge.q, point2)
// Update advancing front
if(aboveEdge) { if(aboveEdge) {
val iNode = if(ahead) { val iNode = aFront.aboveEdge(first, pNode, T.last, point2, ahead)
val n = new Node(point2, pNode.prev.triangle)
aFront link (first, n, T.last)
n.next = pNode
pNode.prev = n
n
} else {
val n = new Node(point2, T.last)
aFront link (n, first, T.last)
pNode.next = n
n.prev = pNode
pNode
}
edgeEvent(new Segment(edge.p, point2), iNode) edgeEvent(new Segment(edge.p, point2), iNode)
} } else {
if(ahead)
aFront link (first, pNode, T.last)
else
aFront link (pNode, first, T.last)
}
} else if(firstTriangle.contains(edge.q, edge.p)) { } else if(firstTriangle.contains(edge.q, edge.p)) {
// Constrained edge lies on the side of a triangle // Constrained edge lies on the side of a triangle

View File

@ -168,7 +168,7 @@ class Triangle(val points: Array[Point]) {
else if(Util.orient2d(points(0), points(2), p) > 0) else if(Util.orient2d(points(0), points(2), p) > 0)
return neighbors(1) return neighbors(1)
else else
throw new Exception("Point not found") return null
} }