public static TriangulationContext<?> createContext( TriangulationAlgorithm algorithm ) { switch( algorithm ) { case DTSweep: default: return new DTSweepContext(); } }
tcx.addToList( triangle ); node.next = newNode; tcx.addNode( newNode ); // XXX: BST if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( newNode ); } tcx.mapTriangleToNodes( triangle );
public DTSweepContext() { clear(); }
/** Triangulate simple polygon with holes **/ public static void triangulate( DTSweepContext tcx ) { tcx.createAdvancingFront(); sweep( tcx ); if( tcx.getTriangulationMode() == TriangulationMode.POLYGON ) { finalizationPolygon( tcx ); } else { finalizationConvexHull( tcx ); } tcx.done(); }
/** * Start sweeping the Y-sorted point set from bottom to top * * @param tcx */ private static void sweep( DTSweepContext tcx ) { List<TriangulationPoint> points; TriangulationPoint point; AdvancingFrontNode node; points = tcx.getPoints(); for( int i=1; i<points.size(); i++ ) { point = points.get(i); node = pointEvent( tcx, point ); if( point.hasEdges() ) { for( DTSweepConstraint e : point.getEdges() ) { if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveConstraint( e ); } edgeEvent( tcx, e, node ); } } tcx.update( null ); } }
private static void fillRightAboveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) { while( node.next.point.getX() < edge.p.getX() ) { if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } // Check if next node is below the edge Orientation o1 = orient2d( edge.q, node.next.point, edge.p ); if( o1 == Orientation.CCW ) { fillRightBelowEdgeEvent( tcx, edge, node ); } else { node = node.next; } } }
/** * Find closes node to the left of the new point and * create a new triangle. If needed new holes and basins * will be filled to. * * @param tcx * @param point * @return */ private static AdvancingFrontNode pointEvent( DTSweepContext tcx, TriangulationPoint point ) { AdvancingFrontNode node,newNode; node = tcx.locateNode( point ); if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } newNode = newFrontTriangle( tcx, point, node ); // Only need to check +epsilon since point never have smaller // x value than node due to how we fetch nodes from the front if( point.getX() <= node.point.getX() + EPSILON ) { fill( tcx, node ); } tcx.addNode( newNode ); fillAdvancingFront( tcx, newNode ); return newNode; }
/** * Adds a triangle to the advancing front to fill a hole. * @param tcx * @param node - middle node, that is the bottom of the hole */ private static void fill( DTSweepContext tcx, AdvancingFrontNode node ) { DelaunayTriangle triangle = new DelaunayTriangle( node.prev.point, node.point, node.next.point ); // TODO: should copy the cEdge value from neighbor triangles // for now cEdge values are copied during the legalize triangle.markNeighbor( node.prev.triangle ); triangle.markNeighbor( node.triangle ); tcx.addToList( triangle ); // Update the advancing front node.prev.next = node.next; node.next.prev = node.prev; tcx.removeNode( node ); // If it was legalized the triangle has already been mapped if( !legalize( tcx, triangle ) ) { tcx.mapTriangleToNodes( triangle ); } }
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; }
if( tcx.isDebugEnabled() ) tcx.getDebugContext().setPrimaryTriangle( t ); tcx.getDebugContext().setSecondaryTriangle( ot ); tcx.mapTriangleToNodes( t ); tcx.mapTriangleToNodes( ot ); && ep == tcx.edgeEvent.constrainedEdge.p) if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - constrained edge done" ); } // TODO: remove t.markConstrainedEdge( ep, eq ); ot.markConstrainedEdge( ep, eq ); if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - subedge done" ); } // TODO: remove if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - flipping and continuing with triangle still crossing edge" ); } // TODO: remove Orientation o = orient2d( eq, op, ep ); t = nextFlipTriangle( tcx, o, t, ot, p, op );
tcx.mapTriangleToNodes( n1.triangle ); tcx.mapTriangleToNodes( t1 ); tcx.mapTriangleToNodes( n1.triangle ); tcx.mapTriangleToNodes( t1 ); do tcx.removeFromList( t1 ); p1 = t1.pointCCW( p1 ); if( p1 == first ) break; while( p1 != first ) tcx.removeFromList( t1 ); p1 = t1.pointCCW( p1 ); t2 = t1.neighborCCW( p1 ); tcx.aFront.tail.next = null; tcx.finalizeTriangulation();
private static void fillLeftAboveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) { while( node.prev.point.getX() > edge.p.getX() ) { if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } // Check if next node is below the edge Orientation o1 = orient2d( edge.q, node.prev.point, edge.p ); if( o1 == Orientation.CW ) { fillLeftBelowEdgeEvent( tcx, edge, node ); } else { node = node.prev; } } }
private static void fillLeftBelowEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) { if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } if( node.point.getX() > edge.p.getX() ) { if( orient2d( node.point, node.prev.point, node.prev.prev.point ) == Orientation.CW ) { // Concave fillLeftConcaveEdgeEvent( tcx, edge, node ); } else { // Convex fillLeftConvexEdgeEvent( tcx, edge, node ); // Retry this one fillLeftBelowEdgeEvent( tcx, edge, node ); } } }
private static void fillRightBelowEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) { if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } if( node.point.getX() < edge.p.getX() ) // needed? { if( orient2d( node.point, node.next.point, node.next.next.point ) == Orientation.CCW ) { // Concave fillRightConcaveEdgeEvent( tcx, edge, node ); } else { // Convex fillRightConvexEdgeEvent( tcx, edge, node ); // Retry this one fillRightBelowEdgeEvent( tcx, edge, node ); } } }
while( c != tcx.aFront.tail ) if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( c ); }
tcx.edgeEvent.right = edge.p.getX() > edge.q.getX(); if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setPrimaryTriangle( node.triangle ); }
if( tcx.isDebugEnabled() ) tcx.getDebugContext().setPrimaryTriangle( t ); tcx.getDebugContext().setSecondaryTriangle( ot );
if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setPrimaryTriangle( triangle ); } if( tcx.isDebugEnabled() ) { logger.info( "EdgeEvent - Point on constrained edge" ); } return; if( tcx.isDebugEnabled() ) { logger.info( "EdgeEvent - Point on constrained edge" ); } return;