diff --git a/application/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java b/application/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java index cd047de6d04..8097bd05c6e 100644 --- a/application/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java +++ b/application/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java @@ -8,6 +8,7 @@ import java.util.Map; import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.model.PathTransfer; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.site.GroupStop; @@ -18,6 +19,8 @@ public class FlexIndex { private final Multimap transfersToStop = ArrayListMultimap.create(); + private final Multimap transfersFromStop = ArrayListMultimap.create(); + private final Multimap> flexTripsByStop = HashMultimap.create(); private final Map routeById = new HashMap<>(); @@ -25,8 +28,10 @@ public class FlexIndex { private final Map> tripById = new HashMap<>(); public FlexIndex(TimetableRepository timetableRepository) { - for (PathTransfer transfer : timetableRepository.getAllPathTransfers()) { + // Flex transfers should only use WALK mode transfers. + for (PathTransfer transfer : timetableRepository.findTransfers(StreetMode.WALK)) { transfersToStop.put(transfer.to, transfer); + transfersFromStop.put(transfer.from, transfer); } for (FlexTrip flexTrip : timetableRepository.getAllFlexTrips()) { routeById.put(flexTrip.getTrip().getRoute().getId(), flexTrip.getTrip().getRoute()); @@ -47,6 +52,10 @@ public Collection getTransfersToStop(StopLocation stopLocation) { return transfersToStop.get(stopLocation); } + public Collection getTransfersFromStop(StopLocation stopLocation) { + return transfersFromStop.get(stopLocation); + } + public Collection> getFlexTripsByStop(StopLocation stopLocation) { return flexTripsByStop.get(stopLocation); } diff --git a/application/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java b/application/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java index 46d9e527980..e7f3d3544ab 100644 --- a/application/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java +++ b/application/src/ext/java/org/opentripplanner/ext/flex/FlexRouter.java @@ -192,7 +192,7 @@ public TransitStopVertex getStopVertexForStopId(FeedScopedId stopId) { @Override public Collection getTransfersFromStop(StopLocation stop) { - return transitService.findPathTransfers(stop); + return transitService.getFlexIndex().getTransfersFromStop(stop); } @Override diff --git a/application/src/main/java/org/opentripplanner/api/parameter/QualifiedModeSet.java b/application/src/main/java/org/opentripplanner/api/parameter/QualifiedModeSet.java index c6f1a3d74ec..98ce58c6d21 100644 --- a/application/src/main/java/org/opentripplanner/api/parameter/QualifiedModeSet.java +++ b/application/src/main/java/org/opentripplanner/api/parameter/QualifiedModeSet.java @@ -126,9 +126,10 @@ public RequestModes getRequestModes() { mBuilder.withEgressMode(StreetMode.CAR_HAILING); mBuilder.withDirectMode(StreetMode.WALK); } else { - mBuilder.withAccessMode(StreetMode.WALK); - mBuilder.withTransferMode(StreetMode.WALK); - mBuilder.withEgressMode(StreetMode.WALK); + // This is necessary for transfer calculations. + mBuilder.withAccessMode(StreetMode.CAR); + mBuilder.withTransferMode(StreetMode.CAR); + mBuilder.withEgressMode(StreetMode.CAR); mBuilder.withDirectMode(StreetMode.CAR); } } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java b/application/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java index c0deb932418..37ac69d88ff 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java @@ -3,10 +3,13 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimaps; import java.time.Duration; +import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.graph_builder.issues.StopNotLinkedForTransfers; @@ -17,6 +20,7 @@ import org.opentripplanner.graph_builder.module.nearbystops.StreetNearbyStopFinder; import org.opentripplanner.model.PathTransfer; import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.NearbyStop; import org.opentripplanner.street.model.edge.Edge; @@ -86,6 +90,17 @@ public void buildGraph() { HashMultimap.create() ); + List flexTransferRequests = new ArrayList<>(); + // Flex transfer requests only use the WALK mode. + if (OTPFeature.FlexRouting.isOn()) { + flexTransferRequests.addAll( + transferRequests + .stream() + .filter(transferProfile -> transferProfile.journey().transfer().mode() == StreetMode.WALK) + .toList() + ); + } + stops .stream() .parallel() @@ -101,7 +116,9 @@ public void buildGraph() { LOG.debug("Linking stop '{}' {}", stop, ts0); + // Calculate default transfers. for (RouteRequest transferProfile : transferRequests) { + StreetMode mode = transferProfile.journey().transfer().mode(); for (NearbyStop sd : nearbyStopFinder.findNearbyStops( ts0, transferProfile, @@ -115,31 +132,51 @@ public void buildGraph() { if (sd.stop.transfersNotAllowed()) { continue; } - distinctTransfers.put( - new TransferKey(stop, sd.stop, sd.edges), - new PathTransfer(stop, sd.stop, sd.distance, sd.edges) - ); + TransferKey transferKey = new TransferKey(stop, sd.stop, sd.edges); + PathTransfer pathTransfer = distinctTransfers.get(transferKey); + if (pathTransfer == null) { + // If the PathTransfer can't be found, it is created. + distinctTransfers.put( + transferKey, + new PathTransfer(stop, sd.stop, sd.distance, sd.edges, EnumSet.of(mode)) + ); + } else { + // If the PathTransfer is found, a new PathTransfer with the added mode is created. + distinctTransfers.put(transferKey, pathTransfer.withAddedMode(mode)); + } } - if (OTPFeature.FlexRouting.isOn()) { - // This code is for finding transfers from AreaStops to Stops, transfers - // from Stops to AreaStops and between Stops are already covered above. - for (NearbyStop sd : nearbyStopFinder.findNearbyStops( - ts0, - transferProfile, - transferProfile.journey().transfer(), - true - )) { - // Skip the origin stop, loop transfers are not needed. - if (sd.stop == stop) { - continue; - } - if (sd.stop instanceof RegularStop) { - continue; - } + } + // Calculate flex transfers if flex routing is enabled. + for (RouteRequest transferProfile : flexTransferRequests) { + // Flex transfer requests only use the WALK mode. + StreetMode mode = StreetMode.WALK; + // This code is for finding transfers from AreaStops to Stops, transfers + // from Stops to AreaStops and between Stops are already covered above. + for (NearbyStop sd : nearbyStopFinder.findNearbyStops( + ts0, + transferProfile, + transferProfile.journey().transfer(), + true + )) { + // Skip the origin stop, loop transfers are not needed. + if (sd.stop == stop) { + continue; + } + if (sd.stop instanceof RegularStop) { + continue; + } + // The TransferKey and PathTransfer are created differently for flex routing. + TransferKey transferKey = new TransferKey(sd.stop, stop, sd.edges); + PathTransfer pathTransfer = distinctTransfers.get(transferKey); + if (pathTransfer == null) { + // If the PathTransfer can't be found, it is created. distinctTransfers.put( - new TransferKey(sd.stop, stop, sd.edges), - new PathTransfer(sd.stop, stop, sd.distance, sd.edges) + transferKey, + new PathTransfer(sd.stop, stop, sd.distance, sd.edges, EnumSet.of(mode)) ); + } else { + // If the PathTransfer is found, a new PathTransfer with the added mode is created. + distinctTransfers.put(transferKey, pathTransfer.withAddedMode(mode)); } } } @@ -172,6 +209,17 @@ public void buildGraph() { nTransfersTotal, nLinkedStops ); + transferRequests + .stream() + .map(transferProfile -> transferProfile.journey().transfer().mode()) + .distinct() + .forEach(mode -> + LOG.info( + "Created {} transfers for mode {}.", + timetableRepository.findTransfers(mode).size(), + mode + ) + ); } /** diff --git a/application/src/main/java/org/opentripplanner/model/PathTransfer.java b/application/src/main/java/org/opentripplanner/model/PathTransfer.java index 5b42a8149e3..c4676fdf06f 100644 --- a/application/src/main/java/org/opentripplanner/model/PathTransfer.java +++ b/application/src/main/java/org/opentripplanner/model/PathTransfer.java @@ -1,19 +1,20 @@ package org.opentripplanner.model; import java.io.Serializable; +import java.util.EnumSet; import java.util.List; import org.opentripplanner.model.transfer.ConstrainedTransfer; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.utils.tostring.ToStringBuilder; /** - * Represents a transfer between stops with the street network path attatched to it. + * Represents a transfer for a set of modes between stops with the street network path attached to it. *

* Do not confuse this with {@link ConstrainedTransfer}. * *

- * TODO these should really have a set of valid modes in case bike vs. walk transfers are different * TODO Should we just store the NearbyStop as a field here, or even switch to using it instead * where this class is used */ @@ -27,11 +28,20 @@ public class PathTransfer implements Serializable { private final List edges; - public PathTransfer(StopLocation from, StopLocation to, double distanceMeters, List edges) { + private final EnumSet modes; + + public PathTransfer( + StopLocation from, + StopLocation to, + double distanceMeters, + List edges, + EnumSet modes + ) { this.from = from; this.to = to; this.distanceMeters = distanceMeters; this.edges = edges; + this.modes = modes; } public String getName() { @@ -43,7 +53,18 @@ public double getDistanceMeters() { } public List getEdges() { - return this.edges; + return edges; + } + + public EnumSet getModes() { + return EnumSet.copyOf(modes); + } + + /** Create a new PathTransfer based on the current one with the mode added to the valid modes. */ + public PathTransfer withAddedMode(StreetMode mode) { + EnumSet newModes = EnumSet.copyOf(modes); + newModes.add(mode); + return new PathTransfer(from, to, distanceMeters, edges, newModes); } @Override @@ -54,6 +75,7 @@ public String toString() { .addObj("to", to) .addNum("distance", distanceMeters) .addColSize("edges", edges) + .addColSize("modes", modes) .toString(); } } diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java index 64c59b71603..15e3307b4e9 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java @@ -126,7 +126,7 @@ else if (pathLeg.isTransferLeg()) { legs.addAll( mapTransferLeg( pathLeg.asTransferLeg(), - transferMode == StreetMode.BIKE ? TraverseMode.BICYCLE : TraverseMode.WALK + StreetModeToTransferTraverseModeMapper.map(transferMode) ) ); } diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StreetModeToTransferTraverseModeMapper.java b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StreetModeToTransferTraverseModeMapper.java new file mode 100644 index 00000000000..65db8e87832 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StreetModeToTransferTraverseModeMapper.java @@ -0,0 +1,21 @@ +package org.opentripplanner.routing.algorithm.mapping; + +import org.opentripplanner.routing.api.request.StreetMode; +import org.opentripplanner.street.search.TraverseMode; + +/** + * Maps street mode to transfer traverse mode. + */ +public class StreetModeToTransferTraverseModeMapper { + + public static TraverseMode map(StreetMode mode) { + return switch (mode) { + case WALK -> TraverseMode.WALK; + case BIKE -> TraverseMode.BICYCLE; + case CAR -> TraverseMode.CAR; + default -> throw new IllegalArgumentException( + String.format("StreetMode %s can not be mapped to a TraverseMode for transfers.", mode) + ); + }; + } +} diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java index 1d9b804067c..8676e863911 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.function.Function; import org.opentripplanner.raptor.api.model.RaptorTransfer; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.search.request.StreetSearchRequest; public class RaptorTransferIndex { @@ -29,9 +30,9 @@ public static RaptorTransferIndex create( ) { var forwardTransfers = new ArrayList>(transfersByStopIndex.size()); var reversedTransfers = new ArrayList>(transfersByStopIndex.size()); + StreetMode mode = request.mode(); for (int i = 0; i < transfersByStopIndex.size(); i++) { - forwardTransfers.add(new ArrayList<>()); reversedTransfers.add(new ArrayList<>()); } @@ -41,13 +42,14 @@ public static RaptorTransferIndex create( var transfers = transfersByStopIndex .get(fromStop) .stream() + .filter(transfer -> transfer.allowsMode(mode)) .flatMap(s -> s.asRaptorTransfer(request).stream()) .collect( toMap(RaptorTransfer::stop, Function.identity(), (a, b) -> a.c1() < b.c1() ? a : b) ) .values(); - forwardTransfers.get(fromStop).addAll(transfers); + forwardTransfers.add(new ArrayList<>(transfers)); for (RaptorTransfer forwardTransfer : transfers) { reversedTransfers diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/Transfer.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/Transfer.java index 32d54787e6f..2643067398e 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/Transfer.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/Transfer.java @@ -2,12 +2,15 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Optional; import java.util.Set; import org.locationtech.jts.geom.Coordinate; import org.opentripplanner.raptor.api.model.RaptorCostConverter; import org.opentripplanner.raptor.api.model.RaptorTransfer; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.preference.WalkPreferences; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.search.request.StreetSearchRequest; @@ -31,16 +34,20 @@ public class Transfer { private final List edges; - public Transfer(int toStop, List edges) { + private final Set modes; + + public Transfer(int toStop, List edges, EnumSet modes) { this.toStop = toStop; this.edges = edges; this.distanceMeters = (int) edges.stream().mapToDouble(Edge::getDistanceMeters).sum(); + this.modes = Collections.unmodifiableSet(modes); } - public Transfer(int toStopIndex, int distanceMeters) { + public Transfer(int toStopIndex, int distanceMeters, EnumSet modes) { this.toStop = toStopIndex; this.distanceMeters = distanceMeters; this.edges = null; + this.modes = Collections.unmodifiableSet(modes); } public List getCoordinates() { @@ -68,6 +75,11 @@ public List getEdges() { return edges; } + /** Check if the given mode is a valid mode for the transfer. */ + public boolean allowsMode(StreetMode mode) { + return modes.contains(mode); + } + public Optional asRaptorTransfer(StreetSearchRequest request) { WalkPreferences walkPreferences = request.preferences().walk(); if (edges == null || edges.isEmpty()) { diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransfersMapper.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransfersMapper.java index ff47cb3ea74..9fc49c5c5e1 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransfersMapper.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransfersMapper.java @@ -18,7 +18,7 @@ static List> mapTransfers( SiteRepository siteRepository, TransitService transitService ) { - List> transferByStopIndex = new ArrayList<>(); + List> transfersByStopIndex = new ArrayList<>(); for (int i = 0; i < siteRepository.stopIndexSize(); ++i) { var stop = siteRepository.stopByIndex(i); @@ -34,10 +34,15 @@ static List> mapTransfers( int toStopIndex = pathTransfer.to.getIndex(); Transfer newTransfer; if (pathTransfer.getEdges() != null) { - newTransfer = new Transfer(toStopIndex, pathTransfer.getEdges()); + newTransfer = + new Transfer(toStopIndex, pathTransfer.getEdges(), pathTransfer.getModes()); } else { newTransfer = - new Transfer(toStopIndex, (int) Math.ceil(pathTransfer.getDistanceMeters())); + new Transfer( + toStopIndex, + (int) Math.ceil(pathTransfer.getDistanceMeters()), + pathTransfer.getModes() + ); } list.add(newTransfer); @@ -45,10 +50,10 @@ static List> mapTransfers( } // Create a copy to compact and make the inner lists immutable - transferByStopIndex.add(List.copyOf(list)); + transfersByStopIndex.add(List.copyOf(list)); } // Return an immutable copy - return List.copyOf(transferByStopIndex); + return List.copyOf(transfersByStopIndex); } } diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerMapper.java b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerMapper.java index d6f9c0709c5..edcfa3f9dc8 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerMapper.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerMapper.java @@ -62,7 +62,7 @@ public static TransitLayer map( private TransitLayer map(TransitTuningParameters tuningParameters) { HashMap> tripPatternsByStopByDate; - List> transferByStopIndex; + List> transfersByStopIndex; ConstrainedTransfersForPatterns constrainedTransfers = null; LOG.info("Mapping transitLayer from TimetableRepository..."); @@ -71,7 +71,7 @@ private TransitLayer map(TransitTuningParameters tuningParameters) { tripPatternsByStopByDate = mapTripPatterns(allTripPatterns); - transferByStopIndex = mapTransfers(siteRepository, transitService); + transfersByStopIndex = mapTransfers(siteRepository, transitService); TransferIndexGenerator transferIndexGenerator = null; if (OTPFeature.TransferConstraints.isOn()) { @@ -86,7 +86,7 @@ private TransitLayer map(TransitTuningParameters tuningParameters) { return new TransitLayer( tripPatternsByStopByDate, - transferByStopIndex, + transfersByStopIndex, transitService.getTransferService(), siteRepository, transferCache, diff --git a/application/src/main/java/org/opentripplanner/transit/service/TimetableRepository.java b/application/src/main/java/org/opentripplanner/transit/service/TimetableRepository.java index b81dd7d4f14..ff8607f3818 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TimetableRepository.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TimetableRepository.java @@ -16,6 +16,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -35,6 +36,7 @@ import org.opentripplanner.model.transfer.DefaultTransferService; import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer; import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.impl.DelegatingTransitAlertServiceImpl; import org.opentripplanner.routing.services.TransitAlertService; import org.opentripplanner.routing.util.ConcurrentPublished; @@ -433,6 +435,15 @@ public Collection getTransfersByStop(StopLocation stop) { return transfersByStop.get(stop); } + /** Pre-generated transfers between all stops filtered based on the modes in the PathTransfer. */ + public List findTransfers(StreetMode mode) { + return transfersByStop + .values() + .stream() + .filter(pathTransfer -> pathTransfer.getModes().contains(mode)) + .toList(); + } + public SiteRepository getSiteRepository() { return siteRepository; } diff --git a/application/src/test/java/org/opentripplanner/graph_builder/module/DirectTransferGeneratorTest.java b/application/src/test/java/org/opentripplanner/graph_builder/module/DirectTransferGeneratorTest.java index 8a17e5258d8..39d2f4b5684 100644 --- a/application/src/test/java/org/opentripplanner/graph_builder/module/DirectTransferGeneratorTest.java +++ b/application/src/test/java/org/opentripplanner/graph_builder/module/DirectTransferGeneratorTest.java @@ -196,7 +196,7 @@ public void testMultipleRequestsWithoutPatterns() { reqWalk.journey().transfer().setMode(StreetMode.WALK); var reqBike = new RouteRequest(); - reqWalk.journey().transfer().setMode(StreetMode.BIKE); + reqBike.journey().transfer().setMode(StreetMode.BIKE); var transferRequests = List.of(reqWalk, reqBike); @@ -223,7 +223,7 @@ public void testMultipleRequestsWithPatterns() { reqWalk.journey().transfer().setMode(StreetMode.WALK); var reqBike = new RouteRequest(); - reqWalk.journey().transfer().setMode(StreetMode.BIKE); + reqBike.journey().transfer().setMode(StreetMode.BIKE); var transferRequests = List.of(reqWalk, reqBike); @@ -250,6 +250,49 @@ public void testMultipleRequestsWithPatterns() { ); } + @Test + public void testPathTransfersWithModesForMultipleRequestsWithPatterns() { + var reqWalk = new RouteRequest(); + reqWalk.journey().transfer().setMode(StreetMode.WALK); + + var reqBike = new RouteRequest(); + reqBike.journey().transfer().setMode(StreetMode.BIKE); + + var transferRequests = List.of(reqWalk, reqBike); + + TestOtpModel model = model(true); + var graph = model.graph(); + graph.hasStreets = true; + var timetableRepository = model.timetableRepository(); + + new DirectTransferGenerator( + graph, + timetableRepository, + DataImportIssueStore.NOOP, + MAX_TRANSFER_DURATION, + transferRequests + ) + .buildGraph(); + + var walkTransfers = timetableRepository.findTransfers(StreetMode.WALK); + var bikeTransfers = timetableRepository.findTransfers(StreetMode.BIKE); + var carTransfers = timetableRepository.findTransfers(StreetMode.CAR); + + assertTransfers( + walkTransfers, + tr(S0, 100, List.of(V0, V11), S11), + tr(S0, 100, List.of(V0, V21), S21), + tr(S11, 100, List.of(V11, V21), S21) + ); + assertTransfers( + bikeTransfers, + tr(S0, 100, List.of(V0, V11), S11), + tr(S0, 100, List.of(V0, V21), S21), + tr(S11, 110, List.of(V11, V22), S22) + ); + assertTransfers(carTransfers); + } + @Test public void testTransferOnIsolatedStations() { var otpModel = model(true, false, true); diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java index 8f2fc45b875..1c43234bd4d 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java @@ -12,6 +12,7 @@ import java.time.LocalDateTime; import java.time.Month; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import org.junit.jupiter.api.Disabled; @@ -54,6 +55,7 @@ import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitLayer; import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.DefaultCostCalculator; import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.TestStateBuilder; @@ -199,7 +201,7 @@ void createItineraryWithOnBoardFlexAccess() { flexAccessEgress, AccessEgressType.ACCESS ); - Transfer transfer = new Transfer(S2.getIndex(), 0); + Transfer transfer = new Transfer(S2.getIndex(), 0, EnumSet.of(StreetMode.WALK)); RaptorTransfer raptorTransfer = new DefaultRaptorTransfer(S1.getIndex(), 0, 0, transfer); RaptorAccessEgress egress = new DefaultAccessEgress(S2.getIndex(), state); PathLeg egressLeg = new EgressPathLeg<>(egress, 0, 0, 0); diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java index 8dc4d548c18..ebae06f5063 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.street.model._data.StreetModelForTest.intersectionVertex; +import java.util.EnumSet; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Nested; @@ -11,6 +12,7 @@ import org.opentripplanner._support.geometry.Coordinates; import org.opentripplanner.raptor.api.model.RaptorCostConverter; import org.opentripplanner.raptor.api.model.RaptorTransfer; +import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.street.model._data.StreetModelForTest; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.search.request.StreetSearchRequest; @@ -34,7 +36,7 @@ void limitMaxCost() { // very long edge from Berlin to Boston that has of course a huge cost to traverse var edge = StreetModelForTest.streetEdge(BERLIN_V, BOSTON_V); - var veryLongTransfer = new Transfer(0, List.of(edge)); + var veryLongTransfer = new Transfer(0, List.of(edge), EnumSet.of(StreetMode.WALK)); assertTrue(veryLongTransfer.getDistanceMeters() > 1_000_000); // cost would be too high, so it should be capped to a maximum value assertMaxCost(veryLongTransfer.asRaptorTransfer(StreetSearchRequest.of().build()).get()); @@ -43,7 +45,7 @@ void limitMaxCost() { @Test void allowLowCost() { var edge = StreetModelForTest.streetEdge(BERLIN_V, BRANDENBURG_GATE_V); - var transfer = new Transfer(0, List.of(edge)); + var transfer = new Transfer(0, List.of(edge), EnumSet.of(StreetMode.WALK)); assertTrue(transfer.getDistanceMeters() < 4000); final Optional raptorTransfer = transfer.asRaptorTransfer( StreetSearchRequest.of().build() @@ -58,26 +60,26 @@ class WithoutEdges { @Test void overflow() { - var veryLongTransfer = new Transfer(0, Integer.MAX_VALUE); + var veryLongTransfer = new Transfer(0, Integer.MAX_VALUE, EnumSet.of(StreetMode.WALK)); assertMaxCost(veryLongTransfer.asRaptorTransfer(StreetSearchRequest.of().build()).get()); } @Test void negativeCost() { - var veryLongTransfer = new Transfer(0, -5); + var veryLongTransfer = new Transfer(0, -5, EnumSet.of(StreetMode.WALK)); assertMaxCost(veryLongTransfer.asRaptorTransfer(StreetSearchRequest.of().build()).get()); } @Test void limitMaxCost() { - var veryLongTransfer = new Transfer(0, 8_000_000); + var veryLongTransfer = new Transfer(0, 8_000_000, EnumSet.of(StreetMode.WALK)); // cost would be too high, so it will be capped before passing to RAPTOR assertMaxCost(veryLongTransfer.asRaptorTransfer(StreetSearchRequest.of().build()).get()); } @Test void allowLowCost() { - var transfer = new Transfer(0, 200); + var transfer = new Transfer(0, 200, EnumSet.of(StreetMode.WALK)); final Optional raptorTransfer = transfer.asRaptorTransfer( StreetSearchRequest.of().build() );