use of org.opentripplanner.routing.location.StreetLocation in project OpenTripPlanner by opentripplanner.
the class SIsochrone method getIsochrone.
/**
* Calculates walksheds for a given location, based on time given to walk and the walk speed.
*
* Depending on the value for the "output" parameter (i.e. "POINTS", "SHED" or "EDGES"), a
* different type of GeoJSON geometry is returned. If a SHED is requested, then a ConcaveHull
* of the EDGES/roads is returned. If that fails, a ConvexHull will be returned.
* <p>
* The ConcaveHull parameter is set to 0.005 degrees. The offroad walkspeed is assumed to be
* 0.83333 m/sec (= 3km/h) until a road is hit.
* <p>
* Note that the set of EDGES/roads returned as well as POINTS returned may contain duplicates.
* If POINTS are requested, then not the end-points are returned at which the max time is
* reached, but instead all the graph nodes/crossings that are within the time limits.
* <p>
* In case there is no road near by within the given time, then a circle for the walktime limit
* is created and returned for the SHED parameter. Otherwise the edge with the direction
* towards the closest road. Note that the circle is calculated in Euclidian 2D coordinates,
* and distortions towards an ellipse will appear if it is transformed/projected to the user location.
* <p>
* An example request may look like this:
* localhost:8080/otp-rest-servlet/ws/iso?layers=traveltime&styles=mask&batch=true&fromPlace=51.040193121307176
* %2C-114.04471635818481&toPlace
* =51.09098935%2C-113.95179705&time=2012-06-06T08%3A00%3A00&mode=WALK&maxWalkDistance=10000&walkSpeed=1.38&walkTime=10.7&output=EDGES
* Though the first parameters (i) layer, (ii) styles and (iii) batch could be discarded.
*
* @param walkmins Maximum number of minutes to walk.
* @param output Can be set to "POINTS", "SHED" or "EDGES" to return different types of GeoJSON
* geometry. SHED returns a ConcaveHull or ConvexHull of the edges/roads. POINTS returns
* all graph nodes that are within the time limit.
* @return a JSON document containing geometries (either points, lineStrings or a polygon).
* @throws Exception
* @author sstein---geo.uzh.ch
*/
@GET
@Produces({ MediaType.APPLICATION_JSON })
public String getIsochrone(@QueryParam("walkTime") @DefaultValue("15") double walkmins, @QueryParam("output") @DefaultValue("POINTS") String output) throws Exception {
this.debugGeoms = new ArrayList();
this.tooFastTraversedEdgeGeoms = new ArrayList();
RoutingRequest sptRequestA = buildRequest();
String from = sptRequestA.from.toString();
int pos = 1;
float lat = 0;
float lon = 0;
for (String s : from.split(",")) {
if (s.isEmpty()) {
// no location
Response.status(Status.BAD_REQUEST).entity("no position").build();
return null;
}
try {
float num = Float.parseFloat(s);
if (pos == 1) {
lat = num;
}
if (pos == 2) {
lon = num;
}
} catch (Exception e) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("Could not parse position string to number. Require numerical lat & long coords.").build());
}
pos++;
}
GeometryFactory gf = new GeometryFactory();
Coordinate dropPoint = new Coordinate(lon, lat);
int walkInMin = (int) Math.floor(walkmins);
double walkInSec = walkmins * 60;
LOG.debug("given travel time: " + walkInMin + " mins + " + (walkInSec - (60 * walkInMin)) + " sec");
// graph dynamically by 1.3 * min -> this should save processing time
if (walkInMin < 30) {
sptRequestA.worstTime = sptRequestA.dateTime + (30 * 60);
} else {
sptRequestA.worstTime = sptRequestA.dateTime + Math.round(walkInMin * 1.3 * 60);
}
// set the switch-time for shed/area calculation, i.e. to decide if the hull is calculated based on points or on edges
TraverseModeSet modes = sptRequestA.modes;
LOG.debug("mode(s): " + modes);
if (modes.contains(TraverseMode.TRANSIT)) {
// 20min (use 20min for transit, since buses may not come all the time)
shedCalcMethodSwitchTimeInSec = 60 * 20;
} else if (modes.contains(TraverseMode.CAR)) {
// 10min
shedCalcMethodSwitchTimeInSec = 60 * 10;
} else if (modes.contains(TraverseMode.BICYCLE)) {
// 10min
shedCalcMethodSwitchTimeInSec = 60 * 10;
} else {
// 20min
shedCalcMethodSwitchTimeInSec = 60 * 20;
}
// set the maxUserSpeed, which is used later to check for u-type streets/crescents when calculating sub-edges;
// Note, that the car speed depends on the edge itself, so this value may be replaced later
this.usesCar = false;
int numberOfModes = modes.getModes().size();
if (numberOfModes == 1) {
if (modes.getWalk()) {
this.maxUserSpeed = sptRequestA.walkSpeed;
} else if (modes.getBicycle()) {
this.maxUserSpeed = sptRequestA.bikeSpeed;
} else if (modes.getCar()) {
this.maxUserSpeed = sptRequestA.carSpeed;
this.usesCar = true;
}
} else {
// for all other cases (multiple-modes)
// sstein: I thought I may set it to 36.111 m/sec = 130 km/h,
// but maybe it is better to assume walk speed for transit, i.e. treat it like if the
// person gets off the bus on the last crossing and walks the "last mile".
this.maxUserSpeed = sptRequestA.walkSpeed;
}
if (doSpeedTest) {
LOG.debug("performing angle and speed based test to detect u-shapes");
} else {
LOG.debug("performing only angle based test to detect u-shapes");
}
// TODO: OTP prefers to snap to car-roads/ways, which is not so nice, when walking,
// and a footpath is closer by. So far there is no option to switch that off
Router router = otpServer.getRouter(routerId);
// create the ShortestPathTree
try {
sptRequestA.setRoutingContext(router.graph);
} catch (Exception e) {
// if we get an exception here, and in particular a VertexNotFoundException,
// then it is likely that we chose a (transit) mode without having that (transit) modes data
LOG.debug("cannot set RoutingContext: " + e.toString());
LOG.debug("cannot set RoutingContext: setting mode=WALK");
// fall back to walk mode
sptRequestA.setMode(TraverseMode.WALK);
sptRequestA.setRoutingContext(router.graph);
}
ShortestPathTree sptA = new AStar().getShortestPathTree(sptRequestA);
StreetLocation origin = (StreetLocation) sptRequestA.rctx.fromVertex;
// remove inserted points
sptRequestA.cleanup();
// create a LineString for display
Coordinate[] pathToStreetCoords = new Coordinate[2];
pathToStreetCoords[0] = dropPoint;
pathToStreetCoords[1] = origin.getCoordinate();
LineString pathToStreet = gf.createLineString(pathToStreetCoords);
// get distance between origin and drop point for time correction
double distanceToRoad = SphericalDistanceLibrary.distance(origin.getY(), origin.getX(), dropPoint.y, dropPoint.x);
long offRoadTimeCorrection = (long) (distanceToRoad / this.offRoadWalkspeed);
//
// --- filter the states ---
//
Set<Coordinate> visitedCoords = new HashSet<Coordinate>();
ArrayList<Edge> allConnectingEdges = new ArrayList<Edge>();
Coordinate[] coords = null;
long maxTime = (long) walkInSec - offRoadTimeCorrection;
// if the initial walk is already to long, there is no need to parse...
if (maxTime <= 0) {
noRoadNearBy = true;
long timeToWalk = (long) walkInSec;
long timeBetweenStates = offRoadTimeCorrection;
long timeMissing = timeToWalk;
double fraction = (double) timeMissing / (double) timeBetweenStates;
pathToStreet = getSubLineString(pathToStreet, fraction);
LOG.debug("no street found within giving travel time (for off-road walkspeed: {} m/sec)", this.offRoadWalkspeed);
} else {
noRoadNearBy = false;
Map<ReversibleLineStringWrapper, Edge> connectingEdgesMap = Maps.newHashMap();
for (State state : sptA.getAllStates()) {
long et = state.getElapsedTimeSeconds();
if (et <= maxTime) {
// 250 points away (while 145 were finally displayed)
if (visitedCoords.contains(state.getVertex().getCoordinate())) {
continue;
} else {
visitedCoords.add(state.getVertex().getCoordinate());
}
// -- get all Edges needed later for the edge representation
// and to calculate an edge-based walkshed
// Note, it can happen that we get a null geometry here, e.g. for hop-edges!
Collection<Edge> vertexEdgesIn = state.getVertex().getIncoming();
for (Iterator<Edge> iterator = vertexEdgesIn.iterator(); iterator.hasNext(); ) {
Edge edge = (Edge) iterator.next();
Geometry edgeGeom = edge.getGeometry();
if (edgeGeom != null) {
// make sure we get only real edges
if (edgeGeom instanceof LineString) {
// allConnectingEdges.add(edge); // instead of this, use a map now, so we don't have similar edge many times
connectingEdgesMap.put(new ReversibleLineStringWrapper((LineString) edgeGeom), edge);
}
}
}
Collection<Edge> vertexEdgesOut = state.getVertex().getOutgoing();
for (Iterator<Edge> iterator = vertexEdgesOut.iterator(); iterator.hasNext(); ) {
Edge edge = (Edge) iterator.next();
Geometry edgeGeom = edge.getGeometry();
if (edgeGeom != null) {
if (edgeGeom instanceof LineString) {
// allConnectingEdges.add(edge); // instead of this, use a map now, so we don't similar edge many times
connectingEdgesMap.put(new ReversibleLineStringWrapper((LineString) edgeGeom), edge);
}
}
}
}
// end : if(et < maxTime)
}
// --
// points from list to array, for later
coords = new Coordinate[visitedCoords.size()];
int i = 0;
for (Coordinate c : visitedCoords) coords[i++] = c;
// connection edges from Map to List
allConnectingEdges.clear();
for (Edge tedge : connectingEdgesMap.values()) allConnectingEdges.add(tedge);
}
StringWriter sw = new StringWriter();
GeometryJSON geometryJSON = new GeometryJSON();
//
try {
if (output.equals(SIsochrone.RESULT_TYPE_POINTS)) {
// and return those points
if (noRoadNearBy) {
Geometry circleShape = createCirle(dropPoint, pathToStreet);
coords = circleShape.getCoordinates();
}
// -- the states/nodes with time elapsed <= X min.
LOG.debug("write multipoint geom with {} points", coords.length);
geometryJSON.write(gf.createMultiPoint(coords), sw);
LOG.debug("done");
} else if (output.equals(SIsochrone.RESULT_TYPE_SHED)) {
Geometry[] geomsArray = null;
// in case there was no road we create a circle
if (noRoadNearBy) {
Geometry circleShape = createCirle(dropPoint, pathToStreet);
geometryJSON.write(circleShape, sw);
} else {
if (maxTime > shedCalcMethodSwitchTimeInSec) {
// eg., walkshed > 20 min
// -- create a point-based walkshed
// less exact and should be used for large walksheds with many edges
LOG.debug("create point-based shed (not from edges)");
geomsArray = new Geometry[coords.length];
for (int j = 0; j < geomsArray.length; j++) {
geomsArray[j] = gf.createPoint(coords[j]);
}
} else {
// -- create an edge-based walkshed
// it is more exact and should be used for short walks
LOG.debug("create edge-based shed (not from points)");
Map<ReversibleLineStringWrapper, LineString> walkShedEdges = Maps.newHashMap();
// add the walk from the pushpin to closest street point
walkShedEdges.put(new ReversibleLineStringWrapper(pathToStreet), pathToStreet);
// get the edges and edge parts within time limits
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
for (LineString ls : withinTimeEdges) {
walkShedEdges.put(new ReversibleLineStringWrapper(ls), ls);
}
geomsArray = new Geometry[walkShedEdges.size()];
int k = 0;
for (LineString ls : walkShedEdges.values()) geomsArray[k++] = ls;
}
// end if-else: maxTime condition
GeometryCollection gc = gf.createGeometryCollection(geomsArray);
// create the concave hull, but in case it fails we just return the convex hull
Geometry outputHull = null;
LOG.debug("create concave hull from {} geoms with edge length limit of about {} m (distance on meridian)", geomsArray.length, concaveHullAlpha * 111132);
// (see wikipedia: http://en.wikipedia.org/wiki/Latitude#The_length_of_a_degree_of_latitude)
try {
ConcaveHull hull = new ConcaveHull(gc, concaveHullAlpha);
outputHull = hull.getConcaveHull();
} catch (Exception e) {
outputHull = gc.convexHull();
LOG.debug("Could not generate ConcaveHull for WalkShed, using ConvexHull instead.");
}
LOG.debug("write shed geom");
geometryJSON.write(outputHull, sw);
LOG.debug("done");
}
} else if (output.equals(SIsochrone.RESULT_TYPE_EDGES)) {
// in case there was no road we return only the suggested path to the street
if (noRoadNearBy) {
geometryJSON.write(pathToStreet, sw);
} else {
// -- if we would use only the edges from the paths to the origin we will miss
// some edges that will be never on the shortest path (e.g. loops/crescents).
// However, we can retrieve all edges by checking the times for each
// edge end-point
Map<ReversibleLineStringWrapper, LineString> walkShedEdges = Maps.newHashMap();
// add the walk from the pushpin to closest street point
walkShedEdges.put(new ReversibleLineStringWrapper(pathToStreet), pathToStreet);
// get the edges and edge parts within time limits
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
for (LineString ls : withinTimeEdges) {
walkShedEdges.put(new ReversibleLineStringWrapper(ls), ls);
}
Geometry mls = null;
LineString[] edges = new LineString[walkShedEdges.size()];
int k = 0;
for (LineString ls : walkShedEdges.values()) edges[k++] = ls;
LOG.debug("create multilinestring from {} geoms", edges.length);
mls = gf.createMultiLineString(edges);
LOG.debug("write geom");
geometryJSON.write(mls, sw);
LOG.debug("done");
}
} else if (output.equals("DEBUGEDGES")) {
// -- for debugging, i.e. display of detected u-shapes/crescents
ArrayList<LineString> withinTimeEdges = this.getLinesAndSubEdgesWithinMaxTime(maxTime, allConnectingEdges, sptA, angleLimitForUShapeDetection, distanceToleranceForUShapeDetection, maxUserSpeed, usesCar, doSpeedTest);
if (this.showTooFastEdgesAsDebugGeomsANDnotUShapes) {
LOG.debug("displaying edges that are traversed too fast");
this.debugGeoms = this.tooFastTraversedEdgeGeoms;
} else {
LOG.debug("displaying detected u-shaped roads/crescents");
}
LineString[] edges = new LineString[this.debugGeoms.size()];
int k = 0;
for (Iterator iterator = debugGeoms.iterator(); iterator.hasNext(); ) {
LineString ls = (LineString) iterator.next();
edges[k] = ls;
k++;
}
Geometry mls = gf.createMultiLineString(edges);
LOG.debug("write debug geom");
geometryJSON.write(mls, sw);
LOG.debug("done");
}
} catch (Exception e) {
LOG.error("Exception creating isochrone", e);
}
return sw.toString();
}
use of org.opentripplanner.routing.location.StreetLocation in project OpenTripPlanner by opentripplanner.
the class GraphPathToTripPlanConverterTest method buildPaths.
/**
* Build three GraphPath objects that can be used for testing for forward, backward and onboard.
* This method doesn't rely on any routing code.
* Leg 0: Walking towards the train station
* Leg 1: First train leg, interlined with leg 2
* Leg 2: Second train leg, interlined with leg 1
* Leg 3: Simple transfer from the train station to the ferry
* Leg 4: Ferry leg
* Leg 5: Walking towards the bike rental station
* Leg 6: Cycling on a rented bike
* Leg 7: Cycling on a rented bike, continued (to demonstrate a {@link LegSwitchingEdge})
* Leg 8: Leaving the bike rental station on foot
* @return An array containing the generated GraphPath objects: forward, then backward, onboard.
*/
private GraphPath[] buildPaths() {
// This set of requested traverse modes implies that bike rental is a possibility.
RoutingRequest options = new RoutingRequest("BICYCLE_RENT,TRANSIT");
String feedId = "FEED";
Graph graph = new Graph();
// Vertices for leg 0
ExitVertex v0 = new ExitVertex(graph, "Vertex 0", 0, 0, 0);
IntersectionVertex v2 = new IntersectionVertex(graph, "Vertex 2", 0, 0);
IntersectionVertex v4 = new IntersectionVertex(graph, "Vertex 4", 1, 1);
// Stops for legs 1, 2 and 4, plus initialization and storage in a list
Stop trainStopDepart = new Stop();
Stop trainStopDwell = new Stop();
Stop trainStopInterline = new Stop();
Stop trainStopArrive = new Stop();
Stop ferryStopDepart = new Stop();
Stop ferryStopArrive = new Stop();
trainStopDepart.setId(new AgencyAndId(feedId, "Depart"));
trainStopDepart.setName("Train stop depart");
trainStopDepart.setLon(1);
trainStopDepart.setLat(1);
trainStopDepart.setCode("Train depart code");
trainStopDepart.setPlatformCode("Train depart platform");
trainStopDepart.setZoneId("Train depart zone");
trainStopDwell.setId(new AgencyAndId(feedId, "Dwell"));
trainStopDwell.setName("Train stop dwell");
trainStopDwell.setLon(45);
trainStopDwell.setLat(23);
trainStopDwell.setCode("Train dwell code");
trainStopDwell.setPlatformCode("Train dwell platform");
trainStopDwell.setZoneId("Train dwell zone");
trainStopInterline.setId(new AgencyAndId(feedId, "Interline"));
trainStopInterline.setName("Train stop interline");
trainStopInterline.setLon(89);
trainStopInterline.setLat(45);
trainStopInterline.setCode("Train interline code");
trainStopInterline.setPlatformCode("Train interline platform");
trainStopInterline.setZoneId("Train interline zone");
trainStopArrive.setId(new AgencyAndId(feedId, "Arrive"));
trainStopArrive.setName("Train stop arrive");
trainStopArrive.setLon(133);
trainStopArrive.setLat(67);
trainStopArrive.setCode("Train arrive code");
trainStopArrive.setPlatformCode("Train arrive platform");
trainStopArrive.setZoneId("Train arrive zone");
ferryStopDepart.setId(new AgencyAndId(feedId, "Depart"));
ferryStopDepart.setName("Ferry stop depart");
ferryStopDepart.setLon(135);
ferryStopDepart.setLat(67);
ferryStopDepart.setCode("Ferry depart code");
ferryStopDepart.setPlatformCode("Ferry depart platform");
ferryStopDepart.setZoneId("Ferry depart zone");
ferryStopArrive.setId(new AgencyAndId(feedId, "Arrive"));
ferryStopArrive.setName("Ferry stop arrive");
ferryStopArrive.setLon(179);
ferryStopArrive.setLat(89);
ferryStopArrive.setCode("Ferry arrive code");
ferryStopArrive.setPlatformCode("Ferry arrive platform");
ferryStopArrive.setZoneId("Ferry arrive zone");
ArrayList<Stop> firstStops = new ArrayList<Stop>();
ArrayList<Stop> secondStops = new ArrayList<Stop>();
ArrayList<Stop> thirdStops = new ArrayList<Stop>();
firstStops.add(trainStopDepart);
firstStops.add(trainStopDwell);
firstStops.add(trainStopInterline);
secondStops.add(trainStopInterline);
secondStops.add(trainStopArrive);
thirdStops.add(ferryStopDepart);
thirdStops.add(ferryStopArrive);
// Agencies for legs 1, 2 and 4, plus initialization
Agency trainAgency = new Agency();
Agency ferryAgency = new Agency();
trainAgency.setId("Train");
trainAgency.setName("John Train");
trainAgency.setUrl("http://www.train.org/");
ferryAgency.setId("Ferry");
ferryAgency.setName("Brian Ferry");
ferryAgency.setUrl("http://www.ferry.org/");
// Routes for legs 1, 2 and 4, plus initialization
Route firstRoute = new Route();
Route secondRoute = new Route();
Route thirdRoute = new Route();
firstRoute.setId(new AgencyAndId(feedId, "A"));
firstRoute.setAgency(trainAgency);
firstRoute.setShortName("A");
firstRoute.setLongName("'A' Train");
firstRoute.setType(2);
firstRoute.setColor("White");
firstRoute.setTextColor("Black");
secondRoute.setId(new AgencyAndId(feedId, "B"));
secondRoute.setAgency(trainAgency);
secondRoute.setShortName("B");
secondRoute.setLongName("Another Train");
secondRoute.setType(2);
secondRoute.setColor("Cyan");
secondRoute.setTextColor("Yellow");
thirdRoute.setId(new AgencyAndId(feedId, "C"));
thirdRoute.setAgency(ferryAgency);
thirdRoute.setShortName("C");
thirdRoute.setLongName("Ferry Cross the Mersey");
thirdRoute.setType(4);
thirdRoute.setColor("Black");
thirdRoute.setTextColor("White");
// Trips for legs 1, 2 and 4, plus initialization
Trip firstTrip = new Trip();
Trip secondTrip = new Trip();
Trip thirdTrip = new Trip();
firstTrip.setId(new AgencyAndId(feedId, "A"));
firstTrip.setTripShortName("A");
firstTrip.setBlockId("Alock");
firstTrip.setRoute(firstRoute);
BikeAccess.setForTrip(firstTrip, BikeAccess.ALLOWED);
firstTrip.setTripHeadsign("Street Fighting Man");
secondTrip.setId(new AgencyAndId(feedId, "B"));
secondTrip.setTripShortName("B");
secondTrip.setBlockId("Block");
secondTrip.setRoute(secondRoute);
BikeAccess.setForTrip(secondTrip, BikeAccess.ALLOWED);
secondTrip.setTripHeadsign("No Expectations");
thirdTrip.setId(new AgencyAndId(feedId, "C"));
thirdTrip.setTripShortName("C");
thirdTrip.setBlockId("Clock");
thirdTrip.setRoute(thirdRoute);
BikeAccess.setForTrip(thirdTrip, BikeAccess.ALLOWED);
thirdTrip.setTripHeadsign("Handsome Molly");
// Scheduled stop times for legs 1, 2 and 4, plus initialization and storage in a list
StopTime trainStopDepartTime = new StopTime();
StopTime trainStopDwellTime = new StopTime();
StopTime trainStopInterlineFirstTime = new StopTime();
StopTime trainStopInterlineSecondTime = new StopTime();
StopTime trainStopArriveTime = new StopTime();
StopTime ferryStopDepartTime = new StopTime();
StopTime ferryStopArriveTime = new StopTime();
trainStopDepartTime.setTrip(firstTrip);
trainStopDepartTime.setStop(trainStopDepart);
trainStopDepartTime.setStopSequence(Integer.MIN_VALUE);
trainStopDepartTime.setDepartureTime(4);
trainStopDepartTime.setPickupType(3);
trainStopDwellTime.setTrip(firstTrip);
trainStopDwellTime.setStop(trainStopDwell);
trainStopDwellTime.setStopSequence(0);
trainStopDwellTime.setArrivalTime(8);
trainStopDwellTime.setDepartureTime(12);
trainStopInterlineFirstTime.setTrip(firstTrip);
trainStopInterlineFirstTime.setStop(trainStopInterline);
trainStopInterlineFirstTime.setStopSequence(Integer.MAX_VALUE);
trainStopInterlineFirstTime.setArrivalTime(16);
trainStopInterlineSecondTime.setTrip(secondTrip);
trainStopInterlineSecondTime.setStop(trainStopInterline);
trainStopInterlineSecondTime.setStopSequence(0);
trainStopInterlineSecondTime.setDepartureTime(20);
trainStopArriveTime.setTrip(secondTrip);
trainStopArriveTime.setStop(trainStopArrive);
trainStopArriveTime.setStopSequence(1);
trainStopArriveTime.setArrivalTime(24);
trainStopArriveTime.setDropOffType(2);
ferryStopDepartTime.setTrip(thirdTrip);
ferryStopDepartTime.setStop(ferryStopDepart);
ferryStopDepartTime.setStopSequence(-1);
ferryStopDepartTime.setDepartureTime(32);
ferryStopDepartTime.setPickupType(2);
ferryStopArriveTime.setTrip(thirdTrip);
ferryStopArriveTime.setStop(ferryStopArrive);
ferryStopArriveTime.setStopSequence(0);
ferryStopArriveTime.setArrivalTime(36);
ferryStopArriveTime.setDropOffType(3);
ArrayList<StopTime> firstStopTimes = new ArrayList<StopTime>();
ArrayList<StopTime> secondStopTimes = new ArrayList<StopTime>();
ArrayList<StopTime> thirdStopTimes = new ArrayList<StopTime>();
firstStopTimes.add(trainStopDepartTime);
firstStopTimes.add(trainStopDwellTime);
firstStopTimes.add(trainStopInterlineFirstTime);
secondStopTimes.add(trainStopInterlineSecondTime);
secondStopTimes.add(trainStopArriveTime);
thirdStopTimes.add(ferryStopDepartTime);
thirdStopTimes.add(ferryStopArriveTime);
// Various patterns that are required to construct a full graph path, plus initialization
StopPattern firstStopPattern = new StopPattern(firstStopTimes);
StopPattern secondStopPattern = new StopPattern(secondStopTimes);
StopPattern thirdStopPattern = new StopPattern(thirdStopTimes);
TripPattern firstTripPattern = new TripPattern(firstRoute, firstStopPattern);
TripPattern secondTripPattern = new TripPattern(secondRoute, secondStopPattern);
TripPattern thirdTripPattern = new TripPattern(thirdRoute, thirdStopPattern);
TripTimes firstTripTimes = new TripTimes(firstTrip, firstStopTimes, new Deduplicator());
TripTimes secondTripTimes = new TripTimes(secondTrip, secondStopTimes, new Deduplicator());
TripTimes thirdTripTimes = new TripTimes(thirdTrip, thirdStopTimes, new Deduplicator());
firstTripPattern.add(firstTripTimes);
secondTripPattern.add(secondTripTimes);
thirdTripPattern.add(thirdTripTimes);
// Vertices for legs 1, 2 and 3
TransitStop v6 = new TransitStop(graph, trainStopDepart);
TransitStopDepart v8 = new TransitStopDepart(graph, trainStopDepart, v6);
// To understand the stop indexes in the vertex constructors, look at firstStopTimes.add() etc. above
PatternDepartVertex v10 = new PatternDepartVertex(graph, firstTripPattern, 0);
PatternArriveVertex v12 = new PatternArriveVertex(graph, firstTripPattern, 1);
PatternDepartVertex v14 = new PatternDepartVertex(graph, firstTripPattern, 1);
PatternArriveVertex v16 = new PatternArriveVertex(graph, firstTripPattern, 2);
PatternDepartVertex v18 = new PatternDepartVertex(graph, secondTripPattern, 0);
PatternArriveVertex v20 = new PatternArriveVertex(graph, secondTripPattern, 1);
TransitStop v24 = new TransitStop(graph, trainStopArrive);
TransitStopArrive v22 = new TransitStopArrive(graph, trainStopArrive, v24);
// Vertices for legs 3 and 4
TransitStop v26 = new TransitStop(graph, ferryStopDepart);
TransitStopDepart v28 = new TransitStopDepart(graph, ferryStopDepart, v26);
PatternDepartVertex v30 = new PatternDepartVertex(graph, thirdTripPattern, 0);
PatternArriveVertex v32 = new PatternArriveVertex(graph, thirdTripPattern, 1);
TransitStop v36 = new TransitStop(graph, ferryStopArrive);
TransitStopArrive v34 = new TransitStopArrive(graph, ferryStopArrive, v36);
// Vertices for leg 5
IntersectionVertex v38 = new IntersectionVertex(graph, "Vertex 38", 179, 89);
IntersectionVertex v40 = new IntersectionVertex(graph, "Vertex 40", 180, 89);
IntersectionVertex v42 = new IntersectionVertex(graph, "Vertex 42", 180, 90);
// Bike rental stations for legs 5, 6 and 7, plus initialization
BikeRentalStation enterPickupStation = new BikeRentalStation();
BikeRentalStation exitPickupStation = new BikeRentalStation();
BikeRentalStation enterDropoffStation = new BikeRentalStation();
BikeRentalStation exitDropoffStation = new BikeRentalStation();
enterPickupStation.id = "Enter pickup";
enterPickupStation.name = new NonLocalizedString("Enter pickup station");
enterPickupStation.x = 180;
enterPickupStation.y = 90;
exitPickupStation.id = "Exit pickup";
exitPickupStation.name = new NonLocalizedString("Exit pickup station");
exitPickupStation.x = 180;
exitPickupStation.y = 90;
enterDropoffStation.id = "Enter dropoff";
enterDropoffStation.name = new NonLocalizedString("Enter dropoff station");
enterDropoffStation.x = 0;
enterDropoffStation.y = 90;
exitDropoffStation.id = "Exit dropoff";
exitDropoffStation.name = new NonLocalizedString("Exit dropoff station");
exitDropoffStation.x = 0;
exitDropoffStation.y = 90;
// Vertices for legs 5 and 6
BikeRentalStationVertex v44 = new BikeRentalStationVertex(graph, enterPickupStation);
BikeRentalStationVertex v46 = new BikeRentalStationVertex(graph, exitPickupStation);
IntersectionVertex v48 = new IntersectionVertex(graph, "Vertex 48", 180, 90);
IntersectionVertex v50 = new IntersectionVertex(graph, "Vertex 50", 90, 90);
// Vertices for leg 7
IntersectionVertex v52 = new IntersectionVertex(graph, "Vertex 52", 90, 90);
IntersectionVertex v54 = new IntersectionVertex(graph, "Vertex 54", 0, 90);
// Vertices for legs 7 and 8
BikeRentalStationVertex v56 = new BikeRentalStationVertex(graph, enterDropoffStation);
BikeRentalStationVertex v58 = new BikeRentalStationVertex(graph, exitDropoffStation);
StreetLocation v60 = new StreetLocation("Vertex 60", new Coordinate(0, 90), "Vertex 60");
// Vertex initialization that can't be done using the constructor
v0.setExitName("Ausfahrt");
v2.freeFlowing = (true);
v4.freeFlowing = (true);
v38.freeFlowing = (true);
v40.freeFlowing = (true);
v42.freeFlowing = (true);
v48.freeFlowing = (true);
v50.freeFlowing = (true);
v52.freeFlowing = (true);
v54.freeFlowing = (true);
// Elevation profiles for the street edges that will be created later
PackedCoordinateSequence elevation3 = new PackedCoordinateSequence.Double(new double[] { 0.0, 0.0, 3.0, 9.9 }, 2);
PackedCoordinateSequence elevation39 = new PackedCoordinateSequence.Double(new double[] { 0.0, 9.9, 2.1, 0.1 }, 2);
PackedCoordinateSequence elevation41 = new PackedCoordinateSequence.Double(new double[] { 0.0, 0.1, 1.9, 2.8 }, 2);
PackedCoordinateSequence elevation49 = new PackedCoordinateSequence.Double(new double[] { 0.0, 2.8, 2.0, 2.6 }, 2);
PackedCoordinateSequence elevation53 = new PackedCoordinateSequence.Double(new double[] { 0.0, 2.6, 1.0, 6.0 }, 2);
// Coordinate sequences and line strings for those same edges
PackedCoordinateSequence coordinates3 = new PackedCoordinateSequence.Double(new double[] { 0, 0, 1, 1 }, 2);
PackedCoordinateSequence coordinates25 = new PackedCoordinateSequence.Double(new double[] { 133, 67, 135, 67 }, 2);
PackedCoordinateSequence coordinates39 = new PackedCoordinateSequence.Double(new double[] { 179, 89, 180, 89 }, 2);
PackedCoordinateSequence coordinates41 = new PackedCoordinateSequence.Double(new double[] { 180, 89, 180, 90 }, 2);
PackedCoordinateSequence coordinates49 = new PackedCoordinateSequence.Double(new double[] { 180, 90, 90, 90 }, 2);
PackedCoordinateSequence coordinates53 = new PackedCoordinateSequence.Double(new double[] { 90, 90, 0, 90 }, 2);
GeometryFactory geometryFactory = new GeometryFactory();
LineString l3 = new LineString(coordinates3, geometryFactory);
LineString l25 = new LineString(coordinates25, geometryFactory);
LineString l39 = new LineString(coordinates39, geometryFactory);
LineString l41 = new LineString(coordinates41, geometryFactory);
LineString l49 = new LineString(coordinates49, geometryFactory);
LineString l53 = new LineString(coordinates53, geometryFactory);
// Edges for leg 0
FreeEdge e1 = new FreeEdge(v0, v2);
StreetWithElevationEdge e3 = new StreetWithElevationEdge(v2, v4, l3, "Edge 3", 3.0, StreetTraversalPermission.ALL, false);
// Edges for legs 1 and 2
StreetTransitLink e5 = new StreetTransitLink(v4, v6, false);
PreBoardEdge e7 = new PreBoardEdge(v6, v8);
TransitBoardAlight e9 = new TransitBoardAlight(v8, v10, 0, TraverseMode.RAIL);
PatternHop e11 = new PatternHop(v10, v12, trainStopDepart, trainStopDwell, 0);
PatternDwell e13 = new PatternDwell(v12, v14, 1, firstTripPattern);
PatternHop e15 = new PatternHop(v14, v16, trainStopDwell, trainStopInterline, 1);
PatternInterlineDwell e17 = new PatternInterlineDwell(v16, v18);
PatternHop e19 = new PatternHop(v18, v20, trainStopInterline, trainStopArrive, 0);
TransitBoardAlight e21 = new TransitBoardAlight(v20, v22, 1, TraverseMode.RAIL);
PreAlightEdge e23 = new PreAlightEdge(v22, v24);
// Edges for legs 3 and 4
SimpleTransfer e25 = new SimpleTransfer(v24, v26, 7, l25);
PreBoardEdge e27 = new PreBoardEdge(v26, v28);
TransitBoardAlight e29 = new TransitBoardAlight(v28, v30, 0, TraverseMode.FERRY);
PatternHop e31 = new PatternHop(v30, v32, ferryStopDepart, ferryStopArrive, 0);
TransitBoardAlight e33 = new TransitBoardAlight(v32, v34, 1, TraverseMode.FERRY);
PreAlightEdge e35 = new PreAlightEdge(v34, v36);
StreetTransitLink e37 = new StreetTransitLink(v36, v38, true);
// Edges for legs 5 and 6, where edges 39 and 41 have the same name to trigger stayOn = true
AreaEdge e39 = new AreaEdge(v38, v40, l39, "Edge 39 / 41", 2.1, StreetTraversalPermission.ALL, false, new AreaEdgeList());
StreetWithElevationEdge e41 = new StreetWithElevationEdge(v40, v42, l41, "Edge 39 / 41", 1.9, StreetTraversalPermission.ALL, false);
StreetBikeRentalLink e43 = new StreetBikeRentalLink(v42, v44);
RentABikeOnEdge e45 = new RentABikeOnEdge(v44, v46, Collections.singleton(""));
StreetBikeRentalLink e47 = new StreetBikeRentalLink(v46, v48);
StreetWithElevationEdge e49 = new StreetWithElevationEdge(v48, v50, l49, "Edge 49", 2.0, StreetTraversalPermission.ALL, false);
// Edges for legs 6, 7 and 8
LegSwitchingEdge e51 = new LegSwitchingEdge(v50, v52);
StreetEdge e53p = new StreetEdge(v52, v54, l53, "Edge 53", 1.0, StreetTraversalPermission.ALL, false);
PartialStreetEdge e53 = new PartialStreetEdge(e53p, v52, v54, l53, "Edge 53", 1.0);
StreetBikeRentalLink e55 = new StreetBikeRentalLink(v54, v56);
RentABikeOffEdge e57 = new RentABikeOffEdge(v56, v58, Collections.singleton(""));
StreetBikeRentalLink e59 = new StreetBikeRentalLink(v58, v60);
// Alert for testing GTFS-RT
AlertPatch alertPatch = new AlertPatch();
alertPatch.setTimePeriods(Collections.singletonList(new TimePeriod(0, Long.MAX_VALUE)));
alertPatch.setAlert(Alert.createSimpleAlerts(alertsExample));
// Edge initialization that can't be done using the constructor
e3.setElevationProfile(elevation3, false);
e17.add(firstTrip, secondTrip);
e39.setElevationProfile(elevation39, false);
e41.setElevationProfile(elevation41, false);
e41.setHasBogusName(true);
e49.setElevationProfile(elevation49, false);
e53.setElevationProfile(elevation53, false);
graph.streetNotesService.addStaticNote(e53p, Alert.createSimpleAlerts(alertsExample), StreetNotesService.ALWAYS_MATCHER);
// Add an extra edge to the graph in order to generate stayOn = true for one walk step.
new StreetEdge(v40, new IntersectionVertex(graph, "Extra vertex", 180, 88), new LineString(new PackedCoordinateSequence.Double(new double[] { 180, 89, 180, 88 }, 2), geometryFactory), "Extra edge", 1.9, StreetTraversalPermission.NONE, true);
// Various bookkeeping operations
graph.serviceCodes.put(firstTrip.getId(), 0);
graph.serviceCodes.put(secondTrip.getId(), 1);
graph.serviceCodes.put(thirdTrip.getId(), 2);
firstTripTimes.serviceCode = graph.serviceCodes.get(firstTrip.getId());
secondTripTimes.serviceCode = graph.serviceCodes.get(secondTrip.getId());
thirdTripTimes.serviceCode = graph.serviceCodes.get(thirdTrip.getId());
CalendarServiceData calendarServiceData = new CalendarServiceDataStub(graph.serviceCodes.keySet());
CalendarServiceImpl calendarServiceImpl = new CalendarServiceImpl(calendarServiceData);
calendarServiceData.putTimeZoneForAgencyId(feedId, timeZone);
calendarServiceData.putTimeZoneForAgencyId(feedId, timeZone);
FareServiceStub fareServiceStub = new FareServiceStub();
ServiceDate serviceDate = new ServiceDate(1970, 1, 1);
// Updates for leg 4, the ferry leg
TripDescriptor.Builder tripDescriptorBuilder = TripDescriptor.newBuilder();
tripDescriptorBuilder.setTripId("C");
StopTimeEvent.Builder ferryStopDepartTimeEventBuilder = StopTimeEvent.newBuilder();
StopTimeEvent.Builder ferryStopArriveTimeEventBuilder = StopTimeEvent.newBuilder();
ferryStopDepartTimeEventBuilder.setTime(40L);
ferryStopArriveTimeEventBuilder.setTime(43L);
StopTimeUpdate.Builder ferryStopDepartUpdateBuilder = StopTimeUpdate.newBuilder();
StopTimeUpdate.Builder ferryStopArriveUpdateBuilder = StopTimeUpdate.newBuilder();
ferryStopDepartUpdateBuilder.setStopSequence(-1);
ferryStopDepartUpdateBuilder.setDeparture(ferryStopDepartTimeEventBuilder);
ferryStopDepartUpdateBuilder.setArrival(ferryStopDepartTimeEventBuilder);
ferryStopDepartUpdateBuilder.setScheduleRelationship(ScheduleRelationship.SCHEDULED);
ferryStopArriveUpdateBuilder.setStopSequence(0);
ferryStopArriveUpdateBuilder.setDeparture(ferryStopArriveTimeEventBuilder);
ferryStopArriveUpdateBuilder.setArrival(ferryStopArriveTimeEventBuilder);
ferryStopArriveUpdateBuilder.setScheduleRelationship(ScheduleRelationship.SCHEDULED);
TripUpdate.Builder tripUpdateBuilder = TripUpdate.newBuilder();
tripUpdateBuilder.setTrip(tripDescriptorBuilder);
tripUpdateBuilder.addStopTimeUpdate(0, ferryStopDepartUpdateBuilder);
tripUpdateBuilder.addStopTimeUpdate(1, ferryStopArriveUpdateBuilder);
TripUpdate tripUpdate = tripUpdateBuilder.build();
// Create dummy TimetableSnapshot
TimetableSnapshot snapshot = new TimetableSnapshot();
// Mock TimetableSnapshotSource to return dummy TimetableSnapshot
TimetableSnapshotSource timetableSnapshotSource = mock(TimetableSnapshotSource.class);
when(timetableSnapshotSource.getTimetableSnapshot()).thenReturn(snapshot);
TripTimes updatedTripTimes = thirdTripPattern.scheduledTimetable.createUpdatedTripTimes(tripUpdate, timeZone, serviceDate);
timetableSnapshotSource.getTimetableSnapshot().update(feedId, thirdTripPattern, updatedTripTimes, serviceDate);
// Further graph initialization
graph.putService(CalendarServiceData.class, calendarServiceData);
graph.putService(FareService.class, fareServiceStub);
graph.addAgency(feedId, trainAgency);
graph.addAgency(feedId, ferryAgency);
graph.timetableSnapshotSource = (timetableSnapshotSource);
graph.addAlertPatch(e29, alertPatch);
// Routing context creation and initialization
ServiceDay serviceDay = new ServiceDay(graph, 0, calendarServiceImpl, feedId);
// Temporary graph objects for onboard depart tests
OnboardDepartVertex onboardDepartVertex = new OnboardDepartVertex("Onboard", 23.0, 12.0);
OnBoardDepartPatternHop onBoardDepartPatternHop = new OnBoardDepartPatternHop(onboardDepartVertex, v12, firstTripPattern.scheduledTimetable.getTripTimes(0), serviceDay, 0, 0.5);
// Traverse the path forward first
RoutingRequest forwardOptions = options.clone();
RoutingContext forwardContext = new RoutingContext(forwardOptions, graph, v0, v60);
forwardContext.serviceDays = new ArrayList<ServiceDay>(1);
forwardContext.serviceDays.add(serviceDay);
forwardOptions.rctx = forwardContext;
forwardOptions.dateTime = 0L;
forwardOptions.bikeRentalPickupTime = 4;
forwardOptions.bikeRentalDropoffTime = 2;
// Forward traversal of all edges
State s0Forward = new State(forwardOptions);
State s2Forward = e1.traverse(s0Forward);
State s4Forward = e3.traverse(s2Forward);
State s6Forward = e5.traverse(s4Forward);
State s8Forward = e7.traverse(s6Forward);
State s10Forward = e9.traverse(s8Forward);
State s12Forward = e11.traverse(s10Forward);
State s14Forward = e13.traverse(s12Forward);
State s16Forward = e15.traverse(s14Forward);
State s18Forward = e17.traverse(s16Forward);
State s20Forward = e19.traverse(s18Forward);
State s22Forward = e21.traverse(s20Forward);
State s24Forward = e23.traverse(s22Forward);
State s26Forward = e25.traverse(s24Forward);
State s28Forward = e27.traverse(s26Forward);
State s30Forward = e29.traverse(s28Forward);
State s32Forward = e31.traverse(s30Forward);
State s34Forward = e33.traverse(s32Forward);
State s36Forward = e35.traverse(s34Forward);
State s38Forward = e37.traverse(s36Forward);
State s40Forward = e39.traverse(s38Forward);
State s42Forward = e41.traverse(s40Forward);
State s44Forward = e43.traverse(s42Forward);
State s46Forward = e45.traverse(s44Forward);
State s48Forward = e47.traverse(s46Forward);
State s50Forward = e49.traverse(s48Forward);
State s52Forward = e51.traverse(s50Forward);
State s54Forward = e53.traverse(s52Forward);
State s56Forward = e55.traverse(s54Forward);
State s58Forward = e57.traverse(s56Forward);
State s60Forward = e59.traverse(s58Forward);
// Also traverse the path backward
RoutingRequest backwardOptions = options.clone();
RoutingContext backwardContext = new RoutingContext(backwardOptions, graph, v60, v0);
backwardContext.serviceDays = new ArrayList<ServiceDay>(1);
backwardContext.serviceDays.add(serviceDay);
backwardOptions.rctx = backwardContext;
backwardOptions.dateTime = 60L;
backwardOptions.bikeRentalPickupTime = 4;
backwardOptions.bikeRentalDropoffTime = 2;
backwardOptions.setArriveBy(true);
// Backward traversal of all edges
State s60Backward = new State(backwardOptions);
State s58Backward = e59.traverse(s60Backward);
State s56Backward = e57.traverse(s58Backward);
State s54Backward = e55.traverse(s56Backward);
State s52Backward = e53.traverse(s54Backward);
State s50Backward = e51.traverse(s52Backward);
State s48Backward = e49.traverse(s50Backward);
State s46Backward = e47.traverse(s48Backward);
State s44Backward = e45.traverse(s46Backward);
State s42Backward = e43.traverse(s44Backward);
State s40Backward = e41.traverse(s42Backward);
State s38Backward = e39.traverse(s40Backward);
State s36Backward = e37.traverse(s38Backward);
State s34Backward = e35.traverse(s36Backward);
State s32Backward = e33.traverse(s34Backward);
State s30Backward = e31.traverse(s32Backward);
State s28Backward = e29.traverse(s30Backward);
State s26Backward = e27.traverse(s28Backward);
State s24Backward = e25.traverse(s26Backward);
State s22Backward = e23.traverse(s24Backward);
State s20Backward = e21.traverse(s22Backward);
State s18Backward = e19.traverse(s20Backward);
State s16Backward = e17.traverse(s18Backward);
State s14Backward = e15.traverse(s16Backward);
State s12Backward = e13.traverse(s14Backward);
State s10Backward = e11.traverse(s12Backward);
State s8Backward = e9.traverse(s10Backward);
State s6Backward = e7.traverse(s8Backward);
State s4Backward = e5.traverse(s6Backward);
State s2Backward = e3.traverse(s4Backward);
State s0Backward = e1.traverse(s2Backward);
// Perform a forward traversal starting onboard
RoutingRequest onboardOptions = options.clone();
RoutingContext onboardContext = new RoutingContext(onboardOptions, graph, onboardDepartVertex, v60);
onboardContext.serviceDays = new ArrayList<ServiceDay>(1);
onboardContext.serviceDays.add(serviceDay);
onboardOptions.rctx = onboardContext;
onboardOptions.dateTime = 6L;
onboardOptions.bikeRentalPickupTime = 4;
onboardOptions.bikeRentalDropoffTime = 2;
// Onboard traversal of all edges
State s10Onboard = new State(onboardOptions);
State s12Onboard = onBoardDepartPatternHop.traverse(s10Onboard);
State s14Onboard = e13.traverse(s12Onboard);
State s16Onboard = e15.traverse(s14Onboard);
State s18Onboard = e17.traverse(s16Onboard);
State s20Onboard = e19.traverse(s18Onboard);
State s22Onboard = e21.traverse(s20Onboard);
State s24Onboard = e23.traverse(s22Onboard);
State s26Onboard = e25.traverse(s24Onboard);
State s28Onboard = e27.traverse(s26Onboard);
State s30Onboard = e29.traverse(s28Onboard);
State s32Onboard = e31.traverse(s30Onboard);
State s34Onboard = e33.traverse(s32Onboard);
State s36Onboard = e35.traverse(s34Onboard);
State s38Onboard = e37.traverse(s36Onboard);
State s40Onboard = e39.traverse(s38Onboard);
State s42Onboard = e41.traverse(s40Onboard);
State s44Onboard = e43.traverse(s42Onboard);
State s46Onboard = e45.traverse(s44Onboard);
State s48Onboard = e47.traverse(s46Onboard);
State s50Onboard = e49.traverse(s48Onboard);
State s52Onboard = e51.traverse(s50Onboard);
State s54Onboard = e53.traverse(s52Onboard);
State s56Onboard = e55.traverse(s54Onboard);
State s58Onboard = e57.traverse(s56Onboard);
State s60Onboard = e59.traverse(s58Onboard);
return new GraphPath[] { new GraphPath(s60Forward, false), new GraphPath(s0Backward, false), new GraphPath(s60Onboard, false) };
}
Aggregations