Search in sources :

Example 1 with LinearLocation

use of org.locationtech.jts.linearref.LinearLocation in project OpenTripPlanner by opentripplanner.

the class GeometryAndBlockProcessor method getHopGeometryViaShapeDistTraveled.

private LineString getHopGeometryViaShapeDistTraveled(FeedScopedId shapeId, StopTime st0, StopTime st1) {
    double startDistance = st0.getShapeDistTraveled();
    double endDistance = st1.getShapeDistTraveled();
    ShapeSegmentKey key = new ShapeSegmentKey(shapeId, startDistance, endDistance);
    LineString geometry = geometriesByShapeSegmentKey.get(key);
    if (geometry != null)
        return geometry;
    double[] distances = getDistanceForShapeId(shapeId);
    if (distances == null) {
        issueStore.add(new BogusShapeGeometry(shapeId));
        return null;
    } else {
        LinearLocation startIndex = getSegmentFraction(distances, startDistance);
        LinearLocation endIndex = getSegmentFraction(distances, endDistance);
        if (equals(startIndex, endIndex)) {
            // bogus shape_dist_traveled
            issueStore.add(new BogusShapeDistanceTraveled(st1));
            return createSimpleGeometry(st0.getStop(), st1.getStop());
        }
        LineString line = getLineStringForShapeId(shapeId);
        LocationIndexedLine lol = new LocationIndexedLine(line);
        geometry = getSegmentGeometry(shapeId, lol, startIndex, endIndex, startDistance, endDistance, st0, st1);
        return geometry;
    }
}
Also used : LineString(org.locationtech.jts.geom.LineString) BogusShapeGeometry(org.opentripplanner.graph_builder.issues.BogusShapeGeometry) LinearLocation(org.locationtech.jts.linearref.LinearLocation) LocationIndexedLine(org.locationtech.jts.linearref.LocationIndexedLine) BogusShapeDistanceTraveled(org.opentripplanner.graph_builder.issues.BogusShapeDistanceTraveled)

Example 2 with LinearLocation

use of org.locationtech.jts.linearref.LinearLocation in project OpenTripPlanner by opentripplanner.

the class GeometryAndBlockProcessor method createGeometry.

/**
 * Creates a set of geometries for a single trip, considering the GTFS shapes.txt,
 * The geometry is broken down into one geometry per inter-stop segment ("hop"). We also need a shape for the entire
 * trip and tripPattern, but given the complexity of the existing code for generating hop geometries, we will create
 * the full-trip geometry by simply concatenating the hop geometries.
 *
 * This geometry will in fact be used for an entire set of trips in a trip pattern. Technically one of the trips
 * with exactly the same sequence of stops could follow a different route on the streets, but that's very uncommon.
 */
private LineString[] createGeometry(FeedScopedId shapeId, List<StopTime> stopTimes) {
    if (hasShapeDist(shapeId, stopTimes)) {
        // this trip has shape_dist in stop_times
        return getHopGeometriesViaShapeDistTravelled(stopTimes, shapeId);
    }
    LineString shapeLineString = getLineStringForShapeId(shapeId);
    if (shapeLineString == null) {
        // create straight line segments between stops for each hop
        return createStraightLineHopeGeometries(stopTimes, shapeId);
    }
    List<LinearLocation> locations = getLinearLocations(stopTimes, shapeLineString);
    if (locations == null) {
        // linking, even though theoretically we could do better.
        return createStraightLineHopeGeometries(stopTimes, shapeId);
    }
    return getGeometriesByShape(stopTimes, shapeId, shapeLineString, locations);
}
Also used : LineString(org.locationtech.jts.geom.LineString) LinearLocation(org.locationtech.jts.linearref.LinearLocation)

Example 3 with LinearLocation

use of org.locationtech.jts.linearref.LinearLocation in project OpenTripPlanner by opentripplanner.

the class StreetMatcher method match.

@SuppressWarnings("unchecked")
public List<Edge> match(Geometry routeGeometry) {
    routeGeometry = removeDuplicatePoints(routeGeometry);
    if (routeGeometry == null)
        return null;
    routeGeometry = DouglasPeuckerSimplifier.simplify(routeGeometry, 0.00001);
    // initial state: start midway along a block.
    LocationIndexedLine indexedLine = new LocationIndexedLine(routeGeometry);
    LinearLocation startIndex = indexedLine.getStartIndex();
    Coordinate routeStartCoordinate = startIndex.getCoordinate(routeGeometry);
    Envelope envelope = new Envelope(routeStartCoordinate);
    double distanceThreshold = DISTANCE_THRESHOLD;
    envelope.expandBy(distanceThreshold);
    BinHeap<MatchState> states = new BinHeap<MatchState>();
    List<Edge> nearbyEdges = index.query(envelope);
    while (nearbyEdges.isEmpty()) {
        envelope.expandBy(distanceThreshold);
        distanceThreshold *= 2;
        nearbyEdges = index.query(envelope);
    }
    // compute initial states
    for (Edge initialEdge : nearbyEdges) {
        Geometry edgeGeometry = initialEdge.getGeometry();
        LocationIndexedLine indexedEdge = new LocationIndexedLine(edgeGeometry);
        LinearLocation initialLocation = indexedEdge.project(routeStartCoordinate);
        double error = MatchState.distance(initialLocation.getCoordinate(edgeGeometry), routeStartCoordinate);
        MidblockMatchState state = new MidblockMatchState(null, routeGeometry, initialEdge, startIndex, initialLocation, error, 0.01);
        // make sure all initial states are visited by inserting them at 0
        states.insert(state, 0);
    }
    // search for best-matching path
    int seen_count = 0, total = 0;
    HashSet<MatchState> seen = new HashSet<MatchState>();
    while (!states.empty()) {
        double k = states.peek_min_key();
        MatchState state = states.extract_min();
        if (++total % 50000 == 0) {
            log.debug("seen / total: " + seen_count + " / " + total);
        }
        if (seen.contains(state)) {
            ++seen_count;
            continue;
        } else {
            if (k != 0) {
                // but do not mark states as closed if we start at them
                seen.add(state);
            }
        }
        if (state instanceof EndMatchState) {
            return toEdgeList(state);
        }
        for (MatchState next : state.getNextStates()) {
            if (seen.contains(next)) {
                continue;
            }
            states.insert(next, next.getTotalError() - next.getDistanceAlongRoute());
        }
    }
    return null;
}
Also used : LocationIndexedLine(org.locationtech.jts.linearref.LocationIndexedLine) LinearLocation(org.locationtech.jts.linearref.LinearLocation) BinHeap(org.opentripplanner.common.pqueue.BinHeap) Envelope(org.locationtech.jts.geom.Envelope) Geometry(org.locationtech.jts.geom.Geometry) Coordinate(org.locationtech.jts.geom.Coordinate) StreetEdge(org.opentripplanner.routing.edgetype.StreetEdge) Edge(org.opentripplanner.routing.graph.Edge) HashSet(java.util.HashSet)

Example 4 with LinearLocation

use of org.locationtech.jts.linearref.LinearLocation in project OpenTripPlanner by opentripplanner.

the class MidblockMatchState method getNextStates.

@Override
public List<MatchState> getNextStates() {
    ArrayList<MatchState> nextStates = new ArrayList<MatchState>();
    if (routeIndex.getSegmentIndex() == routeGeometry.getNumPoints() - 1) {
        // this has either hit the end, or gone off the end. It's not real clear which.
        // for now, let's assume it means that the ending is somewhere along this edge,
        // so we return an end state
        Coordinate pt = routeIndex.getCoordinate(routeGeometry);
        double error = distance(pt, edgeIndex.getCoordinate(edgeGeometry));
        nextStates.add(new EndMatchState(this, error, 0));
        return nextStates;
    }
    LinearIterator it = new LinearIterator(routeGeometry, routeIndex);
    if (it.hasNext()) {
        it.next();
        LinearLocation routeSuccessor = it.getLocation();
        // now we want to see where this new point is in terms of the edge's geometry
        Coordinate newRouteCoord = routeSuccessor.getCoordinate(routeGeometry);
        LinearLocation newEdgeIndex = indexedEdge.project(newRouteCoord);
        Coordinate edgeCoord = newEdgeIndex.getCoordinate(edgeGeometry);
        if (newEdgeIndex.compareTo(edgeIndex) <= 0) {
            /* this should not require the try/catch, but there is a bug in JTS */
            try {
                LinearLocation projected2 = indexedEdge.indexOfAfter(edgeCoord, edgeIndex);
                // another bug in JTS
                if (Double.isNaN(projected2.getSegmentFraction())) {
                    // we are probably moving backwards
                    return Collections.emptyList();
                } else {
                    newEdgeIndex = projected2;
                    if (newEdgeIndex.equals(edgeIndex)) {
                        return Collections.emptyList();
                    }
                }
                edgeCoord = newEdgeIndex.getCoordinate(edgeGeometry);
            } catch (AssertionFailedException e) {
                // we are not making progress, so just return an empty list
                return Collections.emptyList();
            }
        }
        if (newEdgeIndex.getSegmentIndex() == edgeGeometry.getNumPoints() - 1) {
            // we might choose to continue from the end of the edge and a point mid-way
            // along this route segment
            // find nearest point that makes progress along the route
            Vertex toVertex = edge.getToVertex();
            Coordinate endCoord = toVertex.getCoordinate();
            LocationIndexedLine indexedRoute = new LocationIndexedLine(routeGeometry);
            // FIXME: it would be better to do this project/indexOfAfter in one step
            // as the two-step version could snap to a bad place and be unable to escape.
            LinearLocation routeProjectedEndIndex = indexedRoute.project(endCoord);
            Coordinate routeProjectedEndCoord = routeProjectedEndIndex.getCoordinate(routeGeometry);
            if (routeProjectedEndIndex.compareTo(routeIndex) <= 0) {
                try {
                    routeProjectedEndIndex = indexedRoute.indexOfAfter(routeProjectedEndCoord, routeIndex);
                    if (Double.isNaN(routeProjectedEndIndex.getSegmentFraction())) {
                        // can't go forward
                        // this is bad, but not terrible
                        routeProjectedEndIndex = routeIndex;
                    // since we are advancing along the edge
                    }
                } catch (AssertionFailedException e) {
                    routeProjectedEndIndex = routeIndex;
                }
                routeProjectedEndCoord = routeProjectedEndIndex.getCoordinate(routeGeometry);
            }
            double positionError = distance(routeProjectedEndCoord, endCoord);
            double travelAlongRoute = distanceAlongGeometry(routeGeometry, routeIndex, routeProjectedEndIndex);
            double travelAlongEdge = distanceAlongGeometry(edgeGeometry, edgeIndex, newEdgeIndex);
            double travelError = Math.abs(travelAlongEdge - travelAlongRoute);
            double error = positionError + travelError;
            if (error > MAX_ERROR) {
                // totally wrong
                return nextStates;
            }
            for (Edge e : getOutgoingMatchableEdges(toVertex)) {
                double cost = error + NEW_SEGMENT_PENALTY;
                if (!carsCanTraverse(e)) {
                    cost += NO_TRAVERSE_PENALTY;
                }
                MatchState nextState = new MidblockMatchState(this, routeGeometry, e, routeProjectedEndIndex, new LinearLocation(), cost, travelAlongRoute);
                nextStates.add(nextState);
            }
        } else {
            double travelAlongEdge = distanceAlongGeometry(edgeGeometry, edgeIndex, newEdgeIndex);
            double travelAlongRoute = distanceAlongGeometry(routeGeometry, routeIndex, routeSuccessor);
            double travelError = Math.abs(travelAlongRoute - travelAlongEdge);
            double positionError = distance(edgeCoord, newRouteCoord);
            double error = travelError + positionError;
            MatchState nextState = new MidblockMatchState(this, routeGeometry, edge, routeSuccessor, newEdgeIndex, error, travelAlongRoute);
            nextStates.add(nextState);
            // it's also possible that, although we have not yet reached the end of this edge,
            // we are going to turn, because the route turns earlier than the edge. In that
            // case, we jump to the corner, and our error is the distance from the route point
            // and the corner
            Vertex toVertex = edge.getToVertex();
            double travelAlongOldEdge = distanceAlongGeometry(edgeGeometry, edgeIndex, null);
            for (Edge e : getOutgoingMatchableEdges(toVertex)) {
                Geometry newEdgeGeometry = e.getGeometry();
                LocationIndexedLine newIndexedEdge = new LocationIndexedLine(newEdgeGeometry);
                newEdgeIndex = newIndexedEdge.project(newRouteCoord);
                Coordinate newEdgeCoord = newEdgeIndex.getCoordinate(newEdgeGeometry);
                positionError = distance(newEdgeCoord, newRouteCoord);
                travelAlongEdge = travelAlongOldEdge + distanceAlongGeometry(newEdgeGeometry, new LinearLocation(), newEdgeIndex);
                travelError = Math.abs(travelAlongRoute - travelAlongEdge);
                error = travelError + positionError;
                if (error > MAX_ERROR) {
                    // totally wrong
                    return nextStates;
                }
                double cost = error + NEW_SEGMENT_PENALTY;
                if (!carsCanTraverse(e)) {
                    cost += NO_TRAVERSE_PENALTY;
                }
                nextState = new MidblockMatchState(this, routeGeometry, e, routeSuccessor, new LinearLocation(), cost, travelAlongRoute);
                nextStates.add(nextState);
            }
        }
        return nextStates;
    } else {
        Coordinate routeCoord = routeIndex.getCoordinate(routeGeometry);
        LinearLocation projected = indexedEdge.project(routeCoord);
        double locationError = distance(projected.getCoordinate(edgeGeometry), routeCoord);
        MatchState end = new EndMatchState(this, locationError, 0);
        return Arrays.asList(end);
    }
}
Also used : Vertex(org.opentripplanner.routing.graph.Vertex) LinearLocation(org.locationtech.jts.linearref.LinearLocation) LocationIndexedLine(org.locationtech.jts.linearref.LocationIndexedLine) ArrayList(java.util.ArrayList) Geometry(org.locationtech.jts.geom.Geometry) Coordinate(org.locationtech.jts.geom.Coordinate) AssertionFailedException(org.locationtech.jts.util.AssertionFailedException) Edge(org.opentripplanner.routing.graph.Edge)

Example 5 with LinearLocation

use of org.locationtech.jts.linearref.LinearLocation in project OpenTripPlanner by opentripplanner.

the class GeometryAndBlockProcessor method getSegmentFraction.

private LinearLocation getSegmentFraction(double[] distances, double distance) {
    int index = Arrays.binarySearch(distances, distance);
    if (index < 0)
        index = -(index + 1);
    if (index == 0)
        return new LinearLocation(0, 0.0);
    if (index == distances.length)
        return new LinearLocation(distances.length, 0.0);
    double prevDistance = distances[index - 1];
    if (prevDistance == distances[index]) {
        return new LinearLocation(index - 1, 1.0);
    }
    double indexPart = (distance - distances[index - 1]) / (distances[index] - prevDistance);
    return new LinearLocation(index - 1, indexPart);
}
Also used : LinearLocation(org.locationtech.jts.linearref.LinearLocation) ShapePoint(org.opentripplanner.model.ShapePoint)

Aggregations

LinearLocation (org.locationtech.jts.linearref.LinearLocation)15 Coordinate (org.locationtech.jts.geom.Coordinate)7 LocationIndexedLine (org.locationtech.jts.linearref.LocationIndexedLine)7 LineString (org.locationtech.jts.geom.LineString)6 Edge (org.opentripplanner.routing.graph.Edge)6 HashSet (java.util.HashSet)5 StreetEdge (org.opentripplanner.routing.edgetype.StreetEdge)5 Test (org.junit.Test)4 RoutingRequest (org.opentripplanner.routing.api.request.RoutingRequest)4 TemporaryStreetLocation (org.opentripplanner.routing.location.TemporaryStreetLocation)4 NonLocalizedString (org.opentripplanner.util.NonLocalizedString)4 GraphPath (org.opentripplanner.routing.spt.GraphPath)3 ShortestPathTree (org.opentripplanner.routing.spt.ShortestPathTree)3 CoordinateSequence (org.locationtech.jts.geom.CoordinateSequence)2 Geometry (org.locationtech.jts.geom.Geometry)2 P2 (org.opentripplanner.common.model.P2)2 ShapePoint (org.opentripplanner.model.ShapePoint)2 State (org.opentripplanner.routing.core.State)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1