Search in sources :

Example 1 with ConformingDelaunayTriangulationBuilder

use of com.vividsolutions.jts.triangulate.ConformingDelaunayTriangulationBuilder in project OpenTripPlanner by opentripplanner.

the class ConcaveHull method concaveHull.

/**
 * Create the concave hull.
 *
 * @return
 * 		the concave hull
 */
private Geometry concaveHull() {
    // triangulation: create a DelaunayTriangulationBuilder object
    ConformingDelaunayTriangulationBuilder cdtb = new ConformingDelaunayTriangulationBuilder();
    // add geometry collection
    cdtb.setSites(this.geometries);
    QuadEdgeSubdivision qes = cdtb.getSubdivision();
    Collection<QuadEdge> quadEdges = qes.getEdges();
    List<QuadEdgeTriangle> qeTriangles = QuadEdgeTriangle.createOn(qes);
    Collection<com.vividsolutions.jts.triangulate.quadedge.Vertex> qeVertices = qes.getVertices(false);
    int iV = 0;
    for (com.vividsolutions.jts.triangulate.quadedge.Vertex v : qeVertices) {
        this.coordinates.put(v.getCoordinate(), iV);
        this.vertices.put(iV, new Vertex(iV, v.getCoordinate()));
        iV++;
    }
    // border
    List<QuadEdge> qeFrameBorder = new ArrayList<QuadEdge>();
    List<QuadEdge> qeFrame = new ArrayList<QuadEdge>();
    List<QuadEdge> qeBorder = new ArrayList<QuadEdge>();
    for (QuadEdge qe : quadEdges) {
        if (qes.isFrameBorderEdge(qe)) {
            qeFrameBorder.add(qe);
        }
        if (qes.isFrameEdge(qe)) {
            qeFrame.add(qe);
        }
    }
    // border
    for (int j = 0; j < qeFrameBorder.size(); j++) {
        QuadEdge q = qeFrameBorder.get(j);
        if (!qeFrame.contains(q)) {
            qeBorder.add(q);
        }
    }
    // deletion of exterior edges
    for (QuadEdge qe : qeFrame) {
        qes.delete(qe);
    }
    HashMap<QuadEdge, Double> qeDistances = new HashMap<QuadEdge, Double>();
    for (QuadEdge qe : quadEdges) {
        qeDistances.put(qe, qe.toLineSegment().getLength());
    }
    DoubleComparator dc = new DoubleComparator(qeDistances);
    TreeMap<QuadEdge, Double> qeSorted = new TreeMap<QuadEdge, Double>(dc);
    qeSorted.putAll(qeDistances);
    // edges creation
    int i = 0;
    for (QuadEdge qe : qeSorted.keySet()) {
        LineSegment s = qe.toLineSegment();
        s.normalize();
        Integer idS = this.coordinates.get(s.p0);
        Integer idD = this.coordinates.get(s.p1);
        Vertex oV = this.vertices.get(idS);
        Vertex eV = this.vertices.get(idD);
        Edge edge;
        if (qeBorder.contains(qe)) {
            oV.setBorder(true);
            eV.setBorder(true);
            edge = new Edge(i, s, oV, eV, true);
            if (s.getLength() < this.threshold) {
                this.shortLengths.put(i, edge);
            } else {
                this.lengths.put(i, edge);
            }
        } else {
            edge = new Edge(i, s, oV, eV, false);
        }
        this.edges.put(i, edge);
        this.segments.put(s, i);
        i++;
    }
    // hm of linesegment and hm of edges // with id as key
    // hm of triangles using hm of ls and connection with hm of edges
    i = 0;
    for (QuadEdgeTriangle qet : qeTriangles) {
        LineSegment sA = qet.getEdge(0).toLineSegment();
        LineSegment sB = qet.getEdge(1).toLineSegment();
        LineSegment sC = qet.getEdge(2).toLineSegment();
        sA.normalize();
        sB.normalize();
        sC.normalize();
        Edge edgeA = this.edges.get(this.segments.get(sA));
        Edge edgeB = this.edges.get(this.segments.get(sB));
        Edge edgeC = this.edges.get(this.segments.get(sC));
        if (edgeA == null || edgeB == null || edgeC == null)
            continue;
        Triangle triangle = new Triangle(i, qet.isBorder() ? true : false);
        triangle.addEdge(edgeA);
        triangle.addEdge(edgeB);
        triangle.addEdge(edgeC);
        edgeA.addTriangle(triangle);
        edgeB.addTriangle(triangle);
        edgeC.addTriangle(triangle);
        this.triangles.put(i, triangle);
        i++;
    }
    // add triangle neighbourood
    for (Edge edge : this.edges.values()) {
        if (edge.getTriangles().size() > 1) {
            Triangle tA = edge.getTriangles().get(0);
            Triangle tB = edge.getTriangles().get(1);
            tA.addNeighbour(tB);
            tB.addNeighbour(tA);
        }
    }
    // concave hull algorithm
    int index = 0;
    while (index != -1) {
        index = -1;
        Edge e = null;
        // find the max length (smallest id so first entry)
        int si = this.lengths.size();
        if (si != 0) {
            Entry<Integer, Edge> entry = this.lengths.firstEntry();
            int ind = entry.getKey();
            if (entry.getValue().getGeometry().getLength() > this.threshold) {
                index = ind;
                e = entry.getValue();
            }
        }
        if (index != -1) {
            Triangle triangle = e.getTriangles().get(0);
            List<Triangle> neighbours = triangle.getNeighbours();
            // irregular triangle test
            if (neighbours.size() == 1) {
                this.shortLengths.put(e.getId(), e);
                this.lengths.remove(e.getId());
            } else {
                Edge e0 = triangle.getEdges().get(0);
                Edge e1 = triangle.getEdges().get(1);
                // test if all the vertices are on the border
                if (e0.getOV().isBorder() && e0.getEV().isBorder() && e1.getOV().isBorder() && e1.getEV().isBorder()) {
                    this.shortLengths.put(e.getId(), e);
                    this.lengths.remove(e.getId());
                } else {
                    // not sure this is safe
                    if (neighbours.size() < 1)
                        continue;
                    Triangle tA = neighbours.get(0);
                    Triangle tB = neighbours.get(1);
                    // FIXME not necessarily useful
                    tA.setBorder(true);
                    // FIXME not necessarily useful
                    tB.setBorder(true);
                    this.triangles.remove(triangle.getId());
                    tA.removeNeighbour(triangle);
                    tB.removeNeighbour(triangle);
                    // new edges
                    List<Edge> ee = triangle.getEdges();
                    Edge eA = ee.get(0);
                    Edge eB = ee.get(1);
                    Edge eC = ee.get(2);
                    if (eA.isBorder()) {
                        this.edges.remove(eA.getId());
                        eB.setBorder(true);
                        eB.getOV().setBorder(true);
                        eB.getEV().setBorder(true);
                        eC.setBorder(true);
                        eC.getOV().setBorder(true);
                        eC.getEV().setBorder(true);
                        // clean the relationships with the triangle
                        eB.removeTriangle(triangle);
                        eC.removeTriangle(triangle);
                        if (eB.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eB.getId(), eB);
                        } else {
                            this.lengths.put(eB.getId(), eB);
                        }
                        if (eC.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eC.getId(), eC);
                        } else {
                            this.lengths.put(eC.getId(), eC);
                        }
                        this.lengths.remove(eA.getId());
                    } else if (eB.isBorder()) {
                        this.edges.remove(eB.getId());
                        eA.setBorder(true);
                        eA.getOV().setBorder(true);
                        eA.getEV().setBorder(true);
                        eC.setBorder(true);
                        eC.getOV().setBorder(true);
                        eC.getEV().setBorder(true);
                        // clean the relationships with the triangle
                        eA.removeTriangle(triangle);
                        eC.removeTriangle(triangle);
                        if (eA.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eA.getId(), eA);
                        } else {
                            this.lengths.put(eA.getId(), eA);
                        }
                        if (eC.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eC.getId(), eC);
                        } else {
                            this.lengths.put(eC.getId(), eC);
                        }
                        this.lengths.remove(eB.getId());
                    } else {
                        this.edges.remove(eC.getId());
                        eA.setBorder(true);
                        eA.getOV().setBorder(true);
                        eA.getEV().setBorder(true);
                        eB.setBorder(true);
                        eB.getOV().setBorder(true);
                        eB.getEV().setBorder(true);
                        // clean the relationships with the triangle
                        eA.removeTriangle(triangle);
                        eB.removeTriangle(triangle);
                        if (eA.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eA.getId(), eA);
                        } else {
                            this.lengths.put(eA.getId(), eA);
                        }
                        if (eB.getGeometry().getLength() < this.threshold) {
                            this.shortLengths.put(eB.getId(), eB);
                        } else {
                            this.lengths.put(eB.getId(), eB);
                        }
                        this.lengths.remove(eC.getId());
                    }
                }
            }
        }
    }
    // concave hull creation
    List<LineString> edges = new ArrayList<LineString>();
    for (Edge e : this.lengths.values()) {
        LineString l = e.getGeometry().toGeometry(this.geomFactory);
        edges.add(l);
    }
    for (Edge e : this.shortLengths.values()) {
        LineString l = e.getGeometry().toGeometry(this.geomFactory);
        edges.add(l);
    }
    // merge
    LineMerger lineMerger = new LineMerger();
    lineMerger.add(edges);
    LineString merge = (LineString) lineMerger.getMergedLineStrings().iterator().next();
    if (merge.isRing()) {
        LinearRing lr = new LinearRing(merge.getCoordinateSequence(), this.geomFactory);
        Polygon concaveHull = new Polygon(lr, null, this.geomFactory);
        return concaveHull;
    }
    return merge;
}
Also used : Vertex(org.opensphere.geometry.triangulation.model.Vertex) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) QuadEdgeTriangle(com.vividsolutions.jts.triangulate.quadedge.QuadEdgeTriangle) Triangle(org.opensphere.geometry.triangulation.model.Triangle) ConformingDelaunayTriangulationBuilder(com.vividsolutions.jts.triangulate.ConformingDelaunayTriangulationBuilder) Polygon(com.vividsolutions.jts.geom.Polygon) LineSegment(com.vividsolutions.jts.geom.LineSegment) QuadEdge(com.vividsolutions.jts.triangulate.quadedge.QuadEdge) QuadEdgeTriangle(com.vividsolutions.jts.triangulate.quadedge.QuadEdgeTriangle) DoubleComparator(org.opensphere.geometry.triangulation.DoubleComparator) TreeMap(java.util.TreeMap) QuadEdgeSubdivision(com.vividsolutions.jts.triangulate.quadedge.QuadEdgeSubdivision) Point(com.vividsolutions.jts.geom.Point) LineMerger(com.vividsolutions.jts.operation.linemerge.LineMerger) LineString(com.vividsolutions.jts.geom.LineString) LinearRing(com.vividsolutions.jts.geom.LinearRing) QuadEdge(com.vividsolutions.jts.triangulate.quadedge.QuadEdge) Edge(org.opensphere.geometry.triangulation.model.Edge)

Aggregations

LineSegment (com.vividsolutions.jts.geom.LineSegment)1 LineString (com.vividsolutions.jts.geom.LineString)1 LinearRing (com.vividsolutions.jts.geom.LinearRing)1 Point (com.vividsolutions.jts.geom.Point)1 Polygon (com.vividsolutions.jts.geom.Polygon)1 LineMerger (com.vividsolutions.jts.operation.linemerge.LineMerger)1 ConformingDelaunayTriangulationBuilder (com.vividsolutions.jts.triangulate.ConformingDelaunayTriangulationBuilder)1 QuadEdge (com.vividsolutions.jts.triangulate.quadedge.QuadEdge)1 QuadEdgeSubdivision (com.vividsolutions.jts.triangulate.quadedge.QuadEdgeSubdivision)1 QuadEdgeTriangle (com.vividsolutions.jts.triangulate.quadedge.QuadEdgeTriangle)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 TreeMap (java.util.TreeMap)1 DoubleComparator (org.opensphere.geometry.triangulation.DoubleComparator)1 Edge (org.opensphere.geometry.triangulation.model.Edge)1 Triangle (org.opensphere.geometry.triangulation.model.Triangle)1 Vertex (org.opensphere.geometry.triangulation.model.Vertex)1