use of org.opentripplanner.routing.graph.Vertex in project OpenTripPlanner by opentripplanner.
the class SimpleIsochrone method makePointFeatures.
private SimpleFeatureCollection makePointFeatures() throws Exception {
Map<Vertex, Double> points = makePoints();
/* Stage the point features in memory */
DefaultFeatureCollection featureCollection = new DefaultFeatureCollection(null, pointSchema);
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(pointSchema);
GeometryFactory gf = new GeometryFactory();
for (Map.Entry<Vertex, Double> entry : points.entrySet()) {
Vertex vertex = entry.getKey();
Double travelTime = entry.getValue();
fbuilder.add(gf.createPoint(vertex.getCoordinate()));
fbuilder.add(travelTime);
featureCollection.add(fbuilder.buildFeature(null));
}
return featureCollection;
}
use of org.opentripplanner.routing.graph.Vertex in project OpenTripPlanner by opentripplanner.
the class SimpleIsochrone method makePoints.
/**
* @return a map from each vertex to minimum travel time over the course of the day.
*/
private Map<Vertex, Double> makePoints() throws Exception {
rangeCheckParameters();
request = buildRequest();
Router router = otpServer.getRouter(routerId);
Graph graph = router.graph;
// double speed = request.getWalkSpeed();
Coordinate originCoord = request.from.getCoordinate();
if (originCoord == null)
return null;
List<TransitStop> stops = graph.streetIndex.getNearbyTransitStops(originCoord, radiusMeters);
if (stops.isEmpty()) {
LOG.error("No stops found within {} meters.", radiusMeters);
return null;
}
if (shpName == null)
shpName = stops.get(0).getName().split(" ")[0];
StreetVertex origin = new IntersectionVertex(graph, "iso_temp", originCoord.x, originCoord.y);
for (TransitStop stop : stops) {
new StreetTransitLink(origin, stop, false);
LOG.debug("linked to stop {}", stop.getName());
}
request.setRoutingContext(graph, origin, null);
/* Make one request every M minutes over H hours */
int nRequests = (requestTimespanHours * 60) / requestSpacingMinutes;
request.clampInitialWait = (requestSpacingMinutes * 60);
Date date = request.getDateTime();
MinMap<Vertex, Double> points = new MinMap<Vertex, Double>();
for (int r = 0; r < nRequests; r++) {
request.dateTime = date.getTime() / 1000 + r * requestSpacingMinutes * 60;
LOG.debug("date: {} {}", new Date(request.dateTime), request.dateTime);
ShortestPathTree spt = sptService.getShortestPathTree(request, 10);
/* This could even be a good use for a generic SPT merging function */
for (State s : spt.getAllStates()) {
if (stopsOnly && !(s.getVertex() instanceof TransitStop))
continue;
points.putMin(s.getVertex(), (double) (s.getActiveTime()));
}
}
graph.removeVertexAndEdges(origin);
return points;
}
use of org.opentripplanner.routing.graph.Vertex 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);
}
}
use of org.opentripplanner.routing.graph.Vertex in project OpenTripPlanner by opentripplanner.
the class GraphPathToTripPlanConverter method generatePlan.
/**
* Generates a TripPlan from a set of paths
*/
public static TripPlan generatePlan(List<GraphPath> paths, RoutingRequest request) {
Locale requestedLocale = request.locale;
GraphPath exemplar = paths.get(0);
Vertex tripStartVertex = exemplar.getStartVertex();
Vertex tripEndVertex = exemplar.getEndVertex();
String startName = tripStartVertex.getName(requestedLocale);
String endName = tripEndVertex.getName(requestedLocale);
// Use vertex labels if they don't have names
if (startName == null) {
startName = tripStartVertex.getLabel();
}
if (endName == null) {
endName = tripEndVertex.getLabel();
}
Place from = new Place(tripStartVertex.getX(), tripStartVertex.getY(), startName);
Place to = new Place(tripEndVertex.getX(), tripEndVertex.getY(), endName);
from.orig = request.from.name;
to.orig = request.to.name;
TripPlan plan = new TripPlan(from, to, request.getDateTime());
// Convert GraphPaths to Itineraries, keeping track of the best non-transit (e.g. walk/bike-only) option time
long bestNonTransitTime = Long.MAX_VALUE;
List<Itinerary> itineraries = new LinkedList<>();
for (GraphPath path : paths) {
Itinerary itinerary = generateItinerary(path, request.showIntermediateStops, request.disableAlertFiltering, requestedLocale);
itinerary = adjustItinerary(request, itinerary);
if (itinerary.transitTime == 0 && itinerary.walkTime < bestNonTransitTime) {
bestNonTransitTime = itinerary.walkTime;
}
itineraries.add(itinerary);
}
// Filter and add itineraries to plan
for (Itinerary itinerary : itineraries) {
// do not include in plan
if (itinerary.transitTime > 0 && itinerary.walkTime > bestNonTransitTime)
continue;
plan.addItinerary(itinerary);
}
if (plan != null) {
for (Itinerary i : plan.itinerary) {
/* Communicate the fact that the only way we were able to get a response was by removing a slope limit. */
i.tooSloped = request.rctx.slopeRestrictionRemoved;
/* fix up from/to on first/last legs */
if (i.legs.size() == 0) {
LOG.warn("itinerary has no legs");
continue;
}
Leg firstLeg = i.legs.get(0);
firstLeg.from.orig = plan.from.orig;
Leg lastLeg = i.legs.get(i.legs.size() - 1);
lastLeg.to.orig = plan.to.orig;
}
}
request.rctx.debugOutput.finishedRendering();
return plan;
}
use of org.opentripplanner.routing.graph.Vertex in project OpenTripPlanner by opentripplanner.
the class GraphPathToTripPlanConverter method generateWalkSteps.
/**
* Converts a list of street edges to a list of turn-by-turn directions.
*
* @param previous a non-transit leg that immediately precedes this one (bike-walking, say), or null
*
* @return
*/
public static List<WalkStep> generateWalkSteps(Graph graph, State[] states, WalkStep previous, Locale requestedLocale) {
List<WalkStep> steps = new ArrayList<WalkStep>();
WalkStep step = null;
// distance used for appending elevation profiles
double lastAngle = 0, distance = 0;
// track whether we are in a roundabout, and if so the exit number
int roundaboutExit = 0;
String roundaboutPreviousStreet = null;
State onBikeRentalState = null, offBikeRentalState = null;
// Check if this leg is a SimpleTransfer; if so, rebuild state array based on stored transfer edges
if (states.length == 2 && states[1].getBackEdge() instanceof SimpleTransfer) {
SimpleTransfer transferEdge = ((SimpleTransfer) states[1].getBackEdge());
List<Edge> transferEdges = transferEdge.getEdges();
if (transferEdges != null) {
// Create a new initial state. Some parameters may have change along the way, copy them from the first state
StateEditor se = new StateEditor(states[0].getOptions(), transferEdges.get(0).getFromVertex());
se.setNonTransitOptionsFromState(states[0]);
State s = se.makeState();
ArrayList<State> transferStates = new ArrayList<>();
transferStates.add(s);
for (Edge e : transferEdges) {
s = e.traverse(s);
transferStates.add(s);
}
states = transferStates.toArray(new State[transferStates.size()]);
}
}
for (int i = 0; i < states.length - 1; i++) {
State backState = states[i];
State forwardState = states[i + 1];
Edge edge = forwardState.getBackEdge();
if (edge instanceof RentABikeOnEdge)
onBikeRentalState = forwardState;
if (edge instanceof RentABikeOffEdge)
offBikeRentalState = forwardState;
boolean createdNewStep = false, disableZagRemovalForThisStep = false;
if (edge instanceof FreeEdge) {
continue;
}
if (forwardState.getBackMode() == null || !forwardState.getBackMode().isOnStreetNonTransit()) {
// ignore STLs and the like
continue;
}
Geometry geom = edge.getGeometry();
if (geom == null) {
continue;
}
// before or will come after
if (edge instanceof ElevatorAlightEdge) {
// don't care what came before or comes after
step = createWalkStep(graph, forwardState, requestedLocale);
createdNewStep = true;
disableZagRemovalForThisStep = true;
// tell the user where to get off the elevator using the exit notation, so the
// i18n interface will say 'Elevator to <exit>'
// what happens is that the webapp sees name == null and ignores that, and it sees
// exit != null and uses to <exit>
// the floor name is the AlightEdge name
// reset to avoid confusion with 'Elevator on floor 1 to floor 1'
step.streetName = ((ElevatorAlightEdge) edge).getName(requestedLocale);
step.relativeDirection = RelativeDirection.ELEVATOR;
steps.add(step);
continue;
}
String streetName = edge.getName(requestedLocale);
int idx = streetName.indexOf('(');
String streetNameNoParens;
if (idx > 0)
streetNameNoParens = streetName.substring(0, idx - 1);
else
streetNameNoParens = streetName;
if (step == null) {
// first step
step = createWalkStep(graph, forwardState, requestedLocale);
createdNewStep = true;
steps.add(step);
double thisAngle = DirectionUtils.getFirstAngle(geom);
if (previous == null) {
step.setAbsoluteDirection(thisAngle);
step.relativeDirection = RelativeDirection.DEPART;
} else {
step.setDirections(previous.angle, thisAngle, false);
}
// new step, set distance to length of first edge
distance = edge.getDistance();
} else if (((step.streetName != null && !step.streetNameNoParens().equals(streetNameNoParens)) && (!step.bogusName || !edge.hasBogusName())) || // went on to or off of a roundabout
edge.isRoundabout() != (roundaboutExit > 0) || isLink(edge) && !isLink(backState.getBackEdge())) {
// Street name has changed, or we've gone on to or off of a roundabout.
if (roundaboutExit > 0) {
// if we were just on a roundabout,
// make note of which exit was taken in the existing step
// ordinal numbers from
step.exit = Integer.toString(roundaboutExit);
if (streetNameNoParens.equals(roundaboutPreviousStreet)) {
step.stayOn = true;
}
roundaboutExit = 0;
}
/* start a new step */
step = createWalkStep(graph, forwardState, requestedLocale);
createdNewStep = true;
steps.add(step);
if (edge.isRoundabout()) {
// indicate that we are now on a roundabout
// and use one-based exit numbering
roundaboutExit = 1;
roundaboutPreviousStreet = backState.getBackEdge().getName(requestedLocale);
idx = roundaboutPreviousStreet.indexOf('(');
if (idx > 0)
roundaboutPreviousStreet = roundaboutPreviousStreet.substring(0, idx - 1);
}
double thisAngle = DirectionUtils.getFirstAngle(geom);
step.setDirections(lastAngle, thisAngle, edge.isRoundabout());
// new step, set distance to length of first edge
distance = edge.getDistance();
} else {
/* street name has not changed */
double thisAngle = DirectionUtils.getFirstAngle(geom);
RelativeDirection direction = WalkStep.getRelativeDirection(lastAngle, thisAngle, edge.isRoundabout());
boolean optionsBefore = backState.multipleOptionsBefore();
if (edge.isRoundabout()) {
// we are on a roundabout, and have already traversed at least one edge of it.
if (optionsBefore) {
// increment exit count if we passed one.
roundaboutExit += 1;
}
}
if (edge.isRoundabout() || direction == RelativeDirection.CONTINUE) {
// we are continuing almost straight, or continuing along a roundabout.
// just append elevation info onto the existing step.
} else {
// we are not on a roundabout, and not continuing straight through.
// figure out if there were other plausible turn options at the last
// intersection
// to see if we should generate a "left to continue" instruction.
boolean shouldGenerateContinue = false;
if (edge instanceof StreetEdge) {
// the next edges will be PlainStreetEdges, we hope
double angleDiff = getAbsoluteAngleDiff(thisAngle, lastAngle);
for (Edge alternative : backState.getVertex().getOutgoingStreetEdges()) {
if (alternative.getName(requestedLocale).equals(streetName)) {
// are usually caused by street splits
continue;
}
double altAngle = DirectionUtils.getFirstAngle(alternative.getGeometry());
double altAngleDiff = getAbsoluteAngleDiff(altAngle, lastAngle);
if (angleDiff > Math.PI / 4 || altAngleDiff - angleDiff < Math.PI / 16) {
shouldGenerateContinue = true;
break;
}
}
} else {
double angleDiff = getAbsoluteAngleDiff(lastAngle, thisAngle);
// FIXME: this code might be wrong with the removal of the edge-based graph
State twoStatesBack = backState.getBackState();
Vertex backVertex = twoStatesBack.getVertex();
for (Edge alternative : backVertex.getOutgoingStreetEdges()) {
List<Edge> alternatives = alternative.getToVertex().getOutgoingStreetEdges();
if (alternatives.size() == 0) {
// this is not an alternative
continue;
}
alternative = alternatives.get(0);
if (alternative.getName(requestedLocale).equals(streetName)) {
// are usually caused by street splits
continue;
}
double altAngle = DirectionUtils.getFirstAngle(alternative.getGeometry());
double altAngleDiff = getAbsoluteAngleDiff(altAngle, lastAngle);
if (angleDiff > Math.PI / 4 || altAngleDiff - angleDiff < Math.PI / 16) {
shouldGenerateContinue = true;
break;
}
}
}
if (shouldGenerateContinue) {
// turn to stay on same-named street
step = createWalkStep(graph, forwardState, requestedLocale);
createdNewStep = true;
steps.add(step);
step.setDirections(lastAngle, thisAngle, false);
step.stayOn = true;
// new step, set distance to length of first edge
distance = edge.getDistance();
}
}
}
State exitState = backState;
Edge exitEdge = exitState.getBackEdge();
while (exitEdge instanceof FreeEdge) {
exitState = exitState.getBackState();
exitEdge = exitState.getBackEdge();
}
if (exitState.getVertex() instanceof ExitVertex) {
step.exit = ((ExitVertex) exitState.getVertex()).getExitName();
}
if (createdNewStep && !disableZagRemovalForThisStep && forwardState.getBackMode() == backState.getBackMode()) {
// check last three steps for zag
int last = steps.size() - 1;
if (last >= 2) {
WalkStep threeBack = steps.get(last - 2);
WalkStep twoBack = steps.get(last - 1);
WalkStep lastStep = steps.get(last);
if (twoBack.distance < MAX_ZAG_DISTANCE && lastStep.streetNameNoParens().equals(threeBack.streetNameNoParens())) {
if (((lastStep.relativeDirection == RelativeDirection.RIGHT || lastStep.relativeDirection == RelativeDirection.HARD_RIGHT) && (twoBack.relativeDirection == RelativeDirection.RIGHT || twoBack.relativeDirection == RelativeDirection.HARD_RIGHT)) || ((lastStep.relativeDirection == RelativeDirection.LEFT || lastStep.relativeDirection == RelativeDirection.HARD_LEFT) && (twoBack.relativeDirection == RelativeDirection.LEFT || twoBack.relativeDirection == RelativeDirection.HARD_LEFT))) {
// in this case, we have two left turns or two right turns in quick
// succession; this is probably a U-turn.
steps.remove(last - 1);
lastStep.distance += twoBack.distance;
// A U-turn to the left, typical in the US.
if (lastStep.relativeDirection == RelativeDirection.LEFT || lastStep.relativeDirection == RelativeDirection.HARD_LEFT)
lastStep.relativeDirection = RelativeDirection.UTURN_LEFT;
else
lastStep.relativeDirection = RelativeDirection.UTURN_RIGHT;
// in this case, we're definitely staying on the same street
// (since it's zag removal, the street names are the same)
lastStep.stayOn = true;
} else {
// What is a zag? TODO write meaningful documentation for this.
// It appears to mean simplifying out several rapid turns in succession
// from the description.
// total hack to remove zags.
steps.remove(last);
steps.remove(last - 1);
step = threeBack;
step.distance += twoBack.distance;
distance += step.distance;
if (twoBack.elevation != null) {
if (step.elevation == null) {
step.elevation = twoBack.elevation;
} else {
for (P2<Double> d : twoBack.elevation) {
step.elevation.add(new P2<Double>(d.first + step.distance, d.second));
}
}
}
}
}
}
} else {
if (!createdNewStep && step.elevation != null) {
List<P2<Double>> s = encodeElevationProfile(edge, distance, backState.getOptions().geoidElevation ? -graph.ellipsoidToGeoidDifference : 0);
if (step.elevation != null && step.elevation.size() > 0) {
step.elevation.addAll(s);
} else {
step.elevation = s;
}
}
distance += edge.getDistance();
}
// increment the total length for this step
step.distance += edge.getDistance();
step.addAlerts(graph.streetNotesService.getNotes(forwardState), requestedLocale);
lastAngle = DirectionUtils.getLastAngle(geom);
step.edges.add(edge);
}
// add bike rental information if applicable
if (onBikeRentalState != null && !steps.isEmpty()) {
steps.get(steps.size() - 1).bikeRentalOnStation = new BikeRentalStationInfo((BikeRentalStationVertex) onBikeRentalState.getBackEdge().getToVertex());
}
if (offBikeRentalState != null && !steps.isEmpty()) {
steps.get(0).bikeRentalOffStation = new BikeRentalStationInfo((BikeRentalStationVertex) offBikeRentalState.getBackEdge().getFromVertex());
}
return steps;
}
Aggregations