From 476672b6eb9d4ec3178004cb8e2a236323c077b0 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 16:32:55 +0200 Subject: [PATCH 01/16] refactor: Move on-board trip arrivals down into McStopArrivals # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java --- .../multicriteria/McRangeRaptorWorkerState.java | 9 +++------ .../multicriteria/arrivals/McStopArrivals.java | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java index c2e0764bf25..47c44fe0358 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java @@ -1,7 +1,6 @@ package org.opentripplanner.raptor.rangeraptor.multicriteria; import java.util.ArrayList; -import java.util.Collection; import java.util.Iterator; import java.util.List; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; @@ -40,7 +39,6 @@ public final class McRangeRaptorWorkerState private final List> arrivalsCache = new ArrayList<>(); private final RaptorCostCalculator calculatorGeneralizedCost; private final RaptorTransitCalculator transitCalculator; - private final Collection> onBoardAccessStopArrivals; /** * create a RaptorState for a network with a particular number of stops, and a given maximum @@ -61,7 +59,6 @@ public McRangeRaptorWorkerState( this.stopArrivalFactory = stopArrivalFactory; this.calculatorGeneralizedCost = calculatorGeneralizedCost; this.transitCalculator = transitCalculator; - this.onBoardAccessStopArrivals = new ArrayList<>(); // Attach to the RR life cycle lifeCycle.onSetupIteration(ignore -> setupIteration()); @@ -74,7 +71,7 @@ public McRangeRaptorWorkerState( @Override public boolean isNewRoundAvailable() { - return arrivals.updateExist() || !onBoardAccessStopArrivals.isEmpty(); + return arrivals.updateExist(); } @Override @@ -124,12 +121,12 @@ Iterable> listStopArrivalsPreviousRound(int stop) { } Iterable> listOnBoardStopArrivals() { - return onBoardAccessStopArrivals; + return arrivals.listOnBoardTripArrivals(); } public void addOnBoardAccessStopArrival(RaptorAccessEgress accessPath, int departureTime) { var arrival = stopArrivalFactory.createAccessStopArrival(departureTime, accessPath); - onBoardAccessStopArrivals.add(arrival); + arrivals.addOnBoardTripArrival(arrival); } /** diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java index a6fcd96abd2..1795c23064c 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java @@ -4,8 +4,10 @@ import gnu.trove.map.TIntObjectMap; import gnu.trove.set.TIntSet; +import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; +import java.util.List; import java.util.function.Function; import java.util.stream.Stream; import org.opentripplanner.raptor.api.view.ArrivalView; @@ -27,6 +29,8 @@ public final class McStopArrivals { private final ParetoSet>[] arrivals; + private final List> onBoardTripArrivals; + private final BitSet touchedStops; private final DebugHandlerFactory debugHandlerFactory; @@ -42,6 +46,7 @@ public McStopArrivals( ) { //noinspection unchecked this.arrivals = (ParetoSet>[]) new ParetoSet[nStops]; + this.onBoardTripArrivals = new ArrayList<>(); this.touchedStops = new BitSet(nStops); this.comparator = comparatorFactory.compareArrivalTimeRoundAndCost(); this.debugHandlerFactory = debugHandlerFactory; @@ -94,7 +99,7 @@ public int smallestNumberOfTransfers(int stopIndex) { } public boolean updateExist() { - return !touchedStops.isEmpty(); + return !touchedStops.isEmpty() || !onBoardTripArrivals.isEmpty(); } public IntIterator stopsTouchedIterator() { @@ -133,6 +138,14 @@ public void clearTouchedStopsAndSetStopMarkers() { touchedStops.clear(); } + public Iterable> listOnBoardTripArrivals() { + return onBoardTripArrivals; + } + + public void addOnBoardTripArrival(McStopArrival arrival) { + onBoardTripArrivals.add(arrival); + } + /* private methods */ private ParetoSet> findOrCreateSet(final int stop) { From 6ef2c682db64dd851c0eb6710cb4b9ef21f0eb73 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 16:35:07 +0200 Subject: [PATCH 02/16] refator: Use RaptorTripScheduleStopPosition DTO in api access, and add test. # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java --- .../raptor/api/model/RaptorOnBoardAccess.java | 16 +--- .../model/RaptorTripScheduleStopPosition.java | 71 ++++++++++++++++++ .../raptor/api/view/ArrivalView.java | 3 +- .../api/view/TripScheduleStopPosition.java | 17 ----- .../rangeraptor/DefaultRangeRaptorWorker.java | 52 ++++++------- .../arrivals/c1/AccessStopArrival.java | 12 +-- .../transit/TestRaptorOnBoardAccess.java | 33 +++------ .../RaptorTripScheduleStopPositionTest.java | 73 +++++++++++++++++++ 8 files changed, 187 insertions(+), 90 deletions(-) create mode 100644 raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java delete mode 100644 raptor/src/main/java/org/opentripplanner/raptor/api/view/TripScheduleStopPosition.java create mode 100644 raptor/src/test/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPositionTest.java diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java index e4e0d5a254d..42271d358b7 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java @@ -8,21 +8,9 @@ */ public interface RaptorOnBoardAccess extends RaptorAccessEgress { /** - * The index of the boarded route + * Return the trip boarding this access is requiered to use. */ - int routeIndex(); - - /** - * The index of the boarded trip within the route - */ - int tripScheduleIndex(); - - /** - * The stop position in the route pattern for the board stop. It must refer to the same stop as - * the {@link #stop()} method. The stop position is required because the stop can be visited twice - * in case of a circular stop pattern. - */ - int stopPositionInPattern(); + RaptorTripScheduleStopPosition tripBoarding(); /** * The stop index corresponding to {@link #stopPositionInPattern()}. diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java new file mode 100644 index 00000000000..ce2ce38a4a9 --- /dev/null +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java @@ -0,0 +1,71 @@ +package org.opentripplanner.raptor.api.model; + +import java.util.Objects; +import org.opentripplanner.utils.tostring.ToStringBuilder; + +/** + * This class contain information to identify a given stop in a stop pattern for a given trip + * schedule in a route. This can for example be used to identify where a bording or alithing + * happens. + */ +public final class RaptorTripScheduleStopPosition { + + private final int routeIndex; + private final int tripScheduleIndex; + private final int stopPositionInPattern; + + public RaptorTripScheduleStopPosition( + int routeIndex, + int tripScheduleIndex, + int stopPositionInPattern + ) { + this.routeIndex = routeIndex; + this.tripScheduleIndex = tripScheduleIndex; + this.stopPositionInPattern = stopPositionInPattern; + } + + /// The index of the boarded route + public int routeIndex() { + return routeIndex; + } + + /// The index of the boarded trip within the route + public int tripScheduleIndex() { + return tripScheduleIndex; + } + + /// The stop position in the route stop-pattern. Knowing the stop index is not enough to identify + /// a stop, a stop may occour multiple times in a stop pattern, in other word a circular stop + /// pattern visit some of the same stops multiple times. + public int stopPositionInPattern() { + return stopPositionInPattern; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + RaptorTripScheduleStopPosition that = (RaptorTripScheduleStopPosition) o; + return ( + routeIndex == that.routeIndex && + tripScheduleIndex == that.tripScheduleIndex && + stopPositionInPattern == that.stopPositionInPattern + ); + } + + @Override + public int hashCode() { + return Objects.hash(routeIndex, tripScheduleIndex, stopPositionInPattern); + } + + @Override + public String toString() { + // The field labels are shorthen to improve reading - should be easy to get in the context + return ToStringBuilder.of(RaptorTripScheduleStopPosition.class) + .addNum("route", routeIndex) + .addNum("tripSchedule", tripScheduleIndex) + .addNum("stopPosition", stopPositionInPattern) + .toString(); + } +} diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java b/raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java index 41b048e7bda..7f7066cb839 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java @@ -5,6 +5,7 @@ import java.util.function.IntFunction; import javax.annotation.Nullable; +import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; import org.opentripplanner.raptor.spi.RaptorConstants; import org.opentripplanner.raptor.spi.RaptorCostCalculator; import org.opentripplanner.raptor.spi.RaptorTransfer; @@ -146,7 +147,7 @@ default EgressPathView egressPath() { boolean arrivedOnBoard(); - default TripScheduleStopPosition subsequentBoardingConstraint() { + default RaptorTripScheduleStopPosition subsequentBoardingConstraint() { throw new UnsupportedOperationException(); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/view/TripScheduleStopPosition.java b/raptor/src/main/java/org/opentripplanner/raptor/api/view/TripScheduleStopPosition.java deleted file mode 100644 index cb0d918d3ce..00000000000 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/view/TripScheduleStopPosition.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.opentripplanner.raptor.api.view; - -/** - * - * @param routeIndex The index of the boarded route - * @param tripScheduleIndex The index of the boarded trip within the route - * @param stopPositionInPattern The position in the route pattern of the first stop in the journey, - * where the access path just arrived at. Since this is an on-board - * access, this stop represents the most recently visited stop on the - * currently boarded trip. The next stop position after this is the - * first you can alight. - */ -public record TripScheduleStopPosition( - int routeIndex, - int tripScheduleIndex, - int stopPositionInPattern -) {} diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java index e08317da36c..262b9babd2d 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java @@ -3,7 +3,7 @@ import java.util.Collection; import org.opentripplanner.raptor.api.debug.RaptorTimers; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.view.ArrivalView; +import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; import org.opentripplanner.raptor.rangeraptor.internalapi.RangeRaptorWorker; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorRouterResult; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorWorkerState; @@ -129,10 +129,11 @@ public void applyOnBoardStopAccess() { @Override public void applyOnBoardTripAccess(int iterationDepartureTime) { for (var accessPath : accessPaths.onBoardAccessPaths()) { - var route = transitData.getRouteForIndex(accessPath.routeIndex()); - var trip = route.timetable().getTripSchedule(accessPath.tripScheduleIndex()); + var boarding = accessPath.tripBoarding(); + var route = transitData.getRouteForIndex(boarding.routeIndex()); + var trip = route.timetable().getTripSchedule(boarding.tripScheduleIndex()); + var boardTime = trip.departure(boarding.stopPositionInPattern()); - var boardTime = trip.departure(accessPath.stopPositionInPattern()); if (calculator.isInIteration(boardTime, iterationDepartureTime)) { transitWorker.registerOnBoardAccessStopArrival(accessPath, boardTime); } @@ -205,20 +206,20 @@ public void routeTransit() { @Override public void routeTransitUsingOnBoardTripAccess() { - var onBoardStopArrivals = transitWorker.consumeOnBoardStopArrivals(); - while (onBoardStopArrivals.hasNext()) { - var onBoardStopArrival = onBoardStopArrivals.next(); - var route = transitData.getRouteForIndex( - onBoardStopArrival.subsequentBoardingConstraint().routeIndex() - ); + var arrivals = transitWorker.consumeOnBoardStopArrivals(); + while (arrivals.hasNext()) { + var arrival = arrivals.next(); + var boarding = arrival.subsequentBoardingConstraint(); + var route = transitData.getRouteForIndex(boarding.routeIndex()); + var trip = route.timetable().getTripSchedule(boarding.tripScheduleIndex()); + int stopPosition = boarding.stopPositionInPattern(); transitWorker.prepareForTransitWith(route); - - var boarded = tryBoardOnBoardAccess(onBoardStopArrival, route); + boolean boarded = transitWorker.boardAsOnBoardAccess(arrival, stopPosition, trip); if (boarded) { - alightOnBoardAccess(onBoardStopArrival, route); - onBoardStopArrivals.remove(); + alightOnBoardAccess(boarding, route); + arrivals.remove(); } } } @@ -262,35 +263,24 @@ private void addAccessPaths(Collection accessPaths) { } } - private boolean tryBoardOnBoardAccess(ArrivalView onBoardStopArrival, RaptorRoute route) { - var onBoardTripConstraint = onBoardStopArrival.subsequentBoardingConstraint(); - var trip = route.timetable().getTripSchedule(onBoardTripConstraint.tripScheduleIndex()); - - return transitWorker.boardAsOnBoardAccess( - onBoardStopArrival, - onBoardTripConstraint.stopPositionInPattern(), - trip - ); - } - - private void alightOnBoardAccess(ArrivalView onBoardStopArrival, RaptorRoute route) { - var onBoardTripConstraint = onBoardStopArrival.subsequentBoardingConstraint(); - + private void alightOnBoardAccess( + RaptorTripScheduleStopPosition tripBoarding, + RaptorRoute route + ) { var pattern = route.pattern(); IntIterator stopPositions = calculator.patternStopIterator(pattern.numberOfStopsInPattern()); int alightSlack = slackProvider.alightSlack(pattern.slackIndex()); while ( - stopPositions.hasNext() && - stopPositions.next() != onBoardTripConstraint.stopPositionInPattern() + stopPositions.hasNext() && stopPositions.next() != tripBoarding.stopPositionInPattern() ) { // Skip past the initial on-board access stop // We will only consider alighting on stops after this one } var txSearch = enableTransferConstraints - ? calculator.transferConstraintsSearch(transitData, onBoardTripConstraint.routeIndex()) + ? calculator.transferConstraintsSearch(transitData, tripBoarding.routeIndex()) : null; while (stopPositions.hasNext()) { diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java index 8e7bc380bfd..c5718209722 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java @@ -5,9 +5,9 @@ import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; import org.opentripplanner.raptor.api.view.AccessPathView; import org.opentripplanner.raptor.api.view.PathLegType; -import org.opentripplanner.raptor.api.view.TripScheduleStopPosition; import org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.McStopArrival; import org.opentripplanner.raptor.spi.RaptorConstants; import org.opentripplanner.raptor.spi.RaptorTripSchedule; @@ -77,12 +77,12 @@ public McStopArrival addSlackToArrivalTime(int slack) { } @Override - public TripScheduleStopPosition subsequentBoardingConstraint() { + public RaptorTripScheduleStopPosition subsequentBoardingConstraint() { if (access instanceof RaptorOnBoardAccess onBoardAccess) { - return new TripScheduleStopPosition( - onBoardAccess.routeIndex(), - onBoardAccess.tripScheduleIndex(), - onBoardAccess.stopPositionInPattern() + return new RaptorTripScheduleStopPosition( + onBoardAccess.tripBoarding().routeIndex(), + onBoardAccess.tripBoarding().tripScheduleIndex(), + onBoardAccess.tripBoarding().stopPositionInPattern() ); } throw new UnsupportedOperationException(); diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java index 1c45bae88d7..54ec1693c00 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java @@ -1,14 +1,13 @@ package org.opentripplanner.raptor._data.transit; import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; public class TestRaptorOnBoardAccess implements RaptorOnBoardAccess { private final int stop; - private final int stopPositionInPattern; - private final int routeIndex; - private final int tripScheduleIndex; private final int generalizedCost; + private final RaptorTripScheduleStopPosition tripBoarding; public TestRaptorOnBoardAccess( int routeIndex, @@ -17,28 +16,15 @@ public TestRaptorOnBoardAccess( int stop, int generalizedCost ) { - this.routeIndex = routeIndex; - this.tripScheduleIndex = tripScheduleIndex; + this.tripBoarding = new RaptorTripScheduleStopPosition( + routeIndex, + tripScheduleIndex, + stopPositionInPattern + ); this.stop = stop; - this.stopPositionInPattern = stopPositionInPattern; this.generalizedCost = generalizedCost; } - @Override - public int routeIndex() { - return routeIndex; - } - - @Override - public int tripScheduleIndex() { - return tripScheduleIndex; - } - - @Override - public int stopPositionInPattern() { - return stopPositionInPattern; - } - @Override public int stop() { return stop; @@ -49,6 +35,11 @@ public int c1() { return generalizedCost; } + @Override + public RaptorTripScheduleStopPosition tripBoarding() { + return tripBoarding; + } + @Override public String toString() { return asString(true, true, null); diff --git a/raptor/src/test/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPositionTest.java b/raptor/src/test/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPositionTest.java new file mode 100644 index 00000000000..6ad0634fd50 --- /dev/null +++ b/raptor/src/test/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPositionTest.java @@ -0,0 +1,73 @@ +package org.opentripplanner.raptor.api.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; + +class RaptorTripScheduleStopPositionTest { + + private static final int ROUTE_INDEX = 7; + private static final int TRIP_SCHEDULE_INDEX = 3; + private static final int STOP_POSITION_IN_PATTERN = 5; + private static final int OTHER_VALUE = 99; + + private final RaptorTripScheduleStopPosition subject = new RaptorTripScheduleStopPosition( + ROUTE_INDEX, + TRIP_SCHEDULE_INDEX, + STOP_POSITION_IN_PATTERN + ); + + @Test + void routeIndex() { + assertEquals(ROUTE_INDEX, subject.routeIndex()); + } + + @Test + void tripScheduleIndex() { + assertEquals(TRIP_SCHEDULE_INDEX, subject.tripScheduleIndex()); + } + + @Test + void stopPositionInPattern() { + assertEquals(STOP_POSITION_IN_PATTERN, subject.stopPositionInPattern()); + } + + @Test + void testEqualsAndHashCode() { + var same = new RaptorTripScheduleStopPosition( + ROUTE_INDEX, + TRIP_SCHEDULE_INDEX, + STOP_POSITION_IN_PATTERN + ); + var other1 = new RaptorTripScheduleStopPosition( + OTHER_VALUE, + TRIP_SCHEDULE_INDEX, + STOP_POSITION_IN_PATTERN + ); + var other2 = new RaptorTripScheduleStopPosition( + ROUTE_INDEX, + OTHER_VALUE, + STOP_POSITION_IN_PATTERN + ); + var other3 = new RaptorTripScheduleStopPosition(ROUTE_INDEX, TRIP_SCHEDULE_INDEX, OTHER_VALUE); + + // TODO: Move AssertEqualsAndHashCode into utils and use it here + assertEquals(same, subject); + assertEquals(same.hashCode(), subject.hashCode()); + assertNotEquals(other1, subject); + assertNotEquals(other1.hashCode(), subject.hashCode()); + assertNotEquals(other2, subject); + assertNotEquals(other2.hashCode(), subject.hashCode()); + assertNotEquals(other3, subject); + assertNotEquals(other3.hashCode(), subject.hashCode()); + } + + @Test + void testToString() { + assertEquals( + "RaptorTripScheduleStopPosition{route: 7, tripSchedule: 3, stopPosition: 5}", + subject.toString() + ); + } +} From 51246e26df61360f9bf730947c21d5c0a7060156 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 26 Mar 2026 10:56:23 +0100 Subject: [PATCH 03/16] refactor: Move private methods down --- .../transit/request/TripPatternForDates.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripPatternForDates.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripPatternForDates.java index 87e6b51f0e5..fcbca200609 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripPatternForDates.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripPatternForDates.java @@ -183,10 +183,6 @@ public int priorityGroupId() { return priorityGroupId; } - public int transitReluctanceFactorIndex() { - return tripPattern.transitReluctanceFactorIndex(); - } - @Override public String debugInfo() { return tripPattern.debugInfo(); @@ -222,6 +218,10 @@ public int numberOfTripSchedules() { return numberOfTripSchedules; } + public int transitReluctanceFactorIndex() { + return tripPattern.transitReluctanceFactorIndex(); + } + public Route route() { return tripPattern.route(); } From 33306aa7a789f2151ba356521a81e9322540167f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 26 Mar 2026 22:36:38 +0100 Subject: [PATCH 04/16] refactor: Add JavaDoc to BitSetIterator --- .../java/org/opentripplanner/raptor/util/BitSetIterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/util/BitSetIterator.java b/raptor/src/main/java/org/opentripplanner/raptor/util/BitSetIterator.java index 14071d2a1c0..3a6125c9b15 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/util/BitSetIterator.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/util/BitSetIterator.java @@ -4,7 +4,7 @@ import org.opentripplanner.raptor.spi.IntIterator; /** - * TODO TGR + * Iterate over the set bits in the {@code BitSet}. */ public final class BitSetIterator implements IntIterator { From 7f16b8765ff5e479af34200885fd56826f84da4a Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 25 Mar 2026 23:51:39 +0100 Subject: [PATCH 05/16] refactor: Extract boarding and alighting logic into separate method in DefaultRangeRaptorWorker --- .../rangeraptor/DefaultRangeRaptorWorker.java | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java index 262b9babd2d..c1ae4bf13da 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java @@ -16,6 +16,7 @@ import org.opentripplanner.raptor.spi.RaptorConstants; import org.opentripplanner.raptor.spi.RaptorRoute; import org.opentripplanner.raptor.spi.RaptorTransitDataProvider; +import org.opentripplanner.raptor.spi.RaptorTripPattern; import org.opentripplanner.raptor.spi.RaptorTripSchedule; /** @@ -153,53 +154,9 @@ public void routeTransit() { var routeIndex = routeIndexIterator.next(); var route = transitData.getRouteForIndex(routeIndex); var pattern = route.pattern(); - var txSearch = enableTransferConstraints - ? calculator.transferConstraintsSearch(transitData, routeIndex) - : null; + var stopPositions = calculator.patternStopIterator(pattern.numberOfStopsInPattern()); - int alightSlack = slackProvider.alightSlack(pattern.slackIndex()); - int boardSlack = slackProvider.boardSlack(pattern.slackIndex()); - - transitWorker.prepareForTransitWith(route); - - IntIterator stopPositions = calculator.patternStopIterator( - pattern.numberOfStopsInPattern() - ); - - while (stopPositions.hasNext()) { - int stopPos = stopPositions.next(); - int stopIndex = pattern.stopIndex(stopPos); - - transitWorker.prepareForNextStop(stopIndex, stopPos); - - // attempt to alight if we're on board, this is done above the board search - // so that we don't alight on first stop boarded - if (calculator.alightingPossibleAt(pattern, stopPos)) { - if (enableTransferConstraints && txSearch.transferExistSourceStop(stopPos)) { - transitWorker.alightConstrainedTransferExist(stopIndex, stopPos, alightSlack); - } else { - transitWorker.alightOnlyRegularTransferExist(stopIndex, stopPos, alightSlack); - } - } - - if (calculator.boardingPossibleAt(pattern, stopPos)) { - // Don't attempt to board if this stop was not reached in the last round. - // Allow to reboard the same pattern - a pattern may loop and visit the same stop twice - if (state.isStopReachedInPreviousRound(stopIndex)) { - // has constrained transfers - if (enableTransferConstraints && txSearch.transferExistTargetStop(stopPos)) { - transitWorker.boardWithConstrainedTransfer( - stopIndex, - stopPos, - boardSlack, - txSearch - ); - } else { - transitWorker.boardWithRegularTransfer(stopIndex, stopPos, boardSlack); - } - } - } - } + boardAndAlightRoute(routeIndex, route, pattern, stopPositions); } }); } @@ -297,4 +254,50 @@ private void alightOnBoardAccess( } } } + + private void boardAndAlightRoute( + int routeIndex, + RaptorRoute route, + RaptorTripPattern pattern, + IntIterator stopPositions + ) { + var txSearch = enableTransferConstraints + ? calculator.transferConstraintsSearch(transitData, routeIndex) + : null; + + int alightSlack = slackProvider.alightSlack(pattern.slackIndex()); + int boardSlack = slackProvider.boardSlack(pattern.slackIndex()); + + transitWorker.prepareForTransitWith(route); + + while (stopPositions.hasNext()) { + int stopPos = stopPositions.next(); + int stopIndex = pattern.stopIndex(stopPos); + + transitWorker.prepareForNextStop(stopIndex, stopPos); + + // attempt to alight if we're on board, this is done above the board search + // so that we don't alight on first stop boarded + if (calculator.alightingPossibleAt(pattern, stopPos)) { + if (enableTransferConstraints && txSearch.transferExistSourceStop(stopPos)) { + transitWorker.alightConstrainedTransferExist(stopIndex, stopPos, alightSlack); + } else { + transitWorker.alightOnlyRegularTransferExist(stopIndex, stopPos, alightSlack); + } + } + + if (calculator.boardingPossibleAt(pattern, stopPos)) { + // Don't attempt to board if this stop was not reached in the last round. + // Allow to reboard the same pattern - a pattern may loop and visit the same stop twice + if (state.isStopReachedInPreviousRound(stopIndex)) { + // has constrained transfers + if (enableTransferConstraints && txSearch.transferExistTargetStop(stopPos)) { + transitWorker.boardWithConstrainedTransfer(stopIndex, stopPos, boardSlack, txSearch); + } else { + transitWorker.boardWithRegularTransfer(stopIndex, stopPos, boardSlack); + } + } + } + } + } } From cabe572248874aadcc0fe9cec433ed0f73a927c0 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 26 Mar 2026 14:02:15 +0100 Subject: [PATCH 06/16] refactor: Remove iterationDepartureTime parameter from applyOnBoardTripAccess method --- .../raptor/rangeraptor/DefaultRangeRaptorWorker.java | 2 +- .../org/opentripplanner/raptor/rangeraptor/RangeRaptor.java | 2 +- .../raptor/rangeraptor/RangeRaptorWorkerComposite.java | 4 ++-- .../raptor/rangeraptor/internalapi/RangeRaptorWorker.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java index c1ae4bf13da..17437df4c7a 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java @@ -128,7 +128,7 @@ public void applyOnBoardStopAccess() { } @Override - public void applyOnBoardTripAccess(int iterationDepartureTime) { + public void applyOnBoardTripAccess() { for (var accessPath : accessPaths.onBoardAccessPaths()) { var boarding = accessPath.tripBoarding(); var route = transitData.getRouteForIndex(boarding.routeIndex()); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java index 29d328b8dbf..c03f758d68b 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java @@ -126,7 +126,7 @@ public RaptorRouterResult route() { private void runRaptorForMinute(int iterationDepartureTime) { setupIteration(iterationDepartureTime); worker.applyStreetStopAccess(); - worker.applyOnBoardTripAccess(iterationDepartureTime); + worker.applyOnBoardTripAccess(); while (hasMoreRounds()) { lifeCycle.prepareForNextRound(roundTracker.nextRound()); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java index 7b7d85c0deb..b4164f0e046 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java @@ -79,9 +79,9 @@ public void applyOnBoardStopAccess() { } @Override - public void applyOnBoardTripAccess(int iterationDepartureTime) { + public void applyOnBoardTripAccess() { for (RangeRaptorWorker child : children) { - child.applyOnBoardTripAccess(iterationDepartureTime); + child.applyOnBoardTripAccess(); } } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java index 280fe0aac06..f5ba25a9a1e 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java @@ -28,7 +28,7 @@ public interface RangeRaptorWorker { /** * Find on-board access for round (accesses on-board an already started trip) */ - void applyOnBoardTripAccess(int iterationDepartureTime); + void applyOnBoardTripAccess(); /** * Perform a transit search for the current round. From f9a6b1405d1e4eb5862ffc94be23c9ac7ed550f7 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 16:44:10 +0200 Subject: [PATCH 07/16] refactor: Integrate on-board trip access boarding into the regular transit pass Remove the separate `routeTransitUsingOnBoardTripAccess()` method and fold on-board trip access handling into `boardAndAlightPattern`. On-board arrivals are now indexed by route index and stop position (via `OnBoardTripAccessPathsForRoute`), so they can be consumed inline at the correct stop during the regular route traversal instead of in a dedicated second pass. # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java # Conflicts: # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java # raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java --- .../rangeraptor/DefaultRangeRaptorWorker.java | 65 +++---------------- .../raptor/rangeraptor/RangeRaptor.java | 1 - .../RangeRaptorWorkerComposite.java | 7 -- .../OnBoardTripAccessPathsForRoute.java | 43 ++++++++++++ .../internalapi/RangeRaptorWorker.java | 6 -- .../internalapi/RoutingStrategy.java | 14 ++-- .../McRangeRaptorWorkerState.java | 7 +- .../MultiCriteriaRoutingStrategy.java | 8 ++- .../arrivals/McStopArrivals.java | 34 +++++++--- .../raptor/RaptorArchitectureTest.java | 2 +- 10 files changed, 96 insertions(+), 91 deletions(-) create mode 100644 raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/OnBoardTripAccessPathsForRoute.java diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java index 17437df4c7a..b7f9c42b188 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java @@ -3,7 +3,6 @@ import java.util.Collection; import org.opentripplanner.raptor.api.debug.RaptorTimers; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; import org.opentripplanner.raptor.rangeraptor.internalapi.RangeRaptorWorker; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorRouterResult; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorWorkerState; @@ -161,26 +160,6 @@ public void routeTransit() { }); } - @Override - public void routeTransitUsingOnBoardTripAccess() { - var arrivals = transitWorker.consumeOnBoardStopArrivals(); - while (arrivals.hasNext()) { - var arrival = arrivals.next(); - var boarding = arrival.subsequentBoardingConstraint(); - var route = transitData.getRouteForIndex(boarding.routeIndex()); - var trip = route.timetable().getTripSchedule(boarding.tripScheduleIndex()); - int stopPosition = boarding.stopPositionInPattern(); - - transitWorker.prepareForTransitWith(route); - boolean boarded = transitWorker.boardAsOnBoardAccess(arrival, stopPosition, trip); - - if (boarded) { - alightOnBoardAccess(boarding, route); - arrivals.remove(); - } - } - } - @Override public void applyTransfers() { timers.applyTransfers(() -> { @@ -220,41 +199,6 @@ private void addAccessPaths(Collection accessPaths) { } } - private void alightOnBoardAccess( - RaptorTripScheduleStopPosition tripBoarding, - RaptorRoute route - ) { - var pattern = route.pattern(); - IntIterator stopPositions = calculator.patternStopIterator(pattern.numberOfStopsInPattern()); - - int alightSlack = slackProvider.alightSlack(pattern.slackIndex()); - - while ( - stopPositions.hasNext() && stopPositions.next() != tripBoarding.stopPositionInPattern() - ) { - // Skip past the initial on-board access stop - // We will only consider alighting on stops after this one - } - - var txSearch = enableTransferConstraints - ? calculator.transferConstraintsSearch(transitData, tripBoarding.routeIndex()) - : null; - - while (stopPositions.hasNext()) { - int stopPos = stopPositions.next(); - int stopIndex = pattern.stopIndex(stopPos); - - // attempt to alight if we're on board - if (calculator.alightingPossibleAt(pattern, stopPos)) { - if (enableTransferConstraints && txSearch.transferExistSourceStop(stopPos)) { - transitWorker.alightConstrainedTransferExist(stopIndex, stopPos, alightSlack); - } else { - transitWorker.alightOnlyRegularTransferExist(stopIndex, stopPos, alightSlack); - } - } - } - } - private void boardAndAlightRoute( int routeIndex, RaptorRoute route, @@ -269,6 +213,7 @@ private void boardAndAlightRoute( int boardSlack = slackProvider.boardSlack(pattern.slackIndex()); transitWorker.prepareForTransitWith(route); + var onBoardArrivals = transitWorker.consumeOnBoardStopArrivals(routeIndex); while (stopPositions.hasNext()) { int stopPos = stopPositions.next(); @@ -285,6 +230,14 @@ private void boardAndAlightRoute( transitWorker.alightOnlyRegularTransferExist(stopIndex, stopPos, alightSlack); } } + // attempt to board using on-board trip access + if (onBoardArrivals != null && onBoardArrivals.containsKey(stopPos)) { + for (var arrival : onBoardArrivals.listArrivals(stopPos)) { + var boarding = arrival.subsequentBoardingConstraint(); + var trip = route.timetable().getTripSchedule(boarding.tripScheduleIndex()); + transitWorker.boardAsOnBoardAccess(arrival, stopPos, trip); + } + } if (calculator.boardingPossibleAt(pattern, stopPos)) { // Don't attempt to board if this stop was not reached in the last round. diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java index c03f758d68b..a04f6915c32 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptor.java @@ -134,7 +134,6 @@ private void runRaptorForMinute(int iterationDepartureTime) { // NB since we have transfer limiting not bothering to cut off search when there are no // more transfers as that will be rare and complicates the code worker.routeTransit(); - worker.routeTransitUsingOnBoardTripAccess(); lifeCycle.transitsForRoundComplete(); worker.applyOnBoardStopAccess(); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java index b4164f0e046..930e9fb47b8 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/RangeRaptorWorkerComposite.java @@ -92,13 +92,6 @@ public void routeTransit() { } } - @Override - public void routeTransitUsingOnBoardTripAccess() { - for (RangeRaptorWorker child : children) { - child.routeTransitUsingOnBoardTripAccess(); - } - } - @Override public void applyTransfers() { for (RangeRaptorWorker child : children) { diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/OnBoardTripAccessPathsForRoute.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/OnBoardTripAccessPathsForRoute.java new file mode 100644 index 00000000000..62ff85be1bb --- /dev/null +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/OnBoardTripAccessPathsForRoute.java @@ -0,0 +1,43 @@ +package org.opentripplanner.raptor.rangeraptor.internalapi; + +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import java.util.ArrayList; +import java.util.List; +import org.opentripplanner.raptor.api.view.ArrivalView; +import org.opentripplanner.raptor.spi.RaptorTripSchedule; + +/** + * Holds all on-board trip access arrivals for a single route, indexed by stop position in the + * route's stop pattern. + * + *

An on-board trip access represents a passenger who is already on board a vehicle at the + * start of the search — i.e., their "access leg" is the ride itself rather than a walk to a + * stop. Each such arrival carries a {@code RaptorTripScheduleStopPosition} + * that identifies exactly which route, trip, and stop position the passenger must board from. + */ +public final class OnBoardTripAccessPathsForRoute { + + private final TIntObjectMap>> arrivals = new TIntObjectHashMap<>(); + + /** Returns {@code true} if there are on-board arrivals waiting to board at {@code stopPos}. */ + public boolean containsKey(int stopPos) { + return arrivals.containsKey(stopPos); + } + + /** Returns all on-board arrivals that should board at {@code stopPos}. */ + public Iterable> listArrivals(int stopPos) { + return arrivals.get(stopPos); + } + + /** Adds an on-board arrival, indexing it by its boarding stop position in the pattern. */ + public void add(ArrivalView arrival) { + var boardingConstraint = arrival.subsequentBoardingConstraint(); + var list = arrivals.get(boardingConstraint.stopPositionInPattern()); + if (list == null) { + list = new ArrayList<>(); + arrivals.put(boardingConstraint.stopPositionInPattern(), list); + } + list.add(arrival); + } +} diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java index f5ba25a9a1e..e9743a3de68 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RangeRaptorWorker.java @@ -35,12 +35,6 @@ public interface RangeRaptorWorker { */ void routeTransit(); - /** - * Perform on-board (accesses on-board an already started trip) transit search for boardings and - * alight events for the current round. - */ - void routeTransitUsingOnBoardTripAccess(); - /** * Apply transfers for the current round. */ diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java index 811649526a4..99bf292ee3a 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java @@ -1,7 +1,6 @@ package org.opentripplanner.raptor.rangeraptor.internalapi; -import java.util.Collections; -import java.util.Iterator; +import javax.annotation.Nullable; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; import org.opentripplanner.raptor.api.view.ArrivalView; @@ -83,12 +82,13 @@ default void registerOnBoardAccessStopArrival(RaptorOnBoardAccess access, int bo } /** - * @return an iterator over all on-board stop-arrivals currently in the state. - * The iterator allows removal and this is the expected way to remove or a stop-arrival. When - * removed is when we consider a stop-arrival to be "consumed". + * @return all on-board trip access arrival for the given {@code routeIndex}. The arrivals are + * removed from state and can only be fetched once. The method return {@code null} if no + * arrivals exist - this should be very efficient to check. */ - default Iterator> consumeOnBoardStopArrivals() { - return Collections.emptyIterator(); + @Nullable + default OnBoardTripAccessPathsForRoute consumeOnBoardStopArrivals(int routeIndex) { + return null; } /** diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java index 47c44fe0358..325ffd38619 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/McRangeRaptorWorkerState.java @@ -3,7 +3,9 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import javax.annotation.Nullable; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; +import org.opentripplanner.raptor.rangeraptor.internalapi.OnBoardTripAccessPathsForRoute; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorRouterResult; import org.opentripplanner.raptor.rangeraptor.internalapi.RaptorWorkerState; import org.opentripplanner.raptor.rangeraptor.internalapi.WorkerLifeCycle; @@ -120,8 +122,9 @@ Iterable> listStopArrivalsPreviousRound(int stop) { return arrivals.listArrivalsAfterMarker(stop); } - Iterable> listOnBoardStopArrivals() { - return arrivals.listOnBoardTripArrivals(); + @Nullable + OnBoardTripAccessPathsForRoute consumeOnBoardStopArrivals(int routeIndex) { + return arrivals.consumeOnBoardStopArrivals(routeIndex); } public void addOnBoardAccessStopArrival(RaptorAccessEgress accessPath, int departureTime) { diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java index 3d9e00f490a..b59f79cdf1e 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java @@ -2,11 +2,12 @@ import static org.opentripplanner.raptor.api.view.PathLegType.ACCESS; -import java.util.Iterator; import java.util.Objects; +import javax.annotation.Nullable; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; import org.opentripplanner.raptor.api.view.ArrivalView; +import org.opentripplanner.raptor.rangeraptor.internalapi.OnBoardTripAccessPathsForRoute; import org.opentripplanner.raptor.rangeraptor.internalapi.PassThroughPointsService; import org.opentripplanner.raptor.rangeraptor.internalapi.RoutingStrategy; import org.opentripplanner.raptor.rangeraptor.internalapi.SlackProvider; @@ -125,8 +126,9 @@ public void registerOnBoardAccessStopArrival(RaptorOnBoardAccess access, int boa } @Override - public Iterator> consumeOnBoardStopArrivals() { - return state.listOnBoardStopArrivals().iterator(); + @Nullable + public OnBoardTripAccessPathsForRoute consumeOnBoardStopArrivals(int routeIndex) { + return state.consumeOnBoardStopArrivals(routeIndex); } @Override diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java index 1795c23064c..e6f4cf1bf92 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java @@ -3,15 +3,16 @@ import static org.opentripplanner.raptor.api.view.PathLegType.TRANSIT; import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.set.TIntSet; -import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; -import java.util.List; import java.util.function.Function; import java.util.stream.Stream; +import javax.annotation.Nullable; import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.rangeraptor.debug.DebugHandlerFactory; +import org.opentripplanner.raptor.rangeraptor.internalapi.OnBoardTripAccessPathsForRoute; import org.opentripplanner.raptor.spi.IntIterator; import org.opentripplanner.raptor.spi.RaptorTripSchedule; import org.opentripplanner.raptor.util.BitSetIterator; @@ -29,7 +30,7 @@ public final class McStopArrivals { private final ParetoSet>[] arrivals; - private final List> onBoardTripArrivals; + private final TIntObjectMap> onBoardTripArrivalsByRouteQueue; private final BitSet touchedStops; @@ -46,7 +47,7 @@ public McStopArrivals( ) { //noinspection unchecked this.arrivals = (ParetoSet>[]) new ParetoSet[nStops]; - this.onBoardTripArrivals = new ArrayList<>(); + this.onBoardTripArrivalsByRouteQueue = new TIntObjectHashMap<>(); this.touchedStops = new BitSet(nStops); this.comparator = comparatorFactory.compareArrivalTimeRoundAndCost(); this.debugHandlerFactory = debugHandlerFactory; @@ -99,7 +100,7 @@ public int smallestNumberOfTransfers(int stopIndex) { } public boolean updateExist() { - return !touchedStops.isEmpty() || !onBoardTripArrivals.isEmpty(); + return !touchedStops.isEmpty(); } public IntIterator stopsTouchedIterator() { @@ -138,12 +139,29 @@ public void clearTouchedStopsAndSetStopMarkers() { touchedStops.clear(); } - public Iterable> listOnBoardTripArrivals() { - return onBoardTripArrivals; + @Nullable + public OnBoardTripAccessPathsForRoute consumeOnBoardStopArrivals(int routeIndex) { + OnBoardTripAccessPathsForRoute arrivals = null; + if (onBoardTripArrivalsByRouteQueue.containsKey(routeIndex)) { + arrivals = onBoardTripArrivalsByRouteQueue.get(routeIndex); + onBoardTripArrivalsByRouteQueue.remove(routeIndex); + } + return arrivals; } public void addOnBoardTripArrival(McStopArrival arrival) { - onBoardTripArrivals.add(arrival); + var boardingConstraint = arrival.subsequentBoardingConstraint(); + var access = onBoardTripArrivalsByRouteQueue.get(boardingConstraint.routeIndex()); + if (access == null) { + access = new OnBoardTripAccessPathsForRoute<>(); + onBoardTripArrivalsByRouteQueue.put(boardingConstraint.routeIndex(), access); + } + access.add(arrival); + + // Then update the state, both touchedStops and init the pareto-set for the given stop to + // prevent NPE when the state is fetched later. The set is empty, witch is ok. + findOrCreateSet(arrival.stop()); + touchedStops.set(arrival.stop()); } /* private methods */ diff --git a/raptor/src/test/java/org/opentripplanner/raptor/RaptorArchitectureTest.java b/raptor/src/test/java/org/opentripplanner/raptor/RaptorArchitectureTest.java index 298fb82d134..a53ee8ebe92 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/RaptorArchitectureTest.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/RaptorArchitectureTest.java @@ -97,7 +97,7 @@ void enforcePackageDependenciesRaptorPath() { @Test void enforcePackageDependenciesInRangeRaptorSharedPackages() { - RR_INTERNAL_API.dependsOn(OTP_UTILS, RAPTOR_API, RAPTOR_SPI).verify(); + RR_INTERNAL_API.dependsOn(OTP_UTILS, GNU_TROVE, RAPTOR_API, RAPTOR_SPI).verify(); RR_DEBUG.dependsOn(RR_SHARED_PACKAGES).verify(); RR_LIFECYCLE.dependsOn(RR_SHARED_PACKAGES).verify(); RR_TRANSIT.dependsOn(RR_SHARED_PACKAGES, RR_DEBUG, RR_LIFECYCLE).verify(); From 99d90b8a117eaf7c44e0da9761f7035c743eeb91 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 26 Mar 2026 22:44:36 +0100 Subject: [PATCH 08/16] refactor: JavaDoc on ParetoSetEventListener --- .../raptor/util/paretoset/ParetoSetEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/util/paretoset/ParetoSetEventListener.java b/raptor/src/main/java/org/opentripplanner/raptor/util/paretoset/ParetoSetEventListener.java index 24323b1750b..b8abd6c7bac 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/util/paretoset/ParetoSetEventListener.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/util/paretoset/ParetoSetEventListener.java @@ -20,7 +20,7 @@ */ public interface ParetoSetEventListener { /** - * This is the callback called when an element is dropped. + * This is the callback called when an element is accepted. */ default void notifyElementAccepted(T newElement) {} From 1223e42b20defef9694c3f662fb027e256ad68c4 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 26 Mar 2026 23:05:37 +0100 Subject: [PATCH 09/16] refactor: Add test-case to IntIteratorsTest --- .../java/org/opentripplanner/raptor/util/IntIteratorsTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/raptor/src/test/java/org/opentripplanner/raptor/util/IntIteratorsTest.java b/raptor/src/test/java/org/opentripplanner/raptor/util/IntIteratorsTest.java index 598287164c2..a788ad636cc 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/util/IntIteratorsTest.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/util/IntIteratorsTest.java @@ -1,6 +1,7 @@ package org.opentripplanner.raptor.util; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.opentripplanner.raptor.util.IntIterators.intDecIterator; import static org.opentripplanner.raptor.util.IntIterators.intIncIterator; import static org.opentripplanner.raptor.util.IntIterators.singleValueIterator; @@ -86,6 +87,7 @@ public void testSingleValueIterator() { @Test public void testEmptyIterator() { + assertFalse(IntIterators.empty().hasNext()); assertEquals("[]", toString(IntIterators.empty())); } From 567cf810526736a006bef33925b0048836659256 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 27 Mar 2026 16:30:45 +0100 Subject: [PATCH 10/16] refactor: Rename boarding search methods and add java doc --- .../MultiCriteriaRoutingStrategy.java | 6 +- .../standard/ArrivalTimeRoutingStrategy.java | 4 +- .../MinTravelDurationRoutingStrategy.java | 2 +- .../support/TimeBasedBoardingSupport.java | 95 +++++++++++++------ 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java index b59f79cdf1e..ebb71a0366b 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java @@ -141,7 +141,7 @@ public boolean boardAsOnBoardAccess( throw new UnsupportedOperationException(); } - var boarding = boardingSupport.searchRegularTransfer( + var boarding = boardingSupport.searchForRegularBoarding( prevArrival.arrivalTime(), stopPositionInPattern, slackProvider.boardSlack(trip.pattern().slackIndex()) @@ -191,7 +191,7 @@ private void boardWithRegularTransfer( int stopPos, int boardSlack ) { - var result = boardingSupport.searchRegularTransfer( + var result = boardingSupport.searchForRegularBoarding( prevArrival.arrivalTime(), stopPos, boardSlack @@ -208,7 +208,7 @@ private void boardWithConstrainedTransfer( int boardSlack, RaptorConstrainedBoardingSearch txSearch ) { - var boarding = boardingSupport.searchConstrainedTransfer( + var boarding = boardingSupport.searchForConstrainedBoarding( prevArrival.mostRecentTransitArrival(), prevArrival.arrivalTime(), boardSlack, diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java index da4b8d25d2c..d71cda0575a 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java @@ -92,7 +92,7 @@ public void alightConstrainedTransferExist(int stopIndex, int stopPos, int aligh @Override public void boardWithRegularTransfer(int stopIndex, int stopPos, int boardSlack) { int prevArrivalTime = prevArrivalTime(stopIndex); - var boarding = boardingSupport.searchRegularTransfer( + var boarding = boardingSupport.searchForRegularBoarding( prevArrivalTime, stopPos, boardSlack, @@ -110,7 +110,7 @@ public void boardWithConstrainedTransfer( int boardSlack, RaptorConstrainedBoardingSearch txSearch ) { - var boarding = boardingSupport.searchConstrainedTransfer( + var boarding = boardingSupport.searchForConstrainedBoarding( previousTransitArrival(stopIndex), prevArrivalTime(stopIndex), boardSlack, diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java index 9bf2c76caed..d5c5b0516fa 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java @@ -89,7 +89,7 @@ public void alightConstrainedTransferExist(int stopIndex, int stopPos, int aligh @Override public void boardWithRegularTransfer(int stopIndex, int stopPos, int boardSlack) { int prevArrivalTime = prevArrivalTime(stopIndex); - var boarding = boardingSupport.searchRegularTransfer( + var boarding = boardingSupport.searchForRegularBoarding( prevArrivalTime, stopPos, boardSlack, diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/support/TimeBasedBoardingSupport.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/support/TimeBasedBoardingSupport.java index 925acd1fa46..488fe2987c8 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/support/TimeBasedBoardingSupport.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/support/TimeBasedBoardingSupport.java @@ -15,19 +15,30 @@ import org.opentripplanner.raptor.spi.RaptorTripScheduleSearch; /** - * This class contains code which is shared by all time-dependent {@link RoutingStrategy}s. - * + * Shared boarding logic for all time-dependent {@link RoutingStrategy}s. + *

+ * Handles trip search creation and earliest-board-time calculation for both regular and + * constrained (guaranteed/stay-seated) boardings. The choice between an exact trip search + * and a standard trip search depends on whether this is the first iteration and the first + * round, and whether time-dependent access is in use. */ public final class TimeBasedBoardingSupport { private final SlackProvider slackProvider; private final RaptorTransitCalculator calculator; private final boolean hasTimeDependentAccess; + private boolean inFirstIteration = true; private RaptorTimeTable timeTable; private RaptorTripScheduleSearch tripSearch; private int round; + /** + * @param hasTimeDependentAccess {@code true} if any access path is time-dependent, which + * disables the exact-trip-search optimisation in round 1 + * @param calculator direction-aware arithmetic for forward/reverse searches + * @param subscriptions worker lifecycle hooks used to track iteration and round state + */ public TimeBasedBoardingSupport( boolean hasTimeDependentAccess, SlackProvider slackProvider, @@ -42,24 +53,39 @@ public TimeBasedBoardingSupport( subscriptions.onPrepareForNextRound(r -> this.round = r); } + /** + * Set the timetable for the pattern about to be boarded and create a suitable trip search. + * Must be called once per pattern before any {@code searchForBoarding} calls. + */ public void prepareForTransitWith(RaptorTimeTable timeTable) { this.timeTable = timeTable; this.tripSearch = createTripSearch(timeTable); } /** - * Same as {@link #searchRegularTransfer(int, int, int, int)}, but with + * Same as {@link #searchForRegularBoarding(int, int, int, int)}, but with * {@code onTripIndex} unbounded. */ - public RaptorBoardOrAlightEvent searchRegularTransfer( + public RaptorBoardOrAlightEvent searchForRegularBoarding( int prevArrivalTime, int stopPos, int boardSlack ) { - return searchRegularTransfer(prevArrivalTime, stopPos, boardSlack, UNBOUNDED_TRIP_INDEX); + return searchForRegularBoarding(prevArrivalTime, stopPos, boardSlack, UNBOUNDED_TRIP_INDEX); } - public RaptorBoardOrAlightEvent searchRegularTransfer( + /** + * Search for the earliest trip that can be boarded at {@code stopPos}, applying + * {@code boardSlack} to the previous arrival time to derive the earliest board time. + * + * @param prevArrivalTime the time at which the traveller arrives at the board stop + * @param stopPos the stop position within the pattern's stop sequence + * @param boardSlack minimum seconds between arrival and boarding + * @param onTripIndex upper bound on the trip index (used when already on a trip); + * pass {@link RaptorTripScheduleSearch#UNBOUNDED_TRIP_INDEX} for no bound + * @return the board event, or an empty event if no trip is found + */ + public RaptorBoardOrAlightEvent searchForRegularBoarding( int prevArrivalTime, int stopPos, int boardSlack, @@ -70,18 +96,26 @@ public RaptorBoardOrAlightEvent searchRegularTransfer( } /** + * Search for a constrained boarding (stay-seated or guaranteed transfer) at the current stop. + *

+ * If {@code prevTransitStopArrival} is {@code null} — meaning the traveller did not arrive by + * transit — no constrained transfer can apply, and an empty event is returned. + *

+ * When a previous transit arrival exists, the alight slack of that leg is subtracted to derive + * the actual transit arrival time, which is passed to the constrained transfer search together + * with the earliest board time computed from {@code prevArrivalTime} and {@code boardSlack}. * - * @param prevTransitStopArrival the current boarding previous transit arrival. This is used to - * look up any guaranteed transfers. - * @param prevArrivalTime the arrival time for the board stop ({@code stopIndex}), this - * may not be same as the {@code prevTransitStopArrival}, since - * there might be a "walking" transfer to reach stop. - * @param boardSlack The minimum number of seconds to apply to the arrival time - * before boarding a trip. Stay-seated and guaranteed transfers - * may override this. - * @param txSearch The constrained transfer search to use. + * @param prevTransitStopArrival the transit arrival that is the source of a potential constrained + * transfer; {@code null} if the traveller did not arrive by transit + * @param prevArrivalTime the wall-clock arrival time at the board stop; may differ from + * {@code prevTransitStopArrival} when a walking transfer bridges + * the two stops + * @param boardSlack minimum seconds between {@code prevArrivalTime} and boarding; + * stay-seated and guaranteed transfers may override this + * @param txSearch the constrained transfer search for the target pattern + * @return the constrained board event, or an empty event if no constrained transfer is found */ - public RaptorBoardOrAlightEvent searchConstrainedTransfer( + public RaptorBoardOrAlightEvent searchForConstrainedBoarding( TransitArrival prevTransitStopArrival, int prevArrivalTime, int boardSlack, @@ -112,27 +146,32 @@ public RaptorBoardOrAlightEvent searchConstrainedTransfer( } /** - * Add board-slack(forward-search) or alight-slack(reverse-search) + * Compute the earliest time at which a trip may be boarded. + *

+ * In a forward search this adds board slack; in a reverse search it subtracts alight slack. + * The direction-specific arithmetic is delegated to the {@link RaptorTransitCalculator}. */ private int earliestBoardTime(int prevArrivalTime, int boardSlack) { return calculator.plusDuration(prevArrivalTime, boardSlack); } + /** + * Create a trip search appropriate for the current iteration and round. + *

+ * For every iteration after the first, and only in round 1, an exact trip search is + * used when there is no time-dependent access. This restricts the first departure to fall within + * the iteration's time-window — preventing the access path from being time-shifted past the + * previous iteration's departure time. The restriction also enables departure-time to be used + * as a pareto criterion in timetable view. + *

+ * The optimisation is skipped for the first iteration because a traveller could board a bus, + * ride one stop, walk back to the origin, and then wait to board a later trip — results that + * would correctly be dominated by later iterations, but only after those iterations run. + */ private RaptorTripScheduleSearch createTripSearch(RaptorTimeTable timeTable) { if (!inFirstIteration && isFirstRound(round) && !hasTimeDependentAccess) { - // For the first round of every iteration(except the first) we restrict the first - // departure to happen within the time-window of the iteration. Another way to put this, - // is to say that we allow for the access path to be time-shifted to a later departure, - // but not past the previous iteration departure time. This save a bit of processing, - // but most importantly allow us to use the departure-time as a pareto criteria in - // time-table view. This is not valid for the first iteration, because we could jump on - // a bus, take it one stop and walk back and then wait to board a later trip - this kind - // of results would be rejected by earlier iterations, for all iterations except the - // first. return calculator.createExactTripSearch(timeTable); } - - // Default: create a standard trip search return calculator.createTripSearch(timeTable); } } From 75e777cefabd0aa4cb5c79e29c7fbd025b567b5f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 19:21:22 +0200 Subject: [PATCH 11/16] refactor: Rename tripIndex() methods to tripScheduleIndex() --- .../frequency/FrequencyBoardOrAlightEvent.java | 2 +- .../request/TripScheduleAlightSearch.java | 2 +- .../transit/request/TripScheduleBoardSearch.java | 2 +- .../ConstrainedTransferBoarding.java | 2 +- .../transit/request/TripAssert.java | 2 +- .../request/TripScheduleAlightSearchTest.java | 2 +- .../request/TripScheduleBoardSearchTest.java | 2 +- .../ConstrainedBoardingSearchTest.java | 2 +- .../direct/service/DirectTransitSearch.java | 2 +- .../standard/ArrivalTimeRoutingStrategy.java | 2 +- .../MinTravelDurationRoutingStrategy.java | 2 +- .../raptor/spi/EmptyBoardOrAlightEvent.java | 2 +- .../raptor/spi/RaptorBoardOrAlightEvent.java | 2 +- .../_data/transit/TestConstrainedTransfer.java | 2 +- .../_data/transit/TestTripScheduleSearch.java | 2 +- .../transit/TestTripScheduleSearchTest.java | 16 ++++++++-------- .../TripScheduleExactMatchSearchTest.java | 2 +- 17 files changed, 24 insertions(+), 24 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/FrequencyBoardOrAlightEvent.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/FrequencyBoardOrAlightEvent.java index a9ef6ac61c4..a438ac2b73f 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/FrequencyBoardOrAlightEvent.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/FrequencyBoardOrAlightEvent.java @@ -64,7 +64,7 @@ public FrequencyBoardOrAlightEvent( /* RaptorTripScheduleBoardOrAlightEvent implementation */ @Override - public int tripIndex() { + public int tripScheduleIndex() { return tripTimes.getDepartureTime(0) + offset; } diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearch.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearch.java index 92007a99f37..abfbf53e89a 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearch.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearch.java @@ -53,7 +53,7 @@ public T trip() { } @Override - public int tripIndex() { + public int tripScheduleIndex() { return candidateTripIndex; } diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearch.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearch.java index 6aff16813cc..47f64782021 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearch.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearch.java @@ -51,7 +51,7 @@ public T trip() { } @Override - public int tripIndex() { + public int tripScheduleIndex() { return candidateTripIndex; } diff --git a/application/src/main/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedTransferBoarding.java b/application/src/main/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedTransferBoarding.java index 2299cd3a120..437794070f3 100644 --- a/application/src/main/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedTransferBoarding.java +++ b/application/src/main/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedTransferBoarding.java @@ -35,7 +35,7 @@ public ConstrainedTransferBoarding( } @Override - public int tripIndex() { + public int tripScheduleIndex() { return tripIndex; } diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripAssert.java b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripAssert.java index 37620d80bc3..c3dedeab1d7 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripAssert.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripAssert.java @@ -52,7 +52,7 @@ TripAssert assertTripFound() { } TripAssert withIndex(int expectedTripIndex) { - assertEquals(expectedTripIndex, result.tripIndex(), "Trip index"); + assertEquals(expectedTripIndex, result.tripScheduleIndex(), "Trip index"); return this; } diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearchTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearchTest.java index efae7e9952a..b6905c7514a 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearchTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleAlightSearchTest.java @@ -116,7 +116,7 @@ public void noTripsToAlightInEmptyPattern() { } @Test - public void findTripWithGivenTripIndexLowerBound() { + public void findTripWithGivenTripScheduleIndexLowerBound() { // Given a pattern with the following trips: A, B withTrips(tripA, tripB); diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearchTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearchTest.java index 3c262bd6a84..288c22e1ce0 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearchTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleBoardSearchTest.java @@ -111,7 +111,7 @@ public void noTripsToBoardInEmptyPattern() { } @Test - public void findTripWithGivenTripIndexUpperBound() { + public void findTripWithGivenTripScheduleIndexUpperBound() { // Given a pattern with the following trips: A, B int TRIP_INDEX_A = 0; int TRIP_INDEX_B = 1; diff --git a/application/src/test/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedBoardingSearchTest.java b/application/src/test/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedBoardingSearchTest.java index 2e321c929b3..0300126bd77 100644 --- a/application/src/test/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedBoardingSearchTest.java +++ b/application/src/test/java/org/opentripplanner/transfer/constrained/raptoradaptor/ConstrainedBoardingSearchTest.java @@ -446,7 +446,7 @@ private void assertBoarding( assertEquals(expectedConstraint, boarding.transferConstraint()); assertEquals(stopIndex, boarding.boardStopIndex()); assertEquals(targetStopPos, boarding.stopPositionInPattern()); - assertEquals(expectedTripIndex, boarding.tripIndex()); + assertEquals(expectedTripIndex, boarding.tripScheduleIndex()); } else { assertTrue(boarding.empty()); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/extensions/direct/service/DirectTransitSearch.java b/raptor/src/main/java/org/opentripplanner/raptor/extensions/direct/service/DirectTransitSearch.java index 94cf1c52761..527f566c2fc 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/extensions/direct/service/DirectTransitSearch.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/extensions/direct/service/DirectTransitSearch.java @@ -140,7 +140,7 @@ private Optional> findFirstPathInSearchWindow( } if (path.startTime() < latestDepartureTime) { - return Optional.of(new PathAndTripIndex(path, boardEvent.tripIndex())); + return Optional.of(new PathAndTripIndex(path, boardEvent.tripScheduleIndex())); } return Optional.empty(); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java index d71cda0575a..8392b1ba6c1 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/ArrivalTimeRoutingStrategy.java @@ -124,7 +124,7 @@ public void boardWithConstrainedTransfer( } private void board(int stopIndex, RaptorBoardOrAlightEvent boarding) { - onTripIndex = boarding.tripIndex(); + onTripIndex = boarding.tripScheduleIndex(); onTrip = boarding.trip(); onTripBoardTime = boarding.time(); onTripBoardStop = stopIndex; diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java index d5c5b0516fa..a53c5c08a94 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/MinTravelDurationRoutingStrategy.java @@ -137,7 +137,7 @@ private void alight(int stopIndex, int stopPos, int alightSlackApplied) { } private void board(int stopIndex, RaptorBoardOrAlightEvent boarding) { - onTripIndex = boarding.tripIndex(); + onTripIndex = boarding.tripScheduleIndex(); onTrip = boarding.trip(); onTripBoardTime = boarding.earliestBoardTime(); onTripBoardStop = stopIndex; diff --git a/raptor/src/main/java/org/opentripplanner/raptor/spi/EmptyBoardOrAlightEvent.java b/raptor/src/main/java/org/opentripplanner/raptor/spi/EmptyBoardOrAlightEvent.java index 03f08f75b7d..56e9453ec2d 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/spi/EmptyBoardOrAlightEvent.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/spi/EmptyBoardOrAlightEvent.java @@ -6,7 +6,7 @@ record EmptyBoardOrAlightEvent(int earliestBoardTime) implements RaptorBoardOrAlightEvent { @Override - public int tripIndex() { + public int tripScheduleIndex() { return RaptorConstants.NOT_FOUND; } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorBoardOrAlightEvent.java b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorBoardOrAlightEvent.java index 0ab546610c6..8c3e1e78e14 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorBoardOrAlightEvent.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorBoardOrAlightEvent.java @@ -22,7 +22,7 @@ public interface RaptorBoardOrAlightEvent { *

* If not found {@link RaptorConstants#NOT_FOUND} is returned. */ - int tripIndex(); + int tripScheduleIndex(); /** * This i a reference to the trip found. diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestConstrainedTransfer.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestConstrainedTransfer.java index bb40b7e4765..c694c69e517 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestConstrainedTransfer.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestConstrainedTransfer.java @@ -41,7 +41,7 @@ class TestConstrainedTransfer } @Override - public int tripIndex() { + public int tripScheduleIndex() { return targetTripIndex; } diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearch.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearch.java index d22f201c432..dfad37fd94f 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearch.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearch.java @@ -74,7 +74,7 @@ private RaptorBoardOrAlightEvent searchInReverse(int tripIndex } @Override - public int tripIndex() { + public int tripScheduleIndex() { return tripIndex; } diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearchTest.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearchTest.java index 1a8bfc5f9fc..de76b5f4846 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearchTest.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTripScheduleSearchTest.java @@ -78,18 +78,18 @@ void tripSearchWithOneTrip( if (expStatus == Status.EMPTY) { assertTrue(result.empty()); assertTime(searchTime, result.earliestBoardTime()); - assertEquals(NOT_FOUND, result.tripIndex()); + assertEquals(NOT_FOUND, result.tripScheduleIndex()); } else if (expStatus == Status.OK) { assertFalse(result.empty()); assertEquals(stopPos, result.stopPositionInPattern()); assertTime(expTime, result.time()); assertTime(searchTime, result.earliestBoardTime()); - assertEquals(0, result.tripIndex()); + assertEquals(0, result.tripScheduleIndex()); } if (!result.empty()) { // A second search fails if the first search succeeded - int tripIndex = result.tripIndex(); + int tripIndex = result.tripScheduleIndex(); var e = search.search(direction.isForward() ? T09_59_59 : T10_20_01, stopPos, tripIndex); assertTrue(e.empty()); } @@ -139,27 +139,27 @@ void tripSearchWithTwoTrips( if (expTripIndex == NOT_FOUND) { assertTrue(result.empty()); assertTime(searchTime, result.earliestBoardTime()); - assertEquals(NOT_FOUND, result.tripIndex()); + assertEquals(NOT_FOUND, result.tripScheduleIndex()); } else { assertFalse(result.empty()); assertEquals(stopPos, result.stopPositionInPattern()); assertTime(expTime, result.time()); assertTime(searchTime, result.earliestBoardTime()); - assertEquals(expTripIndex, result.tripIndex()); + assertEquals(expTripIndex, result.tripScheduleIndex()); } if (!result.empty()) { int secondTrip = direction.isForward() ? TRIP_TWO : TRIP_ONE; int firstTrip = direction.isForward() ? TRIP_ONE : TRIP_TWO; - int tripIndex = result.tripIndex(); + int tripIndex = result.tripScheduleIndex(); var e = search.search(direction.isForward() ? T09_59_59 : T10_20_01, stopPos, tripIndex); if (tripIndex == secondTrip) { assertFalse(e.empty()); - assertEquals(firstTrip, result.tripIndex()); + assertEquals(firstTrip, result.tripScheduleIndex()); } else { assertTrue(e.empty()); - assertEquals(NOT_FOUND, result.tripIndex()); + assertEquals(NOT_FOUND, result.tripScheduleIndex()); } } } diff --git a/raptor/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripScheduleExactMatchSearchTest.java b/raptor/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripScheduleExactMatchSearchTest.java index cd59508fcd3..1d96bc498ad 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripScheduleExactMatchSearchTest.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripScheduleExactMatchSearchTest.java @@ -85,7 +85,7 @@ public void getCandidateTrip() { public void getCandidateTripIndex() { setup(FORWARD); var r = subject.search(TRIP_TIME, STOP_POS_0); - assertEquals(0, r.tripIndex()); + assertEquals(0, r.tripScheduleIndex()); } @Test From c1c0abe177b1cb46004b9ce7c4320392b2386395 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 19:26:40 +0200 Subject: [PATCH 12/16] refactor: Add tripScheduleIndex() method to TripSchedule interface --- .../algorithm/raptoradapter/transit/TripSchedule.java | 6 ++++++ .../transit/request/TripScheduleWithOffset.java | 5 +++++ .../raptorlegacy/_data/RaptorTestConstants.java | 6 ++++++ .../raptorlegacy/_data/transit/TestTripSchedule.java | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripSchedule.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripSchedule.java index 88d0ca8c96b..40e7b4a3751 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripSchedule.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripSchedule.java @@ -22,6 +22,12 @@ public interface TripSchedule extends DefaultTripSchedule { */ TripPattern getOriginalTripPattern(); + /** + * Return the index used to look up this trip in the + * {@link org.opentripplanner.raptor.spi.RaptorTimeTable#getTripSchedule(int)}. + */ + int tripScheduleIndex(); + /** * Return {@code true} if this trip is not based on a fixed schedule, but instead a frequency * based scheduled trip. The {@link #frequencyHeadwayInSeconds()} is only defined for such trips. diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java index e03e8b723d7..96f22cdb3d9 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java @@ -81,6 +81,11 @@ public TripPattern getOriginalTripPattern() { return pattern.getTripPattern().getPattern(); } + @Override + public int tripScheduleIndex() { + return tripIndexForDates; + } + @Override public LocalDate getServiceDate() { if (tripTimes == null) { diff --git a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/RaptorTestConstants.java b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/RaptorTestConstants.java index 0bfa5cf4bf8..110524d85ce 100644 --- a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/RaptorTestConstants.java +++ b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/RaptorTestConstants.java @@ -87,4 +87,10 @@ public interface RaptorTestConstants { default String stopIndexToName(int index) { return Character.toString('A' + index - 1); } + + static RuntimeException createDeprecatedUnsupportedFeatureException() { + return new UnsupportedOperationException( + "This class is deprecated, we are not adding more features." + ); + } } diff --git a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTripSchedule.java b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTripSchedule.java index fd4f52d175d..b061208af7a 100644 --- a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTripSchedule.java +++ b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTripSchedule.java @@ -1,6 +1,7 @@ package org.opentripplanner.raptorlegacy._data.transit; import static org.opentripplanner.core.model.accessibility.Accessibility.NO_INFORMATION; +import static org.opentripplanner.raptorlegacy._data.RaptorTestConstants.createDeprecatedUnsupportedFeatureException; import java.time.LocalDate; import java.util.Arrays; @@ -125,6 +126,11 @@ public TripPattern getOriginalTripPattern() { return this.originalPattern; } + @Override + public int tripScheduleIndex() { + throw createDeprecatedUnsupportedFeatureException(); + } + @SuppressWarnings("UnusedReturnValue") public static class Builder { From f59a2bba115338d963956a7a0db35a9948b55e0e Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 19:32:35 +0200 Subject: [PATCH 13/16] refactor: Introduce RaptorTripScheduleReference for fetching trips --- .../RaptorRoutingRequestTransitData.java | 6 +++ .../_data/transit/TestTransitData.java | 8 +++ .../raptor/spi/RaptorTransitDataProvider.java | 16 ++++++ .../spi/RaptorTripScheduleReference.java | 53 +++++++++++++++++++ .../raptor/_data/transit/TestTransitData.java | 16 +++++- .../spi/RaptorTripScheduleReferenceTest.java | 51 ++++++++++++++++++ 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReference.java create mode 100644 raptor/src/test/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReferenceTest.java diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java index ccbfba46759..abf49331b85 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java @@ -16,6 +16,7 @@ import org.opentripplanner.raptor.spi.RaptorStopNameResolver; import org.opentripplanner.raptor.spi.RaptorTransfer; import org.opentripplanner.raptor.spi.RaptorTransitDataProvider; +import org.opentripplanner.raptor.spi.RaptorTripScheduleReference; import org.opentripplanner.raptor.util.BitSetIterator; import org.opentripplanner.routing.algorithm.raptoradapter.transit.DefaultSlackProvider; import org.opentripplanner.routing.algorithm.raptoradapter.transit.RaptorTransitData; @@ -260,4 +261,9 @@ public RaptorConstrainedBoardingSearch transferConstraintsReverseS } return new ConstrainedBoardingSearch(false, toStopTransfers, fromStopTransfers); } + + @Override + public RaptorTripScheduleReference tripScheduleReference(TripSchedule trip) { + return new RaptorTripScheduleReference(trip.pattern().patternIndex(), trip.tripScheduleIndex()); + } } diff --git a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTransitData.java b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTransitData.java index 02127d5273f..129d2911c20 100644 --- a/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTransitData.java +++ b/application/src/test/java/org/opentripplanner/raptorlegacy/_data/transit/TestTransitData.java @@ -1,5 +1,7 @@ package org.opentripplanner.raptorlegacy._data.transit; +import static org.opentripplanner.raptorlegacy._data.RaptorTestConstants.createDeprecatedUnsupportedFeatureException; + import java.util.ArrayList; import java.util.BitSet; import java.util.HashSet; @@ -19,6 +21,7 @@ import org.opentripplanner.raptor.spi.RaptorTransfer; import org.opentripplanner.raptor.spi.RaptorTransitDataProvider; import org.opentripplanner.raptor.spi.RaptorTripPattern; +import org.opentripplanner.raptor.spi.RaptorTripScheduleReference; import org.opentripplanner.raptor.util.BitSetIterator; import org.opentripplanner.raptorlegacy._data.RaptorTestConstants; import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.CostCalculatorFactory; @@ -183,6 +186,11 @@ public RaptorConstrainedBoardingSearch transferConstraintsReve return getRoute(routeIndex).transferConstraintsReverseSearch(); } + @Override + public RaptorTripScheduleReference tripScheduleReference(TestTripSchedule trip) { + throw createDeprecatedUnsupportedFeatureException(); + } + public TestRoute getRoute(int index) { return routes.get(index); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTransitDataProvider.java b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTransitDataProvider.java index 596ac06db86..1e7723b7a41 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTransitDataProvider.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTransitDataProvider.java @@ -143,4 +143,20 @@ default void setup() {} * REVERSE search. */ RaptorConstrainedBoardingSearch transferConstraintsReverseSearch(int routeIndex); + + /** + * Return a reference for a give trip schedule. It can be stored and later used to fetch + * {@link RaptorRoute}, {@link RaptorTripPattern} and {@link RaptorTripSchedule} later on. + *

+ * IMPLEMENTATION NOTES + *

+ * Raptor uses this to fetch information in places where the original Raptor routing context + * (iterating over the stop of a pattern) is no longer available. Raptor could pass this + * information down the call stack, but that would have an effect on the performance. An other + * alternative is to add methods for this to the {@link RaptorTripSchedule}, but that would + * couple the trip schedule to the route and trip-pattern. + *

+ * This method is NOT performance critical, but it should not be slow. + */ + RaptorTripScheduleReference tripScheduleReference(T trip); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReference.java b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReference.java new file mode 100644 index 00000000000..b041757c886 --- /dev/null +++ b/raptor/src/main/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReference.java @@ -0,0 +1,53 @@ +package org.opentripplanner.raptor.spi; + +import java.util.Objects; + +/* + * Holds the route index and trip schedule index for a trip, allowing Raptor to look up route + * and pattern information in contexts where the original iteration state is no longer available. + */ +public final class RaptorTripScheduleReference { + + private final int routeIndex; + private final int tripScheduleIndex; + + public RaptorTripScheduleReference(int routeIndex, int tripScheduleIndex) { + this.routeIndex = routeIndex; + this.tripScheduleIndex = tripScheduleIndex; + } + + public int routeIndex() { + return routeIndex; + } + + public int tripScheduleIndex() { + return tripScheduleIndex; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + var that = (RaptorTripScheduleReference) o; + return routeIndex == that.routeIndex && tripScheduleIndex == that.tripScheduleIndex; + } + + @Override + public int hashCode() { + return Objects.hash(routeIndex, tripScheduleIndex); + } + + @Override + public String toString() { + return new StringBuilder() + .append('(') + .append("route: ") + .append(routeIndex) + .append(", ") + .append("trip: ") + .append(tripScheduleIndex) + .append(')') + .toString(); + } +} diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransitData.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransitData.java index 064b3f370dd..dc1d12c753c 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransitData.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransitData.java @@ -24,6 +24,7 @@ import org.opentripplanner.raptor.spi.RaptorTransfer; import org.opentripplanner.raptor.spi.RaptorTransitDataProvider; import org.opentripplanner.raptor.spi.RaptorTripPattern; +import org.opentripplanner.raptor.spi.RaptorTripScheduleReference; import org.opentripplanner.raptor.spi.TestSlackProvider; import org.opentripplanner.raptor.util.BitSetIterator; @@ -208,6 +209,19 @@ public RaptorConstrainedBoardingSearch transferConstraintsReve return getRoute(routeIndex).transferConstraintsReverseSearch(); } + @Override + public RaptorTripScheduleReference tripScheduleReference(TestTripSchedule trip) { + for (int routeIndex = 0; routeIndex < routes.size(); ++routeIndex) { + var route = routes.get(routeIndex); + for (int tripIndex = 0; tripIndex < route.numberOfTripSchedules(); ++tripIndex) { + if (trip == route.getTripSchedule(tripIndex)) { + return new RaptorTripScheduleReference(routeIndex, tripIndex); + } + } + } + throw new IllegalArgumentException("Trip not found: " + trip); + } + public RaptorRequestBuilder requestBuilder() { return requestBuilder; } @@ -252,8 +266,8 @@ public TestTransitData withTimetable(String routeName, String timetable) { } public TestTransitData withRoute(TestRoute route) { + int routeIndex = routes.size(); this.routes.add(route); - int routeIndex = this.routes.indexOf(route); var pattern = route.pattern(); for (int i = 0; i < pattern.numberOfStopsInPattern(); ++i) { int stopIndex = pattern.stopIndex(i); diff --git a/raptor/src/test/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReferenceTest.java b/raptor/src/test/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReferenceTest.java new file mode 100644 index 00000000000..dae315da137 --- /dev/null +++ b/raptor/src/test/java/org/opentripplanner/raptor/spi/RaptorTripScheduleReferenceTest.java @@ -0,0 +1,51 @@ +package org.opentripplanner.raptor.spi; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; + +class RaptorTripScheduleReferenceTest { + + private static final int ROUTE_INDEX = 3; + private static final int TRIP_INDEX = 7; + + private final RaptorTripScheduleReference subject = new RaptorTripScheduleReference( + ROUTE_INDEX, + TRIP_INDEX + ); + + @Test + void routeIndex() { + assertEquals(ROUTE_INDEX, subject.routeIndex()); + } + + @Test + void tripScheduleIndex() { + assertEquals(TRIP_INDEX, subject.tripScheduleIndex()); + } + + @Test + void testEquals() { + assertEquals(subject, new RaptorTripScheduleReference(ROUTE_INDEX, TRIP_INDEX)); + assertNotEquals(subject, new RaptorTripScheduleReference(ROUTE_INDEX + 1, TRIP_INDEX)); + assertNotEquals(subject, new RaptorTripScheduleReference(ROUTE_INDEX, TRIP_INDEX + 1)); + } + + @Test + void testHashCode() { + assertEquals( + subject.hashCode(), + new RaptorTripScheduleReference(ROUTE_INDEX, TRIP_INDEX).hashCode() + ); + assertNotEquals( + subject.hashCode(), + new RaptorTripScheduleReference(ROUTE_INDEX + 1, TRIP_INDEX).hashCode() + ); + } + + @Test + void testToString() { + assertEquals("(route: 3, trip: 7)", subject.toString()); + } +} From bd1a2f036dbeead2670acfa9772297ac84da3e00 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Mon, 30 Mar 2026 16:30:05 +0200 Subject: [PATCH 14/16] refactor: Rename RaptorOnBoardAccess to RaptorStartOnBoardAccess --- ...ess.java => RaptorStartOnBoardAccess.java} | 10 +++---- .../rangeraptor/DefaultRangeRaptorWorker.java | 2 +- .../internalapi/RoutingStrategy.java | 4 +-- .../MultiCriteriaRoutingStrategy.java | 4 +-- .../arrivals/c1/AccessStopArrival.java | 10 +++---- .../rangeraptor/transit/AccessPaths.java | 18 ++++++------ ...java => TestRaptorStartOnBoardAccess.java} | 6 ++-- .../moduletests/N01_OnBoardAccessTest.java | 28 +++++++++---------- 8 files changed, 41 insertions(+), 41 deletions(-) rename raptor/src/main/java/org/opentripplanner/raptor/api/model/{RaptorOnBoardAccess.java => RaptorStartOnBoardAccess.java} (70%) rename raptor/src/test/java/org/opentripplanner/raptor/_data/transit/{TestRaptorOnBoardAccess.java => TestRaptorStartOnBoardAccess.java} (82%) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java similarity index 70% rename from raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java rename to raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java index 42271d358b7..250fd3b6d2a 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorOnBoardAccess.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java @@ -1,12 +1,12 @@ package org.opentripplanner.raptor.api.model; /** - * RaptorOnBoardAccess allows you to board a specific trip at a given stop. The trip is - * identified by the route index and trip schedule index. A typical use-case for this is when you - * want to start a trip on-board, meaning that one is already on the vehicle when the path starts. - * The returned paths will start with a zero duration access and a boarding at the given stop. + * This class allows you to board a specific trip at a given stop. The trip is identified by the + * route index and trip schedule index. A typical use-case for this is when you* want to start a + * trip on-board, meaning that one is already on the vehicle when the path starts. The returned + * paths will start with a zero duration access and a boarding at the given stop. */ -public interface RaptorOnBoardAccess extends RaptorAccessEgress { +public interface RaptorStartOnBoardAccess extends RaptorAccessEgress { /** * Return the trip boarding this access is requiered to use. */ diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java index b7f9c42b188..6a37ef1683e 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/DefaultRangeRaptorWorker.java @@ -128,7 +128,7 @@ public void applyOnBoardStopAccess() { @Override public void applyOnBoardTripAccess() { - for (var accessPath : accessPaths.onBoardAccessPaths()) { + for (var accessPath : accessPaths.startOnBoardAccessPaths()) { var boarding = accessPath.tripBoarding(); var route = transitData.getRouteForIndex(boarding.routeIndex()); var trip = route.timetable().getTripSchedule(boarding.tripScheduleIndex()); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java index 99bf292ee3a..33043c1f288 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java @@ -2,7 +2,7 @@ import javax.annotation.Nullable; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorStartOnBoardAccess; import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.rangeraptor.RangeRaptor; import org.opentripplanner.raptor.spi.RaptorConstrainedBoardingSearch; @@ -75,7 +75,7 @@ void boardWithConstrainedTransfer( RaptorConstrainedBoardingSearch txSearch ); - default void registerOnBoardAccessStopArrival(RaptorOnBoardAccess access, int boardTime) { + default void registerOnBoardAccessStopArrival(RaptorStartOnBoardAccess access, int boardTime) { throw new UnsupportedOperationException( "On-board access is not yet supported for this routing strategy" ); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java index ebb71a0366b..f9456edb333 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java @@ -5,7 +5,7 @@ import java.util.Objects; import javax.annotation.Nullable; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorStartOnBoardAccess; import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.rangeraptor.internalapi.OnBoardTripAccessPathsForRoute; import org.opentripplanner.raptor.rangeraptor.internalapi.PassThroughPointsService; @@ -121,7 +121,7 @@ public void boardWithConstrainedTransfer( } @Override - public void registerOnBoardAccessStopArrival(RaptorOnBoardAccess access, int boardTime) { + public void registerOnBoardAccessStopArrival(RaptorStartOnBoardAccess access, int boardTime) { state.addOnBoardAccessStopArrival(access, boardTime); } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java index c5718209722..5a96372de77 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java @@ -4,7 +4,7 @@ import static org.opentripplanner.raptor.api.view.PathLegType.ACCESS; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorStartOnBoardAccess; import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; import org.opentripplanner.raptor.api.view.AccessPathView; import org.opentripplanner.raptor.api.view.PathLegType; @@ -78,11 +78,11 @@ public McStopArrival addSlackToArrivalTime(int slack) { @Override public RaptorTripScheduleStopPosition subsequentBoardingConstraint() { - if (access instanceof RaptorOnBoardAccess onBoardAccess) { + if (access instanceof RaptorStartOnBoardAccess startOnBoardAccess) { return new RaptorTripScheduleStopPosition( - onBoardAccess.tripBoarding().routeIndex(), - onBoardAccess.tripBoarding().tripScheduleIndex(), - onBoardAccess.tripBoarding().stopPositionInPattern() + startOnBoardAccess.tripBoarding().routeIndex(), + startOnBoardAccess.tripBoarding().tripScheduleIndex(), + startOnBoardAccess.tripBoarding().stopPositionInPattern() ); } throw new UnsupportedOperationException(); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java index a9b2c8e8266..12b669a6896 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/transit/AccessPaths.java @@ -10,7 +10,7 @@ import java.util.function.IntUnaryOperator; import java.util.stream.IntStream; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; -import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorStartOnBoardAccess; import org.opentripplanner.raptor.api.request.RaptorProfile; import org.opentripplanner.raptor.spi.IntIterator; import org.opentripplanner.raptor.spi.RaptorConstants; @@ -34,7 +34,7 @@ public class AccessPaths { private final IntUnaryOperator iterationOp; private final TIntObjectMap> arrivedOnStreetByNumOfRides; private final TIntObjectMap> arrivedOnBoardByNumOfRides; - private final List onBoardAccessPaths; + private final List startOnBoardAccessPaths; private int iterationTimePenaltyLimit = RaptorConstants.TIME_NOT_SET; private AccessPaths( @@ -44,7 +44,7 @@ private AccessPaths( IntUnaryOperator iterationOp, TIntObjectMap> arrivedOnStreetByNumOfRides, TIntObjectMap> arrivedOnBoardByNumOfRides, - List onBoardAccessPaths + List startOnBoardAccessPaths ) { this.iterationStep = iterationStep; this.maxNumberOfRides = maxNumberOfRides; @@ -52,7 +52,7 @@ private AccessPaths( this.iterationOp = iterationOp; this.arrivedOnStreetByNumOfRides = arrivedOnStreetByNumOfRides; this.arrivedOnBoardByNumOfRides = arrivedOnBoardByNumOfRides; - this.onBoardAccessPaths = onBoardAccessPaths; + this.startOnBoardAccessPaths = startOnBoardAccessPaths; } /** @@ -75,8 +75,8 @@ public static AccessPaths create( // and also cannot have time penalties, so we extract them from paths before removing. var onBoardAccessPaths = paths .stream() - .filter(RaptorOnBoardAccess.class::isInstance) - .map(RaptorOnBoardAccess.class::cast) + .filter(RaptorStartOnBoardAccess.class::isInstance) + .map(RaptorStartOnBoardAccess.class::cast) .toList(); if (profile.is(RaptorProfile.MULTI_CRITERIA)) { @@ -139,8 +139,8 @@ public List arrivedOnBoard() { /** * Return the on-board accesses */ - public List onBoardAccessPaths() { - return onBoardAccessPaths; + public List startOnBoardAccessPaths() { + return startOnBoardAccessPaths; } public int maxNumberOfRides() { @@ -194,7 +194,7 @@ public AccessPaths filterOnSegment(int segment) { iterationOp, AccessEgressFunctions.filterOnSegment(arrivedOnStreetByNumOfRides, segment), AccessEgressFunctions.filterOnSegment(arrivedOnBoardByNumOfRides, segment), - AccessEgressFunctions.filterOnSegment(onBoardAccessPaths, segment) + AccessEgressFunctions.filterOnSegment(startOnBoardAccessPaths, segment) ); } diff --git a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorStartOnBoardAccess.java similarity index 82% rename from raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java rename to raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorStartOnBoardAccess.java index 54ec1693c00..732075bf21f 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorOnBoardAccess.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/_data/transit/TestRaptorStartOnBoardAccess.java @@ -1,15 +1,15 @@ package org.opentripplanner.raptor._data.transit; -import org.opentripplanner.raptor.api.model.RaptorOnBoardAccess; +import org.opentripplanner.raptor.api.model.RaptorStartOnBoardAccess; import org.opentripplanner.raptor.api.model.RaptorTripScheduleStopPosition; -public class TestRaptorOnBoardAccess implements RaptorOnBoardAccess { +public class TestRaptorStartOnBoardAccess implements RaptorStartOnBoardAccess { private final int stop; private final int generalizedCost; private final RaptorTripScheduleStopPosition tripBoarding; - public TestRaptorOnBoardAccess( + public TestRaptorStartOnBoardAccess( int routeIndex, int tripScheduleIndex, int stopPositionInPattern, diff --git a/raptor/src/test/java/org/opentripplanner/raptor/moduletests/N01_OnBoardAccessTest.java b/raptor/src/test/java/org/opentripplanner/raptor/moduletests/N01_OnBoardAccessTest.java index 50da3a8a117..c712f0f2056 100644 --- a/raptor/src/test/java/org/opentripplanner/raptor/moduletests/N01_OnBoardAccessTest.java +++ b/raptor/src/test/java/org/opentripplanner/raptor/moduletests/N01_OnBoardAccessTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test; import org.opentripplanner.raptor.RaptorService; import org.opentripplanner.raptor._data.transit.TestAccessEgress; -import org.opentripplanner.raptor._data.transit.TestRaptorOnBoardAccess; +import org.opentripplanner.raptor._data.transit.TestRaptorStartOnBoardAccess; import org.opentripplanner.raptor._data.transit.TestTransitData; import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.request.RaptorProfile; @@ -53,7 +53,7 @@ private RaptorRequestBuilder prepareRequest() { @DisplayName("On-board access with two routes boards the correct route") void onBoardAccess() { data - .access(new TestRaptorOnBoardAccess(0, 0, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 0, 1, STOP_B, 0)) .withRoutes() .withTimetables( """ @@ -83,7 +83,7 @@ void onBoardAccess() { ) void transfer() { data - .access(new TestRaptorOnBoardAccess(0, 0, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 0, 1, STOP_B, 0)) .withRoutes() .withTimetables( """ @@ -113,7 +113,7 @@ void transfer() { @DisplayName("On-board access does not allow invalid boardings or transfers") void noInvalidTransfers() { data - .access(new TestRaptorOnBoardAccess(0, 0, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 0, 1, STOP_B, 0)) .withRoutes() .withTimetables( """ @@ -144,7 +144,7 @@ void noInvalidTransfers() { @DisplayName("On-board access on a ring-line starts from the provided stop position") void ringLineBoardsCorrectStopPosition() { data - .access(new TestRaptorOnBoardAccess(0, 0, 5, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 0, 5, STOP_B, 0)) .withRoutes() .withTimetables( """ @@ -171,7 +171,7 @@ void ringLineBoardsCorrectStopPosition() { ) void correctTrip() { data - .access(new TestRaptorOnBoardAccess(0, 1, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 1, 1, STOP_B, 0)) .withRoutes() .withTimetables( """ @@ -200,7 +200,7 @@ void correctTrip() { @DisplayName("On-board access to a non-existing route results in exception") void nonExistentRoute() { data - .access(new TestRaptorOnBoardAccess(1, 1, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(1, 1, 1, STOP_B, 0)) .withTimetables( """ -- R1 @@ -223,7 +223,7 @@ void nonExistentRoute() { @DisplayName("On-board access to a non-existing trip in route results in exception") void nonExistentTrip() { data - .access(new TestRaptorOnBoardAccess(0, 3, 1, STOP_B, 0)) + .access(new TestRaptorStartOnBoardAccess(0, 3, 1, STOP_B, 0)) .withTimetables( """ -- R1 @@ -248,11 +248,11 @@ void multipleAccesses() { data .access( // Dominated by trip 1 @ C - new TestRaptorOnBoardAccess(0, 1, 1, STOP_B, 0), + new TestRaptorStartOnBoardAccess(0, 1, 1, STOP_B, 0), // Pareto-optimal - new TestRaptorOnBoardAccess(0, 1, 2, STOP_C, 0), + new TestRaptorStartOnBoardAccess(0, 1, 2, STOP_C, 0), // Pareto-optimal - new TestRaptorOnBoardAccess(1, 0, 0, STOP_A, 0) + new TestRaptorStartOnBoardAccess(1, 0, 0, STOP_A, 0) ) .withRoutes() .withTimetables( @@ -289,7 +289,7 @@ void walkAndOnBoard() { // Walk to E to catch a trip that arrives earlier TestAccessEgress.of("Walk 5m ~ E"), // Or stay on board - new TestRaptorOnBoardAccess(0, 0, 1, STOP_B, 0) + new TestRaptorStartOnBoardAccess(0, 0, 1, STOP_B, 0) ) .withRoutes() .withTimetables( @@ -322,8 +322,8 @@ void walkAndOnBoard() { void rangeQuery() { data .access( - new TestRaptorOnBoardAccess(0, 0, 1, STOP_B, 0), - new TestRaptorOnBoardAccess(0, 1, 1, STOP_B, 0) + new TestRaptorStartOnBoardAccess(0, 0, 1, STOP_B, 0), + new TestRaptorStartOnBoardAccess(0, 1, 1, STOP_B, 0) ) .withRoutes() .withTimetables( From 7231a2274fe6cb20e69a2d41c9b088c8101f01b9 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 8 Apr 2026 11:57:01 +0200 Subject: [PATCH 15/16] review: Correct spelling errors in configuration and documentation --- .../src/test/resources/speedtest/speed-test-config.json | 2 +- .../raptor/api/model/RaptorStartOnBoardAccess.java | 4 ++-- .../raptor/api/model/RaptorTripScheduleStopPosition.java | 2 +- script/custom-release.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/src/test/resources/speedtest/speed-test-config.json b/application/src/test/resources/speedtest/speed-test-config.json index e8dc0e793c3..7c2d2332dab 100644 --- a/application/src/test/resources/speedtest/speed-test-config.json +++ b/application/src/test/resources/speedtest/speed-test-config.json @@ -2,6 +2,6 @@ // Run all test-cases on the given date "testDate": "2009-12-17", "feedId": "1", - "graph": "not-used-but-requiered.obj", + "graph": "not-used-but-required.obj", "ignoreStreetResults": true } diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java index 250fd3b6d2a..23fe28cef02 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorStartOnBoardAccess.java @@ -2,13 +2,13 @@ /** * This class allows you to board a specific trip at a given stop. The trip is identified by the - * route index and trip schedule index. A typical use-case for this is when you* want to start a + * route index and trip schedule index. A typical use-case for this is when you want to start a * trip on-board, meaning that one is already on the vehicle when the path starts. The returned * paths will start with a zero duration access and a boarding at the given stop. */ public interface RaptorStartOnBoardAccess extends RaptorAccessEgress { /** - * Return the trip boarding this access is requiered to use. + * Return the trip boarding this access is required to use. */ RaptorTripScheduleStopPosition tripBoarding(); diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java index ce2ce38a4a9..c6ab860cb27 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java @@ -5,7 +5,7 @@ /** * This class contain information to identify a given stop in a stop pattern for a given trip - * schedule in a route. This can for example be used to identify where a bording or alithing + * schedule in a route. This can for example be used to identify where a bording or alighting * happens. */ public final class RaptorTripScheduleStopPosition { diff --git a/script/custom-release.py b/script/custom-release.py index baedfc64a60..854f1079168 100755 --- a/script/custom-release.py +++ b/script/custom-release.py @@ -910,7 +910,7 @@ def print_help(): 1. The configured release-branch is reset hard to the script argument. 2. Then the labeled PRs are merged into the release-branch [if configured]. 3. The config-branches are merged into the release-branch [if configured]. - 4. The pom.xml file is updated with a new version and serialization version id [if requiered]. + 4. The pom.xml file is updated with a new version and serialization version id [if required]. 5. The release is tested, tagged and pushed to Git repo. See the RELEASE_README.md for more details. From a0216a4ebd2297b10d6e41a00a7302fd1a0e0456 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 9 Apr 2026 09:47:16 +0200 Subject: [PATCH 16/16] Apply suggestions from code review Co-authored-by: Sigurd Totland --- .../raptor/api/model/RaptorTripScheduleStopPosition.java | 8 ++++---- .../raptor/rangeraptor/internalapi/RoutingStrategy.java | 4 ++-- .../multicriteria/arrivals/McStopArrivals.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java index c6ab860cb27..1238e7fdb67 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/api/model/RaptorTripScheduleStopPosition.java @@ -4,7 +4,7 @@ import org.opentripplanner.utils.tostring.ToStringBuilder; /** - * This class contain information to identify a given stop in a stop pattern for a given trip + * This class contains information to identify a given stop in a stop pattern for a given trip * schedule in a route. This can for example be used to identify where a bording or alighting * happens. */ @@ -35,8 +35,8 @@ public int tripScheduleIndex() { } /// The stop position in the route stop-pattern. Knowing the stop index is not enough to identify - /// a stop, a stop may occour multiple times in a stop pattern, in other word a circular stop - /// pattern visit some of the same stops multiple times. + /// a stop, a stop may occour multiple times in a stop pattern, in other words a circular stop + /// pattern visits some of the same stops multiple times. public int stopPositionInPattern() { return stopPositionInPattern; } @@ -61,7 +61,7 @@ public int hashCode() { @Override public String toString() { - // The field labels are shorthen to improve reading - should be easy to get in the context + // The field labels are shortened to improve reading - should be easy to get in the context return ToStringBuilder.of(RaptorTripScheduleStopPosition.class) .addNum("route", routeIndex) .addNum("tripSchedule", tripScheduleIndex) diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java index 33043c1f288..91846557e43 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/internalapi/RoutingStrategy.java @@ -82,8 +82,8 @@ default void registerOnBoardAccessStopArrival(RaptorStartOnBoardAccess access, i } /** - * @return all on-board trip access arrival for the given {@code routeIndex}. The arrivals are - * removed from state and can only be fetched once. The method return {@code null} if no + * @return all on-board trip access arrivals for the given {@code routeIndex}. The arrivals are + * removed from state and can only be fetched once. The method returns {@code null} if no * arrivals exist - this should be very efficient to check. */ @Nullable diff --git a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java index e6f4cf1bf92..a7c751f26aa 100644 --- a/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java +++ b/raptor/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivals.java @@ -159,7 +159,7 @@ public void addOnBoardTripArrival(McStopArrival arrival) { access.add(arrival); // Then update the state, both touchedStops and init the pareto-set for the given stop to - // prevent NPE when the state is fetched later. The set is empty, witch is ok. + // prevent NPE when the state is fetched later. The set is empty, which is ok. findOrCreateSet(arrival.stop()); touchedStops.set(arrival.stop()); }