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

View File

@ -107,6 +107,7 @@ object CDT {
class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Triangle) {
// Triangle list
def triangles = mesh.triangles
def triangleMesh = mesh.map
@ -127,19 +128,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
sweep
// Finalize triangulation
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
private def sweep {
@ -148,9 +137,11 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Process Point event
var triangle = pointEvent(point)
// 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}
}
}
// 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 clean cleanTri
//mesh.map.foreach(m => m.edges.foreach(e => if(e) mesh.debug += m))
}
// 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
val pts = Array(point, node.point, node.next.point)
val triangle = new Triangle(pts)
mesh.map += triangle
// Legalize
val newNode = legalization(triangle, node)
// Fill in adjacent triangles if required
scanAFront(newNode)
newNode.triangle
@ -189,7 +180,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Remove intersected triangles
if(firstTriangle != null && !firstTriangle.contains(edge)) {
println("collect")
// Collect intersected triangles
val tList = new ArrayBuffer[Triangle]
tList += firstTriangle
@ -212,16 +203,12 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
val lPoints = 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
tList.foreach(t => {
t.points.foreach(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
if(!lPoints.contains(p)) {
lPoints += p
@ -237,12 +224,16 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
// Triangulate empty areas.
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]
triangulate(rPoints.toArray, List(point1, point2), T2)
triangulate(rPoints.toArray, List(edge.q, edge.p), T2)
// 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
val sNode = aFront.locatePoint(point1)
val eNode = aFront.locatePoint(point2)
@ -266,7 +257,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
first
} else if(firstTriangle == null) {
println("intersect")
// No triangles are intersected by the edge; edge must lie outside the mesh
// 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
} else {
println("contains")
// Mark constrained edge
firstTriangle mark(edge.p, edge.q)
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
private def triangulate(P: Array[Point], ab: List[Point], T: ArrayBuffer[Triangle]) {
val a = ab.first
val b = ab.last
var c = if(!P.isEmpty) P.first else null
var i = 0
if(P.size > 1) {
var i = 0
var c = P.first
for(j <- 1 until P.size) {
if(illegal(a, c, b, P(j))) {
if(illegal(a, P(j), b, c)) {
c = P(j)
i = j
}
@ -354,13 +347,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
}
if(!P.isEmpty) {
val left = if(Util.orient(a, b, c) > 0) true else false
val p2 = if(left) c else b
val p3 = if(left) b else c
val points = Array(a, p2, p3)
val left = Util.orient(a, b, P(i)) < 0
val pB = if(left) P(i) else b
val pC = if(left) b else P(i)
val points = Array(a, pB, pC)
T += new Triangle(points)
mesh.map += T.last
}
}
// 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 cosB = v3 dot v4
if(cosA < 0 && cosB < 0)
if(cosA < 0 && cosB < 0)
return true
if(cosA > 0 && cosB > 0)
return false
val sinA = v1 cross v2
val sinB = v3 cross v4
if((cosA*sinB + sinA*cosB) < 0f)
if((cosA*sinB + sinA*cosB) < 0f)
true
else
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 = {
val t2 = node.triangle
val point = t1.points(0)
val oPoint = t2 oppositePoint t1
if(illegal(t1.points(1), oPoint, t1.points(2), t1.points(0))) {
println("legalize")
// Flip edge and rotate everything clockwise
t1.legalize(oPoint)
t2.legalize(oPoint, point)
// Copy old neighbors
val neighbors = List(t2.neighbors(0), t2.neighbors(1), t2.neighbors(2))
// Clear old neighbors
@ -458,12 +455,12 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
t2.markNeighbor(t1)
// Update advancing front
aFront.insertLegalized(point, t1, node)
aFront.insertLegalized(t1.points(1), t1, node)
} else {
// Update neighbor
t2.markNeighbor(t1)
t2.markNeighbor(t1)
// Update advancing front
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)))
neighbors(2) = t
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 {
t.printDebug
printDebug
println(area + " | " + t.area)
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
def locateFirst(edge: Segment): Triangle = {
val p = edge.p
val q = edge.q
val e = p - q
@ -248,11 +249,14 @@ class Triangle(val points: Array[Point]) {
points(2) = points(1)
points(1) = points(0)
points(0) = nPoint
} else {
} else if (oPoint == points(2)) {
points(0) = points(2)
points(2) = points(1)
points(1) = nPoint
} else {
throw new Exception("legalization error")
}
}
// 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)
if(d <= COLLINEAR_SLOP)
if(Math.abs(d) <= COLLINEAR_SLOP)
true
else
false