diff --git a/pom.xml b/pom.xml index e0208d8fb3d..2b2a3231a12 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ - 15 + 16 25.2 2.12.5 diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/UnscheduledTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/UnscheduledTripTest.java index 0873c0823e7..53b7dc0a09b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/UnscheduledTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/UnscheduledTripTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import java.net.URISyntaxException; import java.util.List; import java.util.Set; import java.util.stream.Collectors; diff --git a/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java b/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java index 51b10b8a1a4..975da258b25 100644 --- a/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java +++ b/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java @@ -4,14 +4,15 @@ import static org.opentripplanner.util.time.DurationUtils.durationToStr; import java.util.List; -import org.locationtech.jts.geom.Coordinate; import org.opentripplanner.common.geometry.SphericalDistanceLibrary; import org.opentripplanner.model.Station; import org.opentripplanner.model.StopLocation; import org.opentripplanner.model.Trip; import org.opentripplanner.model.TripPattern; +import org.opentripplanner.model.WgsCoordinate; import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.model.transfer.RouteTransferPoint; +import org.opentripplanner.model.transfer.RouteStationTransferPoint; +import org.opentripplanner.model.transfer.RouteStopTransferPoint; import org.opentripplanner.model.transfer.StationTransferPoint; import org.opentripplanner.model.transfer.StopTransferPoint; import org.opentripplanner.model.transfer.TransferPoint; @@ -26,6 +27,8 @@ * to read and find special test-cases when needed. */ public class TransfersReport { + private static final boolean BOARD = true; + private static final boolean ALIGHT = false; private static final int NOT_SET = -1; @@ -54,13 +57,16 @@ String export() { ); transfers.forEach(t -> { - var from = pointInfo(t.getFrom(), true); - var to = pointInfo(t.getTo(), false); + var from = pointInfo(t.getFrom(), ALIGHT); + var to = pointInfo(t.getTo(), BOARD); var dist = (from.coordinate == null || to.coordinate == null) ? "" : String.format( "%.0fm", - SphericalDistanceLibrary.fastDistance(from.coordinate, to.coordinate) + SphericalDistanceLibrary.fastDistance( + from.coordinate.asJtsCoordinate(), + to.coordinate.asJtsCoordinate() + ) ); var duration = (from.time == NOT_SET || to.time == NOT_SET) ? "" : durationToStr(to.time - from.time); @@ -72,13 +78,13 @@ String export() { buf.addText(from.entityId); buf.addText(from.route); buf.addText(from.trip); - buf.addText(from.loc); + buf.addText(from.location()); buf.addNumber(from.specificity); buf.addText(to.type); buf.addText(to.entityId); buf.addText(to.route); buf.addText(to.trip); - buf.addText(to.loc); + buf.addText(to.location()); buf.addNumber(to.specificity); buf.addTime(from.time, NOT_SET); buf.addTime(to.time, NOT_SET); @@ -93,10 +99,7 @@ String export() { return buf.toString(); } - private TxPoint pointInfo( - TransferPoint p, - boolean arrival - ) { + private TxPoint pointInfo(TransferPoint p, boolean boarding) { var r = new TxPoint(); if(p instanceof TripTransferPoint) { @@ -109,17 +112,28 @@ private TxPoint pointInfo( r.entityId = trip.getId().getId(); r.route = route.getName() + " " + route.getMode() + " " + route.getLongName(); r.trip = trip.getTripHeadsign(); - addLocation(r, ptn, tp.getStopPositionInPattern(), trip, arrival); + var stop = ptn.getStop(tp.getStopPositionInPattern()); + addLocation(r, ptn, stop, trip, boarding); } - else if(p instanceof RouteTransferPoint) { - var rp = (RouteTransferPoint)p; + else if(p instanceof RouteStopTransferPoint) { + var rp = (RouteStopTransferPoint)p; var route = rp.getRoute(); var ptn = index.getPatternsForRoute().get(route).stream().findFirst().orElse(null); r.operator = route.getOperator().getId().getId(); r.type = "Route"; r.entityId = route.getId().getId(); r.route = route.getName() + " " + route.getMode() + " " + route.getLongName(); - addLocation(r, ptn, rp.getStopPositionInPattern(), null, arrival); + addLocation(r, ptn, rp.getStop(), null, boarding); + } + else if(p instanceof RouteStationTransferPoint) { + var rp = (RouteStationTransferPoint)p; + var route = rp.getRoute(); + r.operator = route.getOperator().getId().getId(); + r.type = "Route"; + r.entityId = route.getId().getId(); + r.route = route.getName() + " " + route.getMode() + " " + route.getLongName(); + r.loc += rp.getStation().getName(); + r.coordinate = rp.getStation().getCoordinate(); } else if(p instanceof StopTransferPoint) { var sp = (StopTransferPoint)p; @@ -127,7 +141,7 @@ else if(p instanceof StopTransferPoint) { r.type = "Stop"; r.entityId = stop.getId().getId(); r.loc = stop.getName(); - r.coordinate = stop.getCoordinate().asJtsCoordinate(); + r.coordinate = stop.getCoordinate(); } else if(p instanceof StationTransferPoint) { var sp = (StationTransferPoint)p; @@ -135,7 +149,7 @@ else if(p instanceof StationTransferPoint) { r.type = "Station"; r.entityId = station.getId().getId(); r.loc = station.getName(); - r.coordinate = station.getCoordinate().asJtsCoordinate(); + r.coordinate = station.getCoordinate(); } r.specificity = p.getSpecificityRanking(); @@ -146,23 +160,29 @@ else if(p instanceof StationTransferPoint) { private static void addLocation( TxPoint r, TripPattern pattern, - int stopPosition, + StopLocation stop, Trip trip, - boolean arrival + boolean boarding ) { - if(pattern == null || stopPosition >= pattern.numberOfStops()) { - r.loc += "[Stop position not found: " + stopPosition + "]"; + if(pattern == null) { + r.loc += stop.getName() + " [Pattern no found]"; + return; + } + int stopPosition = pattern.findStopPosition(stop); + r.coordinate = stop.getCoordinate(); + + if(stopPosition<0) { + r.loc += "[Stop not found in pattern: " + stop.getName() + "]"; return; } - var stop = pattern.getStops().get(stopPosition); - r.loc += stop.getName() + " [" + stopPosition + "]" + " " + stop.getCoordinate(); - r.coordinate = stop.getCoordinate().asJtsCoordinate(); + r.loc += stop.getName() + " [" + stopPosition + "]"; if(trip != null) { var tt = pattern.getScheduledTimetable().getTripTimes(trip); - r.time = arrival - ? tt.getScheduledArrivalTime(stopPosition) - : tt.getScheduledDepartureTime(stopPosition); + r.time = boarding + ? tt.getScheduledDepartureTime(stopPosition) + : tt.getScheduledArrivalTime(stopPosition) + ; } } @@ -174,7 +194,11 @@ static class TxPoint { private String trip = ""; private String route = ""; private Integer specificity = null; - private Coordinate coordinate = null; + private WgsCoordinate coordinate = null; private int time = NOT_SET; + + String location() { + return coordinate == null ? loc : loc + " " + coordinate; + } } } diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java index 7b35aebdb84..5fb77cd7f7c 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java @@ -5,7 +5,6 @@ import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; -import lombok.val; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.opentripplanner.common.model.T2; @@ -42,7 +41,7 @@ public Collection> map(TransitStopVertex input) { String patterns = JSONArray.toJSONString(patternsForStop.stream().map(tripPattern -> { int stopPos = tripPattern.findStopPosition(stop); - val headsign = stopPos < 0 ? "Not Available" : + var headsign = stopPos < 0 ? "Not Available" : tripPattern.getScheduledTimetable().getTripTimes().get(0).getHeadsign(stopPos); return new JSONObject(Map.of( "headsign", headsign, diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java index 6430bb0b7b5..7cb898a6c4d 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java @@ -16,7 +16,8 @@ import org.opentripplanner.model.Trip; import org.opentripplanner.model.TripStopTimes; import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.model.transfer.RouteTransferPoint; +import org.opentripplanner.model.transfer.RouteStationTransferPoint; +import org.opentripplanner.model.transfer.RouteStopTransferPoint; import org.opentripplanner.model.transfer.StationTransferPoint; import org.opentripplanner.model.transfer.StopTransferPoint; import org.opentripplanner.model.transfer.TransferConstraint; @@ -184,11 +185,8 @@ private TransferPoint mapTransferPoint( return stopPositionInPattern < 0 ? null : new TripTransferPoint(trip, stopPositionInPattern); } else if(route != null) { - var trips = tripsByRoute.get(route); - if(trips.isEmpty()) { throw new IllegalStateException("No trips found for route: " + route); } - - int stopPositionInPattern = stopPosition(route, stop, station, boardTrip); - return new RouteTransferPoint(route, stopPositionInPattern); + if(stop != null) { return new RouteStopTransferPoint(route, stop); } + else if(station != null) { return new RouteStationTransferPoint(route, station); } } else if(stop != null) { return new StopTransferPoint(stop); diff --git a/src/main/java/org/opentripplanner/model/StopPattern.java b/src/main/java/org/opentripplanner/model/StopPattern.java index 11873f6e439..f8adc5732f0 100644 --- a/src/main/java/org/opentripplanner/model/StopPattern.java +++ b/src/main/java/org/opentripplanner/model/StopPattern.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.function.Predicate; /** * This class represents what is called a JourneyPattern in Transmodel: the sequence of stops at @@ -77,6 +78,22 @@ int findStopPosition(StopLocation stop) { return -1; } + int findBoardingPosition(StopLocation stop) { + return findStopPosition(0, stops.length-1, (s) -> s == stop, stop); + } + + int findAlightPosition(StopLocation stop) { + return findStopPosition(1, stops.length, (s) -> s == stop, stop); + } + + int findBoardingPosition(Station station) { + return findStopPosition(0, stops.length-1, station::includes, station); + } + + int findAlightPosition(Station station) { + return findStopPosition(1, stops.length, station::includes, station); + } + public boolean equals(Object other) { if (other instanceof StopPattern) { StopPattern that = (StopPattern) other; @@ -180,4 +197,16 @@ private static PickDrop computePickDrop(StopLocation stop, PickDrop pickDrop) { if(stop instanceof FlexStopLocation) { return PickDrop.NONE; } else { return pickDrop; } } + + private int findStopPosition( + final int start, + final int end, + final Predicate match, + final Object entity + ) { + for (int i=start; i") .toString(); } diff --git a/src/main/java/org/opentripplanner/model/transfer/RouteStopTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/RouteStopTransferPoint.java new file mode 100644 index 00000000000..76c504ed0c8 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/transfer/RouteStopTransferPoint.java @@ -0,0 +1,49 @@ +package org.opentripplanner.model.transfer; + +import java.io.Serializable; +import org.opentripplanner.model.Route; +import org.opentripplanner.model.StopLocation; +import org.opentripplanner.model.base.ValueObjectToStringBuilder; + +public final class RouteStopTransferPoint implements TransferPoint, Serializable { + + private static final long serialVersionUID = 1L; + + private final Route route; + private final StopLocation stop; + + public RouteStopTransferPoint(Route route, StopLocation stop) { + this.route = route; + this.stop = stop; + } + + public Route getRoute() { + return route; + } + + public StopLocation getStop() { + return stop; + } + + @Override + public boolean applyToAllTrips() { + return true; + } + + @Override + public int getSpecificityRanking() { return 3; } + + @Override + public boolean isRouteStopTransferPoint() { return true; } + + @Override + public String toString() { + return ValueObjectToStringBuilder.of() + .addText("") + .toString(); + } +} diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java index 21506365543..c9522bdb126 100644 --- a/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java +++ b/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java @@ -18,30 +18,37 @@ * {@link StationTransferPoint} This apply to all trip stopping at a stop part of the given * station. *

The specificity-ranking is above {@link StationTransferPoint}s and less than - * {@link RouteTransferPoint}. + * {@link RouteStationTransferPoint}. * *

  • - * A {@link RouteTransferPoint} is a from/to point for a Route at the given stop/station. This + * A {@link RouteStationTransferPoint} is a from/to point for a Route at the given stop. This * only exist in GTFS, not in the Nordic NeTex profile. * *

    The specificity-ranking is above {@link StopTransferPoint}s and less than + * {@link RouteStopTransferPoint}. + *

  • + *
  • + * A {@link RouteStopTransferPoint} is a from/to point for a Route at the given station. This + * only exist in GTFS, not in the Nordic NeTex profile. + * + *

    The specificity-ranking is above {@link RouteStationTransferPoint}s and less than * {@link TripTransferPoint}. *

  • *
  • * {@link TripTransferPoint} A transfer from/to a Trip at the given stop position(not stop). - * - *

    This is the most specific point type, and will override both {@link RouteTransferPoint} - * and {@link StopTransferPoint} if more than one match exist. + * The GTFS Transfers may specify a transfer from/to a trip and stop/station. But in OTP we + * map the stop to a stop position in pattern. The OTP model {@link TripTransferPoint} do NOT + * reference the stop/station, but the {@code stopPositionInPattern} instead. There is two + * reasons for this. In NeTEx the an interchange is from a trip and stop-point, so this model + * fits better with NeTEx. The second reson is that real-time updates could invalidate the + * trip-transfer-point, since the stop could change to another platform(common for railway + * stations). To account for this the RT-update would need to patch the trip-transfer-point. + * We simplify the RT-updates by converting the stop to a stop-position-in-pattern. + *

    + * This is the most specific point type. *

  • * *

    - * The GTFS Transfers may specify a transfer from/to a route/trip and stop/station. But in OTP we - * map the stop to a stop position in pattern. The OTP model {@link RouteTransferPoint} and - * {@link TripTransferPoint} do NOT reference the stop/station, but the - * {@code stopPositionInPattern} instead. The reason is that real-time updates could invalidate a - * (route+stop) transfer-point, since the stop could change to another platform(common for railway - * stations). To account for this the RT-update would have to patch the (route&stop)-transfer-point. - * We simplify the RT-updates by converting expanding (route+stop) to (trip+stop position). */ public interface TransferPoint { @@ -61,9 +68,18 @@ public interface TransferPoint { default TripTransferPoint asTripTransferPoint() { return (TripTransferPoint) this; } /** is a Route specific transfer point */ - default boolean isRouteTransferPoint() { return false; } + default boolean isRouteStationTransferPoint() { return false; } - default RouteTransferPoint asRouteTransferPoint() { return (RouteTransferPoint) this; } + default RouteStationTransferPoint asRouteStationTransferPoint() { + return (RouteStationTransferPoint) this; + } + + /** is a Route specific transfer point */ + default boolean isRouteStopTransferPoint() { return false; } + + default RouteStopTransferPoint asRouteStopTransferPoint() { + return (RouteStopTransferPoint) this; + } /** is a Stop specific transfer point (no Trip or Route) */ default boolean isStopTransferPoint() { return false; } @@ -92,8 +108,11 @@ static Route getRoute(TransferPoint point) { if(point.isTripTransferPoint()) { return point.asTripTransferPoint().getTrip().getRoute(); } - if(point.isRouteTransferPoint()) { - return point.asRouteTransferPoint().getRoute(); + if(point.isRouteStopTransferPoint()) { + return point.asRouteStopTransferPoint().getRoute(); + } + if(point.isRouteStationTransferPoint()) { + return point.asRouteStationTransferPoint().getRoute(); } return null; } diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java b/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java index 8dcb122c995..87bb8bf1bea 100644 --- a/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java +++ b/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java @@ -20,7 +20,8 @@ */ class TransferPointMap { private final Map, E> tripMap = new HashMap<>(); - private final Map, E> routeMap = new HashMap<>(); + private final Map, E> routeStopMap = new HashMap<>(); + private final Map, E> routeStationMap = new HashMap<>(); private final Map stopMap = new HashMap<>(); private final Map stationMap = new HashMap<>(); @@ -29,9 +30,13 @@ void put(TransferPoint point, E e) { var tp = point.asTripTransferPoint(); tripMap.put(tripKey(tp.getTrip(), tp.getStopPositionInPattern()), e); } - else if(point.isRouteTransferPoint()) { - var rp = point.asRouteTransferPoint(); - routeMap.put(routeKey(rp.getRoute(), rp.getStopPositionInPattern()), e); + else if(point.isRouteStopTransferPoint()) { + var rp = point.asRouteStopTransferPoint(); + routeStopMap.put(routeStopKey(rp.getRoute(), rp.getStop()), e); + } + else if(point.isRouteStationTransferPoint()) { + var rp = point.asRouteStationTransferPoint(); + routeStationMap.put(routeStationKey(rp.getRoute(), rp.getStation()), e); } else if(point.isStopTransferPoint()) { stopMap.put(point.asStopTransferPoint().getStop(), e); @@ -49,9 +54,13 @@ E computeIfAbsent(TransferPoint point, Supplier creator) { var tp = point.asTripTransferPoint(); return tripMap.computeIfAbsent(tripKey(tp.getTrip(), tp.getStopPositionInPattern()), k -> creator.get()); } - else if(point.isRouteTransferPoint()) { - var rp = point.asRouteTransferPoint(); - return routeMap.computeIfAbsent(routeKey(rp.getRoute(), rp.getStopPositionInPattern()), k -> creator.get()); + else if(point.isRouteStopTransferPoint()) { + var rp = point.asRouteStopTransferPoint(); + return routeStopMap.computeIfAbsent(routeStopKey(rp.getRoute(), rp.getStop()), k -> creator.get()); + } + else if(point.isRouteStationTransferPoint()) { + var rp = point.asRouteStationTransferPoint(); + return routeStationMap.computeIfAbsent(routeStationKey(rp.getRoute(), rp.getStation()), k -> creator.get()); } else if(point.isStopTransferPoint()) { var sp = point.asStopTransferPoint(); @@ -64,26 +73,31 @@ else if(point.isStationTransferPoint()) { throw new IllegalArgumentException("Unknown TransferPoint type: " + point); } - /** * List all elements witch matches any of the transfer points added to the map. */ List get(Trip trip, StopLocation stop, int stopPointInPattern) { - return Stream.of( - tripMap.get(tripKey(trip, stopPointInPattern)), - routeMap.get(routeKey(trip.getRoute(), stopPointInPattern)), - stopMap.get(stop), - stationMap.get(stop.getParentStation()) - ) + var list = Stream.of( + tripMap.get(tripKey(trip, stopPointInPattern)), + routeStopMap.get(routeStopKey(trip.getRoute(), stop)), + routeStationMap.get(routeStationKey(trip.getRoute(), stop.getParentStation())), + stopMap.get(stop), + stationMap.get(stop.getParentStation()) + ) .filter(Objects::nonNull) .collect(Collectors.toList()); + return list; } private static T2 tripKey(Trip trip, int stopPositionInPattern) { return new T2<>(trip, stopPositionInPattern); } - private static T2 routeKey(Route route, int stopPositionInPattern) { - return new T2<>(route, stopPositionInPattern); + private static T2 routeStopKey(Route route, StopLocation stop) { + return new T2<>(route, stop); + } + + private static T2 routeStationKey(Route route, Station station) { + return new T2<>(route, station); } } diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferService.java b/src/main/java/org/opentripplanner/model/transfer/TransferService.java index 24f9633e2c9..8f9674e48b5 100644 --- a/src/main/java/org/opentripplanner/model/transfer/TransferService.java +++ b/src/main/java/org/opentripplanner/model/transfer/TransferService.java @@ -5,7 +5,9 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.annotation.Nullable; import org.opentripplanner.model.StopLocation; import org.opentripplanner.model.Trip; @@ -35,8 +37,13 @@ public TransferService() { } public void addAll(Collection transfers) { + Set set = new HashSet<>(transfersList); + for (ConstrainedTransfer transfer : transfers) { - add(transfer); + if(!set.contains(transfer)) { + add(transfer); + set.add(transfer); + } } } @@ -46,19 +53,17 @@ public List listAll() { @Nullable public ConstrainedTransfer findTransfer( - StopLocation fromStop, - StopLocation toStop, Trip fromTrip, - Trip toTrip, int fromStopPosition, - int toStopPosition + StopLocation fromStop, + Trip toTrip, + int toStopPosition, + StopLocation toStop ) { return transfersMap.get(fromTrip, fromStop, fromStopPosition).stream() .map(map2 -> map2.get(toTrip, toStop, toStopPosition)) .flatMap(Collection::stream) .max(comparingInt(ConstrainedTransfer::getSpecificityRanking)) - .stream() - .findFirst() .orElse(null); } diff --git a/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java index 8df22d712a6..ade019000ec 100644 --- a/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java +++ b/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java @@ -31,7 +31,7 @@ public boolean applyToAllTrips() { } @Override - public int getSpecificityRanking() { return 3; } + public int getSpecificityRanking() { return 4; } @Override public boolean isTripTransferPoint() { return true; } @@ -41,7 +41,7 @@ public String toString() { return ValueObjectToStringBuilder.of() .addText("") .toString(); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/StopIndexForRaptor.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/StopIndexForRaptor.java index ebb1effaf89..a9f72d398c1 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/StopIndexForRaptor.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/StopIndexForRaptor.java @@ -6,6 +6,7 @@ import java.util.Map; import org.opentripplanner.model.StopLocation; import org.opentripplanner.model.StopTransferPriority; +import org.opentripplanner.model.TripPattern; import org.opentripplanner.routing.algorithm.raptor.transit.cost.RaptorCostConverter; /** @@ -60,6 +61,18 @@ public int[] listStopIndexesForStops(List stops) { return stopIndex; } + /** + * Create a list of stop indexes for a given list of stops. + */ + public int[] listStopIndexesForPattern(TripPattern pattern) { + int[] stopIndex = new int[pattern.numberOfStops()]; + + for (int i = 0; i < pattern.numberOfStops(); i++) { + stopIndex[i] = indexByStop.get(pattern.getStop(i)); + } + return stopIndex; + } + /** * Create map between stop and index used by Raptor to stop objects in original graph */ diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferIndexGenerator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferIndexGenerator.java index 47ac9214683..ac4bbef9d34 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferIndexGenerator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferIndexGenerator.java @@ -8,15 +8,16 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.ToIntFunction; import java.util.stream.Collectors; -import lombok.val; import org.opentripplanner.model.Route; import org.opentripplanner.model.Station; import org.opentripplanner.model.StopLocation; import org.opentripplanner.model.Trip; import org.opentripplanner.model.TripPattern; import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.model.transfer.RouteTransferPoint; +import org.opentripplanner.model.transfer.RouteStationTransferPoint; +import org.opentripplanner.model.transfer.RouteStopTransferPoint; import org.opentripplanner.model.transfer.StationTransferPoint; import org.opentripplanner.model.transfer.StopTransferPoint; import org.opentripplanner.model.transfer.TransferPoint; @@ -25,6 +26,8 @@ import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes; public class TransferIndexGenerator { + private static final boolean BOARD = true; + private static final boolean ALIGHT = false; private final Collection constrainedTransfers; private final Map> patternsByStation = new HashMap<>(); @@ -51,15 +54,15 @@ public void generateTransfers() { // transfers, but not in Raptor. if (!c.useInRaptorRouting()) { continue; } - for (var fromPoint : findTPoints(tx.getFrom())) { - if (fromPoint.canAlight()) { - for (var toPoint : findTPoints(tx.getTo())) { - if (toPoint.canBoard() && !fromPoint.equals(toPoint)) { - fromPoint.addTransferConstraints(tx, toPoint); + findTPoints(tx.getFrom(), ALIGHT).stream() + .filter(TPoint::canAlight) + .forEachOrdered(fromPoint -> { + for (var toPoint : findTPoints(tx.getTo(), BOARD)) { + if (toPoint.canBoard() && !fromPoint.equals(toPoint)) { + fromPoint.addTransferConstraints(tx, toPoint); + } } - } - } - } + }); } sortAllTransfersByRanking(); } @@ -94,15 +97,18 @@ private void setupPatternByTripIndex(Collection findTPoints(TransferPoint txPoint) { + private Collection findTPoints(TransferPoint txPoint, boolean boarding) { if (txPoint.isStationTransferPoint()) { return findTPoints(txPoint.asStationTransferPoint()); } else if (txPoint.isStopTransferPoint()) { return findTPoints(txPoint.asStopTransferPoint()); } - else if (txPoint.isRouteTransferPoint()) { - return findTPoint(txPoint.asRouteTransferPoint()); + else if (txPoint.isRouteStationTransferPoint()) { + return findTPoint(txPoint.asRouteStationTransferPoint(), boarding); + } + else if (txPoint.isRouteStopTransferPoint()) { + return findTPoint(txPoint.asRouteStopTransferPoint(), boarding); } else { return findTPoints(txPoint.asTripTransferPoint()); @@ -133,7 +139,7 @@ private List findTPoints(StopTransferPoint point) { var result = new ArrayList(); for (TripPatternWithRaptorStopIndexes pattern : patterns) { - val p = pattern.getPattern(); + var p = pattern.getPattern(); for (int pos = 0; pos < p.numberOfStops(); ++pos) { if (point.getStop() == p.getStop(pos)) { result.add(new TPoint(pattern, sourcePoint, null, pos)); @@ -143,15 +149,35 @@ private List findTPoints(StopTransferPoint point) { return result; } - private List findTPoint(RouteTransferPoint point) { - var route = point.getRoute(); + private List findTPoint(RouteStationTransferPoint point, boolean boarding) { + return findTPointForRoute( + point.getRoute(), + boarding ? p -> p.findBoardingStopPositionInPattern(point.getStation()) + : p -> p.findAlightStopPositionInPattern(point.getStation()) + ); + } + + private List findTPoint(RouteStopTransferPoint point, boolean boarding) { + return findTPointForRoute( + point.getRoute(), + boarding ? p -> p.findBoardingStopPositionInPattern(point.getStop()) + : p -> p.findAlightStopPositionInPattern(point.getStop()) + ); + } + + private List findTPointForRoute( + Route route, + ToIntFunction resolveStopPosInPattern + ) { var patterns = patternsByRoute.get(route); - int stopPosInPattern = point.getStopPositionInPattern(); - int stopIndex = patterns.get(0).stopIndex(stopPosInPattern); - var sourcePoint = createTransferPointForPattern(route, stopIndex); - return patterns.stream() - .map(p -> new TPoint(p, sourcePoint, null, stopPosInPattern)) - .collect(Collectors.toList()); + var points = new ArrayList(); + for (var pattern : patterns) { + int stopPosInPattern = resolveStopPosInPattern.applyAsInt(pattern.getPattern()); + int stopIndex = pattern.stopIndex(stopPosInPattern); + var sourcePoint = createTransferPointForPattern(route, stopIndex); + points.add(new TPoint(pattern, sourcePoint, null, stopPosInPattern)); + } + return points; } private List findTPoints(TripTransferPoint point) { diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitData.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitData.java index 06dce86de26..d925f620827 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitData.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitData.java @@ -6,10 +6,9 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import org.opentripplanner.routing.algorithm.raptor.transit.RaptorTransferIndex; -import java.util.function.IntFunction; import javax.annotation.Nullable; import org.opentripplanner.model.transfer.TransferService; +import org.opentripplanner.routing.algorithm.raptor.transit.RaptorTransferIndex; import org.opentripplanner.routing.algorithm.raptor.transit.TransitLayer; import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule; import org.opentripplanner.routing.algorithm.raptor.transit.cost.DefaultCostCalculator; @@ -137,12 +136,12 @@ public RaptorConstrainedTransfer findConstrainedTransfer( TripSchedule fromTrip, int fromStopPosition, TripSchedule toTrip, int toStopPosition ) { return transferService.findTransfer( - transitLayer.getStopByIndex(fromTrip.pattern().stopIndex(fromStopPosition)), - transitLayer.getStopByIndex(toTrip.pattern().stopIndex(toStopPosition)), fromTrip.getOriginalTripTimes().getTrip(), - toTrip.getOriginalTripTimes().getTrip(), fromStopPosition, - toStopPosition + transitLayer.getStopByIndex(fromTrip.pattern().stopIndex(fromStopPosition)), + toTrip.getOriginalTripTimes().getTrip(), + toStopPosition, + transitLayer.getStopByIndex(toTrip.pattern().stopIndex(toStopPosition)) ); } }; diff --git a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferServiceAdaptor.java b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferServiceAdaptor.java index 72ca176e813..8988f9a3cf6 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferServiceAdaptor.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferServiceAdaptor.java @@ -2,7 +2,6 @@ import java.util.function.IntFunction; import javax.annotation.Nullable; -import org.opentripplanner.model.Stop; import org.opentripplanner.model.StopLocation; import org.opentripplanner.model.Trip; import org.opentripplanner.model.transfer.ConstrainedTransfer; @@ -55,12 +54,12 @@ public static TransferServiceAdaptor noop() { @Nullable protected ConstrainedTransfer findTransfer(TripStopTime from, T toTrip, int toStop) { return transferService.findTransfer( - stop(from.stop()), - stop(toStop), trip(from.trip()), - trip(toTrip), from.stopPosition(), - toTrip.findDepartureStopPosition(from.time(), toStop) + stop(from.stop()), + trip(toTrip), + toTrip.findDepartureStopPosition(from.time(), toStop), + stop(toStop) ); } diff --git a/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java b/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java index d45d213040d..2da6ee9cbe5 100644 --- a/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java +++ b/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java @@ -3,15 +3,15 @@ import static java.util.Comparator.comparing; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.gtfs.GtfsContextBuilder.contextBuilder; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.opentripplanner.ConstantsForTests; import org.opentripplanner.gtfs.GtfsContextBuilder; import org.opentripplanner.model.Agency; @@ -37,7 +37,7 @@ public class OtpTransitServiceImplTest { private static OtpTransitService subject; - @BeforeClass + @BeforeAll public static void setup() throws IOException { GtfsContextBuilder contextBuilder = contextBuilder(FEED_ID, ConstantsForTests.FAKE_GTFS); OtpTransitServiceBuilder builder = contextBuilder.getTransitBuilder(); @@ -107,12 +107,12 @@ public void testGetAllTransfers() { ); assertEquals( - "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}\n" + "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}\n" + "ConstrainedTransfer{from: , to: , constraint: {priority: RECOMMENDED}}\n" + "ConstrainedTransfer{from: , to: , constraint: {priority: NOT_ALLOWED}}\n" + "ConstrainedTransfer{from: , to: , constraint: {priority: RECOMMENDED}}\n" + "ConstrainedTransfer{from: , to: , constraint: {priority: NOT_ALLOWED}}\n" - + "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}", + + "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}", result ); } diff --git a/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java b/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java index d7c85919dcf..a78d723a294 100644 --- a/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java +++ b/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java @@ -3,58 +3,112 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_1; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_2; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1A; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1S; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2B; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2S; +import static org.opentripplanner.model.transfer.TransferTestData.STATION_POINT; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_B; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_11; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_21; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_11_1; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_21_3; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class ConstrainedTransferTest implements TransferTestData { +public class ConstrainedTransferTest { private static final TransferConstraint NO_CONSTRAINS = TransferConstraint.create().build(); private static final TransferConstraint GUARANTIED = TransferConstraint.create().guaranteed().build(); - private final ConstrainedTransfer TX_STATIONS = new ConstrainedTransfer(null, STATION_POINT, STATION_POINT, NO_CONSTRAINS); - private final ConstrainedTransfer TX_STATION_TO_A = new ConstrainedTransfer(null, STATION_POINT, STOP_POINT_A, NO_CONSTRAINS); - private final ConstrainedTransfer TX_T11_STATION = new ConstrainedTransfer(null, TRIP_POINT_11, STATION_POINT, NO_CONSTRAINS); - private final ConstrainedTransfer TX_A_TO_B = new ConstrainedTransfer(null, STOP_POINT_A, STOP_POINT_B, NO_CONSTRAINS); - private final ConstrainedTransfer TX_A_TO_R22 = new ConstrainedTransfer(null, STOP_POINT_A, ROUTE_POINT_22, NO_CONSTRAINS); - private final ConstrainedTransfer TX_A_TO_T23 = new ConstrainedTransfer(null, STOP_POINT_A, TRIP_POINT_23, NO_CONSTRAINS); - private final ConstrainedTransfer TX_R11_TO_B = new ConstrainedTransfer(null, ROUTE_POINT_11, STOP_POINT_B, NO_CONSTRAINS); - private final ConstrainedTransfer TX_R11_TO_R22 = new ConstrainedTransfer(null, ROUTE_POINT_11, ROUTE_POINT_22, NO_CONSTRAINS); - private final ConstrainedTransfer TX_T11_TO_R22 = new ConstrainedTransfer(null, TRIP_POINT_11, ROUTE_POINT_22, NO_CONSTRAINS); - private final ConstrainedTransfer TX_T11_TO_T22 = new ConstrainedTransfer(null, TRIP_POINT_11, TRIP_POINT_23, NO_CONSTRAINS); + private final ConstrainedTransfer TX_STATION_TO_STATION = noConstTx(STATION_POINT, STATION_POINT); + private final ConstrainedTransfer TX_STATION_TO_B = noConstTx(STATION_POINT, STOP_POINT_B); + private final ConstrainedTransfer TX_STATION_TO_R2B = noConstTx(STATION_POINT, ROUTE_POINT_2B); + private final ConstrainedTransfer TX_STATION_TO_R2S = noConstTx(STATION_POINT, ROUTE_POINT_2S); + private final ConstrainedTransfer TX_STATION_TO_T23 = noConstTx(STATION_POINT, TRIP_POINT_21_3); - private final ConstrainedTransfer TX_NO_CONSTRAINS = new ConstrainedTransfer(null, STOP_POINT_A, STOP_POINT_B, NO_CONSTRAINS); - private final ConstrainedTransfer TX_GUARANTIED = new ConstrainedTransfer(null, TRIP_POINT_11, TRIP_POINT_23, GUARANTIED); + private final ConstrainedTransfer TX_A_TO_STATION = noConstTx(STOP_POINT_A, STATION_POINT); + private final ConstrainedTransfer TX_A_TO_B = noConstTx(STOP_POINT_A, STOP_POINT_B); + private final ConstrainedTransfer TX_A_TO_R2B = noConstTx(STOP_POINT_A, ROUTE_POINT_2B); + private final ConstrainedTransfer TX_A_TO_R2S = noConstTx(STOP_POINT_A, ROUTE_POINT_2S); + private final ConstrainedTransfer TX_A_TO_T23 = noConstTx(STOP_POINT_A, TRIP_POINT_21_3); + + private final ConstrainedTransfer TX_R1S_TO_STATION = noConstTx(ROUTE_POINT_1S, STATION_POINT); + private final ConstrainedTransfer TX_R1S_TO_B = noConstTx(ROUTE_POINT_1S, STOP_POINT_B); + private final ConstrainedTransfer TX_R1S_TO_R2B = noConstTx(ROUTE_POINT_1S, ROUTE_POINT_2B); + private final ConstrainedTransfer TX_R1S_TO_R2S = noConstTx(ROUTE_POINT_1S, ROUTE_POINT_2S); + private final ConstrainedTransfer TX_R1S_TO_T23 = noConstTx(ROUTE_POINT_1S, TRIP_POINT_21_3); + + private final ConstrainedTransfer TX_R1A_TO_STATION = noConstTx(ROUTE_POINT_1A, STATION_POINT); + private final ConstrainedTransfer TX_R1A_TO_B = noConstTx(ROUTE_POINT_1A, STOP_POINT_B); + private final ConstrainedTransfer TX_R1A_TO_R2B = noConstTx(ROUTE_POINT_1A, ROUTE_POINT_2B); + private final ConstrainedTransfer TX_R1A_TO_R2S = noConstTx(ROUTE_POINT_1A, ROUTE_POINT_2S); + private final ConstrainedTransfer TX_R1A_TO_T23 = noConstTx(ROUTE_POINT_1A, TRIP_POINT_21_3); + + private final ConstrainedTransfer TX_T11_TO_STATION = noConstTx(TRIP_POINT_11_1, STATION_POINT); + private final ConstrainedTransfer TX_T11_TO_B = noConstTx(TRIP_POINT_11_1, STOP_POINT_B); + private final ConstrainedTransfer TX_T11_TO_R2B = noConstTx(TRIP_POINT_11_1, ROUTE_POINT_2B); + private final ConstrainedTransfer TX_T11_TO_R2S = noConstTx(TRIP_POINT_11_1, ROUTE_POINT_2S); + private final ConstrainedTransfer TX_T11_TO_T23 = noConstTx(TRIP_POINT_11_1, TRIP_POINT_21_3); + + private final ConstrainedTransfer TX_NO_CONSTRAINS = noConstTx(STOP_POINT_A, STOP_POINT_B); + + private final ConstrainedTransfer TX_GUARANTIED = new ConstrainedTransfer( + null, TRIP_POINT_11_1, TRIP_POINT_21_3, GUARANTIED + ); @BeforeEach public void setup() { ROUTE_1.setShortName("L1"); ROUTE_2.setShortName("L2"); - TRIP_1.setRoute(ROUTE_1); - TRIP_2.setRoute(ROUTE_2); - TRIP_1.setRoute(ROUTE_1); - TRIP_2.setRoute(ROUTE_2); + TRIP_11.setRoute(ROUTE_1); + TRIP_21.setRoute(ROUTE_2); + TRIP_11.setRoute(ROUTE_1); + TRIP_21.setRoute(ROUTE_2); } @Test public void getSpecificityRanking() { - assertEquals(0, TX_STATIONS.getSpecificityRanking()); - assertEquals(10, TX_STATION_TO_A.getSpecificityRanking()); + assertEquals(0, TX_STATION_TO_STATION.getSpecificityRanking()); + assertEquals(10, TX_STATION_TO_B.getSpecificityRanking()); + assertEquals(20, TX_STATION_TO_R2S.getSpecificityRanking()); + assertEquals(30, TX_STATION_TO_R2B.getSpecificityRanking()); + assertEquals(40, TX_STATION_TO_T23.getSpecificityRanking()); + + assertEquals(11, TX_A_TO_STATION.getSpecificityRanking()); assertEquals(21, TX_A_TO_B.getSpecificityRanking()); - assertEquals(31, TX_A_TO_R22.getSpecificityRanking()); - assertEquals(32, TX_R11_TO_B.getSpecificityRanking()); - assertEquals(33, TX_T11_STATION.getSpecificityRanking()); - assertEquals(41, TX_A_TO_T23.getSpecificityRanking()); - assertEquals(42, TX_R11_TO_R22.getSpecificityRanking()); - assertEquals(53, TX_T11_TO_R22.getSpecificityRanking()); - assertEquals(63, TX_T11_TO_T22.getSpecificityRanking()); + assertEquals(31, TX_A_TO_R2S.getSpecificityRanking()); + assertEquals(41, TX_A_TO_R2B.getSpecificityRanking()); + assertEquals(51, TX_A_TO_T23.getSpecificityRanking()); + + assertEquals(22, TX_R1S_TO_STATION.getSpecificityRanking()); + assertEquals(32, TX_R1S_TO_B.getSpecificityRanking()); + assertEquals(42, TX_R1S_TO_R2S.getSpecificityRanking()); + assertEquals(52, TX_R1S_TO_R2B.getSpecificityRanking()); + assertEquals(62, TX_R1S_TO_T23.getSpecificityRanking()); + + assertEquals(33, TX_R1A_TO_STATION.getSpecificityRanking()); + assertEquals(43, TX_R1A_TO_B.getSpecificityRanking()); + assertEquals(53, TX_R1A_TO_R2S.getSpecificityRanking()); + assertEquals(63, TX_R1A_TO_R2B.getSpecificityRanking()); + assertEquals(73, TX_R1A_TO_T23.getSpecificityRanking()); + + assertEquals(44, TX_T11_TO_STATION.getSpecificityRanking()); + assertEquals(54, TX_T11_TO_B.getSpecificityRanking()); + assertEquals(64, TX_T11_TO_R2S.getSpecificityRanking()); + assertEquals(74, TX_T11_TO_R2B.getSpecificityRanking()); + assertEquals(84, TX_T11_TO_T23.getSpecificityRanking()); } @Test public void testOtherAccessors() { - assertEquals(STOP_POINT_A, TX_A_TO_R22.getFrom()); - assertEquals(ROUTE_POINT_22, TX_A_TO_R22.getTo()); + assertEquals(STOP_POINT_A, TX_A_TO_R2B.getFrom()); + assertEquals(ROUTE_POINT_2B, TX_A_TO_R2B.getTo()); } @Test @@ -70,4 +124,8 @@ public void testToString() { TX_A_TO_B.toString() ); } + + private static ConstrainedTransfer noConstTx(TransferPoint s, TransferPoint t) { + return new ConstrainedTransfer(null, s, t, NO_CONSTRAINS); + } } \ No newline at end of file diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java index c51bce15d62..b2dbedfc8a0 100644 --- a/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java +++ b/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test; import org.opentripplanner.util.time.DurationUtils; -public class TransferConstraintTest implements TransferTestData { +public class TransferConstraintTest { public static final int MAX_WAIT_TIME_ONE_HOUR = DurationUtils.duration("1h"); diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java index 842fb9b0141..49cfc826b24 100644 --- a/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java +++ b/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java @@ -1,12 +1,31 @@ package org.opentripplanner.model.transfer; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.model.transfer.TransferTestData.ANY_STOP; +import static org.opentripplanner.model.transfer.TransferTestData.POS_1; +import static org.opentripplanner.model.transfer.TransferTestData.POS_2; +import static org.opentripplanner.model.transfer.TransferTestData.POS_3; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1A; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1S; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2B; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2S; +import static org.opentripplanner.model.transfer.TransferTestData.STATION; +import static org.opentripplanner.model.transfer.TransferTestData.STATION_POINT; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_B; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_B; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_11; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_21; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_11_1; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_21_3; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -class TransferPointMapTest implements TransferTestData { +class TransferPointMapTest { + private static final int ANY_STOP_POS = 999; final TransferPointMap subject = new TransferPointMap<>(); @@ -17,32 +36,36 @@ void setup() { @Test void addAndGetEmptyMap() { - assertEquals(List.of(), subject.get(TRIP_1, STOP_A, STOP_POSITION_1)); + assertEquals(List.of(), subject.get(TRIP_11, STOP_A, POS_1)); } @Test void addAndGet() { - subject.put(TRIP_POINT_11, "A"); - subject.put(TRIP_POINT_23, "B"); - subject.put(ROUTE_POINT_11, "C"); - subject.put(ROUTE_POINT_22, "D"); - subject.put(STOP_POINT_A, "E"); - subject.put(STOP_POINT_B, "F"); - subject.put(STATION_POINT, "G"); - - assertEquals(List.of("A", "C", "E", "G"), subject.get(TRIP_1, STOP_A, STOP_POSITION_1)); - assertEquals(List.of("D", "F"), subject.get(TRIP_2, STOP_B, STOP_POSITION_2)); + subject.put(TRIP_POINT_11_1, "A"); + subject.put(TRIP_POINT_21_3, "B"); + subject.put(ROUTE_POINT_1A, "C"); + subject.put(ROUTE_POINT_2B, "D"); + subject.put(ROUTE_POINT_1S, "E"); + subject.put(ROUTE_POINT_2S, "F"); + subject.put(STOP_POINT_A, "G"); + subject.put(STOP_POINT_B, "H"); + subject.put(STATION_POINT, "I"); + + assertEquals(List.of("A", "C", "E", "G", "I"), subject.get(TRIP_11, STOP_A, POS_1)); + assertEquals(List.of("F", "G", "I"), subject.get(TRIP_21, STOP_A, ANY_STOP_POS)); + assertEquals(List.of("D", "H"), subject.get(TRIP_21, STOP_B, POS_2)); + assertEquals(List.of("B"), subject.get(TRIP_21, ANY_STOP, POS_3)); } @Test void computeIfAbsent() { - assertEquals("A", subject.computeIfAbsent(TRIP_POINT_11, () -> "A")); - assertEquals("B", subject.computeIfAbsent(ROUTE_POINT_11, () -> "B")); + assertEquals("A", subject.computeIfAbsent(TRIP_POINT_11_1, () -> "A")); + assertEquals("B", subject.computeIfAbsent(ROUTE_POINT_1A, () -> "B")); assertEquals("C", subject.computeIfAbsent(STOP_POINT_B, () -> "C")); assertEquals("D", subject.computeIfAbsent(STATION_POINT, () -> "D")); - assertEquals("B", subject.computeIfAbsent(ROUTE_POINT_11, () -> "E")); + assertEquals("E", subject.computeIfAbsent(ROUTE_POINT_1S, () -> "E")); - assertEquals(List.of("A", "B", "D"), subject.get(TRIP_1, STOP_A, STOP_POSITION_1)); - assertEquals(List.of("C"), subject.get(TRIP_2, STOP_B, STOP_POSITION_2)); + assertEquals(List.of("A", "B", "E", "D"), subject.get(TRIP_11, STOP_A, POS_1)); + assertEquals(List.of("C"), subject.get(TRIP_21, STOP_B, POS_2)); } } \ No newline at end of file diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java index 3c8db6d6474..199d6e7b421 100644 --- a/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java +++ b/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java @@ -3,48 +3,77 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.model.transfer.TransferTestData.POS_1; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_1; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_2; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1A; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1S; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2B; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2S; +import static org.opentripplanner.model.transfer.TransferTestData.STATION; +import static org.opentripplanner.model.transfer.TransferTestData.STATION_POINT; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_B; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_B; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_11; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_11_1; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_21_3; import java.util.List; import org.junit.jupiter.api.Test; -public class TransferPointTest implements TransferTestData { +public class TransferPointTest { @Test public void getStation() { assertEquals(STATION, STATION_POINT.asStationTransferPoint().getStation()); + assertEquals(STATION, ROUTE_POINT_1S.asRouteStationTransferPoint().getStation()); } @Test public void getStop() { assertEquals(STOP_A, STOP_POINT_A.asStopTransferPoint().getStop()); + assertEquals(STOP_A, ROUTE_POINT_1A.asRouteStopTransferPoint().getStop()); + assertEquals(STOP_B, STOP_POINT_B.asStopTransferPoint().getStop()); + assertEquals(STOP_B, ROUTE_POINT_2B.asRouteStopTransferPoint().getStop()); + } + + @Test + public void getRoute() { + assertEquals(ROUTE_1, ROUTE_POINT_1S.asRouteStationTransferPoint().getRoute()); + assertEquals(ROUTE_1, ROUTE_POINT_1A.asRouteStopTransferPoint().getRoute()); + assertEquals(ROUTE_2, ROUTE_POINT_2S.asRouteStationTransferPoint().getRoute()); + assertEquals(ROUTE_2, ROUTE_POINT_2B.asRouteStopTransferPoint().getRoute()); } @Test public void getTrip() { - assertEquals(TRIP_1, TRIP_POINT_11.asTripTransferPoint().getTrip()); + assertEquals(TRIP_11, TRIP_POINT_11_1.asTripTransferPoint().getTrip()); } @Test public void getStopPosition() { - assertEquals(STOP_POSITION_1, TRIP_POINT_11.asTripTransferPoint().getStopPositionInPattern()); - assertEquals(STOP_POSITION_1, ROUTE_POINT_11.asRouteTransferPoint().getStopPositionInPattern()); + assertEquals(POS_1, TRIP_POINT_11_1.asTripTransferPoint().getStopPositionInPattern()); } @Test public void getSpecificityRanking() { assertEquals(0, STATION_POINT.getSpecificityRanking()); assertEquals(1, STOP_POINT_A.getSpecificityRanking()); - assertEquals(2, ROUTE_POINT_11.getSpecificityRanking()); - assertEquals(3, TRIP_POINT_11.getSpecificityRanking()); + assertEquals(2, ROUTE_POINT_1S.getSpecificityRanking()); + assertEquals(3, ROUTE_POINT_1A.getSpecificityRanking()); + assertEquals(4, TRIP_POINT_11_1.getSpecificityRanking()); } @Test - public void isStationTransferPoint() { - List.of(STATION_POINT, STOP_POINT_A, ROUTE_POINT_11, TRIP_POINT_11).forEach( p -> { + public void isNnnTransferPoint() { + List.of(STATION_POINT, STOP_POINT_A, ROUTE_POINT_1A, ROUTE_POINT_1S, TRIP_POINT_11_1).forEach( p -> { assertEquals(p == STATION_POINT, p.isStationTransferPoint()); assertEquals(p == STOP_POINT_A, p.isStopTransferPoint()); - assertEquals(p == ROUTE_POINT_11, p.isRouteTransferPoint()); - assertEquals(p == TRIP_POINT_11, p.isTripTransferPoint()); + assertEquals(p == ROUTE_POINT_1A, p.isRouteStopTransferPoint()); + assertEquals(p == ROUTE_POINT_1S, p.isRouteStationTransferPoint()); + assertEquals(p == TRIP_POINT_11_1, p.isTripTransferPoint()); }); } @@ -52,15 +81,17 @@ public void isStationTransferPoint() { public void applyToAllTrips() { assertTrue(STATION_POINT.applyToAllTrips()); assertTrue(STOP_POINT_A.applyToAllTrips()); - assertTrue(ROUTE_POINT_11.applyToAllTrips()); - assertFalse(TRIP_POINT_11.applyToAllTrips()); + assertTrue(ROUTE_POINT_1A.applyToAllTrips()); + assertTrue(ROUTE_POINT_1S.applyToAllTrips()); + assertFalse(TRIP_POINT_11_1.applyToAllTrips()); } @Test public void testToString() { - assertEquals("", STATION_POINT.toString()); + assertEquals("", STATION_POINT.toString()); assertEquals("", STOP_POINT_A.toString()); - assertEquals("", ROUTE_POINT_11.toString()); - assertEquals("", TRIP_POINT_23.toString()); + assertEquals("", ROUTE_POINT_1A.toString()); + assertEquals("", ROUTE_POINT_1S.toString()); + assertEquals("", TRIP_POINT_21_3.toString()); } } \ No newline at end of file diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java index d66acff5e25..e44b5f3008f 100644 --- a/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java +++ b/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java @@ -1,13 +1,32 @@ package org.opentripplanner.model.transfer; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.model.transfer.TransferTestData.ANY_POS; +import static org.opentripplanner.model.transfer.TransferTestData.ANY_TRIP; +import static org.opentripplanner.model.transfer.TransferTestData.POS_1; +import static org.opentripplanner.model.transfer.TransferTestData.POS_3; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1A; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_1S; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2B; +import static org.opentripplanner.model.transfer.TransferTestData.ROUTE_POINT_2S; +import static org.opentripplanner.model.transfer.TransferTestData.STATION; +import static org.opentripplanner.model.transfer.TransferTestData.STATION_POINT; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_B; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_A; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_POINT_B; +import static org.opentripplanner.model.transfer.TransferTestData.STOP_S; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_11; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_12; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_21; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_11_1; +import static org.opentripplanner.model.transfer.TransferTestData.TRIP_POINT_21_3; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opentripplanner.model.Stop; -public class TransferServiceTest implements TransferTestData { +public class TransferServiceTest { private final TransferService subject = new TransferService(); @@ -18,37 +37,49 @@ public void setup() { @Test public void findTransfer() { - // Given: - var ANY_STOP = Stop.stopForTest("ANY", 67.0, 11.0); - var A = transfer(STATION_POINT, ROUTE_POINT_11); - var B = transfer(STOP_POINT_A, STOP_POINT_B); - var C = transfer(STOP_POINT_A, TRIP_POINT_23); - var D = transfer(ROUTE_POINT_11, STOP_POINT_B); - var E = transfer(TRIP_POINT_11, ROUTE_POINT_22); - var F = transfer(TRIP_POINT_11, TRIP_POINT_23); + // Given: // Ranking + var A = transfer(TRIP_POINT_11_1, TRIP_POINT_21_3); // 84 + var B = transfer(TRIP_POINT_11_1, ROUTE_POINT_2B); // 74 + var C = transfer(TRIP_POINT_11_1, ROUTE_POINT_2S); // 64 + var D = transfer(STOP_POINT_A, TRIP_POINT_21_3); // 51 + var E = transfer(ROUTE_POINT_1A, STOP_POINT_B); // 43 + var F = transfer(ROUTE_POINT_1S, STOP_POINT_B); // 32 + var G = transfer(STATION_POINT, ROUTE_POINT_2B); // 30 + var H = transfer(STATION_POINT, ROUTE_POINT_2S); // 20 + var I = transfer(STATION_POINT, STATION_POINT); // 11 // When: all transfers is added to service - subject.addAll(List.of(A, B, C, D, E, F)); + subject.addAll(List.of(A, B, C, D, E, F, G, H, I)); // Then: - // Find the most specific transfer, Trip and stop position match - stops is ignored - assertEquals(E, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 2)); + // Find the most specific transfer TRIP to TRIP + // Trip and stop position must match, stops are ignored + assertEquals(A, subject.findTransfer(TRIP_11, POS_1, STOP_A, TRIP_21, POS_3, STOP_B)); + + // Find the TRIP to ROUTE+STOP transfer when TO stop position does not match + assertEquals(B, subject.findTransfer(TRIP_11, POS_1, STOP_A, TRIP_21, ANY_POS, STOP_B)); + + // Find the TRIP to ROUTE+STATION transfer when TO stop does not match + assertEquals(C, subject.findTransfer(TRIP_11, POS_1, STOP_A, TRIP_21, ANY_POS, STOP_S)); + + // Find transfer: STOP to TRIP when FROM trip does not match + assertEquals(D, subject.findTransfer(TRIP_12, POS_1, STOP_A, TRIP_21, POS_3, STOP_B)); - // Find the another specific transfer with the stop position changed - assertEquals(F, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 3)); + // Find the ROUTE+STOP to STOP transfer when FROM trip and TO stopPos do not match + assertEquals(E, subject.findTransfer(TRIP_12, POS_1, STOP_A, TRIP_21, ANY_POS, STOP_B)); - // Find the specific transfer: TRIP -> STOP when stop position do not match TO point - assertEquals(D, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 7)); + // Find the ROUTE+STATION to STOP transfer when FROM stop position does not match + assertEquals(F, subject.findTransfer(TRIP_11, ANY_POS, STOP_S, TRIP_21, POS_3, STOP_B)); - // Find the specific transfer: STOP -> TRIP when stop position do not match FROM point - assertEquals(C, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 3)); + // Find STOP to STOP transfer, when FROM trip and TO stop position do not match + assertEquals(G, subject.findTransfer(ANY_TRIP, POS_1, STOP_A, TRIP_21, ANY_POS, STOP_B)); - // Stop position fall back to STOP -> STOP when stop position do not match - assertEquals(B, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 7)); + // Find STATION to ROUTE+STATION when FROM trip and route and TO Stop do not match + assertEquals(H, subject.findTransfer(ANY_TRIP, ANY_POS, STOP_S, TRIP_21, POS_3, STOP_S)); - // - assertEquals(A, subject.findTransfer(STOP_A, ANY_STOP, TRIP_2, TRIP_1, 7, 1)); + // Find STATION to STATION when there are no match for FROM/TO trips and patterns + assertEquals(I, subject.findTransfer(ANY_TRIP, POS_1, STOP_S, ANY_TRIP, ANY_POS, STOP_S)); } @Test @@ -56,18 +87,19 @@ public void addSameTransferTwiceRetrieveFirstAdded() { var A = transfer(STOP_POINT_A, STOP_POINT_B); var A_EQ = transfer(STOP_POINT_A, STOP_POINT_B); - // Adding two transfers between the same stops, will result in only the first being kept + // Adding two transfers between the same stops + // should result in only the first being added subject.addAll(List.of(A, A_EQ)); - assertEquals(A, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 2)); + assertEquals(List.of(A), subject.listAll()); } @Test public void listAll() { // Given: - var A = transfer(STATION_POINT, ROUTE_POINT_11); + var A = transfer(STATION_POINT, ROUTE_POINT_1A); var B = transfer(STOP_POINT_A, STOP_POINT_B); - var C = transfer(STOP_POINT_A, TRIP_POINT_23); + var C = transfer(STOP_POINT_A, TRIP_POINT_21_3); // When: all transfers is added to service subject.addAll(List.of(A, B, C)); diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java b/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java index 02a80a16286..f8e198a0060 100644 --- a/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java +++ b/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java @@ -4,44 +4,53 @@ import org.opentripplanner.model.Route; import org.opentripplanner.model.Station; import org.opentripplanner.model.Stop; -import org.opentripplanner.model.StopTransferPriority; import org.opentripplanner.model.Trip; -import org.opentripplanner.model.WgsCoordinate; -public interface TransferTestData { - String FEED_ID = "F"; +public class TransferTestData { + static final String FEED_ID = "F"; - Station STATION = new Station( - createId(1), - "Central Station", - new WgsCoordinate(60.0, 11.0), - null, null, null, null, - StopTransferPriority.ALLOWED - ); + static final Station STATION = Station.stationForTest("Central Station", 60.0, 11.0); - int STOP_POSITION_1 = 1; - int STOP_POSITION_2 = 2; - int STOP_POSITION_3 = 3; + static final int POS_1 = 1; + static final int POS_2 = 2; + static final int POS_3 = 3; + static final int ANY_POS = 999; - Stop STOP_A = Stop.stopForTest("A", 60.0, 11.0); - Stop STOP_B = Stop.stopForTest("B", 60.0, 11.0); + static final Stop STOP_A = Stop.stopForTest("A", 60.0, 11.0); + static final Stop STOP_B = Stop.stopForTest("B", 60.0, 11.0); + static final Stop STOP_S = Stop.stopForTest("S", 60.0, 11.0); + static final Stop ANY_STOP = Stop.stopForTest("any", 60.0, 11.0); - Route ROUTE_1 = createRoute(1, "L1"); - Route ROUTE_2 = createRoute(2, "L2"); + static final Route ROUTE_1 = createRoute(1, "L1"); + static final Route ROUTE_2 = createRoute(2, "L2"); + static final Route ANY_ROUTE = createRoute(999, "any"); - Trip TRIP_1 = createTrip(1, ROUTE_1); - Trip TRIP_2 = createTrip(2, ROUTE_2); + static final Trip TRIP_11 = createTrip(11, ROUTE_1); + static final Trip TRIP_12 = createTrip(12, ROUTE_1); + static final Trip TRIP_21 = createTrip(21, ROUTE_2); + static final Trip TRIP_22 = createTrip(22, ROUTE_2); + static final Trip ANY_TRIP = createTrip(999, ANY_ROUTE); - TransferPoint STATION_POINT = new StationTransferPoint(STATION); + static final TransferPoint STATION_POINT = new StationTransferPoint(STATION); - TransferPoint STOP_POINT_A = new StopTransferPoint(STOP_A); - TransferPoint STOP_POINT_B = new StopTransferPoint(STOP_B); + static final TransferPoint STOP_POINT_A = new StopTransferPoint(STOP_A); + static final TransferPoint STOP_POINT_B = new StopTransferPoint(STOP_B); - TransferPoint ROUTE_POINT_11 = new RouteTransferPoint(ROUTE_1, STOP_POSITION_1); - TransferPoint ROUTE_POINT_22 = new RouteTransferPoint(ROUTE_2, STOP_POSITION_2); + static final TransferPoint ROUTE_POINT_1S = new RouteStationTransferPoint(ROUTE_1, STATION); + static final TransferPoint ROUTE_POINT_2S = new RouteStationTransferPoint(ROUTE_2, STATION); - TransferPoint TRIP_POINT_11 = new TripTransferPoint(TRIP_1, STOP_POSITION_1); - TransferPoint TRIP_POINT_23 = new TripTransferPoint(TRIP_2, STOP_POSITION_3); + static final TransferPoint ROUTE_POINT_1A = new RouteStopTransferPoint(ROUTE_1, STOP_A); + static final TransferPoint ROUTE_POINT_2B = new RouteStopTransferPoint(ROUTE_2, STOP_B); + + static final TransferPoint TRIP_POINT_11_1 = new TripTransferPoint(TRIP_11, POS_1); + static final TransferPoint TRIP_POINT_21_3 = new TripTransferPoint(TRIP_21, POS_3); + + static { + STATION.addChildStop(STOP_A); + STOP_A.setParentStation(STATION); + STATION.addChildStop(STOP_S); + STOP_S.setParentStation(STATION); + } private static Trip createTrip(int id, Route route) { Trip t = new Trip(createId(id)); @@ -54,6 +63,7 @@ private static Route createRoute(int id, String name) { r.setShortName(name); return r; } + private static FeedScopedId createId(int id) { return new FeedScopedId(FEED_ID, String.valueOf(id)); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap index 96228082f8c..f5600ce790a 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap @@ -9991,8 +9991,8 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "agencyTimeZoneOffset": 0, "arrivalDelay": 0, "departureDelay": 0, - "distanceMeters": 1667.1475209896525, - "endTime": "2009-11-17T18:52:12.000+00:00", + "distanceMeters": 1355.2067620852858, + "endTime": "2009-11-17T18:51:01.000+00:00", "flexibleTrip": false, "from": { "coordinate": { @@ -10027,7 +10027,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "stopSequence": 35, "vertexType": "TRANSIT" }, - "generalizedCost": 972, + "generalizedCost": 901, "headsign": "Rose Qtr TC", "interlinedWithPreviousLeg": false, "intermediateStops": [ @@ -10178,85 +10178,11 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "stopSequence": 39, "vertexType": "TRANSIT" } - }, - { - "arrival": "2009-11-17T18:51:01.000+00:00", - "departure": "2009-11-17T18:51:01.000+00:00", - "place": { - "coordinate": { - "latitude": 45.531569, - "longitude": -122.659045 - }, - "name": "NE Multnomah & 7th", - "stop": { - "code": "4054", - "coordinate": { - "latitude": 45.531569, - "longitude": -122.659045 - }, - "description": "Westbound stop in Portland (Stop ID 4054)", - "fareZones": [ - { - "id": { - "feedId": "prt", - "id": "0" - } - } - ], - "id": { - "feedId": "prt", - "id": "4054" - }, - "name": "NE Multnomah & 7th", - "partOfStation": false, - "wheelchairBoarding": "NO_INFORMATION" - }, - "stopIndex": 39, - "stopSequence": 40, - "vertexType": "TRANSIT" - } - }, - { - "arrival": "2009-11-17T18:51:27.000+00:00", - "departure": "2009-11-17T18:51:27.000+00:00", - "place": { - "coordinate": { - "latitude": 45.531586, - "longitude": -122.660482 - }, - "name": "NE Multnomah & Grand", - "stop": { - "code": "4043", - "coordinate": { - "latitude": 45.531586, - "longitude": -122.660482 - }, - "description": "Westbound stop in Portland (Stop ID 4043)", - "fareZones": [ - { - "id": { - "feedId": "prt", - "id": "0" - } - } - ], - "id": { - "feedId": "prt", - "id": "4043" - }, - "name": "NE Multnomah & Grand", - "partOfStation": false, - "wheelchairBoarding": "NO_INFORMATION" - }, - "stopIndex": 40, - "stopSequence": 41, - "vertexType": "TRANSIT" - } } ], "legGeometry": { - "length": 46, - "points": "{fztG`xrkVwA?mCAmC?oCA}C?sDC??aBAm@@k@AY?uABU@I@IBQFb@fC}@d@OFO@q@???Q?]?gGA??[??nJ???b@?vK?rA???tBCfD???^?nE?V@Z?PH\\Nb@`@~@Rf@" + "length": 33, + "points": "{fztG`xrkVwA?mCAmC?oCA}C?sDC??aBAm@@k@AY?uABU@I@IBQFb@fC}@d@OFO@q@???Q?]?gGA??[??nJ???b@?vK?rA" }, "mode": "BUS", "onStreetNonTransit": false, @@ -10274,17 +10200,17 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "streetNotes": [ ], "to": { "coordinate": { - "latitude": 45.531159, - "longitude": -122.66293 + "latitude": 45.531569, + "longitude": -122.659045 }, - "name": "NE Multnomah & 3rd", + "name": "NE Multnomah & 7th", "stop": { - "code": "11492", + "code": "4054", "coordinate": { - "latitude": 45.531159, - "longitude": -122.66293 + "latitude": 45.531569, + "longitude": -122.659045 }, - "description": "Westbound stop in Portland (Stop ID 11492)", + "description": "Westbound stop in Portland (Stop ID 4054)", "fareZones": [ { "id": { @@ -10295,16 +10221,139 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan ], "id": { "feedId": "prt", - "id": "11492" + "id": "4054" }, - "name": "NE Multnomah & 3rd", + "name": "NE Multnomah & 7th", "partOfStation": false, "wheelchairBoarding": "NO_INFORMATION" }, - "stopIndex": 41, - "stopSequence": 42, + "stopIndex": 39, + "stopSequence": 40, "vertexType": "TRANSIT" }, + "transferToNextLeg": { + "constraint": { + "facilitated": false, + "guaranteed": false, + "maxWaitTime": -1, + "notAllowed": false, + "priority": "RECOMMENDED", + "regularTransfer": false, + "staySeated": false + }, + "from": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "70" + }, + "longName": "12th Ave", + "mode": "BUS", + "shortName": "70", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r070.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "4054", + "coordinate": { + "latitude": 45.531569, + "longitude": -122.659045 + }, + "description": "Westbound stop in Portland (Stop ID 4054)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "4054" + }, + "name": "NE Multnomah & 7th", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + }, + "to": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "77" + }, + "longName": "Broadway/Halsey", + "mode": "BUS", + "shortName": "77", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r077.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "4054", + "coordinate": { + "latitude": 45.531569, + "longitude": -122.659045 + }, + "description": "Westbound stop in Portland (Stop ID 4054)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "4054" + }, + "name": "NE Multnomah & 7th", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + } + }, "transitAlerts": [ ], "transitLeg": true, "trip": { @@ -10359,22 +10408,22 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "agencyTimeZoneOffset": 0, "arrivalDelay": 0, "departureDelay": 0, - "distanceMeters": 3526.7741793792093, + "distanceMeters": 3838.714938283576, "endTime": "2009-11-17T19:08:50.000+00:00", "flexibleTrip": false, "from": { "coordinate": { - "latitude": 45.531159, - "longitude": -122.66293 + "latitude": 45.531569, + "longitude": -122.659045 }, - "name": "NE Multnomah & 3rd", + "name": "NE Multnomah & 7th", "stop": { - "code": "11492", + "code": "4054", "coordinate": { - "latitude": 45.531159, - "longitude": -122.66293 + "latitude": 45.531569, + "longitude": -122.659045 }, - "description": "Westbound stop in Portland (Stop ID 11492)", + "description": "Westbound stop in Portland (Stop ID 4054)", "fareZones": [ { "id": { @@ -10385,20 +10434,94 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan ], "id": { "feedId": "prt", - "id": "11492" + "id": "4054" }, - "name": "NE Multnomah & 3rd", + "name": "NE Multnomah & 7th", "partOfStation": false, "wheelchairBoarding": "NO_INFORMATION" }, - "stopIndex": 83, - "stopSequence": 84, + "stopIndex": 81, + "stopSequence": 82, "vertexType": "TRANSIT" }, - "generalizedCost": 1598, + "generalizedCost": 1669, "headsign": "Montgomery Park", "interlinedWithPreviousLeg": false, "intermediateStops": [ + { + "arrival": "2009-11-17T18:55:05.000+00:00", + "departure": "2009-11-17T18:55:05.000+00:00", + "place": { + "coordinate": { + "latitude": 45.531586, + "longitude": -122.660482 + }, + "name": "NE Multnomah & Grand", + "stop": { + "code": "4043", + "coordinate": { + "latitude": 45.531586, + "longitude": -122.660482 + }, + "description": "Westbound stop in Portland (Stop ID 4043)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "4043" + }, + "name": "NE Multnomah & Grand", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopIndex": 82, + "stopSequence": 83, + "vertexType": "TRANSIT" + } + }, + { + "arrival": "2009-11-17T18:56:09.000+00:00", + "departure": "2009-11-17T18:56:09.000+00:00", + "place": { + "coordinate": { + "latitude": 45.531159, + "longitude": -122.66293 + }, + "name": "NE Multnomah & 3rd", + "stop": { + "code": "11492", + "coordinate": { + "latitude": 45.531159, + "longitude": -122.66293 + }, + "description": "Westbound stop in Portland (Stop ID 11492)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "11492" + }, + "name": "NE Multnomah & 3rd", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopIndex": 83, + "stopSequence": 84, + "vertexType": "TRANSIT" + } + }, { "arrival": "2009-11-17T18:58:00.000+00:00", "departure": "2009-11-17T18:58:00.000+00:00", @@ -10857,8 +10980,8 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } ], "legGeometry": { - "length": 96, - "points": "kx{tG~qtkV`@bANb@FV@R?P?pE?jA@h@AnAbBl@LFJN\\f@LT??NXJPPVJFf@Vf@Pp@Nd@NRLB@RNXZR\\vAhC@BhAhD`AhClAbDBrDCnG@n@@^@d@HdAP`CBjEDvD???LqCFmCDYBGDEBGJkAzAQR??KNa@b@MJuBBY?OHW@u@~@aD`EcBhBBrD@xC??@l@BlE@lD???XBjEBpD???VBlE?dA@t@?b@?h@BfEBrD???VBhEFtKDvJ??@\\DnJ???d@FtKmCBo@@" + "length": 109, + "points": "yz{tG`zskV?tBCfD???^?nE?V@Z?PH\\Nb@`@~@Rf@??`@bANb@FV@R?P?pE?jA@h@AnAbBl@LFJN\\f@LT??NXJPPVJFf@Vf@Pp@Nd@NRLB@RNXZR\\vAhC@BhAhD`AhClAbDBrDCnG@n@@^@d@HdAP`CBjEDvD???LqCFmCDYBGDEBGJkAzAQR??KNa@b@MJuBBY?OHW@u@~@aD`EcBhBBrD@xC??@l@BlE@lD???XBjEBpD???VBlE?dA@t@?b@?h@BfEBrD???VBhEFtKDvJ??@\\DnJ???d@FtKmCBo@@" }, "mode": "BUS", "onStreetNonTransit": false, @@ -10872,7 +10995,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "sequenceNumber": 20091117, "year": 2009 }, - "startTime": "2009-11-17T18:56:09.000+00:00", + "startTime": "2009-11-17T18:54:29.000+00:00", "streetNotes": [ ], "to": { "coordinate": { @@ -10907,6 +11030,129 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "stopSequence": 94, "vertexType": "TRANSIT" }, + "transferFromPrevLeg": { + "constraint": { + "facilitated": false, + "guaranteed": false, + "maxWaitTime": -1, + "notAllowed": false, + "priority": "RECOMMENDED", + "regularTransfer": false, + "staySeated": false + }, + "from": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "70" + }, + "longName": "12th Ave", + "mode": "BUS", + "shortName": "70", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r070.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "4054", + "coordinate": { + "latitude": 45.531569, + "longitude": -122.659045 + }, + "description": "Westbound stop in Portland (Stop ID 4054)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "4054" + }, + "name": "NE Multnomah & 7th", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + }, + "to": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "77" + }, + "longName": "Broadway/Halsey", + "mode": "BUS", + "shortName": "77", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r077.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "4054", + "coordinate": { + "latitude": 45.531569, + "longitude": -122.659045 + }, + "description": "Westbound stop in Portland (Stop ID 4054)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "0" + } + } + ], + "id": { + "feedId": "prt", + "id": "4054" + }, + "name": "NE Multnomah & 7th", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + } + }, "transitAlerts": [ ], "transitLeg": true, "trip": { @@ -11068,10 +11314,10 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "streetOnly": false, "systemNotices": [ ], "tooSloped": false, - "transferPriorityCost": 33, - "transitTimeSeconds": 1133, - "waitTimeOptimizedCost": -149, - "waitingTimeSeconds": 237, + "transferPriorityCost": 32, + "transitTimeSeconds": 1162, + "waitTimeOptimizedCost": -115, + "waitingTimeSeconds": 208, "walkOnly": false, "walkingAllTheWay": false }, @@ -11822,6 +12068,129 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "stopSequence": 109, "vertexType": "TRANSIT" }, + "transferToNextLeg": { + "constraint": { + "facilitated": false, + "guaranteed": false, + "maxWaitTime": -1, + "notAllowed": false, + "priority": "RECOMMENDED", + "regularTransfer": false, + "staySeated": false + }, + "from": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "20" + }, + "longName": "Burnside/Stark", + "mode": "BUS", + "shortName": "20", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r020.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "755", + "coordinate": { + "latitude": 45.523512, + "longitude": -122.698081 + }, + "description": "Westbound stop in Portland (Stop ID 755)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "1" + } + } + ], + "id": { + "feedId": "prt", + "id": "755" + }, + "name": "W Burnside & NW 23rd", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + }, + "to": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "15" + }, + "longName": "Belmont/NW 23rd", + "mode": "BUS", + "shortName": "15", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r015.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "755", + "coordinate": { + "latitude": 45.523512, + "longitude": -122.698081 + }, + "description": "Westbound stop in Portland (Stop ID 755)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "1" + } + } + ], + "id": { + "feedId": "prt", + "id": "755" + }, + "name": "W Burnside & NW 23rd", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + } + }, "transitAlerts": [ ], "transitLeg": true, "trip": { @@ -12042,6 +12411,129 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "stopSequence": 74, "vertexType": "TRANSIT" }, + "transferFromPrevLeg": { + "constraint": { + "facilitated": false, + "guaranteed": false, + "maxWaitTime": -1, + "notAllowed": false, + "priority": "RECOMMENDED", + "regularTransfer": false, + "staySeated": false + }, + "from": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "20" + }, + "longName": "Burnside/Stark", + "mode": "BUS", + "shortName": "20", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r020.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "755", + "coordinate": { + "latitude": 45.523512, + "longitude": -122.698081 + }, + "description": "Westbound stop in Portland (Stop ID 755)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "1" + } + } + ], + "id": { + "feedId": "prt", + "id": "755" + }, + "name": "W Burnside & NW 23rd", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + }, + "to": { + "route": { + "agency": { + "fareUrl": "http://trimet.org/fares/index.htm", + "id": { + "feedId": "prt", + "id": "prt" + }, + "lang": "en", + "name": "TriMet", + "phone": "503-238-7433", + "timezone": "America/Los_Angeles", + "url": "http://trimet.org" + }, + "bikesAllowed": "UNKNOWN", + "id": { + "feedId": "prt", + "id": "15" + }, + "longName": "Belmont/NW 23rd", + "mode": "BUS", + "shortName": "15", + "sortOrder": -999, + "sortOrderSet": false, + "type": 3, + "url": "http://trimet.org/schedules/r015.htm" + }, + "routeStationTransferPoint": false, + "routeStopTransferPoint": true, + "stationTransferPoint": false, + "stop": { + "code": "755", + "coordinate": { + "latitude": 45.523512, + "longitude": -122.698081 + }, + "description": "Westbound stop in Portland (Stop ID 755)", + "fareZones": [ + { + "id": { + "feedId": "prt", + "id": "1" + } + } + ], + "id": { + "feedId": "prt", + "id": "755" + }, + "name": "W Burnside & NW 23rd", + "partOfStation": false, + "wheelchairBoarding": "NO_INFORMATION" + }, + "stopTransferPoint": false, + "tripTransferPoint": false + } + }, "transitAlerts": [ ], "transitLeg": true, "trip": { @@ -12288,7 +12780,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "streetOnly": false, "systemNotices": [ ], "tooSloped": false, - "transferPriorityCost": 33, + "transferPriorityCost": 32, "transitTimeSeconds": 953, "waitTimeOptimizedCost": -229, "waitingTimeSeconds": 307, diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java index 51d9648d4ce..161810deb5a 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java @@ -4,7 +4,14 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.model.transfer.TransferConstraint.REGULAR_TRANSFER; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.RAPTOR_STOP_INDEX; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.STATION_B; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.STOP_A; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.STOP_B; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.STOP_C; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.STOP_D; import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.id; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.stopIndex; import java.util.Collection; import java.util.List; @@ -14,7 +21,8 @@ import org.opentripplanner.model.Stop; import org.opentripplanner.model.TransitMode; import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.model.transfer.RouteTransferPoint; +import org.opentripplanner.model.transfer.RouteStationTransferPoint; +import org.opentripplanner.model.transfer.RouteStopTransferPoint; import org.opentripplanner.model.transfer.StationTransferPoint; import org.opentripplanner.model.transfer.StopTransferPoint; import org.opentripplanner.model.transfer.TransferConstraint; @@ -23,10 +31,9 @@ import org.opentripplanner.routing.algorithm.raptor.transit.TransitTuningParameters; import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes; import org.opentripplanner.routing.algorithm.raptor.transit.request.TestRouteData; -import org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData; -public class ConstrainedBoardingSearchTest implements TestTransitCaseData { +public class ConstrainedBoardingSearchTest { private static final FeedScopedId ID = id("ID"); private static final TransferConstraint GUARANTEED_CONSTRAINT = @@ -137,11 +144,20 @@ void findGuaranteedTransferWithZeroConnectionTimeWithStop() { } @Test - void findGuaranteedTransferWithZeroConnectionTimeWithRouteTransfers() { - int sourceStopPos = route1.stopPosition(STOP_B); - int targetStopPos = route2.stopPosition(STOP_B); - var route1TxPoint = new RouteTransferPoint(route1.getRoute(), sourceStopPos); - var route2TxPoint = new RouteTransferPoint(route2.getRoute(), targetStopPos); + void findGuaranteedTransferWithZeroConnectionTimeWithRouteAndStopTransfers() { + var route1TxPoint = new RouteStopTransferPoint(route1.getRoute(), STOP_B); + var route2TxPoint = new RouteStopTransferPoint(route2.getRoute(), STOP_B); + + var txGuaranteedTrip2Trip = new ConstrainedTransfer( + ID, route1TxPoint, route2TxPoint, GUARANTEED_CONSTRAINT + ); + findGuaranteedTransferWithZeroConnectionTime(List.of(txGuaranteedTrip2Trip)); + } + + @Test + void findGuaranteedTransferWithZeroConnectionTimeWithRouteAndStationTransfers() { + var route1TxPoint = new RouteStationTransferPoint(route1.getRoute(), STATION_B); + var route2TxPoint = new RouteStationTransferPoint(route2.getRoute(), STATION_B); var txGuaranteedTrip2Trip = new ConstrainedTransfer( ID, route1TxPoint, route2TxPoint, GUARANTEED_CONSTRAINT @@ -167,7 +183,7 @@ void findGuaranteedTransferWithMostSpecificTransfers() { int sourceStopPos = route1.stopPosition(STOP_B); int targetStopPos = route2.stopPosition(STOP_B); var trip1TxPoint = new TripTransferPoint(route1.lastTrip().trip(), sourceStopPos); - var route1TxPoint = new RouteTransferPoint(route1.getRoute(), sourceStopPos); + var route1TxPoint = new RouteStopTransferPoint(route1.getRoute(), STOP_B); var trip2TxPoint = new TripTransferPoint(route2.firstTrip().trip(), targetStopPos); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/StopIndexForRaptorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/StopIndexForRaptorTest.java index c9bceacb51f..e3437afeab7 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/StopIndexForRaptorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/StopIndexForRaptorTest.java @@ -4,18 +4,25 @@ import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; +import lombok.val; import org.junit.jupiter.api.Test; import org.opentripplanner.model.FeedScopedId; import org.opentripplanner.model.Station; import org.opentripplanner.model.Stop; import org.opentripplanner.model.StopLocation; +import org.opentripplanner.model.StopPattern; +import org.opentripplanner.model.StopTime; import org.opentripplanner.model.StopTransferPriority; +import org.opentripplanner.model.TripPattern; import org.opentripplanner.model.WgsCoordinate; import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor; import org.opentripplanner.routing.algorithm.raptor.transit.TransitTuningParameters; public class StopIndexForRaptorTest { + private final FeedScopedId ANY_ID = new FeedScopedId("F", "1"); + private final Stop STOP_0 = Stop.stopForTest("ID-" + 1, 0.0, 0.0); private final Stop STOP_1 = Stop.stopForTest("ID-" + 2, 0.0, 0.0); private final Stop STOP_2 = Stop.stopForTest("ID-" + 3, 0.0, 0.0); @@ -32,23 +39,23 @@ public class StopIndexForRaptorTest { @Test public void listStopIndexesForEmptyTripPattern() { StopIndexForRaptor stopIndex = new StopIndexForRaptor(STOPS, TransitTuningParameters.FOR_TEST); + val p = new TripPattern(ANY_ID, null, new StopPattern(List.of())); - int[] result = stopIndex.listStopIndexesForStops(List.of()); + int[] result = stopIndex.listStopIndexesForPattern(p); assertEquals(result.length, 0); } @Test public void listStopIndexesForTripPattern() { - List input = List.of( - STOP_0, - STOP_2, - STOP_4 + var stopIndex = new StopIndexForRaptor(STOPS, TransitTuningParameters.FOR_TEST); + var tripPattern = new TripPattern( + ANY_ID, + null, + new StopPattern(stopTimes(STOP_0, STOP_2, STOP_4)) ); - StopIndexForRaptor stopIndex = new StopIndexForRaptor(STOPS, TransitTuningParameters.FOR_TEST); - - int[] result = stopIndex.listStopIndexesForStops(input); + int[] result = stopIndex.listStopIndexesForPattern(tripPattern); assertEquals("[0, 2, 4]", Arrays.toString(result)); } @@ -68,6 +75,18 @@ public class StopIndexForRaptorTest { } Station createStation(String name, StopTransferPriority pri) { - return new Station(new FeedScopedId("F", name), name, new WgsCoordinate(0, 0), null, null, null, null, pri); + return new Station(ANY_ID, name, new WgsCoordinate(0, 0), null, null, null, null, pri); + } + + private static List stopTimes(Stop ... stops) { + return Arrays.stream(stops) + .map(StopIndexForRaptorTest::stopTime) + .collect(Collectors.toList()); + } + + private static StopTime stopTime(Stop stop) { + val st = new StopTime(); + st.setStop(stop); + return st; } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestRouteData.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestRouteData.java index 55ad155e7e0..507bb9d99a8 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestRouteData.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestRouteData.java @@ -1,6 +1,9 @@ package org.opentripplanner.routing.algorithm.raptor.transit.request; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.DATE; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.OFFSET; import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.id; +import static org.opentripplanner.routing.algorithm.raptor.transit.request.TestTransitCaseData.stopIndex; import java.util.ArrayList; import java.util.Arrays; @@ -25,7 +28,7 @@ import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable; import org.opentripplanner.util.time.TimeUtils; -public class TestRouteData implements TestTransitCaseData { +public class TestRouteData { private final Route route; private final List trips; diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestTransitCaseData.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestTransitCaseData.java index 3e0a770f0f9..69b6bc147cd 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestTransitCaseData.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/TestTransitCaseData.java @@ -6,32 +6,44 @@ import org.opentripplanner.model.Stop; import org.opentripplanner.model.StopLocation; -public interface TestTransitCaseData { - Station STATION_A = Station.stationForTest("A", 60.0, 11.1); - Station STATION_B = Station.stationForTest("B", 61.0, 11.5); +public final class TestTransitCaseData { + public static final Station STATION_A = Station.stationForTest("A", 60.0, 11.1); + public static final Station STATION_B = Station.stationForTest("B", 61.0, 11.5); - Stop STOP_A = Stop.stopForTest("A", 60.0, 11.0, STATION_A); - Stop STOP_B = Stop.stopForTest("B", 60.0, 11.2, STATION_B); - Stop STOP_C = Stop.stopForTest("C", 61.0, 11.4); - Stop STOP_D = Stop.stopForTest("D", 61.0, 11.6); + public static final Stop STOP_A = Stop.stopForTest("A", 60.0, 11.0, STATION_A); + public static final Stop STOP_B = Stop.stopForTest("B", 60.0, 11.2, STATION_B); + public static final Stop STOP_C = Stop.stopForTest("C", 61.0, 11.4); + public static final Stop STOP_D = Stop.stopForTest("D", 61.0, 11.6); // Random order stop indexes - should be different from stopPos in pattern to // make sure code-under-test do not mix stopIndex and stopPosition - Stop[] RAPTOR_STOP_INDEX = { STOP_D, STOP_A, STOP_C, STOP_B }; + public static final Stop[] RAPTOR_STOP_INDEX = { STOP_D, STOP_A, STOP_C, STOP_B }; - LocalDate DATE = LocalDate.of(2021, 12, 24); + public static final LocalDate DATE = LocalDate.of(2021, 12, 24); - int OFFSET = 0; + public static final int OFFSET = 0; - static FeedScopedId id(String id) { + public static FeedScopedId id(String id) { return new FeedScopedId("F", id); } - default int stopIndex(StopLocation stop) { + public static int stopIndex(StopLocation stop) { for (int i=0;i< RAPTOR_STOP_INDEX.length;++i) { if(stop == RAPTOR_STOP_INDEX[i]) { return i; } } throw new IllegalArgumentException(); } + + static { + setupStationStopRelationship(STATION_A, STOP_A); + setupStationStopRelationship(STATION_B, STOP_B); + } + + private static void setupStationStopRelationship(Station station, Stop ... stops) { + for (Stop stop : stops) { + station.addChildStop(stop); + stop.setParentStation(station); + } + } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java index b3f0ef511e0..5814df3340e 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java @@ -254,7 +254,7 @@ public void testConstrainedTransferIsPreferred() { ); // Verify the attached Transfer is exist and is valid assertEquals( - "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}", + "ConstrainedTransfer{from: , to: , constraint: {guaranteed}}", it.accessLeg().nextLeg().asTransitLeg().getConstrainedTransferAfterLeg().toString() ); }