/* 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; } }