mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-26 15:26:12 +01:00
bug fixes and optimizations
This commit is contained in:
parent
5fa8c4501e
commit
14980edabe
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user