diff --git a/pom.xml b/pom.xml
index 9ee06f129f9..2d794811138 100644
--- a/pom.xml
+++ b/pom.xml
@@ -707,7 +707,7 @@
org.onebusaway
onebusaway-gtfs
- 1.3.87
+ 1.3.88-SNAPSHOT
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexAccessEgress.java b/src/ext/java/org/opentripplanner/ext/flex/FlexAccessEgress.java
index 4a966b76d02..20b77154b90 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexAccessEgress.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexAccessEgress.java
@@ -4,15 +4,15 @@
import org.opentripplanner.model.Stop;
import org.opentripplanner.routing.core.State;
-public class FlexAccessEgress {
+public class FlexAccessEgress {
public final Stop stop;
public final int preFlexTime;
public final int flexTime;
public final int postFlexTime;
- private final int fromStopIndex;
- private final int toStopIndex;
+ private final T fromStopIndex;
+ private final T toStopIndex;
private final int differenceFromStartOfTime;
- private final FlexTrip trip;
+ private final FlexTrip trip;
public final State lastState;
public final boolean directToStop;
@@ -21,10 +21,10 @@ public FlexAccessEgress(
int preFlexTime,
int flexTime,
int postFlexTime,
- int fromStopIndex,
- int toStopIndex,
+ T fromStopIndex,
+ T toStopIndex,
int differenceFromStartOfTime,
- FlexTrip trip,
+ FlexTrip trip,
State lastState,
boolean directToStop
) {
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java b/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java
index e1c05946e1e..22878e405f4 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java
@@ -21,11 +21,11 @@
public class FlexIndex {
public Multimap transfersToStop = ArrayListMultimap.create();
- public Multimap flexTripsByStop = HashMultimap.create();
+ public Multimap> flexTripsByStop = HashMultimap.create();
public Multimap locationGroupsByStop = ArrayListMultimap.create();
- public HashGridSpatialIndex locationIndex = new HashGridSpatialIndex();
+ public HashGridSpatialIndex locationIndex = new HashGridSpatialIndex<>();
public Map routeById = new HashMap<>();
@@ -35,7 +35,7 @@ public FlexIndex(Graph graph) {
for (SimpleTransfer transfer : graph.transfersByStop.values()) {
transfersToStop.put(transfer.to, transfer);
}
- for (FlexTrip flexTrip : graph.flexTripsById.values()) {
+ for (FlexTrip> flexTrip : graph.flexTripsById.values()) {
routeById.put(flexTrip.getTrip().getRoute().getId(), flexTrip.getTrip().getRoute());
tripById.put(flexTrip.getTrip().getId(), flexTrip.getTrip());
for (StopLocation stop : flexTrip.getStops()) {
@@ -58,7 +58,7 @@ public FlexIndex(Graph graph) {
}
}
- Stream getFlexTripsByStop(StopLocation stopLocation) {
+ Stream> getFlexTripsByStop(StopLocation stopLocation) {
return flexTripsByStop.get(stopLocation).stream();
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexLegMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexLegMapper.java
index 5073e648e1f..3ffec5311b0 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexLegMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexLegMapper.java
@@ -10,14 +10,18 @@
public class FlexLegMapper {
- static public void fixFlexTripLeg(Leg leg, FlexTripEdge flexTripEdge) {
+ static public void fixFlexTripLeg(Leg leg, FlexTripEdge> flexTripEdge) {
leg.from.stopId = flexTripEdge.s1.getId();
// TODO: Should flex be of its own type
leg.from.vertexType = flexTripEdge.s1 instanceof Stop ? VertexType.TRANSIT : VertexType.NORMAL;
- leg.from.stopIndex = flexTripEdge.flexTemplate.fromStopIndex;
+ if (flexTripEdge.flexTemplate.fromStopIndex instanceof Integer) {
+ leg.from.stopIndex = (Integer) flexTripEdge.flexTemplate.fromStopIndex;
+ }
leg.to.stopId = flexTripEdge.s2.getId();
leg.to.vertexType = flexTripEdge.s2 instanceof Stop ? VertexType.TRANSIT : VertexType.NORMAL;
- leg.to.stopIndex = flexTripEdge.flexTemplate.toStopIndex;
+ if (flexTripEdge.flexTemplate.toStopIndex instanceof Integer) {
+ leg.to.stopIndex = (Integer) flexTripEdge.flexTemplate.toStopIndex;
+ }
leg.intermediateStops = new ArrayList<>();
leg.distanceMeters = flexTripEdge.getDistanceMeters();
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java b/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java
index 1c5feb27b8d..41eeee4fa13 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java
@@ -8,7 +8,9 @@
import org.opentripplanner.ext.flex.template.FlexAccessTemplate;
import org.opentripplanner.ext.flex.template.FlexEgressTemplate;
import org.opentripplanner.ext.flex.trip.FlexTrip;
+import org.opentripplanner.model.Stop;
import org.opentripplanner.model.StopLocation;
+import org.opentripplanner.model.Transfer;
import org.opentripplanner.model.calendar.ServiceDate;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.algorithm.raptor.transit.mappers.DateMapper;
@@ -24,6 +26,7 @@
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -36,7 +39,7 @@ public class FlexRouter {
private final Collection streetAccesses;
private final Collection streetEgresses;
private final FlexIndex flexIndex;
- private final FlexPathCalculator flexPathCalculator;
+ private final FlexPathCalculator flexPathCalculator;
/* Request data */
private final ZonedDateTime startOfTime;
@@ -46,8 +49,9 @@ public class FlexRouter {
private final FlexServiceDate[] dates;
/* State */
- private List flexAccessTemplates = null;
- private List flexEgressTemplates = null;
+ private List> flexAccessTemplates = null;
+ private List> flexEgressTemplates = null;
+ private final Collection transitTransfers;
public FlexRouter(
Graph graph,
@@ -61,6 +65,7 @@ public FlexRouter(
this.graph = graph;
this.streetAccesses = streetAccesses;
this.streetEgresses = egressTransfers;
+ this.transitTransfers = graph.getTransferTable().getTransfers();
this.flexIndex = graph.index.getFlexIndex();
this.flexPathCalculator = new DirectFlexPathCalculator(graph);
@@ -95,9 +100,18 @@ public Collection createFlexOnlyItineraries() {
Set egressStops = streetEgressByStop.keySet();
+ Map> transfersFromStop = transitTransfers
+ .stream()
+ .collect(Collectors.groupingBy(Transfer::getFromStop));
+
+ Map>> flexEgressByStop = flexEgressTemplates
+ .stream()
+ .filter(template -> template.getTransferStop() instanceof Stop)
+ .collect(Collectors.groupingBy(template -> (Stop) template.getTransferStop()));
+
Collection itineraries = new ArrayList<>();
- for (FlexAccessTemplate template : this.flexAccessTemplates) {
+ for (FlexAccessTemplate> template : this.flexAccessTemplates) {
StopLocation transferStop = template.getTransferStop();
if (egressStops.contains(transferStop)) {
for(NearbyStop egress : streetEgressByStop.get(transferStop)) {
@@ -107,12 +121,40 @@ public Collection createFlexOnlyItineraries() {
}
}
}
+ if (transferStop instanceof Stop && transfersFromStop.containsKey(transferStop)) {
+ for (Transfer transfer : transfersFromStop.get(transferStop)) {
+ // TODO: Handle other than route-to-route transfers
+ if (transfer.getFromRoute() == null
+ || transfer.getFromRoute().equals(template.getFlexTrip().getTrip().getRoute())
+ ) {
+ List> templates = flexEgressByStop.get(transfer.getToStop());
+ if (templates == null) { continue; }
+ for (FlexEgressTemplate> egress : templates) {
+ if (transfer.getToRoute() == null
+ || transfer.getToRoute().equals(egress.getFlexTrip().getTrip().getRoute())
+ ) {
+ Itinerary itinerary = template.getTransferItinerary(
+ transfer,
+ egress,
+ arriveBy,
+ departureTime,
+ startOfTime,
+ graph.index.getStopVertexForStop()
+ );
+ if (itinerary != null) {
+ itineraries.add(itinerary);
+ }
+ }
+ }
+ }
+ }
+ }
}
return itineraries;
}
- public Collection createFlexAccesses() {
+ public Collection> createFlexAccesses() {
calculateFlexAccessTemplates();
return this.flexAccessTemplates
@@ -121,7 +163,7 @@ public Collection createFlexAccesses() {
.collect(Collectors.toList());
}
- public Collection createFlexEgresses() {
+ public Collection> createFlexEgresses() {
calculateFlexEgressTemplates();
return this.flexEgressTemplates
@@ -155,19 +197,19 @@ private void calculateFlexEgressTemplates() {
.filter(date -> date.isFlexTripRunning(t2.second, this.graph))
// Create templates from trip, alighting at the nearbyStop
.flatMap(date -> t2.second.getFlexEgressTemplates(t2.first, date, flexPathCalculator)))
- .collect(Collectors.toList());;
+ .collect(Collectors.toList());
}
- private Stream> getClosestFlexTrips(Collection nearbyStops) {
+ private Stream>> getClosestFlexTrips(Collection nearbyStops) {
// Find all trips reachable from the nearbyStops
- Stream> flexTripsReachableFromNearbyStops = nearbyStops
+ Stream>> flexTripsReachableFromNearbyStops = nearbyStops
.stream()
.flatMap(accessEgress -> flexIndex
.getFlexTripsByStop(accessEgress.stop)
.map(flexTrip -> new T2<>(accessEgress, flexTrip)));
// Group all (NearbyStop, FlexTrip) tuples by flexTrip
- Collection>> groupedReachableFlexTrips = flexTripsReachableFromNearbyStops
+ Collection>>> groupedReachableFlexTrips = flexTripsReachableFromNearbyStops
.collect(Collectors.groupingBy(t2 -> t2.second))
.values();
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexServiceDate.java b/src/ext/java/org/opentripplanner/ext/flex/FlexServiceDate.java
index e8289c1fe35..e788695a980 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexServiceDate.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexServiceDate.java
@@ -31,7 +31,7 @@ public class FlexServiceDate {
this.servicesRunning = servicesRunning;
}
- boolean isFlexTripRunning(FlexTrip flexTrip, Graph graph) {
+ boolean isFlexTripRunning(FlexTrip> flexTrip, Graph graph) {
return servicesRunning.contains(graph.getServiceCodes().get(flexTrip.getTrip().getServiceId()));
}
}
\ No newline at end of file
diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java
index 6623508257d..efe612ac4bf 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java
@@ -1,5 +1,6 @@
package org.opentripplanner.ext.flex;
+import org.opentripplanner.ext.flex.trip.ContinuousPickupDropOffTrip;
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip;
import org.opentripplanner.ext.flex.trip.UnscheduledTrip;
@@ -13,14 +14,12 @@
import java.util.ArrayList;
import java.util.List;
-import static org.opentripplanner.model.StopPattern.PICKDROP_NONE;
-
public class FlexTripsMapper {
private static final Logger LOG = LoggerFactory.getLogger(FlexTripsMapper.class);
- static public List createFlexTrips(OtpTransitServiceBuilder builder) {
- List result = new ArrayList<>();
+ static public List> createFlexTrips(OtpTransitServiceBuilder builder) {
+ List> result = new ArrayList<>();
TripStopTimes stopTimesByTrip = builder.getStopTimesSortedByTrip();
final int tripSize = stopTimesByTrip.size();
@@ -38,8 +37,8 @@ static public List createFlexTrips(OtpTransitServiceBuilder builder) {
result.add(new UnscheduledTrip(trip, stopTimes));
} else if (ScheduledDeviatedTrip.isScheduledFlexTrip(stopTimes)) {
result.add(new ScheduledDeviatedTrip(trip, stopTimes));
- } else if (hasContinuousStops(stopTimes)) {
- // result.add(new ContinuousPickupDropOffTrip(trip, stopTimes));
+ } else if (ContinuousPickupDropOffTrip.hasContinuousStops(stopTimes)) {
+ result.add(new ContinuousPickupDropOffTrip(trip, stopTimes));
}
//Keep lambda! A method-ref would causes incorrect class and line number to be logged
@@ -51,10 +50,4 @@ static public List createFlexTrips(OtpTransitServiceBuilder builder) {
return result;
}
- private static boolean hasContinuousStops(List stopTimes) {
- return stopTimes
- .stream()
- .anyMatch(st -> st.getFlexContinuousPickup() != PICKDROP_NONE || st.getFlexContinuousDropOff() != PICKDROP_NONE);
- }
-
}
diff --git a/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTransferEdge.java b/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTransferEdge.java
new file mode 100644
index 00000000000..4873ffcb7d2
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTransferEdge.java
@@ -0,0 +1,45 @@
+package org.opentripplanner.ext.flex.edgetype;
+
+import org.opentripplanner.routing.core.State;
+import org.opentripplanner.routing.core.StateEditor;
+import org.opentripplanner.routing.core.TraverseMode;
+import org.opentripplanner.routing.graph.Edge;
+import org.opentripplanner.routing.graph.Vertex;
+import org.opentripplanner.routing.vertextype.TransitStopVertex;
+
+import java.util.Locale;
+
+public class FlexTransferEdge extends Edge {
+
+ private final int minTransferTimeSeconds;
+
+ public FlexTransferEdge(
+ TransitStopVertex transferFromVertex, TransitStopVertex transferToVertex,
+ int minTransferTimeSeconds
+ ) {
+ super(new Vertex(null, null, 0.0, 0.0) {}, new Vertex(null, null, 0.0, 0.0) {});
+ this.minTransferTimeSeconds = minTransferTimeSeconds;
+ this.fromv = transferFromVertex;
+ this.tov = transferToVertex;
+ // Why is this code so dirty? Because we don't want this edge to be added to the edge lists.
+ }
+
+ @Override
+ public State traverse(State s0) {
+ StateEditor editor = s0.edit(this);
+ editor.setBackMode(TraverseMode.WALK);
+ editor.incrementWeight(minTransferTimeSeconds);
+ editor.incrementTimeInSeconds(minTransferTimeSeconds);
+ return editor.makeState();
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public String getName(Locale locale) {
+ return null;
+ }
+}
diff --git a/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTripEdge.java b/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTripEdge.java
index c45e77f428e..2e5cc8b40a8 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTripEdge.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/edgetype/FlexTripEdge.java
@@ -19,7 +19,7 @@
import java.util.Locale;
-public class FlexTripEdge extends Edge {
+public class FlexTripEdge extends Edge {
private static final Logger LOG = LoggerFactory.getLogger(FlexTripEdge.class);
@@ -27,13 +27,13 @@ public class FlexTripEdge extends Edge {
public StopLocation s1;
public StopLocation s2;
- private FlexTrip trip;
- public FlexAccessEgressTemplate flexTemplate;
+ private final FlexTrip trip;
+ public FlexAccessEgressTemplate flexTemplate;
public FlexPath flexPath;
public FlexTripEdge(
- Vertex v1, Vertex v2, StopLocation s1, StopLocation s2, FlexTrip trip,
- FlexAccessEgressTemplate flexTemplate, FlexPathCalculator calculator
+ Vertex v1, Vertex v2, StopLocation s1, StopLocation s2, FlexTrip trip,
+ FlexAccessEgressTemplate flexTemplate, FlexPathCalculator calculator
) {
// Why is this code so dirty? Because we don't want this edge to be added to the edge lists.
// The first parameter in Vertex constructor is graph. If it is null, the vertex isn't added to it.
diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DirectFlexPathCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DirectFlexPathCalculator.java
index 2e34ce76937..aa68684033e 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DirectFlexPathCalculator.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/DirectFlexPathCalculator.java
@@ -7,20 +7,20 @@
/**
* Calculated driving times and distance based on direct distance and fixed average driving speed.
*/
-public class DirectFlexPathCalculator implements FlexPathCalculator {
+public class DirectFlexPathCalculator implements FlexPathCalculator {
public static final double FLEX_SPEED = 8.0;
private static final int DIRECT_EXTRA_TIME = 5 * 60;
- private double flexSpeed;
+ private final double flexSpeed;
public DirectFlexPathCalculator(Graph graph) {
- this.flexSpeed = FLEX_SPEED;
+ this.flexSpeed = graph.flexSpeed;
}
@Override
public FlexPath calculateFlexPath(
- Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex
+ Vertex fromv, Vertex tov, Integer fromStopIndex, Integer toStopIndex
) {
double distance = SphericalDistanceLibrary.distance(fromv.getCoordinate(), tov.getCoordinate());
diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathCalculator.java
index 41ade3a0f90..0668db2a572 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathCalculator.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/FlexPathCalculator.java
@@ -7,9 +7,9 @@
/**
* FlexPathCalculator is used to calculate the driving times and distances during flex routing
*/
-public interface FlexPathCalculator {
+public interface FlexPathCalculator {
@Nullable
- FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex);
+ FlexPath calculateFlexPath(Vertex fromv, Vertex tov, T fromStopIndex, T toStopIndex);
}
diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java
index 86038036913..549949cdaaa 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/ScheduledFlexPathCalculator.java
@@ -6,18 +6,18 @@
/**
* Calculate the driving times based on the shcheduled timetable for the route.
*/
-public class ScheduledFlexPathCalculator implements FlexPathCalculator {
- private final FlexPathCalculator flexPathCalculator;
- private final FlexTrip trip;
+public class ScheduledFlexPathCalculator implements FlexPathCalculator {
+ private final FlexPathCalculator flexPathCalculator;
+ private final FlexTrip trip;
- public ScheduledFlexPathCalculator(FlexPathCalculator flexPathCalculator, FlexTrip trip) {
+ public ScheduledFlexPathCalculator(FlexPathCalculator flexPathCalculator, FlexTrip trip) {
this.flexPathCalculator = flexPathCalculator;
this.trip = trip;
}
@Override
public FlexPath calculateFlexPath(
- Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex
+ Vertex fromv, Vertex tov, Integer fromStopIndex, Integer toStopIndex
) {
FlexPath flexPath = flexPathCalculator.calculateFlexPath(
fromv,
diff --git a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/StreetFlexPathCalculator.java b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/StreetFlexPathCalculator.java
index c1d7342d4f1..0a8199f6230 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/StreetFlexPathCalculator.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/flexpathcalculator/StreetFlexPathCalculator.java
@@ -22,16 +22,16 @@
* - Use a one-to-many search
* - Cache found times
*/
-public class StreetFlexPathCalculator implements FlexPathCalculator {
- private Graph graph;
- private Map, FlexPath> cache = new HashMap<>();
+public class StreetFlexPathCalculator implements FlexPathCalculator {
+ private final Graph graph;
+ private final Map, FlexPath> cache = new HashMap<>();
public StreetFlexPathCalculator(Graph graph) {
this.graph = graph;
}
@Override
- public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex) {
+ public FlexPath calculateFlexPath(Vertex fromv, Vertex tov, Integer fromStopIndex, Integer toStopIndex) {
T2 key = new T2<>(fromv, tov);
FlexPath cacheValue = cache.get(key);
if (cacheValue != null) return cacheValue;
diff --git a/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessEgressTemplate.java b/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessEgressTemplate.java
index 61e295d41d3..fd2df954338 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessEgressTemplate.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessEgressTemplate.java
@@ -21,24 +21,24 @@
import java.util.List;
import java.util.stream.Stream;
-public abstract class FlexAccessEgressTemplate {
+public abstract class FlexAccessEgressTemplate {
protected final NearbyStop accessEgress;
- protected final FlexTrip trip;
- public final int fromStopIndex;
- public final int toStopIndex;
+ protected final FlexTrip trip;
+ public final T fromStopIndex;
+ public final T toStopIndex;
protected final StopLocation transferStop;
protected final int secondsFromStartOfTime;
public final ServiceDate serviceDate;
- protected final FlexPathCalculator calculator;
+ protected final FlexPathCalculator calculator;
FlexAccessEgressTemplate(
NearbyStop accessEgress,
- FlexTrip trip,
- int fromStopIndex,
- int toStopIndex,
+ FlexTrip trip,
+ T fromStopIndex,
+ T toStopIndex,
StopLocation transferStop,
FlexServiceDate date,
- FlexPathCalculator calculator
+ FlexPathCalculator calculator
) {
this.accessEgress = accessEgress;
this.trip = trip;
@@ -54,7 +54,7 @@ public StopLocation getTransferStop() {
return transferStop;
}
- public FlexTrip getFlexTrip() {
+ public FlexTrip getFlexTrip() {
return trip;
}
@@ -83,19 +83,19 @@ public FlexTrip getFlexTrip() {
/**
* Get the times in seconds, before during and after the flex ride.
*/
- abstract protected int[] getFlexTimes(FlexTripEdge flexEdge, State state);
+ abstract protected int[] getFlexTimes(FlexTripEdge flexEdge, State state);
/**
* Get the FlexTripEdge for the flex ride.
*/
- abstract protected FlexTripEdge getFlexEdge(Vertex flexFromVertex, StopLocation transferStop);
+ abstract protected FlexTripEdge getFlexEdge(Vertex flexFromVertex, StopLocation transferStop);
/**
* Checks whether the routing is possible
*/
abstract protected boolean isRouteable(Vertex flexVertex);
- public Stream createFlexAccessEgressStream(Graph graph) {
+ public Stream> createFlexAccessEgressStream(Graph graph) {
if (transferStop instanceof Stop) {
TransitStopVertex flexVertex = graph.index.getStopVertexForStop().get(transferStop);
if (isRouteable(flexVertex)) {
@@ -119,8 +119,8 @@ public Stream createFlexAccessEgressStream(Graph graph) {
}
}
- protected FlexAccessEgress getFlexAccessEgress(List transferEdges, Vertex flexVertex, Stop stop) {
- FlexTripEdge flexEdge = getFlexEdge(flexVertex, transferStop);
+ protected FlexAccessEgress getFlexAccessEgress(List transferEdges, Vertex flexVertex, Stop stop) {
+ FlexTripEdge flexEdge = getFlexEdge(flexVertex, transferStop);
State state = flexEdge.traverse(accessEgress.state);
for (Edge e : transferEdges) {
@@ -129,13 +129,14 @@ protected FlexAccessEgress getFlexAccessEgress(List transferEdges, Vertex
int[] times = getFlexTimes(flexEdge, state);
- return new FlexAccessEgress(
+ return new FlexAccessEgress<>(
stop,
times[0],
times[1],
times[2],
fromStopIndex,
- toStopIndex, secondsFromStartOfTime,
+ toStopIndex,
+ secondsFromStartOfTime,
trip,
state,
transferEdges.isEmpty()
diff --git a/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessTemplate.java b/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessTemplate.java
index f096c05a8f9..2de53200853 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessTemplate.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/template/FlexAccessTemplate.java
@@ -1,5 +1,6 @@
package org.opentripplanner.ext.flex.template;
+import org.opentripplanner.ext.flex.edgetype.FlexTransferEdge;
import org.opentripplanner.ext.flex.FlexServiceDate;
import org.opentripplanner.ext.flex.edgetype.FlexTripEdge;
import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator;
@@ -7,6 +8,8 @@
import org.opentripplanner.model.SimpleTransfer;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.StopLocation;
+import org.opentripplanner.model.Transfer;
+import org.opentripplanner.model.TransferType;
import org.opentripplanner.model.plan.Itinerary;
import org.opentripplanner.routing.algorithm.mapping.GraphPathToItineraryMapper;
import org.opentripplanner.routing.core.State;
@@ -15,20 +18,22 @@
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.graphfinder.NearbyStop;
import org.opentripplanner.routing.spt.GraphPath;
+import org.opentripplanner.routing.vertextype.TransitStopVertex;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.TimeZone;
-public class FlexAccessTemplate extends FlexAccessEgressTemplate {
+public class FlexAccessTemplate extends FlexAccessEgressTemplate {
public FlexAccessTemplate(
- NearbyStop accessEgress, FlexTrip trip, int fromStopTime, int toStopTime,
- StopLocation transferStop, FlexServiceDate date, FlexPathCalculator calculator
+ NearbyStop accessEgress, FlexTrip trip, T fromStopIndex, T toStopIndex,
+ StopLocation transferStop, FlexServiceDate date, FlexPathCalculator calculator
) {
- super(accessEgress, trip, fromStopTime, toStopTime, transferStop, date, calculator);
+ super(accessEgress, trip, fromStopIndex, toStopIndex, transferStop, date, calculator);
}
public Itinerary createDirectItinerary(
@@ -42,7 +47,7 @@ public Itinerary createDirectItinerary(
return null;
}
- FlexTripEdge flexEdge = getFlexEdge(flexToVertex, egress.stop);
+ FlexTripEdge flexEdge = getFlexEdge(flexToVertex, egress.stop);
State state = flexEdge.traverse(accessEgress.state);
@@ -56,7 +61,7 @@ public Itinerary createDirectItinerary(
int flexTime = flexTimes[1];
int postFlexTime = flexTimes[2];
- Integer timeShift = null;
+ int timeShift;
if (arriveBy) {
int lastStopArrivalTime = departureTime - postFlexTime - secondsFromStartOfTime;
@@ -99,6 +104,63 @@ public Itinerary createDirectItinerary(
return itinerary;
}
+ public Itinerary getTransferItinerary(
+ Transfer transfer, FlexEgressTemplate> template, boolean arriveBy, int departureTime,
+ ZonedDateTime startOfTime, Map stopVertexForStop
+ ) {
+ if (transfer.getFromStop() != transfer.getToStop()) {
+ // TODO: Handle walking between legs
+ return null;
+ }
+
+ boolean isMinTimeTransfer = transfer.getTransferType() == TransferType.MIN_TIME;
+ boolean isGuaranteedTransfer = transfer.getTransferType() == TransferType.GUARANTEED;
+
+ if (!isMinTimeTransfer && !isGuaranteedTransfer) {
+ // TODO: Handle other types of transfers
+ return null;
+ }
+
+ TransitStopVertex transferFromVertex = stopVertexForStop.get(transfer.getFromStop());
+ TransitStopVertex transferToVertex = stopVertexForStop.get(transfer.getToStop());
+
+ if (!this.isRouteable(transferFromVertex) || !template.isRouteable(transferToVertex)) {
+ return null;
+ }
+
+ FlexTripEdge firstFlexEdge = this.getFlexEdge(transferFromVertex, transfer.getFromStop());
+ FlexTripEdge> secondFlexEdge = template.getFlexEdge(transferToVertex, transfer.getToStop());
+
+ List egressEdges = template.accessEgress.edges;
+
+ State state = this.accessEgress.state;
+
+ state = firstFlexEdge.traverse(state);
+
+ // TODO: Remove this and modify state directly
+ if (isMinTimeTransfer) {
+ FlexTransferEdge legSwitchEdge = new FlexTransferEdge(transferFromVertex, transferToVertex, transfer.getMinTransferTimeSeconds());
+ state = legSwitchEdge.traverse(state);
+ }
+
+ state = secondFlexEdge.traverse(state);
+
+ for (Edge e : egressEdges) {
+ state = e.traverse(state);
+ }
+
+ // TODO: Filtering of invalid itineraries
+
+ Itinerary itinerary = GraphPathToItineraryMapper.generateItinerary(
+ new GraphPath(state, false),
+ Locale.ENGLISH
+ );
+
+ // TODO: Timeshift
+
+ return itinerary;
+ }
+
protected List getTransferEdges(SimpleTransfer simpleTransfer) {
return simpleTransfer.getEdges();
}
@@ -124,17 +186,17 @@ protected boolean isRouteable(Vertex flexVertex) {
fromStopIndex,
toStopIndex
) != null;
- };
+ }
- protected int[] getFlexTimes(FlexTripEdge flexEdge, State state) {
+ protected int[] getFlexTimes(FlexTripEdge flexEdge, State state) {
int preFlexTime = (int) accessEgress.state.getElapsedTimeSeconds();
int edgeTimeInSeconds = flexEdge.getTimeInSeconds();
int postFlexTime = (int) state.getElapsedTimeSeconds() - preFlexTime - edgeTimeInSeconds;
return new int[]{ preFlexTime, edgeTimeInSeconds, postFlexTime };
}
- protected FlexTripEdge getFlexEdge(Vertex flexToVertex, StopLocation transferStop) {
- return new FlexTripEdge(
+ protected FlexTripEdge getFlexEdge(Vertex flexToVertex, StopLocation transferStop) {
+ return new FlexTripEdge<>(
accessEgress.state.getVertex(),
flexToVertex,
accessEgress.stop,
diff --git a/src/ext/java/org/opentripplanner/ext/flex/template/FlexEgressTemplate.java b/src/ext/java/org/opentripplanner/ext/flex/template/FlexEgressTemplate.java
index 43cc08f0027..3c2957acefe 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/template/FlexEgressTemplate.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/template/FlexEgressTemplate.java
@@ -17,12 +17,12 @@
import java.util.Collection;
import java.util.List;
-public class FlexEgressTemplate extends FlexAccessEgressTemplate {
+public class FlexEgressTemplate extends FlexAccessEgressTemplate {
public FlexEgressTemplate(
- NearbyStop accessEgress, FlexTrip trip, int fromStopTime, int toStopTime,
- StopLocation transferStop, FlexServiceDate date, FlexPathCalculator calculator
+ NearbyStop accessEgress, FlexTrip trip, T fromStopIndex, T toStopIndex,
+ StopLocation transferStop, FlexServiceDate date, FlexPathCalculator calculator
) {
- super(accessEgress, trip, fromStopTime, toStopTime, transferStop, date, calculator);
+ super(accessEgress, trip, fromStopIndex, toStopIndex, transferStop, date, calculator);
}
protected List getTransferEdges(SimpleTransfer simpleTransfer) {
@@ -50,17 +50,17 @@ protected boolean isRouteable(Vertex flexVertex) {
fromStopIndex,
toStopIndex
) != null;
- };
+ }
- protected int[] getFlexTimes(FlexTripEdge flexEdge, State state) {
+ protected int[] getFlexTimes(FlexTripEdge flexEdge, State state) {
int postFlexTime = (int) accessEgress.state.getElapsedTimeSeconds();
int edgeTimeInSeconds = flexEdge.getTimeInSeconds();
int preFlexTime = (int) state.getElapsedTimeSeconds() - postFlexTime - edgeTimeInSeconds;
return new int[]{ preFlexTime, edgeTimeInSeconds, postFlexTime };
}
- protected FlexTripEdge getFlexEdge(Vertex flexFromVertex, StopLocation transferStop) {
- return new FlexTripEdge(
+ protected FlexTripEdge getFlexEdge(Vertex flexFromVertex, StopLocation transferStop) {
+ return new FlexTripEdge<>(
flexFromVertex,
accessEgress.state.getVertex(),
transferStop,
diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ContinuousPickupDropOffTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ContinuousPickupDropOffTrip.java
new file mode 100644
index 00000000000..113d3f01511
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ContinuousPickupDropOffTrip.java
@@ -0,0 +1,61 @@
+package org.opentripplanner.ext.flex.trip;
+
+import org.opentripplanner.ext.flex.FlexServiceDate;
+import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator;
+import org.opentripplanner.ext.flex.template.FlexAccessTemplate;
+import org.opentripplanner.ext.flex.template.FlexEgressTemplate;
+import org.opentripplanner.model.StopLocation;
+import org.opentripplanner.model.StopTime;
+import org.opentripplanner.model.Trip;
+import org.opentripplanner.routing.graphfinder.NearbyStop;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.opentripplanner.model.StopPattern.PICKDROP_NONE;
+
+public class ContinuousPickupDropOffTrip extends FlexTrip {
+
+ public ContinuousPickupDropOffTrip(Trip trip, List stopTimes) {super(trip);}
+
+ public static boolean hasContinuousStops(List stopTimes) {
+ return stopTimes
+ .stream()
+ .anyMatch(st -> st.getFlexContinuousPickup() != PICKDROP_NONE || st.getFlexContinuousDropOff() != PICKDROP_NONE);
+ }
+
+ @Override
+ public Stream> getFlexAccessTemplates(
+ NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
+ ) {
+ return Stream.empty();
+ }
+
+ @Override
+ public Stream> getFlexEgressTemplates(
+ NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
+ ) {
+ return Stream.empty();
+ }
+
+ @Override
+ public int earliestDepartureTime(
+ int departureTime, Double fromStopIndex, Double toStopIndex, int flexTime
+ ) {
+ return departureTime;
+ }
+
+ @Override
+ public int latestArrivalTime(
+ int arrivalTime, Double fromStopIndex, Double toStopIndex, int flexTime
+ ) {
+ return arrivalTime;
+ }
+
+ @Override
+ public Collection getStops() {
+ return Collections.EMPTY_LIST;
+ }
+}
diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexTrip.java
index b0299819279..540b4cbf429 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/trip/FlexTrip.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/trip/FlexTrip.java
@@ -17,7 +17,7 @@
* subclasses encapsulates the different business logic, which the different types of services
* adhere to.
*/
-public abstract class FlexTrip extends TransitEntity {
+public abstract class FlexTrip extends TransitEntity {
protected final Trip trip;
@@ -26,17 +26,17 @@ public FlexTrip(Trip trip) {
this.trip = trip;
}
- public abstract Stream getFlexAccessTemplates(
- NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
+ public abstract Stream> getFlexAccessTemplates(
+ NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
);
- public abstract Stream getFlexEgressTemplates(
- NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
+ public abstract Stream> getFlexEgressTemplates(
+ NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
);
- public abstract int earliestDepartureTime(int departureTime, int fromStopIndex, int toStopIndex, int flexTime);
+ public abstract int earliestDepartureTime(int departureTime, T fromStopIndex, T toStopIndex, int flexTime);
- public abstract int latestArrivalTime(int arrivalTime, int fromStopIndex, int toStopIndex, int flexTime);
+ public abstract int latestArrivalTime(int arrivalTime, T fromStopIndex, T toStopIndex, int flexTime);
public abstract Collection getStops();
diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java
index cfa202eef4b..1c6c2245833 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java
@@ -29,7 +29,7 @@
* A scheduled deviated trip is similar to a regular scheduled trip, except that is continues stop
* locations, which are not stops, but other types, such as groups of stops or location areas.
*/
-public class ScheduledDeviatedTrip extends FlexTrip {
+public class ScheduledDeviatedTrip extends FlexTrip {
private final ScheduledDeviatedStopTime[] stopTimes;
@@ -57,21 +57,21 @@ public ScheduledDeviatedTrip(Trip trip, List stopTimes) {
}
@Override
- public Stream getFlexAccessTemplates(
- NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
+ public Stream> getFlexAccessTemplates(
+ NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
) {
- FlexPathCalculator scheduledCalculator = new ScheduledFlexPathCalculator(calculator, this);
+ FlexPathCalculator scheduledCalculator = new ScheduledFlexPathCalculator(calculator, this);
int fromIndex = getFromIndex(access);
if (fromIndex == -1) return Stream.empty();
- ArrayList res = new ArrayList<>();
+ ArrayList> res = new ArrayList<>();
for (int toIndex = fromIndex + 1; toIndex < stopTimes.length; toIndex++) {
if (stopTimes[toIndex].dropOffType == PICKDROP_NONE) continue;
for (StopLocation stop : expandStops(stopTimes[toIndex].stop)) {
- res.add(new FlexAccessTemplate(access, this, fromIndex, toIndex, stop, date, scheduledCalculator));
+ res.add(new FlexAccessTemplate<>(access, this, fromIndex, toIndex, stop, date, scheduledCalculator));
}
}
@@ -79,21 +79,21 @@ public Stream getFlexAccessTemplates(
}
@Override
- public Stream getFlexEgressTemplates(
- NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
+ public Stream> getFlexEgressTemplates(
+ NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
) {
- FlexPathCalculator scheduledCalculator = new ScheduledFlexPathCalculator(calculator, this);
+ FlexPathCalculator scheduledCalculator = new ScheduledFlexPathCalculator(calculator, this);
int toIndex = getToIndex(egress);
if (toIndex == -1) return Stream.empty();
- ArrayList res = new ArrayList<>();
+ ArrayList> res = new ArrayList<>();
for (int fromIndex = toIndex - 1; fromIndex >= 0; fromIndex--) {
if (stopTimes[fromIndex].pickupType == PICKDROP_NONE) continue;
for (StopLocation stop : expandStops(stopTimes[fromIndex].stop)) {
- res.add(new FlexEgressTemplate(egress, this, fromIndex, toIndex, stop, date, scheduledCalculator));
+ res.add(new FlexEgressTemplate<>(egress, this, fromIndex, toIndex, stop, date, scheduledCalculator));
}
}
@@ -102,7 +102,7 @@ public Stream getFlexEgressTemplates(
@Override
public int earliestDepartureTime(
- int departureTime, int fromStopIndex, int toStopIndex, int flexTime
+ int departureTime, Integer fromStopIndex, Integer toStopIndex, int flexTime
) {
int stopTime = MISSING_VALUE;
for (int i = fromStopIndex; stopTime == MISSING_VALUE && i >= 0; i--) {
@@ -112,7 +112,7 @@ public int earliestDepartureTime(
}
@Override
- public int latestArrivalTime(int arrivalTime, int fromStopIndex, int toStopIndex, int flexTime) {
+ public int latestArrivalTime(int arrivalTime, Integer fromStopIndex, Integer toStopIndex, int flexTime) {
int stopTime = MISSING_VALUE;
for (int i = toStopIndex; stopTime == MISSING_VALUE && i < stopTimes.length; i++) {
stopTime = stopTimes[i].arrivalTime;
diff --git a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java
index 05ea7174ee6..c2912942c29 100644
--- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java
+++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java
@@ -29,7 +29,7 @@
* on the driving time between the stops, with the schedule times being used just for deciding if a
* trip is possible.
*/
-public class UnscheduledTrip extends FlexTrip {
+public class UnscheduledTrip extends FlexTrip {
private static final int N_STOPS = 2;
private final UnscheduledStopTime[] stopTimes;
@@ -58,36 +58,36 @@ public UnscheduledTrip(Trip trip, List stopTimes) {
}
@Override
- public Stream getFlexAccessTemplates(
- NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
+ public Stream> getFlexAccessTemplates(
+ NearbyStop access, FlexServiceDate date, FlexPathCalculator calculator
) {
int fromIndex = getFromIndex(access);
if (fromIndex != 0) { return Stream.empty(); }
if (stopTimes[1].dropOffType == PICKDROP_NONE) { return Stream.empty(); }
- ArrayList res = new ArrayList<>();
+ ArrayList> res = new ArrayList<>();
for (StopLocation stop : expandStops(stopTimes[1].stop)) {
- res.add(new FlexAccessTemplate(access, this, fromIndex, 1, stop, date, calculator));
+ res.add(new FlexAccessTemplate<>(access, this, fromIndex, 1, stop, date, calculator));
}
return res.stream();
}
@Override
- public Stream getFlexEgressTemplates(
- NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
+ public Stream> getFlexEgressTemplates(
+ NearbyStop egress, FlexServiceDate date, FlexPathCalculator calculator
) {
int toIndex = getToIndex(egress);
if (toIndex != 1) { return Stream.empty(); }
if (stopTimes[0].pickupType == PICKDROP_NONE) { return Stream.empty(); }
- ArrayList res = new ArrayList<>();
+ ArrayList> res = new ArrayList<>();
for (StopLocation stop : expandStops(stopTimes[0].stop)) {
- res.add(new FlexEgressTemplate(egress, this, 0, toIndex, stop, date, calculator));
+ res.add(new FlexEgressTemplate<>(egress, this, 0, toIndex, stop, date, calculator));
}
return res.stream();
@@ -95,7 +95,7 @@ public Stream getFlexEgressTemplates(
@Override
public int earliestDepartureTime(
- int departureTime, int fromStopIndex, int toStopIndex, int flexTime
+ int departureTime, Integer fromStopIndex, Integer toStopIndex, int flexTime
) {
UnscheduledStopTime fromStopTime = stopTimes[fromStopIndex];
UnscheduledStopTime toStopTime = stopTimes[toStopIndex];
@@ -109,7 +109,7 @@ public int earliestDepartureTime(
}
@Override
- public int latestArrivalTime(int arrivalTime, int fromStopIndex, int toStopIndex, int flexTime) {
+ public int latestArrivalTime(int arrivalTime, Integer fromStopIndex, Integer toStopIndex, int flexTime) {
UnscheduledStopTime fromStopTime = stopTimes[fromStopIndex];
UnscheduledStopTime toStopTime = stopTimes[toStopIndex];
if (toStopTime.flexWindowStart > arrivalTime || fromStopTime.flexWindowStart > (
diff --git a/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java b/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java
index c0f0cdbf4cd..544936edbe1 100644
--- a/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java
+++ b/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java
@@ -221,6 +221,15 @@ public static GraphBuilder create(
// Add links to flex areas after the streets has been split, so that also the split edges are connected
if (OTPFeature.FlexRouting.isOn()) {
graphBuilder.addModule(new FlexLocationsToStreetEdgesMapper());
+ graphBuilder.addModule(new GraphBuilderModule() {
+ @Override
+ public void buildGraph(
+ Graph graph, HashMap, Object> extra,
+ DataImportIssueStore issueStore
+ ) { graph.flexSpeed = config.flexSpeed; }
+
+ @Override public void checkInputs() {}
+ });
}
// The stops can be linked to each other once they are already linked to the street network.
if ( ! config.useTransfersTxt) {
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/AddTransitModelEntitiesToGraph.java b/src/main/java/org/opentripplanner/graph_builder/module/AddTransitModelEntitiesToGraph.java
index 817d0a48817..fe15d4872f5 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/AddTransitModelEntitiesToGraph.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/AddTransitModelEntitiesToGraph.java
@@ -362,7 +362,7 @@ private void addTransfersToGraph(Graph graph) {
}
private void addFlexTripsToGraph(Graph graph) {
- for(FlexTrip flexTrip : transitService.getAllFlexTrips())
+ for(FlexTrip> flexTrip : transitService.getAllFlexTrips())
graph.flexTripsById.put(flexTrip.getId(), flexTrip);
}
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
index 528056bf318..7a52ec9095d 100644
--- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
@@ -28,6 +28,13 @@ public class GTFSToOtpTransitServiceMapper {
private final BoardingAreaMapper boardingAreaMapper = new BoardingAreaMapper();
+ private final LocationMapper locationMapper = new LocationMapper();
+
+ private final LocationGroupMapper locationGroupMapper = new LocationGroupMapper(
+ stopMapper,
+ locationMapper
+ );
+
private final FareAttributeMapper fareAttributeMapper = new FareAttributeMapper();
private final ServiceCalendarDateMapper serviceCalendarDateMapper = new ServiceCalendarDateMapper();
@@ -65,7 +72,7 @@ public class GTFSToOtpTransitServiceMapper {
agencyMapper = new AgencyMapper(feedId);
routeMapper = new RouteMapper(agencyMapper);
tripMapper = new TripMapper(routeMapper);
- stopTimeMapper = new StopTimeMapper(stopMapper, tripMapper);
+ stopTimeMapper = new StopTimeMapper(stopMapper, locationMapper, locationGroupMapper, tripMapper);
frequencyMapper = new FrequencyMapper(tripMapper);
transferMapper = new TransferMapper(
routeMapper, stationMapper, stopMapper, tripMapper
@@ -101,6 +108,8 @@ private OtpTransitServiceBuilder map(GtfsRelationalDao data) {
mapGtfsStopsToOtpTypes(data, builder);
+ builder.getLocations().addAll(locationMapper.map(data.getAllLocations()));
+ builder.getLocationGroups().addAll(locationGroupMapper.map(data.getAllLocationGroups()));
builder.getPathways().addAll(pathwayMapper.map(data.getAllPathways()));
builder.getStopTimesSortedByTrip().addAll(stopTimeMapper.map(data.getAllStopTimes()));
builder.getTransfers().addAll(transferMapper.map(data.getAllTransfers()));
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java
new file mode 100644
index 00000000000..1da0a6a2e4a
--- /dev/null
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java
@@ -0,0 +1,60 @@
+package org.opentripplanner.gtfs.mapping;
+
+import org.opentripplanner.model.FlexLocationGroup;
+import org.opentripplanner.util.MapUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.opentripplanner.gtfs.mapping.AgencyAndIdMapper.mapAgencyAndId;
+
+public class LocationGroupMapper {
+ private static Logger LOG = LoggerFactory.getLogger(LocationGroupMapper.class);
+
+ private final StopMapper stopMapper;
+
+ private final LocationMapper locationMapper;
+
+ private final Map mappedLocationGroups = new HashMap<>();
+
+ public LocationGroupMapper(StopMapper stopMapper, LocationMapper locationMapper) {
+ this.stopMapper = stopMapper;
+ this.locationMapper = locationMapper;
+ }
+
+ Collection map(Collection allLocationGroups) {
+ return MapUtils.mapToList(allLocationGroups, this::map);
+ }
+
+ /** Map from GTFS to OTP model, {@code null} safe. */
+ FlexLocationGroup map(org.onebusaway.gtfs.model.LocationGroup orginal) {
+ return orginal == null ? null : mappedLocationGroups.computeIfAbsent(orginal, this::doMap);
+ }
+
+ private FlexLocationGroup doMap(org.onebusaway.gtfs.model.LocationGroup element) {
+ FlexLocationGroup locationGroup;
+
+ locationGroup = new FlexLocationGroup(mapAgencyAndId(element.getId()));
+ locationGroup.setName(element.getName());
+
+ for (org.onebusaway.gtfs.model.Stoplike location : element.getLocations()) {
+ if (location instanceof org.onebusaway.gtfs.model.Stop) {
+ locationGroup.addLocation(stopMapper.map((org.onebusaway.gtfs.model.Stop) location));
+ }
+ else if (location instanceof org.onebusaway.gtfs.model.Location) {
+ locationGroup.addLocation(locationMapper.map((org.onebusaway.gtfs.model.Location) location));
+ }
+ else if (location instanceof org.onebusaway.gtfs.model.LocationGroup) {
+ throw new RuntimeException("Nested LocationGroups are not allowed");
+ }
+ else {
+ throw new RuntimeException("Unknown location type");
+ }
+ }
+
+ return locationGroup;
+ }
+}
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/LocationMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/LocationMapper.java
new file mode 100644
index 00000000000..d3e17d02f0b
--- /dev/null
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/LocationMapper.java
@@ -0,0 +1,44 @@
+package org.opentripplanner.gtfs.mapping;
+
+import org.opentripplanner.common.geometry.GeometryUtils;
+import org.opentripplanner.common.geometry.UnsupportedGeometryException;
+import org.opentripplanner.model.FlexStopLocation;
+import org.opentripplanner.util.MapUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.opentripplanner.gtfs.mapping.AgencyAndIdMapper.mapAgencyAndId;
+
+/** Responsible for mapping GTFS Location into the OTP model. */
+public class LocationMapper {
+ private static Logger LOG = LoggerFactory.getLogger(LocationMapper.class);
+
+ private Map mappedLocations = new HashMap<>();
+
+ Collection map(Collection allLocations) {
+ return MapUtils.mapToList(allLocations, this::map);
+ }
+
+ /** Map from GTFS to OTP model, {@code null} safe. */
+ FlexStopLocation map(org.onebusaway.gtfs.model.Location orginal) {
+ return orginal == null ? null : mappedLocations.computeIfAbsent(orginal, this::doMap);
+ }
+
+ private FlexStopLocation doMap(org.onebusaway.gtfs.model.Location gtfsLocation) {
+ FlexStopLocation otpLocation = new FlexStopLocation(mapAgencyAndId(gtfsLocation.getId()));
+
+ otpLocation.setName(gtfsLocation.getName());
+ try {
+ otpLocation.setGeometry(GeometryUtils.convertGeoJsonToJtsGeometry(gtfsLocation.getGeometry()));
+ }
+ catch (UnsupportedGeometryException e) {
+ LOG.warn("Unsupported geometry type for " + gtfsLocation.getId());
+ }
+
+ return otpLocation;
+ }
+}
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java
index 56c408cb567..6f752a4b80f 100644
--- a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java
@@ -1,5 +1,8 @@
package org.opentripplanner.gtfs.mapping;
+import org.onebusaway.gtfs.model.Location;
+import org.onebusaway.gtfs.model.LocationGroup;
+import org.onebusaway.gtfs.model.Stop;
import org.opentripplanner.model.StopTime;
import org.opentripplanner.util.MapUtils;
@@ -13,12 +16,23 @@
class StopTimeMapper {
private final StopMapper stopMapper;
+ private final LocationMapper locationMapper;
+
+ private final LocationGroupMapper locationGroupMapper;
+
private final TripMapper tripMapper;
- private Map mappedStopTimes = new HashMap<>();
+ private final Map mappedStopTimes = new HashMap<>();
- StopTimeMapper(StopMapper stopMapper, TripMapper tripMapper) {
+ StopTimeMapper(
+ StopMapper stopMapper,
+ LocationMapper locationMapper,
+ LocationGroupMapper locationGroupMapper,
+ TripMapper tripMapper
+ ) {
this.stopMapper = stopMapper;
+ this.locationMapper = locationMapper;
+ this.locationGroupMapper = locationGroupMapper;
this.tripMapper = tripMapper;
}
@@ -35,7 +49,13 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) {
StopTime lhs = new StopTime();
lhs.setTrip(tripMapper.map(rhs.getTrip()));
- lhs.setStop(stopMapper.map(rhs.getStop()));
+ if (rhs.getStop() instanceof Stop){
+ lhs.setStop(stopMapper.map((Stop) rhs.getStop()));
+ } else if (rhs.getStop() instanceof Location) {
+ lhs.setStop(locationMapper.map((Location) rhs.getStop()));
+ } else if (rhs.getStop() instanceof LocationGroup) {
+ lhs.setStop(locationGroupMapper.map((LocationGroup) rhs.getStop()));
+ }
lhs.setArrivalTime(rhs.getArrivalTime());
lhs.setDepartureTime(rhs.getDepartureTime());
lhs.setTimepoint(rhs.getTimepoint());
@@ -46,6 +66,10 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) {
lhs.setDropOffType(rhs.getDropOffType());
lhs.setShapeDistTraveled(rhs.getShapeDistTraveled());
lhs.setFarePeriodId(rhs.getFarePeriodId());
+ lhs.setFlexWindowStart(rhs.getMinArrivalTime());
+ lhs.setFlexWindowEnd(rhs.getMaxDepartureTime());
+ lhs.setFlexContinuousPickup(rhs.getContinuousPickup());
+ lhs.setFlexContinuousDropOff(rhs.getContinuousDropOff());
// Skip mapping of proxy
// private transient StopTimeProxy proxy;
diff --git a/src/main/java/org/opentripplanner/model/OtpTransitService.java b/src/main/java/org/opentripplanner/model/OtpTransitService.java
index 0e5b67be09b..58c6de3d22d 100644
--- a/src/main/java/org/opentripplanner/model/OtpTransitService.java
+++ b/src/main/java/org/opentripplanner/model/OtpTransitService.java
@@ -76,5 +76,5 @@ public interface OtpTransitService {
Collection getAllTrips();
- Collection getAllFlexTrips();
+ Collection> getAllFlexTrips();
}
diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
index dab58fd5a2c..ceae9aa5b48 100644
--- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
+++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
@@ -105,7 +105,7 @@ public class OtpTransitServiceBuilder {
private final Multimap tripPatterns = ArrayListMultimap.create();
- private final EntityById flexTripsById = new EntityById<>();
+ private final EntityById> flexTripsById = new EntityById<>();
public OtpTransitServiceBuilder() {
}
@@ -218,7 +218,7 @@ public Multimap getTripPatterns() {
return tripPatterns;
}
- public EntityById getFlexTripsById() {
+ public EntityById> getFlexTripsById() {
return flexTripsById;
}
diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceImpl.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceImpl.java
index 739244b311b..fd2b9f1a460 100644
--- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceImpl.java
+++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceImpl.java
@@ -93,7 +93,7 @@ class OtpTransitServiceImpl implements OtpTransitService {
private final Collection trips;
- private final Collection flexTrips;
+ private final Collection> flexTrips;
/**
* Create a read only version of the {@link OtpTransitService}.
@@ -249,7 +249,7 @@ public Collection getAllTrips() {
}
@Override
- public Collection getAllFlexTrips() {
+ public Collection> getAllFlexTrips() {
return flexTrips;
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java
index 92d25f5cc56..6c9275184c1 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java
@@ -40,6 +40,8 @@
import java.util.List;
import java.util.TimeZone;
+import static org.opentripplanner.routing.algorithm.mapping.GraphPathToItineraryMapper.getBoardAlightMessage;
+
/**
* This maps the paths found by the Raptor search algorithm to the itinerary structure currently used by OTP. The paths,
* access/egress transfers and transit layer only contains the minimal information needed for routing. Additional
@@ -185,8 +187,9 @@ private Leg mapTransitLeg(
// where you are really boarding or alighting (considering interlining / in-seat transfers).
// That needs to be re-implemented for the Raptor transit case.
// - See e2118e0a -> GraphPathToTripPlanConverter#fixupLegs(List, State[][]))
- // leg.alightRule = ;
- // leg.boardRule = ;
+ TripPattern tripPattern = tripSchedule.getOriginalTripPattern();
+ leg.alightRule = getBoardAlightMessage(tripPattern.getAlightType(alightStopIndexInPattern));
+ leg.boardRule = getBoardAlightMessage(tripPattern.getBoardType(boardStopIndexInPattern));
AlertToLegMapper.addAlertPatchesToLeg(
request.getRoutingContext().graph,
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
index 5e98aa8db36..725d275bff4 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
@@ -38,7 +38,7 @@ public List mapNearbyStops(Collection accessStops, boo
}
public Collection mapFlexAccessEgresses(
- Collection flexAccessEgresses
+ Collection> flexAccessEgresses
) {
return flexAccessEgresses.stream()
.map(flexAccessEgress -> new FlexAccessEgressAdapter(flexAccessEgress, stopIndex))
diff --git a/src/main/java/org/opentripplanner/routing/graph/Graph.java b/src/main/java/org/opentripplanner/routing/graph/Graph.java
index 2247c63ba33..9e3e1fbcadc 100644
--- a/src/main/java/org/opentripplanner/routing/graph/Graph.java
+++ b/src/main/java/org/opentripplanner/routing/graph/Graph.java
@@ -245,7 +245,10 @@ public class Graph implements Serializable {
public Map locationGroupsById = new HashMap<>();
- public Map flexTripsById = new HashMap<>();
+ public Map> flexTripsById = new HashMap<>();
+
+ /** Speed in m/s for flex trips without a time multiplier */
+ public double flexSpeed;
/** The distance between elevation samples used in CompactElevationProfile. */
private double distanceBetweenElevationSamples;
diff --git a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java
index d46994156dd..b694ac93b3e 100644
--- a/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java
+++ b/src/main/java/org/opentripplanner/standalone/config/BuildConfig.java
@@ -277,6 +277,9 @@ public class BuildConfig {
*/
public LocalDate transitServiceEnd;
+ /** Speed in m/s for flex trips without a time multiplier */
+ public double flexSpeed;
+
/**
* Netex specific build parameters.
*/
@@ -337,6 +340,7 @@ public BuildConfig(JsonNode node, String source, boolean logUnusedParams) {
transitServiceEnd = c.asDateOrRelativePeriod( "transitServiceEnd", "P3Y");
useTransfersTxt = c.asBoolean("useTransfersTxt", false);
writeCachedElevations = c.asBoolean("writeCachedElevations", false);
+ flexSpeed = c.asDouble("flexSpeed", 6.0);
// List of complex parameters
fareServiceFactory = DefaultFareServiceFactory.fromConfig(c.asRawNode("fares"));
diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java
index 93b2d023120..167935f105f 100644
--- a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java
+++ b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java
@@ -68,8 +68,15 @@ public class StopTimesMapperTest {
STOP_TIME.setTrip(TRIP);
}
+ private final StopMapper stopMapper = new StopMapper();
+ private final LocationMapper locationMapper = new LocationMapper();
+ private final LocationGroupMapper locationGroupMapper = new LocationGroupMapper(stopMapper, locationMapper);
+
private final StopTimeMapper subject = new StopTimeMapper(
- new StopMapper(), new TripMapper(new RouteMapper(new AgencyMapper(FEED_ID)))
+ stopMapper,
+ locationMapper,
+ locationGroupMapper,
+ new TripMapper(new RouteMapper(new AgencyMapper(FEED_ID)))
);
@Test