Class IncrementalDelaunayTriangulator

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12  
 13 package org.locationtech.jts.triangulate;
 14  
 15 import java.util.Collection;
 16 import java.util.Iterator;
 17  
 18 import org.locationtech.jts.triangulate.quadedge.LocateFailureException;
 19 import org.locationtech.jts.triangulate.quadedge.QuadEdge;
 20 import org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision;
 21 import org.locationtech.jts.triangulate.quadedge.Vertex;
 22  
 23  
 24 /**
 25  * Computes a Delaunay Triangulation of a set of {@link Vertex}es, using an
 26  * incremental insertion algorithm.
 27  * 
 28  * @author Martin Davis
 29  * @version 1.0
 30  */
 31 public class IncrementalDelaunayTriangulator 
 32 {
 33     private QuadEdgeSubdivision subdiv;
 34     private boolean isUsingTolerance = false;
 35  
 36     /**
 37      * Creates a new triangulator using the given {@link QuadEdgeSubdivision}.
 38      * The triangulator uses the tolerance of the supplied subdivision.
 39      * 
 40      * @param subdiv
 41      *          a subdivision in which to build the TIN
 42      */
 43     public IncrementalDelaunayTriangulator(QuadEdgeSubdivision subdiv) {
 44         this.subdiv = subdiv;
 45         isUsingTolerance = subdiv.getTolerance() > 0.0;
 46         
 47     }
 48  
 49     /**
 50      * Inserts all sites in a collection. The inserted vertices <b>MUST</b> be
 51      * unique up to the provided tolerance value. (i.e. no two vertices should be
 52      * closer than the provided tolerance value). They do not have to be rounded
 53      * to the tolerance grid, however.
 54      * 
 55      * @param vertices a Collection of Vertex
 56      * 
 57    * @throws LocateFailureException if the location algorithm fails to converge in a reasonable number of iterations
 58      */
 59     public void insertSites(Collection vertices) {
 60         for (Iterator i = vertices.iterator(); i.hasNext();) {
 61             Vertex v = (Vertex) i.next();
 62             insertSite(v);
 63         }
 64     }
 65  
 66     /**
 67      * Inserts a new point into a subdivision representing a Delaunay
 68      * triangulation, and fixes the affected edges so that the result is still a
 69      * Delaunay triangulation.
 70      * <p>
 71      * 
 72      * @return a quadedge containing the inserted vertex
 73      */
 74     public QuadEdge insertSite(Vertex v) {
 75  
 76         /**
 77          * This code is based on Guibas and Stolfi (1985), with minor modifications
 78          * and a bug fix from Dani Lischinski (Graphic Gems 1993). (The modification
 79          * I believe is the test for the inserted site falling exactly on an
 80          * existing edge. Without this test zero-width triangles have been observed
 81          * to be created)
 82          */
 83         QuadEdge e = subdiv.locate(v);
 84  
 85         if (subdiv.isVertexOfEdge(e, v)) {
 86             // point is already in subdivision.
 87             return e; 
 88         } 
 89         else if (subdiv.isOnEdge(e, v.getCoordinate())) {
 90             // the point lies exactly on an edge, so delete the edge 
 91             // (it will be replaced by a pair of edges which have the point as a vertex)
 92             e = e.oPrev();
 93             subdiv.delete(e.oNext());
 94         }
 95  
 96         /**
 97          * Connect the new point to the vertices of the containing triangle 
 98          * (or quadrilateral, if the new point fell on an existing edge.)
 99          */
100         QuadEdge base = subdiv.makeEdge(e.orig(), v);
101         QuadEdge.splice(base, e);
102         QuadEdge startEdge = base;
103         do {
104             base = subdiv.connect(e, base.sym());
105             e = base.oPrev();
106         } while (e.lNext() != startEdge);
107  
108         // Examine suspect edges to ensure that the Delaunay condition
109         // is satisfied.
110         do {
111             QuadEdge t = e.oPrev();
112             if (t.dest().rightOf(e) && v.isInCircle(e.orig(), t.dest(), e.dest())) {
113                 QuadEdge.swap(e);
114                 e = e.oPrev();
115             } else if (e.oNext() == startEdge) {
116                 return base; // no more suspect edges.
117             } else {
118                 e = e.oNext().lPrev();
119             }
120         } while (true);
121     }
122  
123 }
124