mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-30 01:03:30 +01:00
updated comments
This commit is contained in:
parent
ed89aea7c0
commit
d2dd39686e
@ -42,7 +42,7 @@ import earClip.EarClip
|
|||||||
import cdt.CDT
|
import cdt.CDT
|
||||||
|
|
||||||
// TODO: Lots of documentation!
|
// TODO: Lots of documentation!
|
||||||
|
// : Add Hertel-Mehlhorn algorithm
|
||||||
object Poly2Tri {
|
object Poly2Tri {
|
||||||
|
|
||||||
def main(args: Array[String]) {
|
def main(args: Array[String]) {
|
||||||
@ -250,11 +250,15 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
mousePressed = true
|
mousePressed = true
|
||||||
mousePosOld = mousePos
|
mousePosOld = mousePos
|
||||||
mousePos = Point(x, y)
|
mousePos = Point(x, y)
|
||||||
/*
|
|
||||||
val point = mousePos/scaleFactor + Point(deltaX, deltaY)
|
// Right click
|
||||||
slCDT.addPoint(point)
|
// Correctly adjust for pan and zoom
|
||||||
slCDT.triangulate
|
if(mouseButton == 1) {
|
||||||
*/
|
val point = mousePos/scaleFactor + Point(deltaX, deltaY)
|
||||||
|
slCDT.addPoint(point)
|
||||||
|
slCDT.triangulate
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,6 +310,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
if (hiLighter == -1)
|
if (hiLighter == -1)
|
||||||
hiLighter = seidel.polygons.size-1
|
hiLighter = seidel.polygons.size-1
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == 'm') drawMap = !drawMap
|
if(c == 'm') drawMap = !drawMap
|
||||||
if(c == 'd') drawCDT = !drawCDT
|
if(c == 'd') drawCDT = !drawCDT
|
||||||
if(c == '1') selectModel(nazcaMonkey)
|
if(c == '1') selectModel(nazcaMonkey)
|
||||||
@ -320,6 +325,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
if(c == 's') drawSegs = !drawSegs
|
if(c == 's') drawSegs = !drawSegs
|
||||||
if(c == 'c') drawcdtMesh = !drawcdtMesh
|
if(c == 'c') drawcdtMesh = !drawcdtMesh
|
||||||
if(c == 'e') {drawEarClip = !drawEarClip; drawCDT = false; selectModel(currentModel)}
|
if(c == 'e') {drawEarClip = !drawEarClip; drawCDT = false; selectModel(currentModel)}
|
||||||
|
if(c == 'r') slCDT.refine
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def selectModel(model: String) {
|
def selectModel(model: String) {
|
||||||
@ -434,12 +441,8 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
slCDT triangulate
|
slCDT triangulate
|
||||||
val runTime = System.nanoTime - t1
|
val runTime = System.nanoTime - t1
|
||||||
|
|
||||||
for(j <- 0 until 1) {
|
|
||||||
slCDT.refine
|
|
||||||
}
|
|
||||||
//slCDT.refine
|
|
||||||
println("CDT average (ms) = " + runTime*1e-6)
|
println("CDT average (ms) = " + runTime*1e-6)
|
||||||
println("Number of triangles = " + slCDT.triangles.size)
|
println("Number of triangles = " + slCDT.triangles.size)
|
||||||
println
|
println
|
||||||
|
@ -114,6 +114,23 @@ class AFront(iTriangle: Triangle) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transition from AFront traversal to interior mesh traversal
|
||||||
|
def aboveEdge(first: Node, pNode: Node, last: Triangle,
|
||||||
|
point2: Point, ahead:Boolean): Node =
|
||||||
|
if(ahead) {
|
||||||
|
val n = new Node(point2, pNode.prev.triangle)
|
||||||
|
link (first, n, last)
|
||||||
|
n.next = pNode
|
||||||
|
pNode.prev = n
|
||||||
|
n
|
||||||
|
} else {
|
||||||
|
val n = new Node(point2, last)
|
||||||
|
link (n, first, last)
|
||||||
|
pNode.next = n
|
||||||
|
n.prev = pNode
|
||||||
|
pNode
|
||||||
|
}
|
||||||
|
|
||||||
def -=(tuple: Tuple3[Node, Node, Triangle]) {
|
def -=(tuple: Tuple3[Node, Node, Triangle]) {
|
||||||
val (node, kNode, triangle) = tuple
|
val (node, kNode, triangle) = tuple
|
||||||
kNode.next.prev = node
|
kNode.next.prev = node
|
||||||
|
@ -41,10 +41,6 @@ import utils.Util
|
|||||||
* International Journal of Geographical Information Science
|
* International Journal of Geographical Information Science
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE: May need to implement edge insertion which combines advancing front (AF)
|
|
||||||
// and triangle traversal respectively. See figure 14(a) from Domiter et al.
|
|
||||||
// Although it may not be necessary for simple polygons....
|
|
||||||
|
|
||||||
// clearPoint is any interior point inside the polygon
|
// clearPoint is any interior point inside the polygon
|
||||||
class CDT(polyLine: Array[Point], clearPoint: Point) {
|
class CDT(polyLine: Array[Point], clearPoint: Point) {
|
||||||
|
|
||||||
@ -67,8 +63,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add an internal point
|
// Add an internal point
|
||||||
// Good for manually refining the mesh. Use this when you want to eliminate
|
// Good for manually refining the mesh
|
||||||
// skinny triangles
|
|
||||||
def addPoint(point: Point) {
|
def addPoint(point: Point) {
|
||||||
points = point :: points
|
points = point :: points
|
||||||
}
|
}
|
||||||
@ -186,21 +181,25 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refine the mesh using Steiner points
|
// Delauney Refinement: Refine triangules using Steiner points
|
||||||
|
// Probably overkill for 2D games, and will create a large number of
|
||||||
|
// triangles that are probably unoptimal for a physics engine like
|
||||||
|
// Box2D.... Better to manually enter interior points for mesh "smoothing"
|
||||||
|
// TODO: Finish implementation... Maybe!
|
||||||
def refine {
|
def refine {
|
||||||
cList.clear
|
cList.clear
|
||||||
mesh.triangles.foreach(t => {
|
mesh.triangles.foreach(t => {
|
||||||
if(t.thin) {
|
if(t.thin) {
|
||||||
val center = Util.circumcenter(t.points(0), t.points(1), t.points(2))
|
val center = Util.circumcenter(t.points(0), t.points(1), t.points(2))
|
||||||
cList += center
|
cList += center
|
||||||
addPoint(center)
|
addPoint(center)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Retriangulate
|
// Retriangulate
|
||||||
if(cList.size > 0)
|
if(cList.size > 0)
|
||||||
triangulate
|
triangulate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point event
|
// Point event
|
||||||
private def pointEvent(point: Point): Node = {
|
private def pointEvent(point: Point): Node = {
|
||||||
|
|
||||||
@ -231,6 +230,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
|
|
||||||
if(firstTriangle != null && !firstTriangle.contains(edge)) {
|
if(firstTriangle != null && !firstTriangle.contains(edge)) {
|
||||||
|
|
||||||
|
// Interior mesh traversal - edge is "burried" in the mesh
|
||||||
// Constrained edge lies below the advancing front. Traverse through intersected triangles,
|
// Constrained edge lies below the advancing front. Traverse through intersected triangles,
|
||||||
// form empty pseudo-polygons, and re-triangulate
|
// form empty pseudo-polygons, and re-triangulate
|
||||||
|
|
||||||
@ -238,14 +238,23 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
val tList = new ArrayBuffer[Triangle]
|
val tList = new ArrayBuffer[Triangle]
|
||||||
tList += firstTriangle
|
tList += firstTriangle
|
||||||
|
|
||||||
while(!tList.last.contains(edge.p))
|
while(tList.last != null && !tList.last.contains(edge.p))
|
||||||
tList += tList.last.findNeighbor(edge.p)
|
tList += tList.last.findNeighbor(edge.p)
|
||||||
|
|
||||||
|
// TODO: Finish implementing edge insertion which combines advancing front (AF)
|
||||||
|
// and triangle traversal respectively. See figure 14(a) from Domiter et al.
|
||||||
|
// Should only occur with complex patterns of interior points
|
||||||
|
// Already added provision for transitioning from AFront traversal to
|
||||||
|
// interior mesh traversal - may need to add the opposite case
|
||||||
|
if(tList.last == null)
|
||||||
|
throw new Exception("Not implemented yet - interior points too complex")
|
||||||
|
|
||||||
// Neighbor triangles
|
// Neighbor triangles
|
||||||
|
// HashMap or set may improve performance
|
||||||
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
|
// 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
|
||||||
@ -304,6 +313,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
|
|
||||||
} else if(firstTriangle == null) {
|
} else if(firstTriangle == null) {
|
||||||
|
|
||||||
|
// AFront traversal
|
||||||
// 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 advancing front, and build triangles
|
// Apply constraint; traverse the advancing front, and build triangles
|
||||||
|
|
||||||
@ -315,6 +325,9 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
nTriangles += pNode.triangle
|
nTriangles += pNode.triangle
|
||||||
|
|
||||||
val ahead = (edge.p.x > edge.q.x)
|
val ahead = (edge.p.x > edge.q.x)
|
||||||
|
|
||||||
|
// If this is true we transition from AFront traversal to
|
||||||
|
// interior mesh traversal
|
||||||
var aboveEdge = false
|
var aboveEdge = false
|
||||||
|
|
||||||
if(ahead) {
|
if(ahead) {
|
||||||
@ -327,7 +340,7 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
aboveEdge = edge < pNode.point
|
aboveEdge = edge < pNode.point
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Scal left
|
// Scan left
|
||||||
pNode = pNode.prev
|
pNode = pNode.prev
|
||||||
while(pNode.point != edge.p && !aboveEdge) {
|
while(pNode.point != edge.p && !aboveEdge) {
|
||||||
points += pNode.point
|
points += pNode.point
|
||||||
@ -353,31 +366,19 @@ class CDT(polyLine: Array[Point], clearPoint: Point) {
|
|||||||
// Update neighbors
|
// Update neighbors
|
||||||
edgeNeighbors(nTriangles, T)
|
edgeNeighbors(nTriangles, T)
|
||||||
|
|
||||||
// Update advancing front
|
|
||||||
if(ahead && !aboveEdge)
|
|
||||||
aFront link (first, pNode, T.last)
|
|
||||||
else if(!ahead && !aboveEdge)
|
|
||||||
aFront link (pNode, first, T.last)
|
|
||||||
|
|
||||||
// Mark constrained edge
|
// Mark constrained edge
|
||||||
T.last markEdge(edge.q, point2)
|
T.last markEdge(edge.q, point2)
|
||||||
|
|
||||||
|
// Update advancing front
|
||||||
if(aboveEdge) {
|
if(aboveEdge) {
|
||||||
val iNode = if(ahead) {
|
val iNode = aFront.aboveEdge(first, pNode, T.last, point2, ahead)
|
||||||
val n = new Node(point2, pNode.prev.triangle)
|
|
||||||
aFront link (first, n, T.last)
|
|
||||||
n.next = pNode
|
|
||||||
pNode.prev = n
|
|
||||||
n
|
|
||||||
} else {
|
|
||||||
val n = new Node(point2, T.last)
|
|
||||||
aFront link (n, first, T.last)
|
|
||||||
pNode.next = n
|
|
||||||
n.prev = pNode
|
|
||||||
pNode
|
|
||||||
}
|
|
||||||
edgeEvent(new Segment(edge.p, point2), iNode)
|
edgeEvent(new Segment(edge.p, point2), iNode)
|
||||||
}
|
} else {
|
||||||
|
if(ahead)
|
||||||
|
aFront link (first, pNode, T.last)
|
||||||
|
else
|
||||||
|
aFront link (pNode, first, T.last)
|
||||||
|
}
|
||||||
|
|
||||||
} else if(firstTriangle.contains(edge.q, edge.p)) {
|
} else if(firstTriangle.contains(edge.q, edge.p)) {
|
||||||
// Constrained edge lies on the side of a triangle
|
// Constrained edge lies on the side of a triangle
|
||||||
|
@ -168,7 +168,7 @@ class Triangle(val points: Array[Point]) {
|
|||||||
else if(Util.orient2d(points(0), points(2), p) > 0)
|
else if(Util.orient2d(points(0), points(2), p) > 0)
|
||||||
return neighbors(1)
|
return neighbors(1)
|
||||||
else
|
else
|
||||||
throw new Exception("Point not found")
|
return null
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user