Search in sources :

Example 1 with QuadEdgeSubdivision

use of org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision in project graphhopper by graphhopper.

the class JTSTriangulator method triangulate.

public Result triangulate(Snap snap, QueryGraph queryGraph, ShortestPathTree shortestPathTree, ToDoubleFunction<ShortestPathTree.IsoLabel> fz, double tolerance) {
    final NodeAccess na = queryGraph.getNodeAccess();
    Collection<Coordinate> sites = new ArrayList<>();
    shortestPathTree.search(snap.getClosestNode(), label -> {
        double exploreValue = fz.applyAsDouble(label);
        double lat = na.getLat(label.node);
        double lon = na.getLon(label.node);
        Coordinate site = new Coordinate(lon, lat);
        site.z = exploreValue;
        sites.add(site);
        // add a pillar node to increase precision a bit for longer roads
        if (label.parent != null) {
            EdgeIteratorState edge = queryGraph.getEdgeIteratorState(label.edge, label.node);
            PointList innerPoints = edge.fetchWayGeometry(FetchMode.PILLAR_ONLY);
            if (innerPoints.size() > 0) {
                int midIndex = innerPoints.size() / 2;
                double lat2 = innerPoints.getLat(midIndex);
                double lon2 = innerPoints.getLon(midIndex);
                Coordinate site2 = new Coordinate(lon2, lat2);
                site2.z = exploreValue;
                sites.add(site2);
            }
        }
    });
    if (sites.size() > routerConfig.getMaxVisitedNodes() / 3)
        throw new IllegalArgumentException("Too many nodes would be included in post processing (" + sites.size() + "). Let us know if you need this increased.");
    // Sites may contain repeated coordinates. Especially for edge-based traversal, that's expected -- we visit
    // each node multiple times.
    // But that's okay, the triangulator de-dupes by itself, and it keeps the first z-value it sees, which is
    // what we want.
    Collection<ConstraintVertex> constraintVertices = sites.stream().map(ConstraintVertex::new).collect(Collectors.toList());
    ConformingDelaunayTriangulator conformingDelaunayTriangulator = new ConformingDelaunayTriangulator(constraintVertices, tolerance);
    conformingDelaunayTriangulator.setConstraints(new ArrayList<>(), new ArrayList<>());
    conformingDelaunayTriangulator.formInitialDelaunay();
    conformingDelaunayTriangulator.enforceConstraints();
    Geometry convexHull = conformingDelaunayTriangulator.getConvexHull();
    if (!(convexHull instanceof Polygon)) {
        throw new IllegalArgumentException("Too few points found. " + "Please try a different 'point' or a larger 'time_limit'.");
    }
    QuadEdgeSubdivision tin = conformingDelaunayTriangulator.getSubdivision();
    for (Vertex vertex : (Collection<Vertex>) tin.getVertices(true)) {
        if (tin.isFrameVertex(vertex)) {
            vertex.setZ(Double.MAX_VALUE);
        }
    }
    ReadableTriangulation triangulation = ReadableTriangulation.wrap(tin);
    return new Result(triangulation, triangulation.getEdges());
}
Also used : PointList(com.graphhopper.util.PointList) ConstraintVertex(org.locationtech.jts.triangulate.ConstraintVertex) Vertex(org.locationtech.jts.triangulate.quadedge.Vertex) NodeAccess(com.graphhopper.storage.NodeAccess) ArrayList(java.util.ArrayList) ConformingDelaunayTriangulator(org.locationtech.jts.triangulate.ConformingDelaunayTriangulator) QuadEdgeSubdivision(org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision) ConstraintVertex(org.locationtech.jts.triangulate.ConstraintVertex) Geometry(org.locationtech.jts.geom.Geometry) Coordinate(org.locationtech.jts.geom.Coordinate) EdgeIteratorState(com.graphhopper.util.EdgeIteratorState) Collection(java.util.Collection) Polygon(org.locationtech.jts.geom.Polygon)

Example 2 with QuadEdgeSubdivision

use of org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision in project graphhopper by graphhopper.

the class PtIsochroneResource method doGet.

@GET
@Produces({ MediaType.APPLICATION_JSON })
public Response doGet(@QueryParam("point") GHLocationParam sourceParam, @QueryParam("time_limit") @DefaultValue("600") long seconds, @QueryParam("reverse_flow") @DefaultValue("false") boolean reverseFlow, @QueryParam("pt.earliest_departure_time") @NotNull OffsetDateTimeParam departureTimeParam, @QueryParam("pt.blocked_route_types") @DefaultValue("0") int blockedRouteTypes, @QueryParam("result") @DefaultValue("multipolygon") String format) {
    Instant initialTime = departureTimeParam.get().toInstant();
    GHLocation location = sourceParam.get();
    double targetZ = seconds * 1000;
    GeometryFactory geometryFactory = new GeometryFactory();
    final FlagEncoder footEncoder = encodingManager.getEncoder("foot");
    final Weighting weighting = new FastestWeighting(footEncoder);
    DefaultSnapFilter snapFilter = new DefaultSnapFilter(weighting, graphHopperStorage.getEncodingManager().getBooleanEncodedValue(Subnetwork.key("foot")));
    PtLocationSnapper.Result snapResult = new PtLocationSnapper(graphHopperStorage, locationIndex, gtfsStorage).snapAll(Arrays.asList(location), Arrays.asList(snapFilter));
    GraphExplorer graphExplorer = new GraphExplorer(snapResult.queryGraph, gtfsStorage.getPtGraph(), weighting, gtfsStorage, RealtimeFeed.empty(), reverseFlow, false, false, 5.0, reverseFlow, blockedRouteTypes);
    MultiCriteriaLabelSetting router = new MultiCriteriaLabelSetting(graphExplorer, reverseFlow, false, false, 0, Collections.emptyList());
    Map<Coordinate, Double> z1 = new HashMap<>();
    NodeAccess nodeAccess = snapResult.queryGraph.getNodeAccess();
    for (Label label : router.calcLabels(snapResult.nodes.get(0), initialTime)) {
        if (!((label.currentTime - initialTime.toEpochMilli()) * (reverseFlow ? -1 : 1) <= targetZ)) {
            break;
        }
        if (label.node.streetNode != -1) {
            Coordinate nodeCoordinate = new Coordinate(nodeAccess.getLon(label.node.streetNode), nodeAccess.getLat(label.node.streetNode));
            z1.merge(nodeCoordinate, (double) (label.currentTime - initialTime.toEpochMilli()) * (reverseFlow ? -1 : 1), Math::min);
        } else if (label.edge != null && (label.edge.getType() == GtfsStorage.EdgeType.EXIT_PT || label.edge.getType() == GtfsStorage.EdgeType.ENTER_PT)) {
            GtfsStorage.PlatformDescriptor platformDescriptor = label.edge.getPlatformDescriptor();
            Stop stop = gtfsStorage.getGtfsFeeds().get(platformDescriptor.feed_id).stops.get(platformDescriptor.stop_id);
            Coordinate nodeCoordinate = new Coordinate(stop.stop_lon, stop.stop_lat);
            z1.merge(nodeCoordinate, (double) (label.currentTime - initialTime.toEpochMilli()) * (reverseFlow ? -1 : 1), Math::min);
        }
    }
    if (format.equals("multipoint")) {
        MultiPoint exploredPoints = geometryFactory.createMultiPointFromCoords(z1.keySet().toArray(new Coordinate[0]));
        return wrap(exploredPoints);
    } else {
        MultiPoint exploredPoints = geometryFactory.createMultiPointFromCoords(z1.keySet().toArray(new Coordinate[0]));
        // Get at least all nodes within our bounding box (I think convex hull would be enough.)
        // I think then we should have all possible encroaching points. (Proof needed.)
        locationIndex.query(BBox.fromEnvelope(exploredPoints.getEnvelopeInternal()), edgeId -> {
            EdgeIteratorState edge = snapResult.queryGraph.getEdgeIteratorStateForKey(edgeId * 2);
            z1.merge(new Coordinate(nodeAccess.getLon(edge.getBaseNode()), nodeAccess.getLat(edge.getBaseNode())), Double.MAX_VALUE, Math::min);
            z1.merge(new Coordinate(nodeAccess.getLon(edge.getAdjNode()), nodeAccess.getLat(edge.getAdjNode())), Double.MAX_VALUE, Math::min);
        });
        exploredPoints = geometryFactory.createMultiPointFromCoords(z1.keySet().toArray(new Coordinate[0]));
        CoordinateList siteCoords = DelaunayTriangulationBuilder.extractUniqueCoordinates(exploredPoints);
        List<ConstraintVertex> constraintVertices = new ArrayList<>();
        for (Object siteCoord : siteCoords) {
            Coordinate coord = (Coordinate) siteCoord;
            constraintVertices.add(new ConstraintVertex(coord));
        }
        ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(constraintVertices, JTS_TOLERANCE);
        cdt.setConstraints(new ArrayList(), new ArrayList());
        cdt.formInitialDelaunay();
        QuadEdgeSubdivision tin = cdt.getSubdivision();
        for (Vertex vertex : (Collection<Vertex>) tin.getVertices(true)) {
            if (tin.isFrameVertex(vertex)) {
                vertex.setZ(Double.MAX_VALUE);
            } else {
                Double aDouble = z1.get(vertex.getCoordinate());
                if (aDouble != null) {
                    vertex.setZ(aDouble);
                } else {
                    vertex.setZ(Double.MAX_VALUE);
                }
            }
        }
        ReadableTriangulation triangulation = ReadableTriangulation.wrap(tin);
        ContourBuilder contourBuilder = new ContourBuilder(triangulation);
        MultiPolygon isoline = contourBuilder.computeIsoline(targetZ, triangulation.getEdges());
        // debugging tool
        if (format.equals("triangulation")) {
            Response response = new Response();
            for (Vertex vertex : (Collection<Vertex>) tin.getVertices(true)) {
                JsonFeature feature = new JsonFeature();
                feature.setGeometry(geometryFactory.createPoint(vertex.getCoordinate()));
                HashMap<String, Object> properties = new HashMap<>();
                properties.put("z", vertex.getZ());
                feature.setProperties(properties);
                response.polygons.add(feature);
            }
            for (QuadEdge edge : (Collection<QuadEdge>) tin.getPrimaryEdges(false)) {
                JsonFeature feature = new JsonFeature();
                feature.setGeometry(edge.toLineSegment().toGeometry(geometryFactory));
                HashMap<String, Object> properties = new HashMap<>();
                feature.setProperties(properties);
                response.polygons.add(feature);
            }
            JsonFeature feature = new JsonFeature();
            feature.setGeometry(isoline);
            HashMap<String, Object> properties = new HashMap<>();
            properties.put("z", targetZ);
            feature.setProperties(properties);
            response.polygons.add(feature);
            response.info.copyrights.addAll(ResponsePathSerializer.COPYRIGHTS);
            return response;
        } else {
            return wrap(isoline);
        }
    }
}
Also used : ConstraintVertex(org.locationtech.jts.triangulate.ConstraintVertex) Vertex(org.locationtech.jts.triangulate.quadedge.Vertex) NodeAccess(com.graphhopper.storage.NodeAccess) FlagEncoder(com.graphhopper.routing.util.FlagEncoder) Stop(com.conveyal.gtfs.model.Stop) ConstraintVertex(org.locationtech.jts.triangulate.ConstraintVertex) EdgeIteratorState(com.graphhopper.util.EdgeIteratorState) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) QuadEdge(org.locationtech.jts.triangulate.quadedge.QuadEdge) DefaultSnapFilter(com.graphhopper.routing.util.DefaultSnapFilter) Instant(java.time.Instant) ReadableTriangulation(com.graphhopper.isochrone.algorithm.ReadableTriangulation) ConformingDelaunayTriangulator(org.locationtech.jts.triangulate.ConformingDelaunayTriangulator) QuadEdgeSubdivision(org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision) JsonFeature(com.graphhopper.util.JsonFeature) FastestWeighting(com.graphhopper.routing.weighting.FastestWeighting) Weighting(com.graphhopper.routing.weighting.Weighting) ContourBuilder(com.graphhopper.isochrone.algorithm.ContourBuilder)

Example 3 with QuadEdgeSubdivision

use of org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision in project graphhopper by graphhopper.

the class QuadEdgeSubdivisionTest method createQuadEdgeSubdivisionFromScratch.

@Test
public void createQuadEdgeSubdivisionFromScratch() {
    Vertex v1 = new Vertex(0.0, 0.0, 0.0);
    Vertex v2 = new Vertex(1.0, -1.0, 1.0);
    Vertex v3 = new Vertex(1.0, 1.0, 0.0);
    Vertex v4 = new Vertex(2.0, 0.0, 0.0);
    QuadEdgeSubdivision quadEdgeSubdivision = new QuadEdgeSubdivision(new Envelope(0.0, 2.0, -1.0, 1.0), 0.001);
    QuadEdge e1 = quadEdgeSubdivision.makeEdge(v1, v3);
    QuadEdge e2 = quadEdgeSubdivision.makeEdge(v3, v2);
    QuadEdge.splice(e1.sym(), e2);
    QuadEdge e3 = quadEdgeSubdivision.connect(e2, e1);
    QuadEdge e4 = quadEdgeSubdivision.makeEdge(v4, v2);
    QuadEdge.splice(e2.sym(), e4.lNext());
    QuadEdge e41 = quadEdgeSubdivision.connect(e2.sym(), e4);
    Vertex v5 = new Vertex(1.0, -3.0, 0.0);
    QuadEdge e5 = quadEdgeSubdivision.makeEdge(v5, v1);
    QuadEdge.splice(e3.sym(), e5.lNext());
    QuadEdge e6 = quadEdgeSubdivision.connect(e3.sym(), e5);
    QuadEdge e7 = quadEdgeSubdivision.connect(e4.sym(), e6.sym());
    assertTriangle(ReadableQuadEdge.wrap(e1), ReadableQuadEdge.wrap(e2), ReadableQuadEdge.wrap(e3));
    assertTriangle(ReadableQuadEdge.wrap(e4), ReadableQuadEdge.wrap(e2.sym()), ReadableQuadEdge.wrap(e41));
    assertTriangle(ReadableQuadEdge.wrap(e5), ReadableQuadEdge.wrap(e3.sym()), ReadableQuadEdge.wrap(e6));
    assertTriangle(ReadableQuadEdge.wrap(e6.sym()), ReadableQuadEdge.wrap(e4.sym()), ReadableQuadEdge.wrap(e7));
    assertVertex(ReadableQuadEdge.wrap(e1), ReadableQuadEdge.wrap(e3.sym()), ReadableQuadEdge.wrap(e5.sym()));
    assertVertex(ReadableQuadEdge.wrap(e5), ReadableQuadEdge.wrap(e6.sym()), ReadableQuadEdge.wrap(e7.sym()));
    assertVertex(ReadableQuadEdge.wrap(e7), ReadableQuadEdge.wrap(e4), ReadableQuadEdge.wrap(e41.sym()));
    assertVertex(ReadableQuadEdge.wrap(e41), ReadableQuadEdge.wrap(e2), ReadableQuadEdge.wrap(e1.sym()));
    assertVertex(ReadableQuadEdge.wrap(e3), ReadableQuadEdge.wrap(e2.sym()), ReadableQuadEdge.wrap(e4.sym()), ReadableQuadEdge.wrap(e6));
    ReadableTriangulation triangulation = ReadableTriangulation.wrap(quadEdgeSubdivision);
    ContourBuilder contourBuilder = new ContourBuilder(triangulation);
    Geometry geometry = contourBuilder.computeIsoline(0.5, triangulation.getEdges());
    assertEquals("MULTIPOLYGON (((1 0, 0.5 -0.5, 1 -2, 1.5 -0.5, 1 0)))", geometry.toString());
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) Vertex(org.locationtech.jts.triangulate.quadedge.Vertex) QuadEdge(org.locationtech.jts.triangulate.quadedge.QuadEdge) Envelope(org.locationtech.jts.geom.Envelope) QuadEdgeSubdivision(org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision) Test(org.junit.jupiter.api.Test)

Example 4 with QuadEdgeSubdivision

use of org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision in project graphhopper by graphhopper.

the class QuadEdgeSubdivisionTest method testJtsDelaunayTriangulator.

@Test
public void testJtsDelaunayTriangulator() {
    Vertex v1 = new Vertex(0.0, 0.0, 0.0);
    Vertex v2 = new Vertex(1.0, -1.0, 1.0);
    Vertex v3 = new Vertex(1.0, 1.0, 0.0);
    Vertex v4 = new Vertex(2.0, 0.0, 0.0);
    Vertex v5 = new Vertex(1.0, -3.0, 0.0);
    QuadEdgeSubdivision quadEdgeSubdivision = new QuadEdgeSubdivision(new Envelope(0.0, 2.0, -1.0, 1.0), 0.001);
    IncrementalDelaunayTriangulator triangulator = new IncrementalDelaunayTriangulator(quadEdgeSubdivision);
    triangulator.insertSite(v1);
    triangulator.insertSite(v2);
    triangulator.insertSite(v3);
    triangulator.insertSite(v4);
    triangulator.insertSite(v5);
    assertEquals(5, quadEdgeSubdivision.getVertices(false).size());
}
Also used : Vertex(org.locationtech.jts.triangulate.quadedge.Vertex) IncrementalDelaunayTriangulator(org.locationtech.jts.triangulate.IncrementalDelaunayTriangulator) Envelope(org.locationtech.jts.geom.Envelope) QuadEdgeSubdivision(org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision) Test(org.junit.jupiter.api.Test)

Aggregations

QuadEdgeSubdivision (org.locationtech.jts.triangulate.quadedge.QuadEdgeSubdivision)4 Vertex (org.locationtech.jts.triangulate.quadedge.Vertex)4 NodeAccess (com.graphhopper.storage.NodeAccess)2 EdgeIteratorState (com.graphhopper.util.EdgeIteratorState)2 Test (org.junit.jupiter.api.Test)2 Envelope (org.locationtech.jts.geom.Envelope)2 Geometry (org.locationtech.jts.geom.Geometry)2 ConformingDelaunayTriangulator (org.locationtech.jts.triangulate.ConformingDelaunayTriangulator)2 ConstraintVertex (org.locationtech.jts.triangulate.ConstraintVertex)2 QuadEdge (org.locationtech.jts.triangulate.quadedge.QuadEdge)2 Stop (com.conveyal.gtfs.model.Stop)1 ContourBuilder (com.graphhopper.isochrone.algorithm.ContourBuilder)1 ReadableTriangulation (com.graphhopper.isochrone.algorithm.ReadableTriangulation)1 DefaultSnapFilter (com.graphhopper.routing.util.DefaultSnapFilter)1 FlagEncoder (com.graphhopper.routing.util.FlagEncoder)1 FastestWeighting (com.graphhopper.routing.weighting.FastestWeighting)1 Weighting (com.graphhopper.routing.weighting.Weighting)1 JsonFeature (com.graphhopper.util.JsonFeature)1 PointList (com.graphhopper.util.PointList)1 Instant (java.time.Instant)1