/*********************************************** * created on 12.06.2006 * last modified: * * author: sstein * * description: * * ***********************************************/ package org.openjump.core.graph.delauneySimplexInsert; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Set; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.operation.polygonize.Polygonizer; /** * @author sstein * * Use the class to access the delauney trinagulation by L. Paul Chew * Methods of the class are modified versions from DelaunayPanel.java in DelaunayAp.java. */ public class DTriangulationForJTS { private DelaunayTriangulation dt; // The Delaunay triangulation private Simplex initialTriangle; // The large initial triangle private int initialSize = 10000; // Controls size of initial triangle private boolean isVoronoi; // True iff VoD instead of DT private double dx=0; private double dy=0; private Pnt lowerLeftPnt = null; public boolean debug = false; // True iff printing info for debugging public DTriangulationForJTS(ArrayList pointList){ double argmaxx = 0; double argmaxy = 0; double argminx = 0; double argminy = 0; int count = 0; //-- calc coordinates of initial symplex for (Iterator iter = pointList.iterator(); iter.hasNext();) { Point pt = (Point) iter.next(); if (count==0){ argmaxx = pt.getX(); argminx = pt.getX(); argmaxy = pt.getY(); argminy = pt.getY(); } else{ if (pt.getX() < argminx){argminx = pt.getX();} if (pt.getX() > argmaxx){argmaxx = pt.getX();} if (pt.getY() < argminy){argminy = pt.getY();} if (pt.getY() > argmaxy){argmaxy = pt.getY();} } count++; } this.dx=argmaxx-argminx; this.dy=argmaxy-argminy; //-- the initial simplex must contain all points //-- take the bounding box, move the diagonals (sidewards) // the meeting point will be the mirrored bbox-center on the top edge this.initialTriangle = new Simplex(new Pnt[] { new Pnt(argminx-(1.5*dx), argminy-dy), //lower left new Pnt(argmaxx+(1.5*dx), argminy-dy), //lower right //new Pnt(argminx+(dx/2.0), argmaxy+(dy/2.0))}); //center, top new Pnt(argminx+(dx/2.0), argmaxy+1.5*dy)}); //center, top this.lowerLeftPnt = new Pnt(argminx-(1.5*dx), argminy-dy); this.dt = new DelaunayTriangulation(initialTriangle); this.addPoints(pointList); } /** * * @param pointList * @param envelope the envelope my extend the initial point cloud and result in a larger initial simplex */ public DTriangulationForJTS(ArrayList pointList, Envelope envelope){ double argmaxx = 0; double argmaxy = 0; double argminx = 0; double argminy = 0; int count = 0; //-- calc coordinates of initial symplex for (Iterator iter = pointList.iterator(); iter.hasNext();) { Point pt = (Point) iter.next(); if (count==0){ argmaxx = pt.getX(); argminx = pt.getX(); argmaxy = pt.getY(); argminy = pt.getY(); } else{ if (pt.getX() < argminx){argminx = pt.getX();} if (pt.getX() > argmaxx){argmaxx = pt.getX();} if (pt.getY() < argminy){argminy = pt.getY();} if (pt.getY() > argmaxy){argmaxy = pt.getY();} } count++; } //-- do check also for the delivered envelope if (envelope.getMinX() < argminx){argminx = envelope.getMinX();} if (envelope.getMaxX() > argmaxx){argmaxx = envelope.getMaxX();} if (envelope.getMinY() < argminy){argminy = envelope.getMinY();} if (envelope.getMaxY() > argmaxy){argmaxy = envelope.getMaxY();} //-- this.dx=argmaxx-argminx; this.dy=argmaxy-argminy; //-- the initial simplex must contain all points //-- take the bounding box, move the diagonals (sidewards) // the meeting point will be the mirrored bbox-center on the top edge this.initialTriangle = new Simplex(new Pnt[] { new Pnt(argminx-(1.5*dx), argminy-dy), //lower left new Pnt(argmaxx+(1.5*dx), argminy-dy), //lower right //new Pnt(argminx+(dx/2.0), argmaxy+(dy/2.0))}); //center, top new Pnt(argminx+(dx/2.0), argmaxy+1.5*dy)}); //center, top this.lowerLeftPnt = new Pnt(argminx-(1.5*dx), argminy-dy); this.dt = new DelaunayTriangulation(initialTriangle); this.addPoints(pointList); } public void addPoints(ArrayList pointList){ for (Iterator iter = pointList.iterator(); iter.hasNext();) { try{ Geometry element = (Geometry) iter.next(); if (element instanceof Point){ Point jtsPt = (Point)element; Pnt point = new Pnt(jtsPt.getX(), jtsPt.getY()); dt.delaunayPlace(point); } else{ if (debug) System.out.println("no point geometry"); } } catch(Exception e){ if (debug) System.out.println("no geometry"); } } } public void addPoint(double x, double y){ Pnt point = new Pnt(x, y); if (debug) System.out.println("Click " + point); dt.delaunayPlace(point); } /** * Draw all the Delaunay edges. * @return Arraylist with LineString geometries. */ public ArrayList drawAllDelaunay() { // Loop through all the edges of the DT (each is done twice) GeometryFactory gf = new GeometryFactory(); ArrayList lines = new ArrayList(); for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex) it.next(); for (Iterator otherIt = triangle.facets().iterator(); otherIt.hasNext();) { Set facet = (Set) otherIt.next(); Pnt[] endpoint = (Pnt[]) facet.toArray(new Pnt[2]); Coordinate[] coords = new Coordinate[2]; coords[0] = new Coordinate(endpoint[0].coord(0), endpoint[0].coord(1)); coords[1] = new Coordinate(endpoint[1].coord(0), endpoint[1].coord(1)); LineString ls = gf.createLineString(coords); lines.add(ls); } } return lines; } /** * Draw all the Voronoi edges. * @return Arraylist with LineString geometries. */ public ArrayList drawAllVoronoi () { GeometryFactory gf = new GeometryFactory(); ArrayList lines = new ArrayList(); // Loop through all the edges of the DT (each is done twice) for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex) it.next(); for (Iterator otherIt = dt.neighbors(triangle).iterator(); otherIt.hasNext();) { Simplex other = (Simplex) otherIt.next(); Pnt p = Pnt.circumcenter((Pnt[]) triangle.toArray(new Pnt[0])); Pnt q = Pnt.circumcenter((Pnt[]) other.toArray(new Pnt[0])); Coordinate[] coords = new Coordinate[2]; coords[0] = new Coordinate(p.coord(0), p.coord(1)); coords[1] = new Coordinate(q.coord(0), q.coord(1)); LineString ls = gf.createLineString(coords); lines.add(ls); } } return lines; } /** * Draw all the sites (i.e., the input points) of the DT. * @return Arraylist with point geometries. */ public ArrayList drawAllSites () { // Loop through all sites of the DT // Each is done several times, about 6 times each on average; this // can be proved via Euler's formula. GeometryFactory gf = new GeometryFactory(); ArrayList points = new ArrayList(); for (Iterator it = dt.iterator(); it.hasNext();) { for (Iterator otherIt = ((Simplex) it.next()).iterator(); otherIt.hasNext();){ Pnt pt = (Pnt) otherIt.next(); Coordinate coord = new Coordinate(pt.coord(0), pt.coord(1)); Point jtsPt = gf.createPoint(coord); points.add(jtsPt); } } return points; } /** * Draw all the empty circles (one for each triangle) of the DT. * @return Arraylist with polygon geometries. */ public ArrayList drawAllCircles () { // Loop through all triangles of the DT GeometryFactory gf = new GeometryFactory(); ArrayList circles = new ArrayList(); loop: for (Iterator it = dt.iterator(); it.hasNext();) { Simplex triangle = (Simplex) it.next(); for (Iterator otherIt = initialTriangle.iterator(); otherIt.hasNext();) { Pnt p = (Pnt) otherIt.next(); if (triangle.contains(p)) continue loop; } Pnt c = Pnt.circumcenter((Pnt[]) triangle.toArray(new Pnt[0])); double radius = c.subtract((Pnt) triangle.iterator().next()).magnitude(); Coordinate coord = new Coordinate(c.coord(0), c.coord(1)); Point jtsPt = gf.createPoint(coord); circles.add(jtsPt.buffer(radius)); } return circles; } public DelaunayTriangulation getDelaunayTriangulation() { return dt; } /** * * @return the corner points of the initial simplex which is divided * into smaller simplexes by the iterative insertion of the point dataset */ public ArrayList getInitialSimmplexAsJTSPoints(){ GeometryFactory gf = new GeometryFactory(); ArrayList points = new ArrayList(); for (Iterator otherIt = this.initialTriangle.iterator(); otherIt.hasNext();){ Pnt pt = (Pnt) otherIt.next(); Coordinate coord = new Coordinate(pt.coord(0), pt.coord(1)); Point jtsPt = gf.createPoint(coord); points.add(jtsPt); } return points; } /** * the size of the box has been empirically defined to get "undistorted" * outer thiessen polygons * @return a bounding box necesseray to create the final thiessenpolygons */ public Geometry getThiessenBoundingBox(){ GeometryFactory gf = new GeometryFactory(); Coordinate[] coords = new Coordinate[5]; coords[0] = new Coordinate(this.lowerLeftPnt.coord(0)+1*this.dx, this.lowerLeftPnt.coord(1)+0.5*this.dy); //lowerleft coords[1] = new Coordinate(this.lowerLeftPnt.coord(0)+3*this.dx, this.lowerLeftPnt.coord(1)+0.5*this.dy); //lowerright coords[2] = new Coordinate(this.lowerLeftPnt.coord(0)+3*this.dx, this.lowerLeftPnt.coord(1)+2.5*this.dy); //topright coords[3] = new Coordinate(this.lowerLeftPnt.coord(0)+1*this.dx, this.lowerLeftPnt.coord(1)+2.5*this.dy); //topleft //-- to close linestring coords[4] = new Coordinate(this.lowerLeftPnt.coord(0)+1*this.dx, this.lowerLeftPnt.coord(1)+0.5*dy); //lowerleft LinearRing lr = gf.createLinearRing(coords); Geometry bbox = gf.createPolygon(lr, null); return bbox; } /** * Method returns thiessen polygons within a empirically enlarged * bounding box around the point set. Therefore the voronoi edges are * polygonized and the intersecting voronoi polygons with the bounding box * are calculated. These intersecting thiessen polygons (in the bounding box) are returned.<p> * Note: "thiesen" and "voronoi" is exchangeable. * @return a list of Polygons */ public ArrayList getThiessenPolys(){ //-- do union of all edges and use the polygonizer to create polygons from it if (debug) System.out.println("get voronoi egdes"); ArrayList edges = this.drawAllVoronoi(); if (debug) System.out.println("merge voronoi egdes to multiLineString"); Geometry mls = (Geometry)edges.get(0); for (int i = 1; i < edges.size(); i++) { Geometry line = (Geometry)edges.get(i); mls = mls.union(line); } if (debug) System.out.println("polygonize"); Polygonizer poly = new Polygonizer(); poly.add(mls); Collection polys = poly.getPolygons(); //-- get final polygons in bounding box (=intersection polygons with the bbox) Geometry bbox= this.getThiessenBoundingBox(); if (debug) System.out.println("get intersections and final polys.."); ArrayList finalPolys = new ArrayList(); for (Iterator iter = polys.iterator(); iter.hasNext();) { Geometry candPoly = (Geometry) iter.next(); Geometry intersection = bbox.intersection(candPoly); if( intersection != null){ if (intersection.getArea() > 0){ finalPolys.add(intersection); } } } return finalPolys; } }