mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-12-29 06:03:31 +01:00
edge event work
This commit is contained in:
parent
be0112a0a3
commit
54b7fbd009
@ -85,7 +85,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
val strange = "data/strange.dat"
|
val strange = "data/strange.dat"
|
||||||
val i18 = "data/i.18"
|
val i18 = "data/i.18"
|
||||||
|
|
||||||
var currentModel = nazcaMonkey
|
var currentModel = i18
|
||||||
|
|
||||||
def init(container: GameContainer) {
|
def init(container: GameContainer) {
|
||||||
selectModel(currentModel)
|
selectModel(currentModel)
|
||||||
@ -153,7 +153,7 @@ class Poly2TriDemo extends BasicGame("Poly2Tri") {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if(drawCDT) {
|
if(drawCDT) {
|
||||||
slCDT.mesh.map.foreach( t => {
|
slCDT.triangles.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)
|
||||||
triangle.addPoint(t.points(1).x, t.points(1).y)
|
triangle.addPoint(t.points(1).x, t.points(1).y)
|
||||||
|
@ -44,6 +44,7 @@ object CDT {
|
|||||||
|
|
||||||
// Inital triangle factor
|
// Inital triangle factor
|
||||||
val ALPHA = 0.3f
|
val ALPHA = 0.3f
|
||||||
|
val SHEER = 0.00001f
|
||||||
|
|
||||||
// Triangulate simple polygon
|
// Triangulate simple polygon
|
||||||
def init(points: ArrayBuffer[Point]): CDT = {
|
def init(points: ArrayBuffer[Point]): CDT = {
|
||||||
@ -78,19 +79,15 @@ object CDT {
|
|||||||
// Create segments and connect end points; update edge event pointer
|
// Create segments and connect end points; update edge event pointer
|
||||||
private def initSegments(points: ArrayBuffer[Point]): List[Segment] = {
|
private def initSegments(points: ArrayBuffer[Point]): List[Segment] = {
|
||||||
var segments = List[Segment]()
|
var segments = List[Segment]()
|
||||||
for(i <- 0 until points.size-1)
|
for(i <- 0 until points.size-1) {
|
||||||
segments = segment(points(i), points(i+1)) :: segments
|
segments = new Segment(points(i), points(i+1)) :: segments
|
||||||
segments = segment(points.first, points.last) :: segments
|
segments.first.updateEdge
|
||||||
|
}
|
||||||
|
segments = new Segment(points.first, points.last) :: segments
|
||||||
|
segments.first.updateEdge
|
||||||
segments
|
segments
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new segment and updates edge pointer
|
|
||||||
private def segment(p1: Point, p2: Point): Segment = {
|
|
||||||
val seg = new Segment(p1, p2)
|
|
||||||
p1.updateEdges(p2, seg)
|
|
||||||
seg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insertion sort is one of the fastest algorithms for sorting arrays containing
|
// Insertion sort is one of the fastest algorithms for sorting arrays containing
|
||||||
// fewer than ten elements, or for lists that are already mostly sorted.
|
// fewer than ten elements, or for lists that are already mostly sorted.
|
||||||
// Merge sort: O(n log n)
|
// Merge sort: O(n log n)
|
||||||
@ -103,19 +100,20 @@ 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
|
||||||
//val SHEER = 0.0001f
|
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.0001f)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
def triangles = mesh.map
|
||||||
// The triangle mesh
|
// The triangle mesh
|
||||||
val mesh = new Mesh(iTriangle)
|
private val mesh = new Mesh(iTriangle)
|
||||||
// Advancing front
|
// Advancing front
|
||||||
val aFront = new AFront(iTriangle)
|
private val aFront = new AFront(iTriangle)
|
||||||
|
|
||||||
val PI_2 = Math.Pi/2
|
private val PI_2 = Math.Pi/2
|
||||||
|
|
||||||
// Sweep points; build mesh
|
// Sweep points; build mesh
|
||||||
sweep
|
sweep
|
||||||
@ -124,13 +122,14 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
|||||||
|
|
||||||
// Implement sweep-line
|
// Implement sweep-line
|
||||||
private def sweep {
|
private def sweep {
|
||||||
|
for(i <- 1 until 9 /*points.size*/) {
|
||||||
for(i <- 1 until points.size) {
|
|
||||||
val point = points(i)
|
val point = points(i)
|
||||||
|
println(point)
|
||||||
|
// Process Point event
|
||||||
val triangle = pointEvent(point)
|
val triangle = pointEvent(point)
|
||||||
edgeEvent(point, triangle)
|
// Process edge events
|
||||||
|
point.edges.foreach(e => edgeEvent(e, triangle))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point event
|
// Point event
|
||||||
@ -159,17 +158,23 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
|||||||
// Update advancing front
|
// Update advancing front
|
||||||
val newNode = aFront.insert(point, triangle, node)
|
val newNode = aFront.insert(point, triangle, node)
|
||||||
// Fill in adjacent triangles if required
|
// Fill in adjacent triangles if required
|
||||||
march(newNode)
|
scan(newNode)
|
||||||
triangle
|
triangle
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeEvent
|
// EdgeEvent
|
||||||
private def edgeEvent(point: Point, triangle: Triangle) {
|
private def edgeEvent(edge: Segment, triangle: Triangle) {
|
||||||
mesh.addEdge(point, triangle)
|
// STEP 1: Locate the first intersected triangle
|
||||||
|
val first = triangle.locateFirst(edge)
|
||||||
|
println(first)
|
||||||
|
if(first != null && first != triangle && !first.contains(edge))
|
||||||
|
mesh.map -= first
|
||||||
|
// STEP 2: Remove intersected triangles
|
||||||
|
// STEP 3: Triangulate empty areas.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan left and right to fill holes in the mesh
|
// Scan left and right along AFront to fill holes
|
||||||
def march(n: Node) {
|
def scan(n: Node) {
|
||||||
|
|
||||||
var node = n.next
|
var node = n.next
|
||||||
// Update right
|
// Update right
|
||||||
@ -192,14 +197,18 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill empty space with a triangle
|
||||||
def fill(node: Node): Double = {
|
def fill(node: Node): Double = {
|
||||||
val a = (node.prev.point - node.point)
|
val a = (node.prev.point - node.point)
|
||||||
val b = (node.next.point - node.point)
|
val b = (node.next.point - node.point)
|
||||||
val angle = Math.abs(Math.atan2(a cross b, a dot b))
|
val angle = Math.abs(Math.atan2(a cross b, a dot b))
|
||||||
if(angle <= PI_2) {
|
if(angle <= PI_2) {
|
||||||
val points = Array(node.point, node.next.point, node.prev.point)
|
val points = Array(node.prev.point, node.next.point, node.point)
|
||||||
val neighbors = Array(null, node.prev.triangle, node.triangle)
|
val neighbors = Array(node.prev.triangle, null, node.triangle)
|
||||||
val triangle = new Triangle(points, neighbors)
|
val triangle = new Triangle(points, neighbors)
|
||||||
|
// Update neighbor pointers
|
||||||
|
node.prev.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle)
|
||||||
|
node.triangle.updateNeighbors(triangle.points(1), triangle.points(2), triangle)
|
||||||
mesh.map += triangle
|
mesh.map += triangle
|
||||||
aFront -= (node.prev, node, triangle)
|
aFront -= (node.prev, node, triangle)
|
||||||
}
|
}
|
||||||
@ -231,10 +240,10 @@ class CDT(val points: List[Point], val segments: List[Segment], iTriangle: Trian
|
|||||||
t2.points(0) = t2.points(2)
|
t2.points(0) = t2.points(2)
|
||||||
t2.points(2) = tmp
|
t2.points(2) = tmp
|
||||||
// Rotate neighbors
|
// Rotate neighbors
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def finalization {
|
private def finalization {
|
||||||
}
|
}
|
||||||
|
|
||||||
def triangles = mesh.map
|
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,4 @@ case class Point(val x: Float, val y: Float) {
|
|||||||
@inline def !(p: Point) = !(p.x == x && p.y == y)
|
@inline def !(p: Point) = !(p.x == x && p.y == y)
|
||||||
@inline override def clone = Point(x, y)
|
@inline override def clone = Point(x, y)
|
||||||
|
|
||||||
def updateEdges(point: Point, segment: Segment) {
|
|
||||||
if(point.y > y)
|
|
||||||
point.edges += segment
|
|
||||||
else
|
|
||||||
edges += segment
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.poly2tri.shapes
|
package org.poly2tri.shapes
|
||||||
|
|
||||||
import scala.collection.mutable.{ArrayBuffer}
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
// Represents a simple polygon's edge
|
// Represents a simple polygon's edge
|
||||||
// TODO: Rename this class to Edge?
|
// TODO: Rename this class to Edge?
|
||||||
@ -51,4 +51,15 @@ class Segment(var p: Point, var q: Point) {
|
|||||||
// Determines if this segment lies below the given point
|
// Determines if this segment lies below the given point
|
||||||
def < (point: Point) = (Math.floor(point.y) > Math.floor(slope * point.x + b))
|
def < (point: Point) = (Math.floor(point.y) > Math.floor(slope * point.x + b))
|
||||||
|
|
||||||
|
// Update point edge list for CDT
|
||||||
|
def updateEdge {
|
||||||
|
if(p.y > q.y) {
|
||||||
|
// For CDT we want q to be the point with > y
|
||||||
|
val tmp = p
|
||||||
|
p = q
|
||||||
|
q = tmp
|
||||||
|
}
|
||||||
|
q.edges += this
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,20 +35,16 @@ package org.poly2tri.shapes
|
|||||||
// "Triangulations in CGAL"
|
// "Triangulations in CGAL"
|
||||||
class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
|
class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
|
||||||
|
|
||||||
|
val ik = points(2) - points(0)
|
||||||
|
val ij = points(1) - points(0)
|
||||||
|
val jk = points(2) - points(1)
|
||||||
|
val ji = points(0) - points(1)
|
||||||
|
val kj = points(1) - points(2)
|
||||||
|
val ki = points(0) - points(2)
|
||||||
|
|
||||||
// Flags to determine if an edge is the final Delauney edge
|
// Flags to determine if an edge is the final Delauney edge
|
||||||
val edges = new Array[Boolean](3)
|
val edges = new Array[Boolean](3)
|
||||||
|
|
||||||
def contains(point: Point) = {
|
|
||||||
if(point == points(0) || point == points(1) || point == points(2))
|
|
||||||
true
|
|
||||||
else
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
def legalize {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update neighbor pointers
|
// Update neighbor pointers
|
||||||
def updateNeighbors(ccwPoint: Point, cwPoint: Point, triangle: Triangle) {
|
def updateNeighbors(ccwPoint: Point, cwPoint: Point, triangle: Triangle) {
|
||||||
if(ccwPoint == points(2) && cwPoint == points(1))
|
if(ccwPoint == points(2) && cwPoint == points(1))
|
||||||
@ -68,23 +64,45 @@ class Triangle(val points: Array[Point], val neighbors: Array[Triangle]) {
|
|||||||
points(0)
|
points(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def contains(p: Point): Boolean = (p == points(0) || p == points(1) || p == points(2))
|
||||||
|
def contains(e: Segment): Boolean = (contains(e.p) || contains(e.q))
|
||||||
|
|
||||||
// Fast point in triangle test
|
// Fast point in triangle test
|
||||||
def pointIn(point: Point): Boolean = {
|
def pointIn(point: Point): Boolean = {
|
||||||
|
|
||||||
val ab = points(1) - points(0)
|
|
||||||
val bc = points(2) - points(1)
|
|
||||||
val ca = points(0) - points(2)
|
|
||||||
|
|
||||||
val pab = (point - points(0)).cross(ab)
|
val pab = (point - points(0)).cross(ij)
|
||||||
val pbc = (point - points(1)).cross(bc)
|
val pbc = (point - points(1)).cross(jk)
|
||||||
var sameSign = Math.signum(pab) == Math.signum(pbc)
|
var sameSign = Math.signum(pab) == Math.signum(pbc)
|
||||||
if (!sameSign) return false
|
if (!sameSign) return false
|
||||||
|
|
||||||
val pca = (point - points(2)).cross(ca)
|
val pca = (point - points(2)).cross(ki)
|
||||||
sameSign = Math.signum(pab) == Math.signum(pca)
|
sameSign = Math.signum(pab) == Math.signum(pca)
|
||||||
if (!sameSign) return false
|
if (!sameSign) return false
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def locateFirst(edge: Segment): Triangle = {
|
||||||
|
val p = edge.p
|
||||||
|
if(contains(p)) return this
|
||||||
|
val q = edge.q
|
||||||
|
val e = q - p
|
||||||
|
if(q == points(0)) {
|
||||||
|
val sameSign = Math.signum(ik cross e) == Math.signum(ij cross e)
|
||||||
|
if(!sameSign) return this
|
||||||
|
if(neighbors(2) == null) return null
|
||||||
|
return neighbors(2).locateFirst(edge)
|
||||||
|
} else if(q == points(1)) {
|
||||||
|
val sameSign = Math.signum(jk cross e) == Math.signum(ji cross e)
|
||||||
|
if(!sameSign) return this
|
||||||
|
if(neighbors(0) == null) return null
|
||||||
|
return neighbors(0).locateFirst(edge)
|
||||||
|
} else if(q == points(2)) {
|
||||||
|
val sameSign = Math.signum(kj cross e) == Math.signum(ki cross e)
|
||||||
|
if(!sameSign) return this
|
||||||
|
if(neighbors(1) == null) return null
|
||||||
|
return neighbors(1).locateFirst(edge)
|
||||||
|
}
|
||||||
|
throw new Exception("location error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user