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 tank = "data/tank.dat"
|
||||
|
||||
var currentModel = tank
|
||||
var currentModel = strange
|
||||
var doCDT = true
|
||||
|
||||
var mouseButton = 0
|
||||
@ -112,7 +112,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
|
||||
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("'m' to show trapezoidal map (Seidel debug mode)", 10, 544)
|
||||
g.drawString("'e' to switch Seidel / EarClip", 10, 556)
|
||||
@ -305,13 +305,14 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
||||
CDT.clearPoint = 7
|
||||
loadModel(i18, 20f, Point(600f, 500f), 20)
|
||||
case "data/nazca_heron.dat" =>
|
||||
doCDT = false; drawCDT = false; drawcdtMesh = false
|
||||
CDT.clearPoint = 7
|
||||
loadModel(nazcaHeron, 4.5f, Point(400f, 300f), 1500)
|
||||
loadModel(nazcaHeron, 4.2f, Point(400f, 300f), 1500)
|
||||
case "data/tank.dat" =>
|
||||
//doCDT = false; drawCDT = false; drawcdtMesh = false
|
||||
doCDT = true; drawCDT = true
|
||||
CDT.clearPoint = 50
|
||||
loadModel(tank, -1f, Point(0f, 0f), 10)
|
||||
CDT.clearPoint = 38
|
||||
loadModel(tank, -1f, Point(100f, 0f), 10)
|
||||
case _ =>
|
||||
assert(false)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ package org.poly2tri.cdt
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
import shapes.{Point, Triangle}
|
||||
import shapes.{Point, Triangle, Segment}
|
||||
|
||||
// Advancing front
|
||||
class AFront(iTriangle: Triangle) {
|
||||
@ -91,11 +91,13 @@ class AFront(iTriangle: Triangle) {
|
||||
|
||||
// Update advancing front with constrained edge triangles
|
||||
def constrainedEdge(sNode: Node, eNode: Node, T1: ArrayBuffer[Triangle],
|
||||
T2: ArrayBuffer[Triangle]): Triangle = {
|
||||
T2: ArrayBuffer[Triangle], edge: Segment): Triangle = {
|
||||
|
||||
var node = sNode
|
||||
var t1r, t2r = false
|
||||
|
||||
// Scan the advancing front and update Node triangle pointers
|
||||
// Either T1 OR T2
|
||||
while(node != eNode) {
|
||||
|
||||
T2.foreach(t => {
|
||||
@ -116,67 +118,43 @@ class AFront(iTriangle: Triangle) {
|
||||
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
|
||||
|
||||
}
|
||||
// Select edge triangles
|
||||
|
||||
// Update advancing front with qNode
|
||||
def constrainedEdge(qNode: Node, tList: ArrayBuffer[Triangle], T1: ArrayBuffer[Triangle],
|
||||
T2: ArrayBuffer[Triangle]): Triangle = {
|
||||
var edgeTri1: Triangle = null
|
||||
var i = 0
|
||||
while(edgeTri1 == null) {
|
||||
if(T1(i).contains(point1, point2))
|
||||
edgeTri1 = T1(i)
|
||||
i += 1
|
||||
}
|
||||
|
||||
var t1r, t2r = false
|
||||
// Mark constrained edge
|
||||
edgeTri1 markEdge(point1, point2)
|
||||
|
||||
for(t <- tList) {
|
||||
var edgeTri2: Triangle = null
|
||||
i = 0
|
||||
while(edgeTri2 == null) {
|
||||
if(T2(i).contains(point1, point2))
|
||||
edgeTri2 = T2(i)
|
||||
i += 1
|
||||
}
|
||||
|
||||
if(qNode.triangle == t) {
|
||||
// Mark constrained edge
|
||||
edgeTri2 markEdge(point1, point2)
|
||||
|
||||
val p1 = qNode.point
|
||||
val p2 = qNode.next.point
|
||||
|
||||
T2.foreach(tri => if(tri.contains(p1, p2)) {
|
||||
qNode.triangle = tri
|
||||
t2r = true
|
||||
})
|
||||
|
||||
if(!t2r)
|
||||
T1.foreach(tri => if(tri.contains(p1, p2)) {
|
||||
qNode.triangle = tri
|
||||
t1r = true
|
||||
})
|
||||
|
||||
} else if(qNode.prev.triangle == t) {
|
||||
|
||||
val p1 = qNode.prev.point
|
||||
val p2 = qNode.point
|
||||
|
||||
T2.foreach(tri => if(tri.contains(p1, p2)) {
|
||||
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!")
|
||||
}
|
||||
|
||||
}
|
||||
// Update neighbor pointer
|
||||
edgeTri1.markNeighbor(edgeTri2)
|
||||
|
||||
if(t1r && !t2r)
|
||||
T1.first
|
||||
else if(t2r && !t1r)
|
||||
T2.first
|
||||
else
|
||||
edgeTri1
|
||||
else if(t2r && !t1r) {
|
||||
edgeTri2
|
||||
} else {
|
||||
throw new Exception("edge insertion error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -193,6 +171,7 @@ class AFront(iTriangle: Triangle) {
|
||||
node1.triangle = t
|
||||
}
|
||||
|
||||
// NOT IMPLEMENTED
|
||||
def basin(node: Node) {
|
||||
if(node.next != tail) {
|
||||
val p1 = node.point
|
||||
|
@ -30,7 +30,7 @@
|
||||
*/
|
||||
package org.poly2tri.cdt
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.collection.mutable.{ArrayBuffer, Set}
|
||||
|
||||
import shapes.{Segment, Point, Triangle}
|
||||
import utils.Util
|
||||
@ -44,7 +44,7 @@ object CDT {
|
||||
|
||||
// Inital triangle factor
|
||||
val ALPHA = 0.3f
|
||||
val SHEER = 0.001f
|
||||
val SHEER = 0.0001
|
||||
|
||||
var clearPoint = 0
|
||||
|
||||
@ -101,7 +101,7 @@ object CDT {
|
||||
|
||||
// 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
|
||||
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 {
|
||||
case e: Exception =>
|
||||
throw new Exception("Systect point = " + i)
|
||||
//throw new Exception("Suspect point = " + i)
|
||||
}
|
||||
|
||||
}
|
||||
@ -154,7 +154,7 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
||||
// Clean exterior triangles
|
||||
private def finalization {
|
||||
|
||||
mesh.map.foreach(m => m.markEdges)
|
||||
mesh.map.foreach(m => m.markNeighborEdges)
|
||||
mesh clean cleanTri
|
||||
|
||||
}
|
||||
@ -191,17 +191,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
||||
val tList = new ArrayBuffer[Triangle]
|
||||
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)
|
||||
|
||||
// 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
|
||||
val nTriangles = new ArrayBuffer[Triangle]
|
||||
|
||||
// Remove old triangles; collect neighbor triangles
|
||||
// Keep duplicates out
|
||||
tList.foreach(t => {
|
||||
t.neighbors.foreach(n => if(n != null && !tList.contains(n)) nTriangles += n)
|
||||
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 point2 = if(ahead) edge.p else edge.q
|
||||
|
||||
var first: Triangle = null
|
||||
val sNode = aFront.locatePoint(point1)
|
||||
val eNode = aFront.locatePoint(point2)
|
||||
val sNode = aFront.locate(point1)
|
||||
val eNode = aFront.locate(point2)
|
||||
|
||||
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)
|
||||
}
|
||||
val first = aFront.constrainedEdge(sNode, eNode, T1, T2, edge)
|
||||
|
||||
// Update neighbors
|
||||
edgeNeighbors(nTriangles, T1)
|
||||
edgeNeighbors(nTriangles, T2)
|
||||
|
||||
// Select edge triangle
|
||||
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
|
||||
first
|
||||
|
||||
} else if(firstTriangle == null) {
|
||||
|
||||
@ -330,17 +296,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
||||
edgeNeighbors(nTriangles, T)
|
||||
|
||||
// Mark constrained edge
|
||||
edgeTri mark(edge.p, edge.q)
|
||||
edgeTri markEdge(point1, point2)
|
||||
|
||||
// Return original triangle
|
||||
triangle
|
||||
|
||||
} else if(firstTriangle.contains(edge.p, edge.q)) {
|
||||
// Mark constrained edge
|
||||
firstTriangle mark(edge.p, edge.q)
|
||||
firstTriangle markEdge(edge.p, edge.q)
|
||||
triangle
|
||||
} else {
|
||||
throw new Exception("Triangulation error")
|
||||
//null
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,17 +42,25 @@ class Mesh(initialTriangle: Triangle) {
|
||||
val debug = HashSet.empty[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
|
||||
def clean(triangle: Triangle) {
|
||||
if(triangle != null && !triangle.clean) {
|
||||
triangle.clean = true
|
||||
if(triangle != null && !triangle.interior) {
|
||||
triangle.interior = true
|
||||
triangles += triangle
|
||||
if(!triangle.edges(0))
|
||||
clean(triangle.neighbors(0))
|
||||
if(!triangle.edges(1))
|
||||
clean(triangle.neighbors(1))
|
||||
if(!triangle.edges(2))
|
||||
clean(triangle.neighbors(2))
|
||||
for(i <- 0 until 3) {
|
||||
if(!triangle.edges(i))
|
||||
clean(triangle.neighbors(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,12 @@ class Triangle(val points: Array[Point]) {
|
||||
val edges = Array(false, false, false)
|
||||
|
||||
// Finalization flag
|
||||
var clean = false
|
||||
var interior = false
|
||||
|
||||
var finalized = false
|
||||
|
||||
var test = false
|
||||
|
||||
// Update neighbor pointers
|
||||
private def markNeighbor(p1: Point, p2: Point, t: Triangle) {
|
||||
|
||||
@ -285,14 +287,8 @@ class Triangle(val points: Array[Point]) {
|
||||
|
||||
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
|
||||
def markEdges {
|
||||
def markNeighborEdges {
|
||||
for(i <- 0 to 2)
|
||||
if(edges(i))
|
||||
i match {
|
||||
@ -302,18 +298,24 @@ class Triangle(val points: Array[Point]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Mark neighbor's edge
|
||||
private def markNeighborEdge(p: Point, q: Point) =
|
||||
neighbors.foreach(n => if(n != null) n.markEdge(p, q))
|
||||
def markEdge(triangle: Triangle) {
|
||||
for(i <- 0 to 2)
|
||||
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
|
||||
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))) {
|
||||
finalized = true
|
||||
edges(2) = true
|
||||
} else if ((q == points(0) && p == points(2)) || (q == points(2) && p == points(0))) {
|
||||
finalized = true
|
||||
edges(1) = true
|
||||
finalized = true
|
||||
} else if ((q == points(1) && p == points(2)) || (q == points(2) && p == points(1))){
|
||||
finalized = true
|
||||
edges(0) = true
|
||||
|
@ -8,7 +8,7 @@ import shapes.Point
|
||||
object Util {
|
||||
|
||||
// Almost zero
|
||||
val COLLINEAR_SLOP = 0.01f
|
||||
val COLLINEAR_SLOP = 0.1f
|
||||
|
||||
val epsilon = exactinit
|
||||
val ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon
|
||||
|
Loading…
Reference in New Issue
Block a user