Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Flex continuous stops implementation #3457

Draft
wants to merge 5 commits into
base: dev-2.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
import org.opentripplanner.model.Stop;
import org.opentripplanner.routing.core.State;

public class FlexAccessEgress {
public class FlexAccessEgress<T> {
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<T> trip;
public final State lastState;
public final boolean directToStop;

Expand All @@ -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<T> trip,
State lastState,
boolean directToStop
) {
Expand Down
8 changes: 4 additions & 4 deletions src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
public class FlexIndex {
public Multimap<StopLocation, SimpleTransfer> transfersToStop = ArrayListMultimap.create();

public Multimap<StopLocation, FlexTrip> flexTripsByStop = HashMultimap.create();
public Multimap<StopLocation, FlexTrip<?>> flexTripsByStop = HashMultimap.create();

public Multimap<StopLocation, FlexLocationGroup> locationGroupsByStop = ArrayListMultimap.create();

public HashGridSpatialIndex<FlexStopLocation> locationIndex = new HashGridSpatialIndex<FlexStopLocation>();
public HashGridSpatialIndex<FlexStopLocation> locationIndex = new HashGridSpatialIndex<>();

public Map<FeedScopedId, Route> routeById = new HashMap<>();

Expand All @@ -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()) {
Expand All @@ -58,7 +58,7 @@ public FlexIndex(Graph graph) {
}
}

Stream<FlexTrip> getFlexTripsByStop(StopLocation stopLocation) {
Stream<FlexTrip<?>> getFlexTripsByStop(StopLocation stopLocation) {
return flexTripsByStop.get(stopLocation).stream();
}
}
10 changes: 7 additions & 3 deletions src/ext/java/org/opentripplanner/ext/flex/FlexLegMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
21 changes: 10 additions & 11 deletions src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.opentripplanner.common.model.T2;
import org.opentripplanner.ext.flex.flexpathcalculator.DirectFlexPathCalculator;
import org.opentripplanner.ext.flex.flexpathcalculator.FlexPathCalculator;
import org.opentripplanner.ext.flex.flexpathcalculator.StreetFlexPathCalculator;
import org.opentripplanner.ext.flex.template.FlexAccessTemplate;
Expand Down Expand Up @@ -37,7 +36,7 @@ public class FlexRouter {
private final Collection<NearbyStop> streetAccesses;
private final Collection<NearbyStop> streetEgresses;
private final FlexIndex flexIndex;
private final FlexPathCalculator flexPathCalculator;
private final FlexPathCalculator<Integer> flexPathCalculator;

/* Request data */
private final ZonedDateTime startOfTime;
Expand All @@ -47,8 +46,8 @@ public class FlexRouter {
private final FlexServiceDate[] dates;

/* State */
private List<FlexAccessTemplate> flexAccessTemplates = null;
private List<FlexEgressTemplate> flexEgressTemplates = null;
private List<FlexAccessTemplate<?>> flexAccessTemplates = null;
private List<FlexEgressTemplate<?>> flexEgressTemplates = null;

public FlexRouter(
Graph graph,
Expand Down Expand Up @@ -98,7 +97,7 @@ public Collection<Itinerary> createFlexOnlyItineraries() {

Collection<Itinerary> 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)) {
Expand All @@ -113,7 +112,7 @@ public Collection<Itinerary> createFlexOnlyItineraries() {
return itineraries;
}

public Collection<FlexAccessEgress> createFlexAccesses() {
public Collection<FlexAccessEgress<?>> createFlexAccesses() {
calculateFlexAccessTemplates();

return this.flexAccessTemplates
Expand All @@ -122,7 +121,7 @@ public Collection<FlexAccessEgress> createFlexAccesses() {
.collect(Collectors.toList());
}

public Collection<FlexAccessEgress> createFlexEgresses() {
public Collection<FlexAccessEgress<?>> createFlexEgresses() {
calculateFlexEgressTemplates();

return this.flexEgressTemplates
Expand Down Expand Up @@ -156,19 +155,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<T2<NearbyStop, FlexTrip>> getClosestFlexTrips(Collection<NearbyStop> nearbyStops) {
private Stream<T2<NearbyStop, FlexTrip<?>>> getClosestFlexTrips(Collection<NearbyStop> nearbyStops) {
// Find all trips reachable from the nearbyStops
Stream<T2<NearbyStop, FlexTrip>> flexTripsReachableFromNearbyStops = nearbyStops
Stream<T2<NearbyStop, FlexTrip<?>>> flexTripsReachableFromNearbyStops = nearbyStops
.stream()
.flatMap(accessEgress -> flexIndex
.getFlexTripsByStop(accessEgress.stop)
.map(flexTrip -> new T2<>(accessEgress, flexTrip)));

// Group all (NearbyStop, FlexTrip) tuples by flexTrip
Collection<List<T2<NearbyStop, FlexTrip>>> groupedReachableFlexTrips = flexTripsReachableFromNearbyStops
Collection<List<T2<NearbyStop, FlexTrip<?>>>> groupedReachableFlexTrips = flexTripsReachableFromNearbyStops
.collect(Collectors.groupingBy(t2 -> t2.second))
.values();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class FlexServiceDate {
this.servicesRunning = servicesRunning;
}

boolean isFlexTripRunning(FlexTrip flexTrip, Graph graph) {
boolean isFlexTripRunning(FlexTrip<?> flexTrip, Graph graph) {
return servicesRunning != null
&& servicesRunning.contains(graph.getServiceCodes().get(flexTrip.getTrip().getServiceId()));
}
Expand Down
27 changes: 17 additions & 10 deletions src/ext/java/org/opentripplanner/ext/flex/FlexTripsMapper.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package org.opentripplanner.ext.flex;

import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.ext.flex.trip.ContinuousPickupDropOffTrip;
import org.opentripplanner.ext.flex.trip.ScheduledDeviatedTrip;
import org.opentripplanner.ext.flex.trip.UnscheduledTrip;
import org.opentripplanner.graph_builder.module.map.StreetMatcher;
import org.opentripplanner.model.StopTime;
import org.opentripplanner.model.TripStopTimes;
import org.opentripplanner.model.impl.OtpTransitServiceBuilder;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.util.ProgressTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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<FlexTrip> createFlexTrips(OtpTransitServiceBuilder builder) {
List<FlexTrip> result = new ArrayList<>();
static public List<FlexTrip<?>> createFlexTrips(OtpTransitServiceBuilder builder) {
List<FlexTrip<?>> result = new ArrayList<>();
TripStopTimes stopTimesByTrip = builder.getStopTimesSortedByTrip();

final int tripSize = stopTimesByTrip.size();
Expand All @@ -38,8 +39,8 @@ static public List<FlexTrip> 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
Expand All @@ -51,10 +52,16 @@ static public List<FlexTrip> createFlexTrips(OtpTransitServiceBuilder builder) {
return result;
}

private static boolean hasContinuousStops(List<StopTime> stopTimes) {
return stopTimes
public static void addGeometriesToContinuousStops(Graph graph) {
graph.index();

StreetMatcher matcher = new StreetMatcher(graph);

graph.flexTripsById
.values()
.stream()
.anyMatch(st -> st.getFlexContinuousPickup() != PICKDROP_NONE || st.getFlexContinuousDropOff() != PICKDROP_NONE);
.filter(ContinuousPickupDropOffTrip.class::isInstance)
.map(ContinuousPickupDropOffTrip.class::cast)
.forEach(continuousPickupDropOffTrip -> continuousPickupDropOffTrip.addGeometries(graph, matcher));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@

import java.util.Locale;

public class FlexTripEdge extends Edge {
public class FlexTripEdge<T> extends Edge {

private static final Logger LOG = LoggerFactory.getLogger(FlexTripEdge.class);

private static final long serialVersionUID = 1L;

public StopLocation s1;
public StopLocation s2;
private FlexTrip trip;
public FlexAccessEgressTemplate flexTemplate;
private final FlexTrip<T> trip;
public FlexAccessEgressTemplate<T> 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<T> trip,
FlexAccessEgressTemplate<T> flexTemplate, FlexPathCalculator<T> 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.opentripplanner.ext.flex.flexpathcalculator;

import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.ext.flex.trip.ContinuousPickupDropOffTrip;
import org.opentripplanner.routing.graph.Vertex;

public class ContinuousStopsFlexPathCalculator implements FlexPathCalculator<Double> {

private final ContinuousPickupDropOffTrip trip;

public ContinuousStopsFlexPathCalculator(ContinuousPickupDropOffTrip trip) {
this.trip = trip;
}

@Override
public FlexPath calculateFlexPath(
Vertex fromv, Vertex tov, Double fromStopIndex, Double toStopIndex
) {
int distance = 0;
int departureTime = trip.earliestDepartureTime(Integer.MIN_VALUE, fromStopIndex, toStopIndex, 0);
int arrivalTime = trip.latestArrivalTime(Integer.MAX_VALUE, fromStopIndex, toStopIndex, 0);

if (departureTime >= arrivalTime) return null;
//TODO: Generate geometry from edges
Copy link

@amenk amenk Oct 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by this TODO? Does this mean it is currently generating a straight line between to regular stops and has still to be aligned with the shape ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it calculates a direct path to the following stop

return new FlexPath(
distance,
arrivalTime - departureTime,
GeometryUtils.makeLineString(fromv.getLon(), fromv.getLat(), tov.getLon(), tov.getLat())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,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<Integer> {
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;
}

@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());
LineString geometry = GeometryUtils.getGeometryFactory().createLineString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
/**
* FlexPathCalculator is used to calculate the driving times and distances during flex routing
*/
public interface FlexPathCalculator {
public interface FlexPathCalculator<T> {

@Nullable
FlexPath calculateFlexPath(Vertex fromv, Vertex tov, int fromStopIndex, int toStopIndex);
FlexPath calculateFlexPath(Vertex fromv, Vertex tov, T fromStopIndex, T toStopIndex);

}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Integer> {
private final FlexPathCalculator<Integer> flexPathCalculator;
private final FlexTrip<Integer> trip;

public ScheduledFlexPathCalculator(FlexPathCalculator flexPathCalculator, FlexTrip trip) {
public ScheduledFlexPathCalculator(FlexPathCalculator<Integer> flexPathCalculator, FlexTrip<Integer> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* Subsequents requests from the same fromVertex can fetch the path to the toVertex from the
* existing ShortestPathTree. This one-to-many approach is needed to make the performance acceptable.
*/
public class StreetFlexPathCalculator implements FlexPathCalculator {
public class StreetFlexPathCalculator implements FlexPathCalculator<Integer> {

private static final long MAX_FLEX_TRIP_DURATION_SECONDS = Duration.ofMinutes(45).toSeconds();

Expand All @@ -35,7 +35,7 @@ public StreetFlexPathCalculator(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) {

ShortestPathTree shortestPathTree;
if (cache.containsKey(fromv)) {
Expand Down
Loading