fixed triangulate

This commit is contained in:
zzzzrrr 2009-08-10 23:17:39 -04:00
parent f06c23d4e8
commit 2abca79e6e
4 changed files with 54 additions and 45 deletions

View File

@ -170,8 +170,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
}) })
if(drawCDT) { if(drawCDT) {
//val draw = if(drawcdtMesh) slCDT.triangleMesh else slCDT.triangles val draw = if(drawcdtMesh) slCDT.triangleMesh else slCDT.triangles
val draw = slCDT.testTri //val draw = slCDT.testTri
draw.foreach( t => { draw.foreach( t => {
val triangle = new Polygon val triangle = new Polygon
triangle.addPoint(t.points(0).x, t.points(0).y) triangle.addPoint(t.points(0).x, t.points(0).y)
@ -180,6 +180,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
g.setColor(red) g.setColor(red)
g.draw(triangle) g.draw(triangle)
}) })
slCDT.debugTriangles.foreach( t => { slCDT.debugTriangles.foreach( t => {
val triangle = new Polygon val triangle = new Polygon
triangle.addPoint(t.points(0).x, t.points(0).y) triangle.addPoint(t.points(0).x, t.points(0).y)
@ -188,6 +189,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
g.setColor(blue) g.setColor(blue)
g.draw(triangle) g.draw(triangle)
}) })
} }
if(drawSegs) { if(drawSegs) {

View File

@ -107,6 +107,7 @@ object CDT {
class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Triangle) { class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Triangle) {
// Triangle list // Triangle list
def triangles = mesh.triangles def triangles = mesh.triangles
def triangleMesh = mesh.map def triangleMesh = mesh.map
@ -127,19 +128,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
sweep sweep
// Finalize triangulation // Finalize triangulation
finalization finalization
val testTri = new ArrayBuffer[Triangle]
val p1 = Point(200, 300)
val p2 = Point(500, 300)
val p3 = Point(250, 500)
val p4 = Point(350, 400)
val p5 = Point(400, 350)
val pts = Array(p3, p4, p5)
triangulate(pts, List(p1, p2), testTri)
// Implement sweep-line // Implement sweep-line
private def sweep { private def sweep {
@ -148,9 +137,11 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Process Point event // Process Point event
var triangle = pointEvent(point) var triangle = pointEvent(point)
// Process edge events // Process edge events
point.edges.foreach(e => triangle = edgeEvent(e, triangle)) if(triangle != null)
point.edges.foreach(e => triangle = edgeEvent(e, triangle))
if(i == CDT.clearPoint) {cleanTri = triangle; mesh.debug += cleanTri} if(i == CDT.clearPoint) {cleanTri = triangle; mesh.debug += cleanTri}
} }
} }
// Final step in the sweep-line CDT algo // Final step in the sweep-line CDT algo
@ -159,7 +150,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
mesh.map.foreach(m => m.markEdges) mesh.map.foreach(m => m.markEdges)
mesh clean cleanTri mesh clean cleanTri
//mesh.map.foreach(m => m.edges.foreach(e => if(e) mesh.debug += m))
} }
// Point event // Point event
@ -170,11 +161,11 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Projected point hits advancing front; create new triangle // Projected point hits advancing front; create new triangle
val pts = Array(point, node.point, node.next.point) val pts = Array(point, node.point, node.next.point)
val triangle = new Triangle(pts) val triangle = new Triangle(pts)
mesh.map += triangle mesh.map += triangle
// Legalize // Legalize
val newNode = legalization(triangle, node) val newNode = legalization(triangle, node)
// Fill in adjacent triangles if required // Fill in adjacent triangles if required
scanAFront(newNode) scanAFront(newNode)
newNode.triangle newNode.triangle
@ -189,7 +180,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Remove intersected triangles // Remove intersected triangles
if(firstTriangle != null && !firstTriangle.contains(edge)) { if(firstTriangle != null && !firstTriangle.contains(edge)) {
println("collect")
// Collect intersected triangles // Collect intersected triangles
val tList = new ArrayBuffer[Triangle] val tList = new ArrayBuffer[Triangle]
tList += firstTriangle tList += firstTriangle
@ -212,16 +203,12 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val lPoints = new ArrayBuffer[Point] val lPoints = new ArrayBuffer[Point]
val rPoints = new ArrayBuffer[Point] val rPoints = new ArrayBuffer[Point]
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
// Collect points left and right of edge // Collect points left and right of edge
tList.foreach(t => { tList.foreach(t => {
t.points.foreach(p => { t.points.foreach(p => {
if(p != edge.q && p != edge.p) { if(p != edge.q && p != edge.p) {
if(t.orient(point1, point2, p) > 0 ) { if(t.orient(edge.q, edge.p, p) > 0 ) {
// Keep duplicate points out // Keep duplicate points out
if(!lPoints.contains(p)) { if(!lPoints.contains(p)) {
lPoints += p lPoints += p
@ -237,12 +224,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Triangulate empty areas. // Triangulate empty areas.
val T1 = new ArrayBuffer[Triangle] val T1 = new ArrayBuffer[Triangle]
triangulate(lPoints.toArray, List(point1, point2), T1) triangulate(lPoints.toArray, List(edge.q, edge.p), T1)
val T2 = new ArrayBuffer[Triangle] val T2 = new ArrayBuffer[Triangle]
triangulate(rPoints.toArray, List(point1, point2), T2) triangulate(rPoints.toArray, List(edge.q, edge.p), T2)
// Update advancing front // Update advancing front
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
var first: Triangle = null var first: Triangle = null
val sNode = aFront.locatePoint(point1) val sNode = aFront.locatePoint(point1)
val eNode = aFront.locatePoint(point2) val eNode = aFront.locatePoint(point2)
@ -266,7 +257,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
first first
} else if(firstTriangle == null) { } else if(firstTriangle == null) {
println("intersect")
// 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 AFront, and build triangles // Apply constraint; traverse the AFront, and build triangles
@ -311,6 +302,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
triangle triangle
} else { } else {
println("contains")
// Mark constrained edge // Mark constrained edge
firstTriangle mark(edge.p, edge.q) firstTriangle mark(edge.p, edge.q)
triangle triangle
@ -332,17 +324,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
} }
// Marc Vigo Anglada's triangulate pseudo-polygon algo // Marc Vigo Anglada's triangulate pseudo-polygon algo
private def triangulate(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) { private def triangulate(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) {
val a = ab.first val a = ab.first
val b = ab.last val b = ab.last
var c = if(!P.isEmpty) P.first else null var i = 0
if(P.size > 1) { if(P.size > 1) {
var i = 0 var c = P.first
for(j <- 1 until P.size) { for(j <- 1 until P.size) {
if(illegal(a, c, b, P(j))) { if(illegal(a, P(j), b, c)) {
c = P(j) c = P(j)
i = j i = j
} }
@ -354,13 +347,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
} }
if(!P.isEmpty) { if(!P.isEmpty) {
val left = if(Util.orient(a, b, c) > 0) true else false val left = Util.orient(a, b, P(i)) < 0
val p2 = if(left) c else b val pB = if(left) P(i) else b
val p3 = if(left) b else c val pC = if(left) b else P(i)
val points = Array(a, p2, p3) val points = Array(a, pB, pC)
T += new Triangle(points) T += new Triangle(points)
mesh.map += T.last mesh.map += T.last
} }
} }
// Scan left and right along AFront to fill holes // Scan left and right along AFront to fill holes
@ -416,15 +410,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val cosA = v1 dot v2 val cosA = v1 dot v2
val cosB = v3 dot v4 val cosB = v3 dot v4
if(cosA < 0 && cosB < 0) if(cosA < 0 && cosB < 0)
return true return true
if(cosA > 0 && cosB > 0) if(cosA > 0 && cosB > 0)
return false return false
val sinA = v1 cross v2 val sinA = v1 cross v2
val sinB = v3 cross v4 val sinB = v3 cross v4
if((cosA*sinB + sinA*cosB) < 0f) if((cosA*sinB + sinA*cosB) < 0f)
true true
else else
false false
@ -435,15 +430,17 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
private def legalization(t1: Triangle, node: Node): Node = { private def legalization(t1: Triangle, node: Node): Node = {
val t2 = node.triangle val t2 = node.triangle
val point = t1.points(0) val point = t1.points(0)
val oPoint = t2 oppositePoint t1 val oPoint = t2 oppositePoint t1
if(illegal(t1.points(1), oPoint, t1.points(2), t1.points(0))) { if(illegal(t1.points(1), oPoint, t1.points(2), t1.points(0))) {
println("legalize")
// Flip edge and rotate everything clockwise // Flip edge and rotate everything clockwise
t1.legalize(oPoint) t1.legalize(oPoint)
t2.legalize(oPoint, point) t2.legalize(oPoint, point)
// Copy old neighbors // Copy old neighbors
val neighbors = List(t2.neighbors(0), t2.neighbors(1), t2.neighbors(2)) val neighbors = List(t2.neighbors(0), t2.neighbors(1), t2.neighbors(2))
// Clear old neighbors // Clear old neighbors
@ -458,12 +455,12 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
t2.markNeighbor(t1) t2.markNeighbor(t1)
// Update advancing front // Update advancing front
aFront.insertLegalized(point, t1, node) aFront.insertLegalized(t1.points(1), t1, node)
} else { } else {
// Update neighbor // Update neighbor
t2.markNeighbor(t1) t2.markNeighbor(t1)
// Update advancing front // Update advancing front
aFront.insert(point, t1, node) aFront.insert(point, t1, node)

View File

@ -58,7 +58,7 @@ class Triangle(val points: Array[Point]) {
else if((p1 == points(0) && p2 == points(1)) || (p1 == points(1) && p2 == points(0))) else if((p1 == points(0) && p2 == points(1)) || (p1 == points(1) && p2 == points(0)))
neighbors(2) = t neighbors(2) = t
else { else {
throw new Exception("Neighbor pointer error, please report!") throw new Exception("Neighbor error, please report!")
} }
} }
@ -92,6 +92,8 @@ class Triangle(val points: Array[Point]) {
else { else {
t.printDebug t.printDebug
printDebug printDebug
println(area + " | " + t.area)
throw new Exception("Point location error, please report") throw new Exception("Point location error, please report")
} }
@ -121,7 +123,6 @@ class Triangle(val points: Array[Point]) {
// Locate first triangle crossed by constrained edge // Locate first triangle crossed by constrained edge
def locateFirst(edge: Segment): Triangle = { def locateFirst(edge: Segment): Triangle = {
val p = edge.p val p = edge.p
val q = edge.q val q = edge.q
val e = p - q val e = p - q
@ -248,11 +249,14 @@ class Triangle(val points: Array[Point]) {
points(2) = points(1) points(2) = points(1)
points(1) = points(0) points(1) = points(0)
points(0) = nPoint points(0) = nPoint
} else { } else if (oPoint == points(2)) {
points(0) = points(2) points(0) = points(2)
points(2) = points(1) points(2) = points(1)
points(1) = nPoint points(1) = nPoint
} else {
throw new Exception("legalization error")
} }
} }
// Make legalized triangle will not be collinear // Make legalized triangle will not be collinear
@ -324,4 +328,10 @@ class Triangle(val points: Array[Point]) {
} }
} }
def area = {
val b = points(0).x - points(1).x
val h = points(2).y - points(1).y
(b*h*0.5f)
}
} }

View File

@ -42,7 +42,7 @@ object Util {
val d = (p2 - p1) cross (p1 - p3) val d = (p2 - p1) cross (p1 - p3)
if(d <= COLLINEAR_SLOP) if(Math.abs(d) <= COLLINEAR_SLOP)
true true
else else
false false