Skip to content

Commit

Permalink
feature: Support for min-booking-notice and latest-booking-time
Browse files Browse the repository at this point in the history
  • Loading branch information
t2gran committed May 28, 2024
1 parent ab83cdf commit e64c957
Show file tree
Hide file tree
Showing 20 changed files with 308 additions and 288 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.test.support.ResourceLoader;
import org.opentripplanner.transit.model.framework.Deduplicator;
import org.opentripplanner.transit.model.timetable.booking.RoutingBookingInfo;
import org.opentripplanner.transit.service.StopModel;
import org.opentripplanner.transit.service.TransitModel;

Expand All @@ -39,6 +40,7 @@ public final class FlexIntegrationTestData {
public static final FlexServiceDate FLEX_DATE = new FlexServiceDate(
SERVICE_DATE,
SECONDS_SINCE_MIDNIGHT,
RoutingBookingInfo.NOT_SET,
new TIntHashSet()
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.timetable.Trip;
import org.opentripplanner.transit.model.timetable.booking.RoutingBookingInfo;

class FlexTemplateFactoryTest {

Expand Down Expand Up @@ -61,6 +62,7 @@ class FlexTemplateFactoryTest {
private static final FlexServiceDate DATE = new FlexServiceDate(
LocalDate.of(2024, Month.MAY, 17),
SERVICE_TIME_OFFSET,
RoutingBookingInfo.NOT_SET,
new TIntHashSet()
);

Expand Down Expand Up @@ -101,7 +103,7 @@ void testCreateAccessTemplateForUnscheduledTripWithTwoStopsAndNoBoardRestriction
assertEquals(1, template.toStopIndex);
assertSame(CALCULATOR, template.calculator);
assertSame(STOP_B, template.transferStop);
assertSame(DATE.serviceDate, template.serviceDate);
assertSame(DATE.serviceDate(), template.serviceDate);
assertEquals(SERVICE_TIME_OFFSET, template.secondsFromStartOfTime);
assertEquals(1, subject.size(), subject::toString);

Expand Down Expand Up @@ -133,7 +135,7 @@ void testCreateEgressTemplateForUnscheduledTripWithTwoStopsAndNoBoardRestriction
assertEquals(1, template.toStopIndex);
assertSame(CALCULATOR, template.calculator);
assertSame(STOP_A, template.transferStop);
assertSame(DATE.serviceDate, template.serviceDate);
assertSame(DATE.serviceDate(), template.serviceDate);
assertEquals(SERVICE_TIME_OFFSET, template.secondsFromStartOfTime);
assertEquals(1, subject.size(), subject::toString);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void calculateDirectFare() {
new DefaultTransitService(transitModel),
FlexParameters.defaultValues(),
OffsetDateTime.parse("2021-11-12T10:15:24-05:00").toInstant(),
null,
1,
1,
List.of(from),
Expand Down
64 changes: 40 additions & 24 deletions src/ext/java/org/opentripplanner/ext/flex/FlexAccessEgress.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import static org.opentripplanner.model.StopTime.MISSING_VALUE;

import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nullable;
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.framework.time.TimeUtils;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.street.search.state.State;
import org.opentripplanner.transit.model.site.RegularStop;
Expand All @@ -20,8 +19,7 @@ public final class FlexAccessEgress {
private final FlexTrip<?, ?> trip;
private final State lastState;
private final boolean stopReachedOnBoard;

@Nullable
private final int requestedBookingTime;
private final RoutingBookingInfo routingBookingInfo;

public FlexAccessEgress(
Expand All @@ -31,7 +29,8 @@ public FlexAccessEgress(
int toStopIndex,
FlexTrip<?, ?> trip,
State lastState,
boolean stopReachedOnBoard
boolean stopReachedOnBoard,
int requestedBookingTime
) {
this.stop = stop;
this.pathDurations = pathDurations;
Expand All @@ -40,7 +39,8 @@ public FlexAccessEgress(
this.trip = Objects.requireNonNull(trip);
this.lastState = lastState;
this.stopReachedOnBoard = stopReachedOnBoard;
this.routingBookingInfo = createRoutingBookingInfo().orElse(null);
this.routingBookingInfo = createRoutingBookingInfo();
this.requestedBookingTime = requestedBookingTime;
}

public RegularStop stop() {
Expand All @@ -56,41 +56,61 @@ public boolean stopReachedOnBoard() {
}

public int earliestDepartureTime(int departureTime) {
int requestedDepartureTime = pathDurations.mapToFlexTripDepartureTime(departureTime);
int tripDepartureTime = pathDurations.mapToFlexTripDepartureTime(departureTime);

int tmp = tripDepartureTime;
tripDepartureTime =
routingBookingInfo.earliestDepartureTime(requestedBookingTime, tripDepartureTime);

if (tmp != tripDepartureTime) {
System.out.println("departure time ....... : " + TimeUtils.timeToStrLong(tmp));
System.out.println("min notice dep.time .. : " + TimeUtils.timeToStrLong(tripDepartureTime));
}

int earliestDepartureTime = trip.earliestDepartureTime(
requestedDepartureTime,
tripDepartureTime,
fromStopIndex,
toStopIndex,
pathDurations.trip()
);
if (earliestDepartureTime == MISSING_VALUE) {
return MISSING_VALUE;
}
/*
if (
!routingBookingInfo.isThereEnoughTimeToBookForDeparture(
earliestDepartureTime,
requestedBookingTime
)
) {
return MISSING_VALUE;
}
*/
return pathDurations.mapToRouterDepartureTime(earliestDepartureTime);
}

public int latestArrivalTime(int arrivalTime) {
int requestedArrivalTime = pathDurations.mapToFlexTripArrivalTime(arrivalTime);
int tripArrivalTime = pathDurations.mapToFlexTripArrivalTime(arrivalTime);
int latestArrivalTime = trip.latestArrivalTime(
requestedArrivalTime,
tripArrivalTime,
fromStopIndex,
toStopIndex,
pathDurations.trip()
);
if (latestArrivalTime == MISSING_VALUE) {
return MISSING_VALUE;
}
if (
routingBookingInfo.exceedsMinimumBookingNotice(
latestArrivalTime - pathDurations.trip(),
requestedBookingTime
)
) {
return MISSING_VALUE;
}
return pathDurations.mapToRouterArrivalTime(latestArrivalTime);
}

/**
* Return routing booking info for the boarding stop. Empty, if there are not any
* booking restrictions, witch applies to routing.
*/
public Optional<RoutingBookingInfo> routingBookingInfo() {
return Optional.ofNullable(routingBookingInfo);
}

@Override
public String toString() {
return ToStringBuilder
Expand All @@ -105,14 +125,10 @@ public String toString() {
.toString();
}

private Optional<RoutingBookingInfo> createRoutingBookingInfo() {
var bookingInfo = trip.getPickupBookingInfo(fromStopIndex);
if (bookingInfo == null) {
return Optional.empty();
}
private RoutingBookingInfo createRoutingBookingInfo() {
return RoutingBookingInfo
.of()
.withBookingInfo(bookingInfo)
.withBookingInfo(trip.getPickupBookingInfo(fromStopIndex))
.withLegDurationInSeconds(pathDurations.total())
.withTimeOffsetInSeconds(pathDurations.access())
.build();
Expand Down
17 changes: 13 additions & 4 deletions src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.opentripplanner.street.model.vertex.TransitStopVertex;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.timetable.booking.RoutingBookingInfo;
import org.opentripplanner.transit.service.TransitService;

public class FlexRouter {
Expand All @@ -47,14 +48,16 @@ public class FlexRouter {

/* Request data */
private final ZonedDateTime startOfTime;
private final int departureTime;
private final int requestedTime;
private final int requestedBookingTime;
private final List<FlexServiceDate> dates;

public FlexRouter(
Graph graph,
TransitService transitService,
FlexParameters flexParameters,
Instant requestedTime,
Instant requestedBookingTime,
int additionalPastSearchDays,
int additionalFutureSearchDays,
Collection<NearbyStop> streetAccesses,
Expand Down Expand Up @@ -89,7 +92,11 @@ public FlexRouter(
ZoneId tz = transitService.getTimeZone();
LocalDate searchDate = LocalDate.ofInstant(requestedTime, tz);
this.startOfTime = ServiceDateUtils.asStartOfService(searchDate, tz);
this.departureTime = ServiceDateUtils.secondsSinceStartOfTime(startOfTime, requestedTime);
this.requestedTime = ServiceDateUtils.secondsSinceStartOfTime(startOfTime, requestedTime);
this.requestedBookingTime =
requestedBookingTime == null
? RoutingBookingInfo.NOT_SET
: ServiceDateUtils.secondsSinceStartOfTime(startOfTime, requestedBookingTime);
this.dates =
createFlexServiceDates(
transitService,
Expand All @@ -108,7 +115,7 @@ public List<Itinerary> createFlexOnlyItineraries(boolean arriveBy) {
egressFlexPathCalculator,
flexParameters.maxTransferDuration()
)
.calculateDirectFlexPaths(streetAccesses, streetEgresses, dates, departureTime, arriveBy);
.calculateDirectFlexPaths(streetAccesses, streetEgresses, dates, requestedTime, arriveBy);

var itineraries = new ArrayList<Itinerary>();

Expand Down Expand Up @@ -161,6 +168,7 @@ private List<FlexServiceDate> createFlexServiceDates(
new FlexServiceDate(
date,
ServiceDateUtils.secondsSinceStartOfTime(startOfTime, date),
requestedBookingTime,
transitService.getServiceCodesRunningForDate(date)
)
);
Expand Down Expand Up @@ -198,7 +206,8 @@ public Collection<PathTransfer> getTransfersToStop(StopLocation stop) {

@Override
public boolean isDateActive(FlexServiceDate date, FlexTrip<?, ?> trip) {
return date.isFlexTripRunning(trip, transitService);
int serviceCode = transitService.getServiceCodeForId(trip.getTrip().getServiceId());
return date.isTripServiceRunning(serviceCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ abstract class AbstractFlexTemplate {
protected final StopLocation transferStop;
protected final int secondsFromStartOfTime;
public final LocalDate serviceDate;
protected final int requestedBookingTime;
protected final FlexPathCalculator calculator;
private final Duration maxTransferDuration;

Expand Down Expand Up @@ -77,8 +78,9 @@ abstract class AbstractFlexTemplate {
this.fromStopIndex = boardStopPosition;
this.toStopIndex = alightStopPosition;
this.transferStop = transferStop;
this.secondsFromStartOfTime = date.secondsFromStartOfTime;
this.serviceDate = date.serviceDate;
this.secondsFromStartOfTime = date.secondsFromStartOfTime();
this.serviceDate = date.serviceDate();
this.requestedBookingTime = date.requestedBookingTime();
this.calculator = calculator;
this.maxTransferDuration = maxTransferDuration;
}
Expand Down Expand Up @@ -210,7 +212,8 @@ private FlexAccessEgress createFlexAccessEgress(
toStopIndex,
trip,
finalState,
transferEdges.isEmpty()
transferEdges.isEmpty(),
requestedBookingTime
);
})
.orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.opentripplanner.ext.flex.trip.FlexTrip;
import org.opentripplanner.framework.lang.IntUtils;
import org.opentripplanner.routing.graphfinder.NearbyStop;
import org.opentripplanner.transit.model.timetable.booking.RoutingBookingInfo;

/**
* The combination of the closest stop, trip and trip active date.
Expand Down Expand Up @@ -54,7 +55,7 @@ static Collection<ClosestTrip> of(
boolean pickup
) {
var closestTrips = findAllTripsReachableFromNearbyStop(callbackService, nearbyStops, pickup);
return findActiveDatesForTripAndDecorateResult(callbackService, dates, closestTrips);
return findActiveDatesForTripAndDecorateResult(callbackService, dates, closestTrips, true);
}

@Override
Expand Down Expand Up @@ -90,7 +91,8 @@ public FlexServiceDate activeDate() {
private static ArrayList<ClosestTrip> findActiveDatesForTripAndDecorateResult(
FlexAccessEgressCallbackAdapter callbackService,
List<FlexServiceDate> dates,
Map<FlexTrip<?, ?>, ClosestTrip> map
Map<FlexTrip<?, ?>, ClosestTrip> map,
boolean pickup
) {
var result = new ArrayList<ClosestTrip>();
// Add active dates
Expand All @@ -99,6 +101,11 @@ private static ArrayList<ClosestTrip> findActiveDatesForTripAndDecorateResult(
var closestTrip = e.getValue();
// Include dates where the service is running
for (FlexServiceDate date : dates) {
// Filter away boardings early. This needs to be done for egress as well when the
// board stop is known (not known here).
if (pickup && exceedsLatestBookingTime(trip, date, closestTrip.stopPos())) {
continue;
}
if (callbackService.isDateActive(date, trip)) {
result.add(closestTrip.withDate(date));
}
Expand All @@ -111,4 +118,17 @@ private ClosestTrip withDate(FlexServiceDate date) {
Objects.requireNonNull(date);
return new ClosestTrip(this, date);
}

/**
* Check if the trip can be booked at the given date and boarding stop position.
*/
private static boolean exceedsLatestBookingTime(
FlexTrip<?, ?> trip,
FlexServiceDate date,
int stopPos
) {
return RoutingBookingInfo
.of(trip.getPickupBookingInfo(stopPos))
.exceedsLatestBookingTime(date.requestedBookingTime());
}
}
Loading

0 comments on commit e64c957

Please sign in to comment.