org.opentripplanner.profile.StreetSegment Maven / Gradle / Ivy
package org.opentripplanner.profile;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.google.common.collect.Lists;
import org.locationtech.jts.geom.LineString;
import org.opentripplanner.api.model.Itinerary;
import org.opentripplanner.api.model.Leg;
import org.opentripplanner.api.model.WalkStep;
import org.opentripplanner.api.parameter.QualifiedMode;
import org.opentripplanner.api.resource.CoordinateArrayListSequence;
import org.opentripplanner.api.resource.GraphPathToTripPlanConverter;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.error.TrivialPathException;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.spt.GraphPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/**
* A response object describing a non-transit part of an Option. This is either an access/egress leg of a transit
* trip, or a direct path to the destination that does not use transit.
*/
public class StreetSegment {
private static final Logger LOG = LoggerFactory.getLogger(StreetSegment.class);
@JsonSerialize(using = ToStringSerializer.class) // as a string (e.g. "BICYCLE_RENT" instead of a nested object)
public QualifiedMode mode;
public int time;
public List streetEdges = Lists.newArrayList();
/**
* Build the walksteps from the final State of a path.
* The path may contain more than one leg, because you may need to walk the bike.
* Therefore accumulate the geometries into one long polyline, and accumulate the walksteps.
*/
public StreetSegment (State state) {
GraphPath path = new GraphPath(state, false);
CoordinateArrayListSequence coordinates = new CoordinateArrayListSequence();
for (Edge edge : path.edges) {
LineString geometry = edge.getGeometry();
if (geometry != null) {
if (coordinates.size() == 0) {
coordinates.extend(geometry.getCoordinates());
} else {
coordinates.extend(geometry.getCoordinates(), 1); // Avoid duplications
}
}
}
//TODO: localize
try {
Itinerary itin = GraphPathToTripPlanConverter.generateItinerary(path, false, true, new Locale("en"));
for (Leg leg : itin.legs) {
// populate the streetEdges array
for (WalkStep walkStep : leg.walkSteps) {
int i = 0;
// TODO this initialization logic seems like it should be in the walkStep constructor,
// or walkstep and edgeInfo should be merged. We are also iterating over the edges twice (see above)
// to build up the geometry separately.
for (Edge edge : walkStep.edges) {
StreetEdgeInfo edgeInfo = new StreetEdgeInfo(edge);
if (i == 0) {
edgeInfo.mode = walkStep.newMode;
edgeInfo.streetName = walkStep.streetName;
edgeInfo.absoluteDirection = walkStep.absoluteDirection;
edgeInfo.relativeDirection = walkStep.relativeDirection;
edgeInfo.stayOn = walkStep.stayOn;
edgeInfo.area = walkStep.area;
edgeInfo.bogusName = walkStep.bogusName;
edgeInfo.bikeRentalOffStation = walkStep.bikeRentalOffStation;
}
if (i == walkStep.edges.size() - 1) {
edgeInfo.bikeRentalOnStation = walkStep.bikeRentalOnStation;
}
streetEdges.add(edgeInfo);
i++;
}
}
}
} catch (TrivialPathException e) {
// a trivial path exception implies that this path contains no edges (i.e. it starts and ends at the same vertex).
// this is possible when the origin and destination are coincident.
LOG.warn("Path from {} to {} was trivial, if these points are coincident this is not unexpected; otherwise, you might want to look into it.",
path.states.get(0).getVertex(),
path.states.get(path.states.size() - 1).getVertex());
}
time = (int) (state.getElapsedTimeSeconds());
}
/** A StreetSegment is very similar to a StopAtDistance but it's a response object so the State has to be rendered into walksteps. */
public StreetSegment (StopAtDistance sd) {
this(sd.state);
mode = sd.qmode; // Intended mode is known more reliably in a StopAtDistance than from a State.
}
/** Make a collections of StreetSegments from a collection of StopAtDistance. */
public static List list(Collection sds) {
if (sds == null || sds.isEmpty()) return null;
List ret = Lists.newArrayList();
for (StopAtDistance sd : sds) {
ret.add(new StreetSegment(sd));
}
return ret;
}
}