mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-26 15:26:12 +01:00
fixed triangulate
This commit is contained in:
parent
f06c23d4e8
commit
2abca79e6e
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user