/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Poly2Tri nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.poly2tri.triangulation.delaunay.sweep;
import java.util.ArrayList;
import java.util.Collections;
import org.poly2tri.triangulation.Triangulatable;
import org.poly2tri.triangulation.TriangulationAlgorithm;
import org.poly2tri.triangulation.TriangulationConstraint;
import org.poly2tri.triangulation.TriangulationContext;
import org.poly2tri.triangulation.TriangulationPoint;
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
import org.poly2tri.triangulation.point.TPoint;
/**
*
* @author Thomas �hl�n, thahlen@gmail.com
*
*/
public class DTSweepContext extends TriangulationContext<DTSweepDebugContext> {
// Inital triangle factor, seed triangle will extend 30% of
// PointSet width to both left and right.
private final float ALPHA = 0.3f;
/** Advancing front **/
protected AdvancingFront aFront;
/** head point used with advancing front */
private TriangulationPoint _head;
/** tail point used with advancing front */
private TriangulationPoint _tail;
protected Basin basin = new Basin();
protected EdgeEvent edgeEvent = new EdgeEvent();
private DTSweepPointComparator _comparator = new DTSweepPointComparator();
public DTSweepContext() {
clear();
}
public void isDebugEnabled(boolean b) {
if (b) {
if (_debug == null) {
_debug = new DTSweepDebugContext(this);
}
}
_debugEnabled = b;
}
public void removeFromList(DelaunayTriangle triangle) {
_triList.remove(triangle);
// TODO: remove all neighbor pointers to this triangle
// for( int i=0; i<3; i++ )
// {
// if( triangle.neighbors[i] != null )
// {
// triangle.neighbors[i].clearNeighbor( triangle );
// }
// }
// triangle.clearNeighbors();
}
protected void meshClean(DelaunayTriangle triangle) {
DelaunayTriangle t1, t2;
if (triangle != null) {
ArrayList<DelaunayTriangle> deque = new ArrayList<DelaunayTriangle>();
deque.add(0, triangle);
triangle.isInterior(true);
while (!deque.isEmpty()) {
t1 = deque.remove(0);
_triUnit.addTriangle(t1);
for (int i = 0; i < 3; ++i) {
if (!t1.cEdge[i]) {
t2 = t1.neighbors[i];
if (t2 != null && !t2.isInterior()) {
t2.isInterior(true);
deque.add(t2);
}
}
}
}
}
}
public void clear() {
super.clear();
_triList.clear();
}
public AdvancingFront getAdvancingFront() {
return aFront;
}
public void setHead(TriangulationPoint p1) {
_head = p1;
}
public TriangulationPoint getHead() {
return _head;
}
public void setTail(TriangulationPoint p1) {
_tail = p1;
}
public TriangulationPoint getTail() {
return _tail;
}
public void addNode(AdvancingFrontNode node) {
// System.out.println( "add:" + node.key + ":" + System.identityHashCode(node.key));
// m_nodeTree.put( node.getKey(), node );
aFront.addNode(node);
}
public void removeNode(AdvancingFrontNode node) {
// System.out.println( "remove:" + node.key + ":" + System.identityHashCode(node.key));
// m_nodeTree.delete( node.getKey() );
aFront.removeNode(node);
}
public AdvancingFrontNode locateNode(TriangulationPoint point) {
return aFront.locateNode(point);
}
public void createAdvancingFront() {
AdvancingFrontNode head, tail, middle;
// Initial triangle
DelaunayTriangle iTriangle = new DelaunayTriangle(_points.get(0),
getTail(), getHead());
addToList(iTriangle);
head = new AdvancingFrontNode(iTriangle.points[1]);
head.triangle = iTriangle;
middle = new AdvancingFrontNode(iTriangle.points[0]);
middle.triangle = iTriangle;
tail = new AdvancingFrontNode(iTriangle.points[2]);
aFront = new AdvancingFront(head, tail);
aFront.addNode(middle);
// TODO: I think it would be more intuitive if head is middles next and not previous
// so swap head and tail
aFront.head.next = middle;
middle.next = aFront.tail;
middle.prev = aFront.head;
aFront.tail.prev = middle;
}
class Basin {
AdvancingFrontNode leftNode;
AdvancingFrontNode bottomNode;
AdvancingFrontNode rightNode;
public double width;
public boolean leftHighest;
}
class EdgeEvent {
DTSweepConstraint constrainedEdge;
public boolean right;
}
/**
* Try to map a node to all sides of this triangle that don't have
* a neighbor.
*
* @param t
*/
public void mapTriangleToNodes(DelaunayTriangle t) {
AdvancingFrontNode n;
for (int i = 0; i < 3; i++) {
if (t.neighbors[i] == null) {
n = aFront.locatePoint(t.pointCW(t.points[i]));
if (n != null) {
n.triangle = t;
}
}
}
}
@Override
public void prepareTriangulation(Triangulatable t) {
super.prepareTriangulation(t);
double xmax, xmin;
double ymax, ymin;
xmax = xmin = _points.get(0).getX();
ymax = ymin = _points.get(0).getY();
// Calculate bounds. Should be combined with the sorting
for (TriangulationPoint p : _points) {
if (p.getX() > xmax)
xmax = p.getX();
if (p.getX() < xmin)
xmin = p.getX();
if (p.getY() > ymax)
ymax = p.getY();
if (p.getY() < ymin)
ymin = p.getY();
}
double deltaX = ALPHA * (xmax - xmin);
double deltaY = ALPHA * (ymax - ymin);
TPoint p1 = new TPoint(xmax + deltaX, ymin - deltaY);
TPoint p2 = new TPoint(xmin - deltaX, ymin - deltaY);
setHead(p1);
setTail(p2);
// long time = System.nanoTime();
// Sort the points along y-axis
Collections.sort(_points, _comparator);
// logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 );
}
public void finalizeTriangulation() {
_triUnit.addTriangles(_triList);
_triList.clear();
}
@Override
public TriangulationConstraint newConstraint(TriangulationPoint a,
TriangulationPoint b) {
return new DTSweepConstraint(a, b);
}
@Override
public TriangulationAlgorithm algorithm() {
return TriangulationAlgorithm.DTSweep;
}
}