diff --git a/src/ext/java/org/opentripplanner/ext/reportapi/model/CsvReportBuilder.java b/src/ext/java/org/opentripplanner/ext/reportapi/model/CsvReportBuilder.java
index f9d3d8b8cf9..cfd01782b24 100644
--- a/src/ext/java/org/opentripplanner/ext/reportapi/model/CsvReportBuilder.java
+++ b/src/ext/java/org/opentripplanner/ext/reportapi/model/CsvReportBuilder.java
@@ -6,7 +6,7 @@
/**
* A very simple CSV builder to create CSV reports.
*
- * This class helps formatting common types like time, duration and enums.
+ * This class helps to format common types like time, duration and enums.
*/
class CsvReportBuilder {
private final String sep;
@@ -51,12 +51,12 @@ void addText(String text) {
}
void addNumber(Number num) {
- buf.append(num.toString());
+ buf.append(num == null ? "" : num.toString());
sep();
}
void addBoolean(Boolean b) {
- buf.append(b.toString());
+ buf.append(b == null ? "" : b.toString());
sep();
}
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 6a6652dad56..2bb48f1eb68 100644
--- a/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java
+++ b/src/ext/java/org/opentripplanner/ext/reportapi/model/TransfersReport.java
@@ -6,17 +6,23 @@
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.Stop;
+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.StationTransferPoint;
import org.opentripplanner.model.transfer.StopTransferPoint;
import org.opentripplanner.model.transfer.TransferPoint;
+import org.opentripplanner.model.transfer.TripTransferPoint;
import org.opentripplanner.routing.graph.GraphIndex;
/**
* This class is used to export transfers for human verification to a CSV file. This is useful
* when trying to debug the rather complicated NeTEx data format or to get the GTFS transfers in a
- * more human readable form. It can also be used to test transfer functionality, since it is easy
+ * more human-readable form. It can also be used to test transfer functionality, since it is easy
* to read and find special test-cases when needed.
*/
public class TransfersReport {
@@ -41,32 +47,39 @@ public static String export(List transfers, GraphIndex inde
String export() {
buf.addHeader(
- "Id", "Operator", "FromTripId", "FromTrip", "FromStop",
- "ToTripId", "ToTrip", "ToStop", "ArrivalTime", "DepartureTime", "TransferTime",
- "Walk", "Priority", "MaxWaitTime", "StaySeated", "Guaranteed"
+ "Id", "Operator", "From", "FromId", "FromRoute", "FromTrip", "FromStop",
+ "FromSpecificity", "To", "ToId", "ToRoute", "ToTrip", "ToStop", "ToSpecificity",
+ "ArrivalTime", "DepartureTime", "TransferTime", "Walk", "Priority", "MaxWaitTime",
+ "StaySeated", "Guaranteed"
);
transfers.forEach(t -> {
var from = pointInfo(t.getFrom(), true);
var to = pointInfo(t.getTo(), false);
- var dist = (from.c == null || to.c == null)
+ var dist = (from.coordinate == null || to.coordinate == null)
? ""
: String.format(
"%.0fm",
- SphericalDistanceLibrary.fastDistance(from.c, to.c)
+ SphericalDistanceLibrary.fastDistance(from.coordinate, to.coordinate)
);
var duration = (from.time == NOT_SET || to.time == NOT_SET)
? "" : durationToStr(to.time - from.time);
var c = t.getTransferConstraint();
buf.addText(t.getId() == null ? "" : t.getId().getId());
- buf.addText(t.getFrom().getTrip().getOperator().getId().getId());
- buf.addText(from.tripId);
+ buf.addText((from.operator.isEmpty() ? to : from).operator);
+ buf.addText(from.type);
+ buf.addText(from.entityId);
+ buf.addText(from.route);
buf.addText(from.trip);
buf.addText(from.loc);
- buf.addText(to.tripId);
+ 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.addNumber(to.specificity);
buf.addTime(from.time, NOT_SET);
buf.addTime(to.time, NOT_SET);
buf.addText(duration);
@@ -85,42 +98,83 @@ private TxPoint pointInfo(
boolean arrival
) {
var r = new TxPoint();
- if (p instanceof StopTransferPoint) {
- r.loc = p.getStop().getName();
- return r;
- }
- var ptn = index.getPatternForTrip().get(p.getTrip());
- var trip = p.getTrip();
- var route = trip.getRoute();
-
- r.tripId = trip.getId().getId();
- r.trip = route.getName() + " " + route.getMode() + " " + route.getLongName()
- + " " + trip.getTripHeadsign();
- r.c = null;
-
+ if(p instanceof TripTransferPoint) {
+ var tp = (TripTransferPoint)p;
+ var trip = tp.getTrip();
+ var route = trip.getRoute();
+ var ptn = index.getPatternForTrip().get(trip);
+ r.operator = trip.getOperator().getId().getId();
+ r.type = "Trip";
+ r.entityId = trip.getId().getId();
+ r.route = route.getName() + " " + route.getMode() + " " + route.getLongName();
+ r.trip = trip.getTripHeadsign();
+ addLocation(r, ptn, tp.getStopPositionInPattern(), trip, arrival);
+ }
+ else if(p instanceof RouteTransferPoint) {
+ var rp = (RouteTransferPoint)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);
+ }
+ else if(p instanceof StopTransferPoint) {
+ var sp = (StopTransferPoint)p;
+ Stop stop = sp.getStop();
+ r.type = "Stop";
+ r.entityId = stop.getId().getId();
+ r.loc = stop.getName();
+ r.coordinate = stop.getCoordinate().asJtsCoordinate();
+ }
+ else if(p instanceof StationTransferPoint) {
+ var sp = (StationTransferPoint)p;
+ Station station = sp.getStation();
+ r.type = "Station";
+ r.entityId = station.getId().getId();
+ r.loc = station.getName();
+ r.coordinate = station.getCoordinate().asJtsCoordinate();
+ }
+ r.specificity = p.getSpecificityRanking();
+ r.coordinate = null;
+ return r;
+ }
- if (ptn.getStops().size() > p.getStopPosition()) {
- int pos = p.getStopPosition();
- Stop stop = ptn.getStops().get(pos);
- var tt = ptn.getScheduledTimetable().getTripTimes(trip);
- r.loc += stop.getName() + " [" + pos + "]" + " " + stop.getCoordinate();
- r.time = arrival ? tt.getScheduledArrivalTime(pos) : tt.getScheduledDepartureTime(pos);
- r.c = stop.getCoordinate().asJtsCoordinate();
+ private static void addLocation(
+ TxPoint r,
+ TripPattern pattern,
+ int stopPosition,
+ Trip trip,
+ boolean arrival
+ ) {
+ if(pattern == null || stopPosition >= pattern.getStopPattern().getSize()) {
+ r.loc += "[Stop position not found: " + stopPosition + "]";
+ return;
}
- else {
- r.loc += "[Stop index not found: " + p.getStopPosition() + "]";
+ Stop stop = pattern.getStops().get(stopPosition);
+ r.loc += stop.getName() + " [" + stopPosition + "]" + " " + stop.getCoordinate();
+ r.coordinate = stop.getCoordinate().asJtsCoordinate();
+
+ if(trip != null) {
+ var tt = pattern.getScheduledTimetable().getTripTimes(trip);
+ r.time = arrival
+ ? tt.getScheduledArrivalTime(stopPosition)
+ : tt.getScheduledDepartureTime(stopPosition);
}
- r.loc += " " + p.getSpecificityRanking();
- return r;
}
static class TxPoint {
+ private String operator = "";
+ private String type = "";
+ private String entityId = "";
private String loc = "";
- private String tripId = "";
private String trip = "";
- private Coordinate c = null;
+ private String route = "";
+ private Integer specificity = null;
+ private Coordinate coordinate = null;
private int time = NOT_SET;
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java b/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java
index 506186272f8..563ffb95c20 100644
--- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java
+++ b/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java
@@ -5,9 +5,13 @@
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
+import java.util.function.Function;
import org.opentripplanner.ext.transmodelapi.model.EnumTypes;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Trip;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.model.transfer.TransferConstraint;
+import org.opentripplanner.model.transfer.TransferPoint;
public class InterchangeType {
@@ -52,36 +56,36 @@ public static GraphQLObjectType create(
.deprecate(
"This is the same as using the `fromServiceJourney { line }` field.")
.type(lineType)
- .dataFetcher(env -> transfer(env).getFrom().getTrip().getRoute())
+ .dataFetcher(env -> transferRoute(env, ConstrainedTransfer::getFrom))
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("ToLine")
.deprecate(
"This is the same as using the `toServiceJourney { line }` field.")
.type(lineType)
- .dataFetcher(env -> transfer(env).getTo().getTrip().getRoute())
+ .dataFetcher(env -> transferRoute(env, ConstrainedTransfer::getTo))
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
- .name("FromServiceJourney")
+ .name("fromServiceJourney")
.type(serviceJourneyType)
- .deprecate("Use fromServiceJourney instead")
- .dataFetcher(env -> transfer(env).getFrom().getTrip())
+ .dataFetcher(env -> transferTrip(env, ConstrainedTransfer::getFrom))
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
- .name("ToServiceJourney")
+ .name("toServiceJourney")
.type(serviceJourneyType)
- .deprecate("Use toServiceJourney instead")
- .dataFetcher(env -> transfer(env).getTo().getTrip())
+ .dataFetcher(env -> transferTrip(env, ConstrainedTransfer::getTo))
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
- .name("fromServiceJourney")
+ .name("FromServiceJourney")
.type(serviceJourneyType)
- .dataFetcher(env -> transfer(env).getFrom().getTrip())
+ .deprecate("Use fromServiceJourney instead")
+ .dataFetcher(env -> transferTrip(env, ConstrainedTransfer::getFrom))
.build())
.field(GraphQLFieldDefinition.newFieldDefinition()
- .name("toServiceJourney")
+ .name("ToServiceJourney")
.type(serviceJourneyType)
- .dataFetcher(env -> transfer(env).getTo().getTrip())
+ .deprecate("Use toServiceJourney instead")
+ .dataFetcher(env -> transferTrip(env, ConstrainedTransfer::getTo))
.build())
.build();
}
@@ -90,6 +94,27 @@ private static ConstrainedTransfer transfer(DataFetchingEnvironment environment)
return environment.getSource();
}
+ private static TransferPoint transferPoint(
+ DataFetchingEnvironment environment,
+ Function fromTo
+ ) {
+ return fromTo.apply(transfer(environment));
+ }
+
+ private static Trip transferTrip(
+ DataFetchingEnvironment environment,
+ Function fromTo
+ ) {
+ return TransferPoint.getTrip(transferPoint(environment, fromTo));
+ }
+
+ private static Route transferRoute(
+ DataFetchingEnvironment environment,
+ Function fromTo
+ ) {
+ return TransferPoint.getRoute(transferPoint(environment, fromTo));
+ }
+
private static TransferConstraint constraint(DataFetchingEnvironment environment) {
return transfer(environment).getTransferConstraint();
}
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
index ca55fe7a926..8aca5642c8f 100644
--- a/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/GTFSToOtpTransitServiceMapper.java
@@ -56,8 +56,6 @@ public class GTFSToOtpTransitServiceMapper {
private final TripMapper tripMapper;
- private final BookingRuleMapper bookingRuleMapper;
-
private final StopTimeMapper stopTimeMapper;
private final FrequencyMapper frequencyMapper;
@@ -82,8 +80,13 @@ public GTFSToOtpTransitServiceMapper(
agencyMapper = new AgencyMapper(feedId);
routeMapper = new RouteMapper(agencyMapper);
tripMapper = new TripMapper(routeMapper);
- bookingRuleMapper = new BookingRuleMapper();
- stopTimeMapper = new StopTimeMapper(stopMapper, locationMapper, locationGroupMapper, tripMapper, bookingRuleMapper);
+ stopTimeMapper = new StopTimeMapper(
+ stopMapper,
+ locationMapper,
+ locationGroupMapper,
+ tripMapper,
+ new BookingRuleMapper()
+ );
frequencyMapper = new FrequencyMapper(tripMapper);
fareRuleMapper = new FareRuleMapper(
routeMapper, fareAttributeMapper
@@ -95,7 +98,6 @@ public OtpTransitServiceBuilder getBuilder() {
}
public void mapStopTripAndRouteDatantoBuilder() {
-
builder.getAgenciesById().addAll(agencyMapper.map(data.getAllAgencies()));
builder.getCalendarDates().addAll(serviceCalendarDateMapper.map(data.getAllCalendarDates()));
builder.getCalendars().addAll(serviceCalendarMapper.map(data.getAllCalendars()));
diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java
index cc02fa75043..20a3b07a491 100644
--- a/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java
+++ b/src/main/java/org/opentripplanner/gtfs/mapping/TransferMapper.java
@@ -1,20 +1,23 @@
package org.opentripplanner.gtfs.mapping;
-import java.util.ArrayList;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.function.BiFunction;
+import java.util.Objects;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
-import javax.annotation.Nullable;
import org.onebusaway.gtfs.model.Transfer;
import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
+import org.opentripplanner.model.StopLocation;
import org.opentripplanner.model.StopTime;
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.StationTransferPoint;
import org.opentripplanner.model.transfer.StopTransferPoint;
import org.opentripplanner.model.transfer.TransferConstraint;
import org.opentripplanner.model.transfer.TransferPoint;
@@ -69,6 +72,9 @@ class TransferMapper {
private final TripStopTimes stopTimesByTrip;
+ private final Multimap tripsByRoute = ArrayListMultimap.create();
+
+
TransferMapper(
RouteMapper routeMapper,
StationMapper stationMapper,
@@ -97,27 +103,17 @@ static TransferPriority mapTypeToPriority(int type) {
}
Collection map(Collection allTransfers) {
- List result = new ArrayList<>();
+ setup(!allTransfers.isEmpty());
- for (org.onebusaway.gtfs.model.Transfer it : allTransfers) {
- result.addAll(map(it));
- }
- return result;
+ return allTransfers.stream().map(this::map)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
}
- /**
- * Map from GTFS to OTP model, {@code null} safe.
- */
- Collection map(org.onebusaway.gtfs.model.Transfer original) {
- return original == null ? List.of() : doMap(original);
- }
-
- private Collection doMap(org.onebusaway.gtfs.model.Transfer rhs) {
-
+ ConstrainedTransfer map(org.onebusaway.gtfs.model.Transfer rhs) {
Trip fromTrip = tripMapper.map(rhs.getFromTrip());
Trip toTrip = tripMapper.map(rhs.getToTrip());
- Route fromRoute = routeMapper.map(rhs.getFromRoute());
- Route toRoute = routeMapper.map(rhs.getToRoute());
+
TransferConstraint constraint = mapConstraint(rhs, fromTrip, toTrip);
// TODO TGR - Create a transfer for this se issue #3369
@@ -131,35 +127,21 @@ private Collection doMap(org.onebusaway.gtfs.model.Transfer
else {
LOG.warn("Transfer skipped - no effect on routing: " + rhs);
}
- return List.of();
+ return null;
}
- // Transfers may be specified using parent stations
- // (https://developers.google.com/transit/gtfs/reference/transfers-file)
- // "If the stop ID refers to a station that contains multiple stops, this transfer rule
- // applies to all stops in that station." we thus expand transfers that use parent stations
- // to all the member stops.
-
- Collection fromStops = getStopOrChildStops(rhs.getFromStop());
- Collection toStops = getStopOrChildStops(rhs.getToStop());
-
- Collection fromPoints = mapTransferPoints(fromStops, fromTrip, fromRoute);
- Collection toPoints = mapTransferPoints(toStops, toTrip, toRoute);
-
- Collection result = new ArrayList<>();
-
- for (TransferPoint fromPoint : fromPoints) {
- for (TransferPoint toPoint : toPoints) {
- var transfer = new ConstrainedTransfer(
- null,
- fromPoint,
- toPoint,
- constraint
- );
- result.add(transfer);
- }
+ TransferPoint fromPoint = mapTransferPoint(rhs.getFromStop(), rhs.getFromRoute(), fromTrip, false);
+ TransferPoint toPoint = mapTransferPoint(rhs.getToStop(), rhs.getToRoute(), toTrip, true);
+
+ return new ConstrainedTransfer(null, fromPoint, toPoint, constraint);
+ }
+
+ private void setup(boolean run) {
+ if(!run) { return; }
+
+ for (Trip trip : tripMapper.mappedTrips()) {
+ tripsByRoute.put(trip.getRoute(), trip);
}
- return result;
}
private TransferConstraint mapConstraint(Transfer rhs, Trip fromTrip, Trip toTrip) {
@@ -172,64 +154,90 @@ private TransferConstraint mapConstraint(Transfer rhs, Trip fromTrip, Trip toTri
return builder.build();
}
- private Collection mapTransferPoints(
- Collection stops,
- Trip trip,
- Route route
+ private TransferPoint mapTransferPoint(
+ org.onebusaway.gtfs.model.Stop rhsStopOrStation,
+ org.onebusaway.gtfs.model.Route rhsRoute,
+ Trip trip,
+ boolean boardTrip
) {
- Collection result = new ArrayList<>();
- if (trip != null) {
- result.addAll(createTransferPointForTrip(stops, trip, TripTransferPoint::new));
- }
- else if (route != null) {
- /*
- TODO - This code result in a OutOfMemory exception, fin out why and fix it
- - See issue https://github.com/opentripplanner/OpenTripPlanner/issues/3429
- for (Trip tripInRoute : tripsByRoute.get(route)) {
- result.addAll(
- createTransferPointForTrip(
- stops,
- tripInRoute,
- (t,i) -> new RouteTransferPoint(route, t, i)
- )
- );
- }
- */
+ Route route = routeMapper.map(rhsRoute);
+ Station station = null;
+ Stop stop = null;
+
+ // A transfer is specified using Stops and/or Station, according to the GTFS specification:
+ //
+ // If the stop ID refers to a station that contains multiple stops, this transfer rule
+ // applies to all stops in that station.
+ //
+ // Source: https://developers.google.com/transit/gtfs/reference/transfers-file
+
+ if (rhsStopOrStation.getLocationType() == 0) {
+ stop = stopMapper.map(rhsStopOrStation);
}
else {
- for (Stop stop : stops) {
- result.add(new StopTransferPoint(stop));
- }
+ station = stationMapper.map(rhsStopOrStation);
+ }
+ if(trip != null) {
+ int stopPositionInPattern = stopPosition(trip, stop, station, boardTrip);
+ 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 fr route: " + route); }
+ int stopPositionInPattern = stopPosition(route, stop, station, boardTrip);
+ return new RouteTransferPoint(route, stopPositionInPattern);
+ }
+ else if(stop != null) {
+ return new StopTransferPoint(stop);
+ }
+ else if(station != null) {
+ return new StationTransferPoint(station);
}
- return result;
+
+ throw new IllegalStateException("Should not get here!");
}
- private Collection createTransferPointForTrip(
- Collection stops,
- Trip trip,
- BiFunction createPoint
- ) {
- Collection result = new ArrayList<>();
+
+ private int stopPosition(Route route, Stop stop, Station station, boolean boardTrip) {
+ var stopPosList = tripsByRoute.get(route).stream()
+ .map(t -> stopPosition(t, stop, station, boardTrip))
+ .distinct()
+ .collect(Collectors.toList());
+
+ if(stopPosList.size() == 1) { return stopPosList.get(0); }
+
+ LOG.error(
+ "In GTFS 'transfers.txt' a transfer-point can be a combination of route and stop/station!"
+ + "OTP only support this case, if the stop/station have the same stop point in trip-"
+ + "pattern for all trips in the route. Route: " + route
+ );
+ return -1;
+ }
+
+
+ private int stopPosition(Trip trip, Stop stop, Station station, boolean boardTrip) {
List stopTimes = stopTimesByTrip.get(trip);
- for (int i = 0; i < stopTimes.size(); ++i) {
+
+ // We can board at the first stop, but not alight.
+ final int firstStopPos = boardTrip ? 0 : 1;
+ // We can alight at the last stop, but not board, the lastStopPos is exclusive
+ final int lastStopPos = stopTimes.size() - (boardTrip ? 1 : 0);
+
+ Predicate stopMatches = station != null
+ ? (s) -> (s instanceof Stop && ((Stop)s).getParentStation() == station)
+ : (s) -> s == stop;
+
+ for (int i = firstStopPos; i < lastStopPos; i++) {
StopTime stopTime = stopTimes.get(i);
+ if(boardTrip && !stopTime.getPickupType().isRoutable()) { continue; }
+ if(!boardTrip && !stopTime.getDropOffType().isRoutable()) { continue; }
- //noinspection SuspiciousMethodCalls
- if (stops.contains(stopTime.getStop())) {
- result.add(createPoint.apply(trip, i));
+ if(stopMatches.test(stopTime.getStop())) {
+ return i;
}
}
- return result;
- }
-
- private Collection getStopOrChildStops(org.onebusaway.gtfs.model.Stop gtfsStop) {
- if (gtfsStop.getLocationType() == 0) {
- return Collections.singletonList(stopMapper.map(gtfsStop));
- }
- else {
- return stationMapper.map(gtfsStop).getChildStops();
- }
+ return -1;
}
private boolean sameBlockId(Trip a, Trip b) {
@@ -238,16 +246,4 @@ private boolean sameBlockId(Trip a, Trip b) {
}
return a.getBlockId() != null && a.getBlockId().equals(b.getBlockId());
}
-
- @Nullable
- private Map> createTripsByRouteMapIfRouteTransfersExist(
- Collection trips,
- Collection allTransfers
- ) {
- if(allTransfers.stream().anyMatch(t -> t.getFromRoute() != null || t.getToRoute() != null)) {
- return trips.stream().collect(Collectors.groupingBy(Trip::getRoute));
- }
- // Return null, not an empty map to enforce NPE if used when no Route exist
- return null;
- }
}
diff --git a/src/main/java/org/opentripplanner/model/TripPattern.java b/src/main/java/org/opentripplanner/model/TripPattern.java
index ec5a9d5b016..d417c33ce81 100644
--- a/src/main/java/org/opentripplanner/model/TripPattern.java
+++ b/src/main/java/org/opentripplanner/model/TripPattern.java
@@ -7,17 +7,6 @@
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.LineString;
-import org.opentripplanner.common.geometry.CompactLineString;
-import org.opentripplanner.common.geometry.GeometryUtils;
-import org.opentripplanner.graph_builder.DataImportIssueStore;
-import org.opentripplanner.graph_builder.issues.NonUniqueRouteName;
-import org.opentripplanner.routing.trippattern.FrequencyEntry;
-import org.opentripplanner.routing.trippattern.TripTimes;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
@@ -31,6 +20,16 @@
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.LineString;
+import org.opentripplanner.common.geometry.CompactLineString;
+import org.opentripplanner.common.geometry.GeometryUtils;
+import org.opentripplanner.graph_builder.DataImportIssueStore;
+import org.opentripplanner.graph_builder.issues.NonUniqueRouteName;
+import org.opentripplanner.routing.trippattern.FrequencyEntry;
+import org.opentripplanner.routing.trippattern.TripTimes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Represents a group of trips on a route, with the same direction id that all call at the same
@@ -241,9 +240,10 @@ public PickDrop getBoardType(int stopIndex) {
* trip as one of the scheduled trips on this pattern.
*/
public void add(TripTimes tt) {
- // Only scheduled trips (added at graph build time, rather than directly to the timetable via updates) are in this list.
- getTrips().add(tt.getTrip());
+ // Only scheduled trips (added at graph build time, rather than directly to the timetable
+ // via updates) are in this list.
scheduledTimetable.addTripTimes(tt);
+
// Check that all trips added to this pattern are on the initially declared route.
// Identity equality is valid on GTFS entity objects.
if (this.route != tt.getTrip().getRoute()) {
@@ -307,7 +307,7 @@ public Direction getDirection() {
* to search for trips/TripIds in the Timetable rather than the enclosing TripPattern.
*/
public List getTrips() {
- return scheduledTimetable.getTripTimes().stream().map(t -> t.getTrip()).collect(Collectors.toList());
+ return scheduledTimetable.getTripTimes().stream().map(TripTimes::getTrip).collect(Collectors.toList());
}
/** The human-readable, unique name for this trip pattern. */
diff --git a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
index d20401aeeb7..1f750f2c566 100644
--- a/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
+++ b/src/main/java/org/opentripplanner/model/impl/OtpTransitServiceBuilder.java
@@ -332,19 +332,24 @@ private void fixOrRemovePatternsWhichReferenceNoneExistingTrips() {
/** Remove all transfers witch reference none existing trips */
private void removeTransfersForNoneExistingTrips() {
int orgSize = transfers.size();
- transfers.removeIf(this::transferTripsDoesNotExist);
+ transfers.removeIf(this::transferTripReferencesDoNotExist);
logRemove("Trip", orgSize, transfers.size(), "Transfer to/from trip does not exist.");
}
/** Return {@code true} if the from/to trip reference is none null, but do not exist. */
- private boolean transferTripsDoesNotExist(ConstrainedTransfer t) {
- return transferTripPointDoesNotExist(t.getFrom())
- || transferTripPointDoesNotExist(t.getTo());
+ private boolean transferTripReferencesDoNotExist(ConstrainedTransfer t) {
+ return transferPointTripReferenceDoesNotExist(t.getFrom())
+ || transferPointTripReferenceDoesNotExist(t.getTo());
}
- /** Return true if the trip is a valid reference; {@code null} or exist. */
- private boolean transferTripPointDoesNotExist(TransferPoint p) {
- return p.getTrip() != null && !tripsById.containsKey(p.getTrip().getId());
+ /**
+ * Return {@code true} if the the point is a trip-transfer-point and the trip reference
+ * is missing.
+ */
+ private boolean transferPointTripReferenceDoesNotExist(TransferPoint point) {
+ if(!point.isTripTransferPoint()) { return false; }
+ var trip = point.asTripTransferPoint().getTrip();
+ return !tripsById.containsKey(trip.getId());
}
private static void logRemove(String type, int orgSize, int newSize, String reason) {
diff --git a/src/main/java/org/opentripplanner/model/transfer/ConstrainedTransfer.java b/src/main/java/org/opentripplanner/model/transfer/ConstrainedTransfer.java
index 5a6be6d9d15..44569e5aa72 100644
--- a/src/main/java/org/opentripplanner/model/transfer/ConstrainedTransfer.java
+++ b/src/main/java/org/opentripplanner/model/transfer/ConstrainedTransfer.java
@@ -18,6 +18,8 @@
public final class ConstrainedTransfer implements RaptorConstrainedTransfer, Serializable {
private static final long serialVersionUID = 1L;
+ private static final int FROM_RANKING_COEFFICIENT = 11;
+ private static final int TO_RANKING_COEFFICIENT = 10;
private final FeedScopedId id;
@@ -67,17 +69,43 @@ public boolean noConstraints() {
return constraint.isRegularTransfer();
}
- public boolean matchesStopPos(int fromStopPos, int toStopPos) {
- return from.getStopPosition() == fromStopPos && to.getStopPosition() == toStopPos;
- }
-
/**
*
* Specificity of a transfer
*
+ *
+ * The ranking implemented here is slightly modified:
+ *
*/
public int getSpecificityRanking() {
- return from.getSpecificityRanking() + to.getSpecificityRanking();
+ return from.getSpecificityRanking() * FROM_RANKING_COEFFICIENT
+ + to.getSpecificityRanking() * TO_RANKING_COEFFICIENT;
}
@Override
diff --git a/src/main/java/org/opentripplanner/model/transfer/RouteTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/RouteTransferPoint.java
index 6faa133cf00..d0a4b2a8ad5 100644
--- a/src/main/java/org/opentripplanner/model/transfer/RouteTransferPoint.java
+++ b/src/main/java/org/opentripplanner/model/transfer/RouteTransferPoint.java
@@ -2,7 +2,7 @@
import java.io.Serializable;
import org.opentripplanner.model.Route;
-import org.opentripplanner.model.Trip;
+import org.opentripplanner.model.base.ValueObjectToStringBuilder;
/**
* This is a specialized version of the {@link TripTransferPoint}, it represent a
@@ -12,15 +12,24 @@
* By expanding a route into trips, we can drop expanded-trips(lower specificity ranking)
* if a "real" trip-transfers-point exist.
*/
-public class RouteTransferPoint extends TripTransferPoint implements Serializable {
+public final class RouteTransferPoint implements TransferPoint, Serializable {
private static final long serialVersionUID = 1L;
private final Route route;
+ private final int stopPositionInPattern;
- public RouteTransferPoint(Route route, Trip trip, int stopPosition) {
- super(trip, stopPosition);
+ public RouteTransferPoint(Route route, int stopPositionInPattern) {
this.route = route;
+ this.stopPositionInPattern = stopPositionInPattern;
+ }
+
+ public Route getRoute() {
+ return route;
+ }
+
+ public int getStopPositionInPattern() {
+ return stopPositionInPattern;
}
@Override
@@ -29,12 +38,19 @@ public boolean applyToAllTrips() {
}
@Override
- public int getSpecificityRanking() { return 1; }
+ public int getSpecificityRanking() { return 2; }
+
+ @Override
+ public boolean isRouteTransferPoint() { return true; }
@Override
public String toString() {
- return "";
+ return ValueObjectToStringBuilder.of()
+ .addText("")
+ .toString();
}
}
diff --git a/src/main/java/org/opentripplanner/model/transfer/StationTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/StationTransferPoint.java
new file mode 100644
index 00000000000..dece0b8886d
--- /dev/null
+++ b/src/main/java/org/opentripplanner/model/transfer/StationTransferPoint.java
@@ -0,0 +1,42 @@
+package org.opentripplanner.model.transfer;
+
+import java.io.Serializable;
+import org.opentripplanner.model.Station;
+import org.opentripplanner.model.base.ValueObjectToStringBuilder;
+
+public final class StationTransferPoint implements TransferPoint, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Station station;
+
+
+ public StationTransferPoint(Station station) {
+ this.station = station;
+ }
+
+ public Station getStation() {
+ return station;
+ }
+
+ @Override
+ public boolean applyToAllTrips() {
+ return true;
+ }
+
+ @Override
+ public int getSpecificityRanking() {
+ return 0;
+ }
+
+ @Override
+ public boolean isStationTransferPoint() { return true; }
+
+ public String toString() {
+ return ValueObjectToStringBuilder.of()
+ .addText("")
+ .toString();
+ }
+}
diff --git a/src/main/java/org/opentripplanner/model/transfer/StopTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/StopTransferPoint.java
index 9a5e5bd30aa..b0d9217f620 100644
--- a/src/main/java/org/opentripplanner/model/transfer/StopTransferPoint.java
+++ b/src/main/java/org/opentripplanner/model/transfer/StopTransferPoint.java
@@ -1,7 +1,6 @@
package org.opentripplanner.model.transfer;
import java.io.Serializable;
-import java.util.Objects;
import org.opentripplanner.model.Stop;
public class StopTransferPoint implements TransferPoint, Serializable {
@@ -10,11 +9,11 @@ public class StopTransferPoint implements TransferPoint, Serializable {
private final Stop stop;
+
public StopTransferPoint(Stop stop) {
this.stop = stop;
}
- @Override
public Stop getStop() {
return stop;
}
@@ -26,24 +25,13 @@ public boolean applyToAllTrips() {
@Override
public int getSpecificityRanking() {
- return 0;
+ return 1;
}
@Override
+ public boolean isStopTransferPoint() { return true; }
+
public String toString() {
return "";
}
-
- @Override
- public boolean equals(Object o) {
- if (this == o) { return true; }
- if (!(o instanceof StopTransferPoint)) { return false; }
- final StopTransferPoint that = (StopTransferPoint) o;
- return Objects.equals(stop.getId(), that.stop.getId());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(stop.getId());
- }
}
diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferConstraint.java b/src/main/java/org/opentripplanner/model/transfer/TransferConstraint.java
index 6e0f276c51d..3f54dc5473e 100644
--- a/src/main/java/org/opentripplanner/model/transfer/TransferConstraint.java
+++ b/src/main/java/org/opentripplanner/model/transfer/TransferConstraint.java
@@ -110,12 +110,16 @@ public boolean isGuaranteed() {
* if the alight-slack or board-slack is too tight. We ignore slack for facilitated transfers.
*
* This is an aggregated field, which encapsulates an OTP specific rule. A facilitated transfer
- * is either stay-seated or guaranteed. High priority transfers are not.
+ * is either stay-seated or guaranteed. High priority transfers are not facilitated.
*/
public boolean isFacilitated() {
return staySeated || guaranteed;
}
+ public boolean useInRaptorRouting() {
+ return isStaySeated() || isGuaranteed() || isNotAllowed();
+ }
+
@Override
public boolean isNotAllowed() {
return priority == NOT_ALLOWED;
diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java
index ec20c5bd54b..656bbe7c927 100644
--- a/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java
+++ b/src/main/java/org/opentripplanner/model/transfer/TransferPoint.java
@@ -1,9 +1,11 @@
package org.opentripplanner.model.transfer;
+import javax.annotation.Nullable;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Trip;
-
/**
* This interface is used to represent a point or location where a transfer start from or end.
*
@@ -46,26 +48,19 @@ public interface TransferPoint {
int NOT_AVAILABLE = -1;
- default Stop getStop() {
- return null;
- }
+ /* *
+ * If this do not {@link #applyToAllTrips()} then this method can be used to return the
+ * trip for witch the {@link ConstrainedTransfer} apply to.
+ * /
+ @Nullable
default Trip getTrip() {
return null;
- }
+ }/*
/** Return {@code true} if this transfer point apply to all trips in pattern */
boolean applyToAllTrips();
- /**
- * If the given transfer point is a {@link TripTransferPoint}, this method return the stop
- * position in the trip pattern. If this transfer point is just a stop or a stop+route this
- * method return {@link #NOT_AVAILABLE}.
- */
- default int getStopPosition() {
- return NOT_AVAILABLE;
- }
-
/**
*
* Specificity of a transfer
@@ -73,8 +68,62 @@ default int getStopPosition() {
*/
int getSpecificityRanking();
- default boolean matches(Trip trip, int stopPos) {
- // Note! We use "==" here since there should not be duplicate instances of trips
- return getStopPosition() == stopPos && getTrip() == trip;
+ default boolean isTripTransferPoint() { return false; }
+
+ default TripTransferPoint asTripTransferPoint() { return (TripTransferPoint) this; }
+
+ default boolean isRouteTransferPoint() { return false; }
+
+ default RouteTransferPoint asRouteTransferPoint() { return (RouteTransferPoint) this; }
+
+ default boolean isStopTransferPoint() { return false; }
+
+ default StopTransferPoint asStopTransferPoint() { return (StopTransferPoint) this; }
+
+ default boolean isStationTransferPoint() { return false; }
+
+ default StationTransferPoint asStationTransferPoint() { return (StationTransferPoint) this; }
+
+
+ @Nullable
+ static Station getStation(TransferPoint point) {
+ if(point.isStationTransferPoint()) {
+ return point.asStationTransferPoint().getStation();
+ }
+ if(point.isStopTransferPoint()) {
+ return point.asStopTransferPoint().getStop().getParentStation();
+ }
+ return null;
+ }
+
+ @Nullable
+ static Stop getStop(TransferPoint point) {
+ return point.isStopTransferPoint() ? point.asStopTransferPoint().getStop() : null;
+ }
+
+ @Nullable
+ static Trip getTrip(TransferPoint point) {
+ return point.isTripTransferPoint() ? point.asTripTransferPoint().getTrip() : null;
+ }
+
+ @Nullable
+ static Route getRoute(TransferPoint point) {
+ if(point.isTripTransferPoint()) {
+ return point.asTripTransferPoint().getTrip().getRoute();
+ }
+ if(point.isRouteTransferPoint()) {
+ return point.asRouteTransferPoint().getRoute();
+ }
+ return null;
+ }
+
+ static int getStopPositionInPattern(TransferPoint point) {
+ if(point.isTripTransferPoint()) {
+ return point.asTripTransferPoint().getStopPositionInPattern();
+ }
+ if(point.isRouteTransferPoint()) {
+ return point.asRouteTransferPoint().getStopPositionInPattern();
+ }
+ return NOT_AVAILABLE;
}
}
diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java b/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java
new file mode 100644
index 00000000000..d2acb3ff4bb
--- /dev/null
+++ b/src/main/java/org/opentripplanner/model/transfer/TransferPointMap.java
@@ -0,0 +1,81 @@
+package org.opentripplanner.model.transfer;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.opentripplanner.common.model.T2;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Station;
+import org.opentripplanner.model.Stop;
+import org.opentripplanner.model.Trip;
+
+class TransferPointMap {
+ private final Map, E> tripMap = new HashMap<>();
+ private final Map, E> routeMap = new HashMap<>();
+ private final Map stopMap = new HashMap<>();
+ private final Map stationMap = new HashMap<>();
+
+ void put(TransferPoint point, E e) {
+ if(point.isTripTransferPoint()) {
+ 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.isStopTransferPoint()) {
+ stopMap.put(point.asStopTransferPoint().getStop(), e);
+ }
+ else if(point.isStationTransferPoint()) {
+ stationMap.put(point.asStationTransferPoint().getStation(), e);
+ }
+ else {
+ throw new IllegalArgumentException("Unknown TransferPoint type: " + point);
+ }
+ }
+
+ E computeIfAbsent(TransferPoint point, Supplier creator) {
+ if(point.isTripTransferPoint()) {
+ 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.isStopTransferPoint()) {
+ var sp = point.asStopTransferPoint();
+ return stopMap.computeIfAbsent(sp.getStop(), k -> creator.get());
+ }
+ else if(point.isStationTransferPoint()) {
+ var sp = point.asStationTransferPoint();
+ return stationMap.computeIfAbsent(sp.getStation(), k -> creator.get());
+ }
+ throw new IllegalArgumentException("Unknown TransferPoint type: " + point);
+ }
+
+
+ List get(Trip trip, Stop stop, int stopPointInPattern) {
+ return Stream.of(
+ tripMap.get(tripKey(trip, stopPointInPattern)),
+ routeMap.get(routeKey(trip.getRoute(), stopPointInPattern)),
+ stopMap.get(stop),
+ stationMap.get(stop.getParentStation())
+ )
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ 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);
+ }
+}
diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferService.java b/src/main/java/org/opentripplanner/model/transfer/TransferService.java
index b9ecc975d8f..26cccfb32c0 100644
--- a/src/main/java/org/opentripplanner/model/transfer/TransferService.java
+++ b/src/main/java/org/opentripplanner/model/transfer/TransferService.java
@@ -1,20 +1,14 @@
package org.opentripplanner.model.transfer;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
+import static java.util.Comparator.comparingInt;
+
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.annotation.Nullable;
-import org.opentripplanner.common.model.P2;
-import org.opentripplanner.common.model.T2;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.Trip;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* This class represents all transfer information in the graph. Transfers are grouped by
@@ -25,37 +19,19 @@
*/
public class TransferService implements Serializable {
- private static final Logger LOG = LoggerFactory.getLogger(TransferService.class);
-
- /** Index of constrained transfers with an effect on routing by the to/destination point. */
- private final Multimap constrainedTransferByToPoint;
-
- /**
- * Table which contains transfers between two trips/routes
- */
- private final Map, ConstrainedTransfer> trip2tripTransfers;
+ private final List transfersList;
/**
- * Table which contains transfers between a trip/route and a stops
+ * A map of map may seem a bit odd, but the first map have the FROM-transfer-point
+ * as its key, while the second map have the TO-transfer-point as its key. This allows us to
+ * support all combination of (Trip, Route, Stop and Station) in total 16 possible combination
+ * of keys to the ConstrainedTransfer.
*/
- private final Map, ConstrainedTransfer> trip2StopTransfers;
-
- /**
- * Table which contains transfers between a stop and a trip/route
- */
- private final Map, ConstrainedTransfer> stop2TripTransfers;
-
- /**
- * Table which contains transfers between two stops
- */
- private final Map, ConstrainedTransfer> stop2StopTransfers;
+ private final TransferPointMap> transfersMap;
public TransferService() {
- this.constrainedTransferByToPoint = ArrayListMultimap.create();
- this.trip2tripTransfers = new HashMap<>();
- this.trip2StopTransfers = new HashMap<>();
- this.stop2TripTransfers = new HashMap<>();
- this.stop2StopTransfers = new HashMap<>();
+ this.transfersList = new ArrayList<>();
+ this.transfersMap = new TransferPointMap<>();
}
public void addAll(Collection transfers) {
@@ -65,16 +41,7 @@ public void addAll(Collection transfers) {
}
public List listAll() {
- var list = new ArrayList();
- list.addAll(trip2tripTransfers.values());
- list.addAll(trip2StopTransfers.values());
- list.addAll(stop2TripTransfers.values());
- list.addAll(stop2StopTransfers.values());
- return list;
- }
-
- public Collection listConstrainedTransfersTo(Trip toTrip, int toStopIndex) {
- return constrainedTransferByToPoint.get(new TripTransferPoint(toTrip, toStopIndex));
+ return transfersList;
}
@Nullable
@@ -86,105 +53,20 @@ public ConstrainedTransfer findTransfer(
int fromStopPosition,
int toStopPosition
) {
- var fromTripKey = new TripTransferPoint(fromTrip, fromStopPosition);
- var toTripKey = new TripTransferPoint(toTrip, toStopPosition);
- ConstrainedTransfer result;
-
- // Check the highest specificity ranked transfers first (trip-2-trip)
- result = trip2tripTransfers.get(new P2<>(fromTripKey, toTripKey));
- if (result != null) { return result; }
-
- // Then check the next specificity ranked transfers (trip-2-stop and stop-2-trip)
- result = trip2StopTransfers.get(new T2<>(fromTripKey, toStop));
- if (result != null) { return result; }
-
- // Then check the next specificity ranked transfers (trip-2-stop and stop-2-trip)
- result = stop2TripTransfers.get(new T2<>(fromStop, toTripKey));
- if (result != null) { return result; }
-
- // If no specificity ranked transfers found return stop-2-stop transfers (lowest ranking)
- return stop2StopTransfers.get(new P2<>(fromStop, toStop));
- }
-
- void add(ConstrainedTransfer transfer) {
- TransferPoint from = transfer.getFrom();
- TransferPoint to = transfer.getTo();
-
- addFacilitatedTransfer(transfer);
-
- if (from instanceof TripTransferPoint) {
- var fromTrip = (TripTransferPoint) from;
- if (to instanceof TripTransferPoint) {
- var key = new P2<>(fromTrip, (TripTransferPoint) to);
- if (doAddTransferBasedOnSpecificityRanking(transfer, trip2tripTransfers.get(key))) {
- trip2tripTransfers.put(key, transfer);
- }
- }
- else {
- var key = new T2<>(fromTrip, to.getStop());
- if (doAddTransferBasedOnSpecificityRanking(transfer, trip2StopTransfers.get(key))) {
- trip2StopTransfers.put(key, transfer);
- }
- }
- }
- else if (to instanceof TripTransferPoint) {
- var key = new T2<>(from.getStop(), (TripTransferPoint) to);
- if (doAddTransferBasedOnSpecificityRanking(transfer, stop2TripTransfers.get(key))) {
- stop2TripTransfers.put(key, transfer);
- }
- }
- else {
- var key = new P2<>(from.getStop(), to.getStop());
- if (doAddTransferBasedOnSpecificityRanking(transfer, stop2StopTransfers.get(key))) {
- stop2StopTransfers.put(key, transfer);
- }
- }
- }
-
- /**
- * A transfer goes from/to a stop, route* or trip. Route transfers are expanded to all trips
- * using the special {@link RouteTransferPoint} subtype of {@link TripTransferPoint}. This
- * expansion make sure that there can only be one match for each combination of from and to
- * combination (from -> to):
- *
- * - trip -> trip
- *
- trip -> stop
- *
- stop -> trip
- *
- stop -> stop
- *
- * For each pair of the above combination we can drop the transfers that have a the lowest
- * specificity-ranking, thus using maps instead of multi-maps.
- */
- private boolean doAddTransferBasedOnSpecificityRanking(
- ConstrainedTransfer newTransfer,
- ConstrainedTransfer existingTransfer
- ) {
- if (existingTransfer == null) { return true; }
-
- if (existingTransfer.getSpecificityRanking() < newTransfer.getSpecificityRanking()) {
- return true;
- }
- if (existingTransfer.getSpecificityRanking() > newTransfer.getSpecificityRanking()) {
- return false;
- }
- if (existingTransfer.equals(newTransfer)) {
- return false;
- }
- LOG.warn(
- "Two colliding transfers A and B with the same specificity-ranking is imported, B is "
- + "dropped. A={}, B={}", existingTransfer, newTransfer
- );
- return false;
+ 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);
}
- private void addFacilitatedTransfer(ConstrainedTransfer transfer) {
- var c = transfer.getTransferConstraint();
- var toPoint = transfer.getTo();
+ private void add(ConstrainedTransfer transfer) {
+ var from = transfer.getFrom();
+ var to = transfer.getTo();
- if(c.isFacilitated()) {
- if(toPoint instanceof TripTransferPoint) {
- constrainedTransferByToPoint.put((TripTransferPoint) toPoint, transfer);
- }
- }
+ transfersMap.computeIfAbsent(from, TransferPointMap::new).put(to, transfer);
+ transfersList.add(transfer);
}
}
diff --git a/src/main/java/org/opentripplanner/model/transfer/TransferType.java b/src/main/java/org/opentripplanner/model/transfer/TransferType.java
deleted file mode 100644
index af62c5ac0e3..00000000000
--- a/src/main/java/org/opentripplanner/model/transfer/TransferType.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.opentripplanner.model.transfer;
-
-public enum TransferType {
- /**
- * This transfer is recommended over other transfers. The routing algorithm should prefer
- * this transfer compared to other transfers, for example by assigning a lower weight to it.
- */
- RECOMMENDED(0),
- /**
- * This means the departing vehicle will wait for the arriving one and leave sufficient time
- * for a rider to transfer between routes.
- */
- GUARANTEED(1),
- /**
- * This is a regular transfer that is defined in the transit data (as opposed to
- * OpenStreetMap data). In the case that both are present, this should take precedence.
- * Because the the duration of the transfer is given and not the distance, walk speed will
- * have no effect on this.
- */
- MIN_TIME(2),
- /**
- * Transfers between these stops (and route/trip) is not possible (or not allowed), even if
- * a transfer is already defined via OpenStreetMap data or in transit data.
- */
- FORBIDDEN(3);
-
- TransferType(int gtfsCode) {
- this.gtfsCode = gtfsCode;
- }
-
- public final int gtfsCode;
-
- public static TransferType valueOfGtfsCode(int gtfsCode) {
- for (TransferType value : values()) {
- if (value.gtfsCode == gtfsCode) {
- return value;
- }
- }
- throw new IllegalArgumentException("Unknown GTFS TransferType: " + gtfsCode);
- }
-}
diff --git a/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java b/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java
index 12bde682375..8df22d712a6 100644
--- a/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java
+++ b/src/main/java/org/opentripplanner/model/transfer/TripTransferPoint.java
@@ -1,30 +1,28 @@
package org.opentripplanner.model.transfer;
import java.io.Serializable;
-import java.util.Objects;
import org.opentripplanner.model.Trip;
+import org.opentripplanner.model.base.ValueObjectToStringBuilder;
-public class TripTransferPoint implements TransferPoint, Serializable {
+public final class TripTransferPoint implements TransferPoint, Serializable {
private static final long serialVersionUID = 1L;
private final Trip trip;
- private final int stopPosition;
+ private final int stopPositionInPattern;
- public TripTransferPoint(Trip trip, int stopPosition) {
+ public TripTransferPoint(Trip trip, int stopPositionInPattern) {
this.trip = trip;
- this.stopPosition = stopPosition;
+ this.stopPositionInPattern = stopPositionInPattern;
}
- @Override
- public final Trip getTrip() {
+ public Trip getTrip() {
return trip;
}
- @Override
- public final int getStopPosition() {
- return stopPosition;
+ public int getStopPositionInPattern() {
+ return stopPositionInPattern;
}
@Override
@@ -32,36 +30,20 @@ public boolean applyToAllTrips() {
return false;
}
- /**
- *
- * GTFS Specificity of a transfer
- *
- * {@link #equals(Object)}
- */
@Override
- public int getSpecificityRanking() { return 2; }
+ public int getSpecificityRanking() { return 3; }
@Override
- public String toString() {
- return "";
- }
+ public boolean isTripTransferPoint() { return true; }
- /**
- * This equals is intentionally final and enforce equality based on the *trip* and
- * *stop-position*. Any sub-type is equal if the trip and stop-position match, the type is not
- * used. This allow us to create sub-types and override the {@link #getSpecificityRanking()}.
- */
@Override
- public final boolean equals(Object o) {
- if (this == o) { return true; }
- if (!(o instanceof TripTransferPoint)) { return false; }
-
- TripTransferPoint that = (TripTransferPoint) o;
- return stopPosition == that.stopPosition && trip.getId().equals(that.trip.getId());
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(trip.getId(), stopPosition);
+ public String toString() {
+ return ValueObjectToStringBuilder.of()
+ .addText("")
+ .toString();
}
}
diff --git a/src/main/java/org/opentripplanner/netex/mapping/StationMapper.java b/src/main/java/org/opentripplanner/netex/mapping/StationMapper.java
index 1eeaf424238..90400c80932 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/StationMapper.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/StationMapper.java
@@ -26,7 +26,7 @@ Station map(StopPlace stopPlace) {
stopPlace.getDescription() != null ? stopPlace.getDescription().getValue() : null,
null,
null,
- TransferPriorityMapper.mapToDomain(stopPlace.getWeighting())
+ StopTransferPriorityMapper.mapToDomain(stopPlace.getWeighting())
);
if (station.getCoordinate() == null) {
diff --git a/src/main/java/org/opentripplanner/netex/mapping/TransferPriorityMapper.java b/src/main/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapper.java
similarity index 95%
rename from src/main/java/org/opentripplanner/netex/mapping/TransferPriorityMapper.java
rename to src/main/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapper.java
index 4a4c22af136..53a0e22b50e 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/TransferPriorityMapper.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapper.java
@@ -4,7 +4,7 @@
import org.opentripplanner.model.StopTransferPriority;
import org.rutebanken.netex.model.InterchangeWeightingEnumeration;
-class TransferPriorityMapper {
+class StopTransferPriorityMapper {
@Nullable
static StopTransferPriority mapToDomain(InterchangeWeightingEnumeration value) {
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/FlexAccessEgressAdapter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/FlexAccessEgressAdapter.java
index ce8c7f1b4af..a4296a54f5a 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/FlexAccessEgressAdapter.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/FlexAccessEgressAdapter.java
@@ -12,7 +12,7 @@ public FlexAccessEgressAdapter(
FlexAccessEgress flexAccessEgress, boolean isEgress, StopIndexForRaptor stopIndex
) {
super(
- stopIndex.indexByStop.get(flexAccessEgress.stop),
+ stopIndex.indexOf(flexAccessEgress.stop),
isEgress ? flexAccessEgress.lastState.reverse() : flexAccessEgress.lastState
);
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 b7c4c25fcae..35313455dbf 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
@@ -1,6 +1,5 @@
package org.opentripplanner.routing.algorithm.raptor.transit;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -26,24 +25,27 @@
* The scope of instances of this class is limited to the mapping process, the final state is
* stored in the {@link TransitLayer}.
*/
-public class StopIndexForRaptor {
- public final List stopsByIndex;
- public final Map indexByStop = new HashMap<>();
+public final class StopIndexForRaptor {
+ private final List stopsByIndex;
+ private final Map indexByStop = new HashMap<>();
public final int[] stopBoardAlightCosts;
public StopIndexForRaptor(Collection stops, TransitTuningParameters tuningParameters) {
- this.stopsByIndex = new ArrayList<>(stops);
+ this.stopsByIndex = List.copyOf(stops);
initializeIndexByStop();
this.stopBoardAlightCosts = createStopBoardAlightCosts(stopsByIndex, tuningParameters);
}
- /**
- * Create map between stop and index used by Raptor to stop objects in original graph
- */
- void initializeIndexByStop() {
- for(int i = 0; i< stopsByIndex.size(); ++i) {
- indexByStop.put(stopsByIndex.get(i), i);
- }
+ public Stop stopByIndex(int index) {
+ return stopsByIndex.get(index);
+ }
+
+ public int indexOf(Stop stop) {
+ return indexByStop.get(stop);
+ }
+
+ public int size() {
+ return stopsByIndex.size();
}
/**
@@ -58,6 +60,15 @@ public int[] listStopIndexesForStops(Stop[] stops) {
return stopIndex;
}
+ /**
+ * Create map between stop and index used by Raptor to stop objects in original graph
+ */
+ private void initializeIndexByStop() {
+ for(int i = 0; i< stopsByIndex.size(); ++i) {
+ indexByStop.put(stopsByIndex.get(i), i);
+ }
+ }
+
/**
* Create static board/alight cost for Raptor to include for each stop.
*/
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TransitLayer.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TransitLayer.java
index 69e3f4436cf..74cfa35ab41 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TransitLayer.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TransitLayer.java
@@ -75,12 +75,12 @@ public TransitLayer(
}
public int getIndexByStop(Stop stop) {
- return stopIndex.indexByStop.get(stop);
+ return stopIndex.indexOf(stop);
}
@Nullable
public Stop getStopByIndex(int stop) {
- return stop != -1 ? this.stopIndex.stopsByIndex.get(stop) : null;
+ return stop == -1 ? null : this.stopIndex.stopByIndex(stop);
}
public StopIndexForRaptor getStopIndex() {
@@ -103,7 +103,7 @@ public ZoneId getTransitDataZoneId() {
}
public int getStopCount() {
- return stopIndex.stopsByIndex.size();
+ return stopIndex.size();
}
@Nullable
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TripPatternWithRaptorStopIndexes.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TripPatternWithRaptorStopIndexes.java
index af812371686..4f2d2b3366e 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TripPatternWithRaptorStopIndexes.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TripPatternWithRaptorStopIndexes.java
@@ -1,47 +1,44 @@
package org.opentripplanner.routing.algorithm.raptor.transit;
-import gnu.trove.map.TIntObjectMap;
-import gnu.trove.map.hash.TIntObjectHashMap;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.TransitMode;
import org.opentripplanner.model.TripPattern;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
-import org.opentripplanner.routing.algorithm.raptor.transit.request.ConstrainedBoardingSearch;
+import org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer.ConstrainedBoardingSearch;
+import org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer.TransferForPattern;
+import org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer.TransferForPatternByStopPos;
import org.opentripplanner.transit.raptor.api.transit.RaptorConstrainedTripScheduleBoardingSearch;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripPattern;
public class TripPatternWithRaptorStopIndexes {
- private final TripPattern pattern;
+ private final TripPattern pattern;
private final int[] stopIndexes;
/**
- * List of transfers TO this pattern for each stop position in pattern used by Raptor during
- * the FORWARD search.
+ * List of transfers TO this pattern for each stop position in pattern used by Raptor during the
+ * FORWARD search.
*/
- private final TIntObjectMap> constrainedTransfersForwardSearch =
- new TIntObjectHashMap<>();
+ private final TransferForPatternByStopPos
+ constrainedTransfersForwardSearch = new TransferForPatternByStopPos();
/**
* List of transfers FROM this pattern for each stop position in pattern used by Raptor during
* the REVERSE search.
*/
- private final TIntObjectMap> constrainedTransfersReverseSearch =
- new TIntObjectHashMap<>();
+ private final TransferForPatternByStopPos
+ constrainedTransfersReverseSearch = new TransferForPatternByStopPos();
public TripPatternWithRaptorStopIndexes(
- int[] stopIndexes,
- TripPattern pattern
+ TripPattern pattern,
+ int[] stopIndexes
) {
- this.stopIndexes = stopIndexes;
this.pattern = pattern;
+ this.stopIndexes = stopIndexes;
}
- public FeedScopedId getId() { return pattern.getId(); }
+ public FeedScopedId getId() {return pattern.getId();}
public TransitMode getTransitMode() {
return pattern.getMode();
@@ -70,20 +67,19 @@ public RaptorConstrainedTripScheduleBoardingSearch constrainedTran
return new ConstrainedBoardingSearch(false, constrainedTransfersReverseSearch);
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(getId());
+ }
@Override
public boolean equals(Object o) {
- if (this == o) { return true; }
- if (o == null || getClass() != o.getClass()) { return false; }
+ if (this == o) {return true;}
+ if (o == null || getClass() != o.getClass()) {return false;}
TripPatternWithRaptorStopIndexes that = (TripPatternWithRaptorStopIndexes) o;
return getId() == that.getId();
}
- @Override
- public int hashCode() {
- return Objects.hash(getId());
- }
-
@Override
public String toString() {
return "TripPattern{" +
@@ -92,26 +88,32 @@ public String toString() {
'}';
}
- /** This is public to allow the mappers to inject transfers */
- public void addTransferConstraintsForwardSearch(ConstrainedTransfer tx) {
- // In the Raptor search the transfer is looked up using the target
- // trip, the trip boarded after the transfer is done for a forward search.
- add(constrainedTransfersForwardSearch, tx, tx.getTo().getStopPosition());
+ /**
+ * This is public to allow the mappers to inject transfers
+ */
+ public void addTransferConstraintsForwardSearch(
+ int targetStopPosition,
+ TransferForPattern transferForPattern
+ ) {
+ constrainedTransfersForwardSearch.add(targetStopPosition, transferForPattern);
}
- /** This is public to allow the mappers to inject transfers */
- public void addTransferConstraintsReverseSearch(ConstrainedTransfer tx) {
- // In the Raptor search the transfer is looked up using the target
- // trip. Thus, the transfer "from trip" should be used in a reverse search.
- add(constrainedTransfersReverseSearch, tx, tx.getFrom().getStopPosition());
+ /**
+ * This is public to allow the mappers to inject transfers
+ */
+ public void addTransferConstraintsReverseSearch(
+ int targetStopPosition,
+ TransferForPattern transferForPattern
+ ) {
+ constrainedTransfersReverseSearch.add(targetStopPosition, transferForPattern);
}
- private static void add(TIntObjectMap> index, T e, int pos) {
- var list = index.get(pos);
- if(list == null) {
- list = new ArrayList<>();
- index.put(pos, list);
- }
- list.add(e);
+ /**
+ * This method should be called AFTER all transfers are added, and before the
+ * pattern is used in a Raptor search.
+ */
+ public void sortConstrainedTransfers() {
+ constrainedTransfersForwardSearch.sortOnSpecificityRanking();
+ constrainedTransfersReverseSearch.sortOnSpecificityRanking();
}
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearch.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearch.java
similarity index 53%
rename from src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearch.java
rename to src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearch.java
index 9c9d5b7527b..a51a8ed358a 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearch.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearch.java
@@ -1,15 +1,14 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
-import gnu.trove.map.TIntObjectMap;
-import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
+import org.opentripplanner.common.model.T2;
import org.opentripplanner.model.Trip;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.model.transfer.TransferConstraint;
import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
import org.opentripplanner.transit.raptor.api.transit.RaptorConstrainedTripScheduleBoardingSearch;
import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTransferConstraint;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripScheduleBoardOrAlightEvent;
@@ -26,22 +25,23 @@ public final class ConstrainedBoardingSearch
private static final ConstrainedBoardingSearchStrategy FORWARD_STRATEGY = new ConstrainedBoardingSearchForward();
private static final ConstrainedBoardingSearchStrategy REVERSE_STRATEGY = new ConstrainedBoardingSearchReverse();
+ /** Handle forward and reverse specific tasks */
private final ConstrainedBoardingSearchStrategy translator;
/**
* List of transfers for each stop position in pattern
*/
- private final TIntObjectMap> transfers;
+ private final TransferForPatternByStopPos transfers;
- private List currentTransfers;
+ private List currentTransfers;
private int currentTargetStopPos;
public ConstrainedBoardingSearch(
boolean forwardSearch,
- TIntObjectMap> transfers
+ TransferForPatternByStopPos transfers
) {
- this.translator = forwardSearch ? FORWARD_STRATEGY : REVERSE_STRATEGY;
this.transfers = transfers;
+ this.translator = forwardSearch ? FORWARD_STRATEGY : REVERSE_STRATEGY;
}
@Override
@@ -61,18 +61,13 @@ public RaptorTripScheduleBoardOrAlightEvent find(
int sourceStopIndex,
int sourceArrivalTime
) {
- final Trip sourceTrip = sourceTripSchedule.getOriginalTripTimes().getTrip();
- final int sourceStopPos = translator.findSourceStopPosition(
- sourceTripSchedule, sourceArrivalTime, sourceStopIndex
- );
+ var transfers = findMatchingTransfers(sourceTripSchedule, sourceStopIndex);
- var list = findMatchingTransfers(sourceTrip, sourceStopPos);
+ if(transfers.isEmpty()) { return null; }
- if(list.isEmpty()) { return null; }
-
- var tripInfo = translator.findTimetableTripInfo(
+ T2 tripInfo = findTimetableTripInfo(
timetable,
- list,
+ transfers,
currentTargetStopPos,
sourceArrivalTime
);
@@ -80,7 +75,7 @@ public RaptorTripScheduleBoardOrAlightEvent find(
if(tripInfo == null) { return null; }
final int tripIndex = tripInfo.first;
- final TransferConstraint transferConstraint = tripInfo.second;
+ final var transferConstraint = tripInfo.second;
var trip = timetable.getTripSchedule(tripIndex);
int departureTime = translator.time(trip, currentTargetStopPos);
@@ -90,12 +85,56 @@ public RaptorTripScheduleBoardOrAlightEvent find(
);
}
- private Collection findMatchingTransfers(
- Trip sourceTrip,
- int sourceStopPos
+ private List findMatchingTransfers(
+ TripSchedule tripSchedule,
+ int stopIndex
) {
+ final Trip trip = tripSchedule.getOriginalTripTimes().getTrip();
return currentTransfers.stream()
- .filter(tx -> translator.source(tx).matches(sourceTrip, sourceStopPos))
+ .filter(t -> t.matchesSourcePoint(stopIndex, trip))
.collect(Collectors.toList());
}
+
+ /**
+ * Find the trip to board (trip index) and the transfer constraint
+ */
+ public T2 findTimetableTripInfo(
+ RaptorTimeTable timetable,
+ List transfers,
+ int stopPos,
+ int sourceTime
+ ) {
+ // Abort after 6 hours
+ boolean useNextNormalTrip = false;
+
+ var index = translator.scheduleIndexIterator(timetable);
+ outer:
+ while (index.hasNext()) {
+ final int i = index.next();
+ var it = timetable.getTripSchedule(i);
+ int time = translator.time(it, stopPos);
+ if (translator.timeIsBefore(time, sourceTime)) { continue; }
+
+ var targetTrip = it.getOriginalTripTimes().getTrip();
+
+ for (TransferForPattern tx : transfers) {
+ if (tx.applyToAllTargetTrips()) {
+ return new T2<>(i, tx.getTransferConstraint());
+ }
+ else if (tx.applyToTargetTrip(targetTrip)) {
+ if (tx.getTransferConstraint().isNotAllowed()) {
+ useNextNormalTrip = true;
+ continue outer;
+ }
+ else {
+ return new T2<>(i, tx.getTransferConstraint());
+ }
+ }
+ }
+ if (useNextNormalTrip) {
+ return new T2<>(i, TransferConstraint.REGULAR_TRANSFER);
+ }
+ }
+ return null;
+ }
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchForward.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchForward.java
new file mode 100644
index 00000000000..9493baec4b4
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchForward.java
@@ -0,0 +1,27 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
+import org.opentripplanner.transit.raptor.api.transit.IntIterator;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
+import org.opentripplanner.transit.raptor.util.IntIterators;
+
+class ConstrainedBoardingSearchForward
+ implements ConstrainedBoardingSearchStrategy {
+
+ @Override
+ public int time(RaptorTripSchedule schedule, int stopPos) {
+ return schedule.departure(stopPos);
+ }
+
+ @Override
+ public boolean timeIsBefore(int time0, int time1) {
+ return time0 < time1;
+ }
+
+ @Override
+ public IntIterator scheduleIndexIterator(RaptorTimeTable timetable) {
+ return IntIterators.intIncIterator(0, timetable.numberOfTripSchedules());
+ }
+}
+
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchReverse.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchReverse.java
new file mode 100644
index 00000000000..274977c9b6e
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchReverse.java
@@ -0,0 +1,26 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
+import org.opentripplanner.transit.raptor.api.transit.IntIterator;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
+import org.opentripplanner.transit.raptor.util.IntIterators;
+
+class ConstrainedBoardingSearchReverse implements ConstrainedBoardingSearchStrategy {
+
+ @Override
+ public int time(RaptorTripSchedule schedule, int stopPos) {
+ return schedule.arrival(stopPos);
+ }
+
+ @Override
+ public boolean timeIsBefore(int time0, int time1) {
+ return time0 > time1;
+ }
+
+ @Override
+ public IntIterator scheduleIndexIterator(RaptorTimeTable timetable) {
+ return IntIterators.intDecIterator(timetable.numberOfTripSchedules(), 0);
+ }
+
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchStrategy.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchStrategy.java
new file mode 100644
index 00000000000..2f81bf1dc93
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchStrategy.java
@@ -0,0 +1,17 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
+import org.opentripplanner.transit.raptor.api.transit.IntIterator;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
+
+interface ConstrainedBoardingSearchStrategy {
+
+ int time(RaptorTripSchedule schedule, int stopPos);
+
+ boolean timeIsBefore(int time0, int time1);
+
+ //int findSourceStopPosition(RaptorTripSchedule schedule, int timeLimit, int stop);
+
+ IntIterator scheduleIndexIterator(RaptorTimeTable timetable);
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedTransferBoarding.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedTransferBoarding.java
similarity index 72%
rename from src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedTransferBoarding.java
rename to src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedTransferBoarding.java
index a205e30242f..6022b37cf65 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedTransferBoarding.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedTransferBoarding.java
@@ -1,22 +1,24 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
import javax.validation.constraints.NotNull;
-import org.opentripplanner.model.transfer.TransferConstraint;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTransferConstraint;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
import org.opentripplanner.transit.raptor.api.transit.RaptorTripScheduleBoardOrAlightEvent;
-
+/**
+ * A boarding event passed to Raptor to perform a boarding.
+ */
public class ConstrainedTransferBoarding
implements RaptorTripScheduleBoardOrAlightEvent {
- private final TransferConstraint constraint;
+ private final RaptorTransferConstraint constraint;
private final int tripIndex;
private final T trip;
private final int stopPositionInPattern;
private final int time;
ConstrainedTransferBoarding(
- @NotNull TransferConstraint constraint,
+ @NotNull RaptorTransferConstraint constraint,
int tripIndex,
@NotNull T trip,
int stopPositionInPattern,
@@ -44,7 +46,5 @@ public class ConstrainedTransferBoarding
@Override
@NotNull
- public TransferConstraint getTransferConstraint() {
- return constraint;
- }
+ public RaptorTransferConstraint getTransferConstraint() { return constraint; }
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPattern.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPattern.java
new file mode 100644
index 00000000000..25211761020
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPattern.java
@@ -0,0 +1,70 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import javax.annotation.Nullable;
+import org.opentripplanner.model.Trip;
+import org.opentripplanner.transit.raptor.api.transit.RaptorTransferConstraint;
+
+
+/**
+ *
+ */
+public class TransferForPattern implements Comparable {
+
+ /**
+ * Used to filter transfers based on the source-stop-arrival.
+ */
+ private final TransferPointForPattern sourcePoint;
+
+ /**
+ * If {@code null} the constraint apply to all trips
+ */
+ @Nullable
+ private final Trip targetTrip;
+ private final RaptorTransferConstraint transferConstraint;
+ private final int specificityRanking;
+
+ TransferForPattern(
+ TransferPointForPattern sourcePoint,
+ @Nullable Trip targetTrip,
+ int specificityRanking,
+ RaptorTransferConstraint transferConstraint
+ ) {
+ this.sourcePoint = sourcePoint;
+ this.targetTrip = targetTrip;
+ this.specificityRanking = specificityRanking;
+ this.transferConstraint = transferConstraint;
+ }
+
+ public RaptorTransferConstraint getTransferConstraint() {
+ return transferConstraint;
+ }
+
+ public boolean matchesSourcePoint(int stopIndex, Trip trip) {
+ return sourcePoint.match(stopIndex, trip);
+ }
+
+ /**
+ * A transfer either apply to all target-trips (station-, stop- and route-transfer-points) or
+ * to a specific trip (trip-transfer-point).
+ */
+ public boolean applyToAllTargetTrips() {
+ return targetTrip == null;
+ }
+
+ /**
+ * return {@code true} if this transfer apply to the specified trip, and only that trip.
+ * @see #applyToAllTargetTrips()
+ */
+ public boolean applyToTargetTrip(Trip targetTrip) {
+ return this.targetTrip == targetTrip;
+ }
+
+ /**
+ * Transfers should be sorted after the specificityRanking, this make sure the
+ * transfer with the highest ranking is used by raptor.
+ */
+ @Override
+ public int compareTo(TransferForPattern o) {
+ return o.specificityRanking - specificityRanking;
+ }
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPatternByStopPos.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPatternByStopPos.java
new file mode 100644
index 00000000000..e83c46f01c4
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferForPatternByStopPos.java
@@ -0,0 +1,34 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+
+import gnu.trove.map.TIntObjectMap;
+import gnu.trove.map.hash.TIntObjectHashMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class TransferForPatternByStopPos {
+
+ private final TIntObjectMap> transfers = new TIntObjectHashMap<>();
+
+
+ /**
+ * Sort in decreasing specificityRanking order
+ */
+ public void sortOnSpecificityRanking() {
+ transfers.forEachValue(it -> { Collections.sort(it); return true; });
+ }
+
+ public void add(int targetStopPos, TransferForPattern transfer) {
+ var c = transfers.get(targetStopPos);
+ if(c == null) {
+ c = new ArrayList<>();
+ transfers.put(targetStopPos, c);
+ }
+ c.add(transfer);
+ }
+
+ public List get(int targetStopPos) {
+ return transfers.get(targetStopPos);
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 00000000000..c19df86c8ab
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferIndexGenerator.java
@@ -0,0 +1,229 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import static org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer.TransferPointForPatternFactory.createTransferPointForPattern;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Station;
+import org.opentripplanner.model.Stop;
+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.StationTransferPoint;
+import org.opentripplanner.model.transfer.StopTransferPoint;
+import org.opentripplanner.model.transfer.TransferPoint;
+import org.opentripplanner.model.transfer.TripTransferPoint;
+import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
+import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
+
+public class TransferIndexGenerator {
+
+ private final Collection constrainedTransfers;
+ private final Map> patternsByStation = new HashMap<>();
+ private final Map> patternsByStop = new HashMap<>();
+ private final Map> patternsByRoute = new HashMap<>();
+ private final Map> patternsByTrip = new HashMap<>();
+ private final StopIndexForRaptor stopIndex;
+
+ public TransferIndexGenerator(
+ Collection constrainedTransfers,
+ Collection tripPatterns,
+ StopIndexForRaptor stopIndex
+ ) {
+ this.constrainedTransfers = constrainedTransfers;
+ this.stopIndex = stopIndex;
+ setupPatternByTripIndex(tripPatterns);
+ }
+
+ public void generateTransfers() {
+ for (ConstrainedTransfer tx : constrainedTransfers) {
+ var c = tx.getTransferConstraint();
+ // Only add transfers witch have an effect on the Raptor routing here.
+ // Some transfers only have the priority set, and that is used in optimized-
+ // 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);
+ }
+ }
+ }
+ }
+ }
+ sortAllTransfersByRanking();
+ }
+
+ private void sortAllTransfersByRanking() {
+ for (var patterns : patternsByRoute.values()) {
+ for (var pattern : patterns) {
+ pattern.sortConstrainedTransfers();
+ }
+ }
+ }
+
+ private void setupPatternByTripIndex(Collection tripPatterns) {
+ for (TripPatternWithRaptorStopIndexes pattern : tripPatterns) {
+ TripPattern tripPattern = pattern.getPattern();
+
+ patternsByRoute
+ .computeIfAbsent(tripPattern.getRoute(), t -> new ArrayList<>())
+ .add(pattern);
+
+ for (Trip trip : tripPattern.getTrips()) {
+ patternsByTrip.computeIfAbsent(trip, t -> new ArrayList<>()).add(pattern);
+ }
+
+ for (Stop stop : tripPattern.getStops()) {
+ patternsByStop.computeIfAbsent(stop, t -> new ArrayList<>()).add(pattern);
+ Station station = stop.getParentStation();
+ if (station != null) {
+ patternsByStation.computeIfAbsent(station, t -> new ArrayList<>()).add(pattern);
+ }
+ }
+ }
+ }
+
+ private Collection findTPoints(TransferPoint txPoint) {
+ if (txPoint.isStationTransferPoint()) {
+ return findTPoints(txPoint.asStationTransferPoint());
+ }
+ else if (txPoint.isStopTransferPoint()) {
+ return findTPoints(txPoint.asStopTransferPoint());
+ }
+ else if (txPoint.isRouteTransferPoint()) {
+ return findTPoint(txPoint.asRouteTransferPoint());
+ }
+ else {
+ return findTPoints(txPoint.asTripTransferPoint());
+ }
+ }
+
+ private List findTPoints(StationTransferPoint point) {
+ var station = point.getStation();
+ var patterns = patternsByStation.get(station);
+ var sourcePoint = createTransferPointForPattern(station, stopIndex);
+ var result = new ArrayList();
+
+ for (TripPatternWithRaptorStopIndexes pattern : patterns) {
+ Stop[] stops = pattern.getPattern().getStopPattern().getStops();
+ for (int pos = 0; pos < stops.length; ++pos) {
+ if (point.getStation() == stops[pos].getParentStation()) {
+ result.add(new TPoint(pattern, sourcePoint, null, pos));
+ }
+ }
+ }
+ return result;
+ }
+
+ private List findTPoints(StopTransferPoint point) {
+ var stop = point.asStopTransferPoint().getStop();
+ var patterns = patternsByStop.get(stop);
+ var sourcePoint = createTransferPointForPattern(stopIndex.indexOf(stop));
+
+ var result = new ArrayList();
+ for (TripPatternWithRaptorStopIndexes pattern : patterns) {
+ Stop[] stops = pattern.getPattern().getStopPattern().getStops();
+ for (int pos = 0; pos < stops.length; ++pos) {
+ if (point.getStop() == stops[pos]) {
+ result.add(new TPoint(pattern, sourcePoint, null, pos));
+ }
+ }
+ }
+ return result;
+ }
+
+ private List findTPoint(RouteTransferPoint point) {
+ var route = point.getRoute();
+ 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());
+ }
+
+ private List findTPoints(TripTransferPoint point) {
+ var trip = point.getTrip();
+ var patterns = patternsByTrip.get(trip);
+ int stopPosInPattern = point.getStopPositionInPattern();
+ int stopIndex = patterns.get(0).stopIndex(stopPosInPattern);
+ var sourcePoint = createTransferPointForPattern(trip, stopIndex);
+ return patterns.stream()
+ .map(p -> new TPoint(p, sourcePoint, trip, stopPosInPattern))
+ .collect(Collectors.toList());
+ }
+
+ private static class TPoint {
+ TripPatternWithRaptorStopIndexes pattern;
+ TransferPointForPattern sourcePoint;
+ Trip trip;
+ int stopPosition;
+
+ private TPoint(
+ TripPatternWithRaptorStopIndexes pattern,
+ TransferPointForPattern sourcePoint,
+ Trip trip,
+ int stopPosition
+ ) {
+ this.pattern = pattern;
+ this.sourcePoint = sourcePoint;
+ this.trip = trip;
+ this.stopPosition = stopPosition;
+ }
+
+ boolean canBoard() {
+ // We prevent boarding at the last stop, this might be enforced by the
+ // canBoard method, but we do not trust it here.
+ int lastStopPosition = pattern.getPattern().getStopPattern().getSize() - 1;
+ return stopPosition != lastStopPosition && pattern.getPattern().canBoard(stopPosition);
+ }
+
+ boolean canAlight() {
+ // We prevent alighting at the first stop, this might be enforced by the
+ // canAlight method, but we do not trust it here.
+ return stopPosition != 0 && pattern.getPattern().canAlight(stopPosition);
+ }
+
+ void addTransferConstraints(ConstrainedTransfer tx, TPoint to) {
+ int rank = tx.getSpecificityRanking();
+ var c = tx.getTransferConstraint();
+
+ // Forward search
+ to.pattern.addTransferConstraintsForwardSearch(
+ to.stopPosition,
+ new TransferForPattern(sourcePoint, to.trip, rank, c)
+ );
+ // Reverse search
+ pattern.addTransferConstraintsReverseSearch(
+ stopPosition,
+ new TransferForPattern(to.sourcePoint, trip, rank, c)
+ );
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {return true;}
+ if (!(o instanceof TPoint)) {return false;}
+ final TPoint tPoint = (TPoint) o;
+ return stopPosition == tPoint.stopPosition
+ && Objects.equals(pattern, tPoint.pattern)
+ && Objects.equals(trip, tPoint.trip);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(pattern, trip, stopPosition);
+ }
+ }
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPattern.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPattern.java
new file mode 100644
index 00000000000..d9882a0a81d
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPattern.java
@@ -0,0 +1,8 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import org.opentripplanner.model.Trip;
+
+interface TransferPointForPattern {
+
+ boolean match(int stopIndex, Trip trip);
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPatternFactory.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPatternFactory.java
new file mode 100644
index 00000000000..4365e214aa7
--- /dev/null
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/TransferPointForPatternFactory.java
@@ -0,0 +1,105 @@
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
+
+import java.util.function.IntFunction;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Station;
+import org.opentripplanner.model.Stop;
+import org.opentripplanner.model.Trip;
+import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
+
+
+/**
+ * This class generate TransferPoints adapted to Raptor. The internal model
+ * {@link org.opentripplanner.model.transfer.TransferPoint} can not be used by Raptor as is, so
+ * we transform them into {@link TransferPointForPattern}. For example to speed ut the search in
+ * Raptor we avoid fetching Stops from memory and instead uses a {@code stopIndex}. This index is
+ * not necessarily fixed, but generated for the
+ * {@link org.opentripplanner.routing.algorithm.raptor.transit.TransitLayer}, so we need to
+ * generate
+ */
+
+
+final class TransferPointForPatternFactory {
+
+ /** private constructor to prevent utility class from instantiation */
+ private TransferPointForPatternFactory() { /* empty */ }
+
+ static TransferPointForPattern createTransferPointForPattern(
+ Station station,
+ StopIndexForRaptor stopIndex
+ ) {
+ return new StationSP(stopIndex::stopByIndex, station);
+ }
+
+ static TransferPointForPattern createTransferPointForPattern(int stopIndex) {
+ return new StopSP(stopIndex);
+ }
+
+ static TransferPointForPattern createTransferPointForPattern(Route route, int sourceStopIndex) {
+ return new RouteSP(route, sourceStopIndex);
+ }
+
+ static TransferPointForPattern createTransferPointForPattern(Trip trip, int sourceStopIndex) {
+ return new TripSP(trip, sourceStopIndex);
+ }
+
+ private static class StationSP implements TransferPointForPattern {
+
+ private final IntFunction toStop;
+ private final Station station;
+
+ private StationSP(IntFunction toStop, Station station) {
+ this.toStop = toStop;
+ this.station = station;
+ }
+
+ @Override
+ public boolean match(int stopIndex, Trip trip) {
+ return station == toStop.apply(stopIndex).getParentStation();
+ }
+ }
+
+ private static class StopSP implements TransferPointForPattern {
+
+ private final int stopIndex;
+
+ private StopSP(int stopIndex) {this.stopIndex = stopIndex;}
+
+ @Override
+ public boolean match(int stopIndex, Trip trip) {
+ return this.stopIndex == stopIndex;
+ }
+ }
+
+ private static class RouteSP implements TransferPointForPattern {
+
+ private final Route route;
+ private final int stopIndex;
+
+ private RouteSP(Route route, int stopIndex) {
+ this.route = route;
+ this.stopIndex = stopIndex;
+ }
+
+ @Override
+ public boolean match(int stopIndex, Trip trip) {
+ return this.stopIndex == stopIndex && this.route == trip.getRoute();
+ }
+ }
+
+ private static class TripSP implements TransferPointForPattern {
+
+ private final Trip trip;
+ private final int stopIndex;
+
+ private TripSP(Trip trip, int stopIndex) {
+ this.trip = trip;
+ this.stopIndex = stopIndex;
+ }
+
+ @Override
+ public boolean match(int stopIndex, Trip trip) {
+ return this.stopIndex == stopIndex && this.trip == trip;
+ }
+ }
+}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
index 882ced15f3a..c41fc8090d8 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/AccessEgressMapper.java
@@ -1,5 +1,9 @@
package org.opentripplanner.routing.algorithm.raptor.transit.mappers;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
import org.opentripplanner.ext.flex.FlexAccessEgress;
import org.opentripplanner.model.Stop;
import org.opentripplanner.routing.algorithm.raptor.transit.AccessEgress;
@@ -7,11 +11,6 @@
import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
import org.opentripplanner.routing.graphfinder.NearbyStop;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
public class AccessEgressMapper {
private final StopIndexForRaptor stopIndex;
@@ -23,7 +22,9 @@ public AccessEgressMapper(StopIndexForRaptor stopIndex) {
public AccessEgress mapNearbyStop(NearbyStop nearbyStop, boolean isEgress) {
if (!(nearbyStop.stop instanceof Stop)) { return null; }
return new AccessEgress(
- stopIndex.indexByStop.get(nearbyStop.stop),
+ // TODO: This cast is potentially causing problems look into if it is possible
+ // to improve the code and get rid of the cast
+ stopIndex.indexOf((Stop)nearbyStop.stop),
isEgress ? nearbyStop.state.reverse() : nearbyStop.state
);
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransferIndexGenerator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransferIndexGenerator.java
deleted file mode 100644
index f024ea9c8a2..00000000000
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransferIndexGenerator.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.mappers;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.opentripplanner.model.Trip;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
-import org.opentripplanner.model.transfer.TransferService;
-import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
-
-public class TransferIndexGenerator {
- private final TransferService transferService;
- private final Map patternByTrip = new HashMap<>();
-
- private TransferIndexGenerator(TransferService transferService) {
- this.transferService = transferService;
- }
-
- public static void generateTransfers(
- TransferService transferService,
- Collection tripPatterns
- ) {
- var generator = new TransferIndexGenerator(transferService);
-
- generator.setupPatternByTripIndex(tripPatterns);
-
- for (TripPatternWithRaptorStopIndexes pattern : tripPatterns) {
- generator.generateTransfers(pattern);
- }
- }
-
- private void setupPatternByTripIndex(Collection tripPatterns) {
- for (TripPatternWithRaptorStopIndexes pattern : tripPatterns) {
- for (Trip trip : pattern.getPattern().getTrips()) {
- patternByTrip.put(trip, pattern);
- }
- }
- }
-
- private void generateTransfers(TripPatternWithRaptorStopIndexes pattern) {
- for (Trip trip : pattern.getPattern().getTrips()) {
- int nStops = pattern.getPattern().getStops().size();
- for (int stopPos=0; stopPos < nStops; ++stopPos) {
- var transfers= transferService.listConstrainedTransfersTo(trip, stopPos);
- for (ConstrainedTransfer tx : transfers) {
- var c = tx.getTransferConstraint();
- if(c.isFacilitated()) {
- var fromTrip = tx.getFrom().getTrip();
- var toTrip = tx.getTo().getTrip();
- if (fromTrip != null && toTrip != null) {
- var fromPattern = patternByTrip.get(fromTrip);
- if (fromPattern != null) {
- pattern.addTransferConstraintsForwardSearch(tx);
- fromPattern.addTransferConstraintsReverseSearch(tx);
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransfersMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransfersMapper.java
index 47ec4e5a97f..955979ed4a2 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransfersMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransfersMapper.java
@@ -21,14 +21,14 @@ static List> mapTransfers(
List> transferByStopIndex = new ArrayList<>();
- for (int i = 0; i < stopIndex.stopsByIndex.size(); ++i) {
- Stop stop = stopIndex.stopsByIndex.get(i);
+ for (int i = 0; i < stopIndex.size(); ++i) {
+ Stop stop = stopIndex.stopByIndex(i);
ArrayList list = new ArrayList<>();
transferByStopIndex.add(list);
for (PathTransfer pathTransfer : transfersByStop.get(stop)) {
if (pathTransfer.to instanceof Stop) {
- int toStopIndex = stopIndex.indexByStop.get(pathTransfer.to);
+ int toStopIndex = stopIndex.indexOf((Stop)pathTransfer.to);
Transfer newTransfer;
if (pathTransfer.getEdges() != null) {
newTransfer = new Transfer(
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransitLayerMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransitLayerMapper.java
index 7eb269f352f..77362128a66 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransitLayerMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TransitLayerMapper.java
@@ -23,6 +23,7 @@
import org.opentripplanner.routing.algorithm.raptor.transit.TransitTuningParameters;
import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternForDate;
import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
+import org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer.TransferIndexGenerator;
import org.opentripplanner.routing.algorithm.raptor.transit.request.RaptorRequestTransferCache;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.trippattern.TripTimes;
@@ -76,10 +77,11 @@ private TransitLayer map(TransitTuningParameters tuningParameters) {
transferByStopIndex = mapTransfers(stopIndex, graph.transfersByStop);
if(OTPFeature.TransferConstraints.isOn()) {
- TransferIndexGenerator.generateTransfers(
- graph.getTransferService(),
- newTripPatternForOld.values()
- );
+ new TransferIndexGenerator(
+ graph.getTransferService().listAll(),
+ newTripPatternForOld.values(),
+ stopIndex
+ ).generateTransfers();
}
var transferCache = new RaptorRequestTransferCache(tuningParameters.transferCacheMaxSize());
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TripPatternMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TripPatternMapper.java
index 6aaf89bef0a..fbd10852057 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TripPatternMapper.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/TripPatternMapper.java
@@ -1,12 +1,11 @@
package org.opentripplanner.routing.algorithm.raptor.transit.mappers;
-import org.opentripplanner.model.TripPattern;
-import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
-import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
-
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import org.opentripplanner.model.TripPattern;
+import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
+import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
public class TripPatternMapper {
@@ -23,8 +22,8 @@ static Map mapOldTripPatternToRap
for (TripPattern oldTripPattern : oldTripPatterns) {
TripPatternWithRaptorStopIndexes newTripPattern = new TripPatternWithRaptorStopIndexes(
- stopIndex.listStopIndexesForStops(oldTripPattern.getStopPattern().getStops()),
- oldTripPattern
+ oldTripPattern,
+ stopIndex.listStopIndexesForStops(oldTripPattern.getStopPattern().getStops())
);
newTripPatternForOld.put(oldTripPattern, newTripPattern);
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchForward.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchForward.java
deleted file mode 100644
index 98c497c17b2..00000000000
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchForward.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
-
-import java.util.Collection;
-import org.opentripplanner.common.model.T2;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
-import org.opentripplanner.model.transfer.TransferConstraint;
-import org.opentripplanner.model.transfer.TransferPoint;
-import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
-
-class ConstrainedBoardingSearchForward
- implements ConstrainedBoardingSearchStrategy {
-
- @Override
- public TransferPoint source(ConstrainedTransfer tx) {return tx.getFrom();}
-
- @Override
- public int time(RaptorTripSchedule schedule, int stopPos) {
- return schedule.departure(stopPos);
- }
-
- @Override
- public int findSourceStopPosition(RaptorTripSchedule schedule, int timeLimit, int stop) {
- return schedule.findArrivalStopPosition(timeLimit, stop);
- }
-
- @Override
- public T2 findTimetableTripInfo(
- RaptorTimeTable timetable,
- Collection transfers,
- int stopPos,
- int sourceArrivalTime
- ) {
- // Abort after 6 hours
- boolean boardNextNormalTrip = false;
-
- outer:
- for (int i = 0; i < timetable.numberOfTripSchedules(); ++i) {
- var it = timetable.getTripSchedule(i);
- int departureTime = it.departure(stopPos);
- if (departureTime < sourceArrivalTime) { continue; }
-
- var targetTrip = it.getOriginalTripTimes().getTrip();
-
- for (ConstrainedTransfer tx : transfers) {
- if (tx.getTo().applyToAllTrips()) {
- return new T2<>(i, tx.getTransferConstraint());
- }
- if (targetTrip == tx.getTo().getTrip()) {
- if (tx.getTransferConstraint().isNotAllowed()) {
- boardNextNormalTrip = true;
- continue outer;
- }
- else {
- return new T2<>(i, tx.getTransferConstraint());
- }
- }
- }
- if (boardNextNormalTrip) {
- return new T2<>(i, TransferConstraint.REGULAR_TRANSFER);
- }
- }
- return null;
- }
-}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchReverse.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchReverse.java
deleted file mode 100644
index dc2c004fef9..00000000000
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchReverse.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
-
-import java.util.Collection;
-import org.opentripplanner.common.model.T2;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
-import org.opentripplanner.model.transfer.TransferConstraint;
-import org.opentripplanner.model.transfer.TransferPoint;
-import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
-
-class ConstrainedBoardingSearchReverse
- implements ConstrainedBoardingSearchStrategy {
-
- @Override
- public TransferPoint source(ConstrainedTransfer tx) {return tx.getTo();}
-
- @Override
- public int time(RaptorTripSchedule schedule, int stopPos) {
- return schedule.arrival(stopPos);
- }
-
- @Override
- public int findSourceStopPosition(RaptorTripSchedule schedule, int timeLimit, int stop) {
- return schedule.findDepartureStopPosition(timeLimit, stop);
- }
-
- @Override
- public T2 findTimetableTripInfo(
- RaptorTimeTable timetable,
- Collection transfers,
- int stopPos,
- int sourceDepartureTime
- ) {
- // Abort after 6 hours
- boolean alightPrevNormalTrip = false;
-
- outer:
- for (int i = timetable.numberOfTripSchedules()-1; i >= 0; --i) {
- var it = timetable.getTripSchedule(i);
- int arrivalTime = it.arrival(stopPos);
- if (arrivalTime > sourceDepartureTime) { continue; }
-
- var targetTrip = it.getOriginalTripTimes().getTrip();
-
- for (ConstrainedTransfer tx : transfers) {
- if (tx.getFrom().applyToAllTrips()) {
- return new T2<>(i, tx.getTransferConstraint());
- }
- if (targetTrip == tx.getFrom().getTrip()) {
- if (tx.getTransferConstraint().isNotAllowed()) {
- alightPrevNormalTrip = true;
- continue outer;
- }
- else {
- return new T2<>(i, tx.getTransferConstraint());
- }
- }
- }
- if (alightPrevNormalTrip) {
- return new T2<>(i, TransferConstraint.REGULAR_TRANSFER);
- }
- }
- return null;
- }
-}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchStrategy.java b/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchStrategy.java
deleted file mode 100644
index e4c0ff29d1b..00000000000
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchStrategy.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
-
-import java.util.Collection;
-import org.opentripplanner.common.model.T2;
-import org.opentripplanner.model.transfer.ConstrainedTransfer;
-import org.opentripplanner.model.transfer.TransferConstraint;
-import org.opentripplanner.model.transfer.TransferPoint;
-import org.opentripplanner.routing.algorithm.raptor.transit.TripSchedule;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTimeTable;
-import org.opentripplanner.transit.raptor.api.transit.RaptorTripSchedule;
-
-interface ConstrainedBoardingSearchStrategy {
-
- TransferPoint source(ConstrainedTransfer tx);
-
- int time(RaptorTripSchedule schedule, int stopPos);
-
- int findSourceStopPosition(RaptorTripSchedule schedule, int timeLimit, int stop);
-
- /**
- * Find the trip to board (trip index) and the transfer constraint
- */
- T2 findTimetableTripInfo(
- RaptorTimeTable timetable,
- Collection transfers,
- int stopPos,
- int sourceTime
- );
-}
diff --git a/src/main/java/org/opentripplanner/transit/raptor/rangeraptor/RangeRaptorWorker.java b/src/main/java/org/opentripplanner/transit/raptor/rangeraptor/RangeRaptorWorker.java
index 211bbb8b467..ef6c97b1ede 100644
--- a/src/main/java/org/opentripplanner/transit/raptor/rangeraptor/RangeRaptorWorker.java
+++ b/src/main/java/org/opentripplanner/transit/raptor/rangeraptor/RangeRaptorWorker.java
@@ -214,7 +214,7 @@ private void findAllTransitForRound() {
var route = routeIterator.next();
var pattern = route.pattern();
var tripSearch = createTripSearch(route.timetable());
- var txService = enableTransferConstraints
+ var txSearch = enableTransferConstraints
? calculator.transferConstraintsSearch(route) : null;
int alightSlack = slackProvider.alightSlack(pattern);
@@ -239,7 +239,7 @@ private void findAllTransitForRound() {
transitWorker.forEachBoarding(stopIndex, (int prevArrivalTime) -> {
boolean handled = boardWithConstrainedTransfer(
- txService, route.timetable(), stopIndex, stopPos
+ txSearch, route.timetable(), stopIndex, stopPos
);
// Find the best trip and board [no guaranteed transfer exist]
@@ -282,14 +282,14 @@ private void boardWithRegularTransfer(
* trip search from execution.
*/
private boolean boardWithConstrainedTransfer(
- RaptorConstrainedTripScheduleBoardingSearch txService,
+ RaptorConstrainedTripScheduleBoardingSearch txSearch,
RaptorTimeTable targetTimetable,
int targetStopIndex,
int targetStopPos
) {
if(!enableTransferConstraints) { return false; }
- if(!txService.transferExist(targetStopPos)) { return false; }
+ if(!txSearch.transferExist(targetStopPos)) { return false; }
// Get the previous transit stop arrival (transfer source)
TransitArrival sourceStopArrival = transitWorker.previousTransit(targetStopIndex);
@@ -302,7 +302,7 @@ private boolean boardWithConstrainedTransfer(
slackProvider.alightSlack(sourceStopArrival.trip().pattern())
);
- var result = txService.find(
+ var result = txSearch.find(
targetTimetable,
sourceStopArrival.trip(),
sourceStopArrival.stop(),
diff --git a/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java b/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java
index 250a7a90ce4..4320ed95500 100644
--- a/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java
+++ b/src/test/java/org/opentripplanner/model/impl/OtpTransitServiceImplTest.java
@@ -105,12 +105,9 @@ public void testGetAllTransfers() {
.collect(joining("\n"))
);
- // There is 9 transfers, but because of the route to trip we get more
- // TODO TGR - Support Route to trip expansion
assertEquals(
- //"Transfer{from: (route: 2, trip: 2.1, stopPos: 2), to: (route: 5, trip: 5.1, stopPos: 0), constraint: {guaranteed}}\n"
- //+ "Transfer{from: (route: 2, trip: 2.2, stopPos: 2), to: (route: 5, trip: 5.1, stopPos: 0), constraint: {guaranteed}}\n"
- "ConstrainedTransfer{from: , to: , constraint: {priority: RECOMMENDED}}\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"
diff --git a/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java b/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java
index e741ff15a1f..3ebe606fd29 100644
--- a/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java
+++ b/src/test/java/org/opentripplanner/model/transfer/ConstrainedTransferTest.java
@@ -13,6 +13,8 @@ public class ConstrainedTransferTest implements TransferTestData {
private static final TransferConstraint NO_CONSTRAINS = TransferConstraint.create().build();
private static final TransferConstraint GUARANTIED = TransferConstraint.create().guaranteed().build();
+ 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);
@@ -36,13 +38,15 @@ public void setup() {
@Test
public void getSpecificityRanking() {
- assertEquals(0, TX_A_TO_B.getSpecificityRanking());
- assertEquals(1, TX_R11_TO_B.getSpecificityRanking());
- assertEquals(1, TX_A_TO_R22.getSpecificityRanking());
- assertEquals(2, TX_R11_TO_R22.getSpecificityRanking());
- assertEquals(2, TX_A_TO_T23.getSpecificityRanking());
- assertEquals(3, TX_T11_TO_R22.getSpecificityRanking());
- assertEquals(4, TX_T11_TO_T22.getSpecificityRanking());
+ assertEquals(10, TX_STATION_TO_A.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());
}
@Test
diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java
index 14a421b82fb..c51bce15d62 100644
--- a/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java
+++ b/src/test/java/org/opentripplanner/model/transfer/TransferConstraintTest.java
@@ -48,6 +48,14 @@ public void isFacilitated() {
assertFalse(NOT_ALLOWED.isFacilitated());
}
+ @Test
+ public void useInRaptorRouting() {
+ assertTrue(GUARANTIED.useInRaptorRouting());
+ assertTrue(STAY_SEATED.useInRaptorRouting());
+ assertFalse(NO_CONSTRAINS.useInRaptorRouting());
+ assertTrue(NOT_ALLOWED.useInRaptorRouting());
+ }
+
@Test
public void isNotAllowed() {
assertTrue(NOT_ALLOWED.isNotAllowed());
diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java b/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java
new file mode 100644
index 00000000000..842fb9b0141
--- /dev/null
+++ b/src/test/java/org/opentripplanner/model/transfer/TransferPointMapTest.java
@@ -0,0 +1,48 @@
+package org.opentripplanner.model.transfer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class TransferPointMapTest implements TransferTestData {
+
+ final TransferPointMap subject = new TransferPointMap<>();
+
+ @BeforeEach
+ void setup() {
+ STOP_A.setParentStation(STATION);
+ }
+
+ @Test
+ void addAndGetEmptyMap() {
+ assertEquals(List.of(), subject.get(TRIP_1, STOP_A, STOP_POSITION_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));
+ }
+
+ @Test
+ void computeIfAbsent() {
+ assertEquals("A", subject.computeIfAbsent(TRIP_POINT_11, () -> "A"));
+ assertEquals("B", subject.computeIfAbsent(ROUTE_POINT_11, () -> "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(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));
+ }
+}
\ 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 8a5b4787c6d..3c8db6d6474 100644
--- a/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java
+++ b/src/test/java/org/opentripplanner/model/transfer/TransferPointTest.java
@@ -1,86 +1,66 @@
package org.opentripplanner.model.transfer;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+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 org.junit.Test;
+import java.util.List;
+import org.junit.jupiter.api.Test;
public class TransferPointTest implements TransferTestData {
- public static final int STOP_POSITION_1 = 1;
- public static final int STOP_POSITION_2 = 2;
-
- private final TransferPoint otherPoint = new RouteTransferPoint(ROUTE_2, TRIP_2, STOP_POSITION_2);
-
+ @Test
+ public void getStation() {
+ assertEquals(STATION, STATION_POINT.asStationTransferPoint().getStation());
+ }
@Test
public void getStop() {
- assertEquals(STOP_A, STOP_POINT_A.getStop());
- assertNull(TRIP_POINT_11.getStop());
- assertNull(ROUTE_POINT_11.getStop());
+ assertEquals(STOP_A, STOP_POINT_A.asStopTransferPoint().getStop());
}
@Test
public void getTrip() {
- assertNull(STOP_POINT_A.getTrip());
- assertEquals(TRIP_1, TRIP_POINT_11.getTrip());
- assertEquals(TRIP_1, ROUTE_POINT_11.getTrip());
+ assertEquals(TRIP_1, TRIP_POINT_11.asTripTransferPoint().getTrip());
}
@Test
public void getStopPosition() {
- assertEquals(TransferPoint.NOT_AVAILABLE, STOP_POINT_A.getStopPosition());
- assertEquals(STOP_POSITION_1, TRIP_POINT_11.getStopPosition());
- assertEquals(STOP_POSITION_1, ROUTE_POINT_11.getStopPosition());
+ assertEquals(STOP_POSITION_1, TRIP_POINT_11.asTripTransferPoint().getStopPositionInPattern());
+ assertEquals(STOP_POSITION_1, ROUTE_POINT_11.asRouteTransferPoint().getStopPositionInPattern());
}
@Test
public void getSpecificityRanking() {
- assertEquals(0, STOP_POINT_A.getSpecificityRanking());
- assertEquals(1, ROUTE_POINT_11.getSpecificityRanking());
- assertEquals(2, TRIP_POINT_11.getSpecificityRanking());
+ assertEquals(0, STATION_POINT.getSpecificityRanking());
+ assertEquals(1, STOP_POINT_A.getSpecificityRanking());
+ assertEquals(2, ROUTE_POINT_11.getSpecificityRanking());
+ assertEquals(3, TRIP_POINT_11.getSpecificityRanking());
+ }
+
+ @Test
+ public void isStationTransferPoint() {
+ List.of(STATION_POINT, STOP_POINT_A, ROUTE_POINT_11, TRIP_POINT_11).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());
+ });
}
@Test
public void applyToAllTrips() {
+ assertTrue(STATION_POINT.applyToAllTrips());
assertTrue(STOP_POINT_A.applyToAllTrips());
assertTrue(ROUTE_POINT_11.applyToAllTrips());
assertFalse(TRIP_POINT_11.applyToAllTrips());
}
- @Test
- public void equalsAndHashCode() {
- // A STOP_POINT_A should never match a route or trip point
- assertNotEquals(STOP_POINT_A, ROUTE_POINT_11);
- assertNotEquals(STOP_POINT_A, TRIP_POINT_11);
- assertNotEquals(ROUTE_POINT_11, STOP_POINT_A);
- assertNotEquals(TRIP_POINT_11, STOP_POINT_A);
-
- assertNotEquals(STOP_POINT_A.hashCode(), ROUTE_POINT_11.hashCode());
- assertNotEquals(STOP_POINT_A.hashCode(), TRIP_POINT_11.hashCode());
- assertNotEquals(ROUTE_POINT_11.hashCode(), STOP_POINT_A.hashCode());
- assertNotEquals(TRIP_POINT_11.hashCode(), STOP_POINT_A.hashCode());
-
- // If the trip and stopPosition is the same then trip and route point should match
- assertEquals(TRIP_POINT_11, ROUTE_POINT_11);
- assertEquals(ROUTE_POINT_11, TRIP_POINT_11);
-
- assertEquals(TRIP_POINT_11.hashCode(), ROUTE_POINT_11.hashCode());
- assertEquals(ROUTE_POINT_11.hashCode(), TRIP_POINT_11.hashCode());
-
- assertNotEquals(TRIP_POINT_11, otherPoint);
- assertNotEquals(ROUTE_POINT_11, otherPoint);
- assertNotEquals(TRIP_POINT_11.hashCode(), otherPoint.hashCode());
- assertNotEquals(ROUTE_POINT_11.hashCode(), otherPoint.hashCode());
- }
-
@Test
public void testToString() {
+ assertEquals("", STATION_POINT.toString());
assertEquals("", STOP_POINT_A.toString());
- assertEquals("", ROUTE_POINT_11.toString());
- assertEquals("", TRIP_POINT_11.toString());
+ assertEquals("", ROUTE_POINT_11.toString());
+ assertEquals("", TRIP_POINT_23.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 9fd1ba7ffc8..d66acff5e25 100644
--- a/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java
+++ b/src/test/java/org/opentripplanner/model/transfer/TransferServiceTest.java
@@ -1,43 +1,54 @@
package org.opentripplanner.model.transfer;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.model.Stop;
public class TransferServiceTest implements TransferTestData {
private final TransferService subject = new TransferService();
+ @BeforeEach
+ public void setup() {
+ STOP_A.setParentStation(STATION);
+ }
@Test
- public void addOneTransferForEachCombinationOfFromToTypesAndRetriveEachOfThem() {
+ public void findTransfer() {
// Given:
- var A = transfer(STOP_POINT_A, STOP_POINT_B);
- var B = transfer(STOP_POINT_A, TRIP_POINT_23);
- var C = transfer(ROUTE_POINT_11, STOP_POINT_B);
- var D = transfer(TRIP_POINT_11, ROUTE_POINT_22);
- var E = transfer(TRIP_POINT_11, TRIP_POINT_23);
+ 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);
// When: all transfers is added to service
- subject.addAll(List.of(A, B, C, D, E));
+ subject.addAll(List.of(A, B, C, D, E, F));
- /* THEN */
+ // Then:
// Find the most specific transfer, Trip and stop position match - stops is ignored
- assertEquals(D, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 2));
+ assertEquals(E, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 2));
// Find the another specific transfer with the stop position changed
- assertEquals(E, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 3));
+ assertEquals(F, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 3));
// Find the specific transfer: TRIP -> STOP when stop position do not match TO point
- assertEquals(C, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 7));
+ assertEquals(D, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 7));
// Find the specific transfer: STOP -> TRIP when stop position do not match FROM point
- assertEquals(B, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 3));
+ assertEquals(C, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 3));
// Stop position fall back to STOP -> STOP when stop position do not match
- assertEquals(A, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 7));
+ assertEquals(B, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 7, 7));
+
+ //
+ assertEquals(A, subject.findTransfer(STOP_A, ANY_STOP, TRIP_2, TRIP_1, 7, 1));
}
@Test
@@ -51,6 +62,19 @@ public void addSameTransferTwiceRetrieveFirstAdded() {
assertEquals(A, subject.findTransfer(STOP_A, STOP_B, TRIP_1, TRIP_2, 1, 2));
}
+ @Test
+ public void listAll() {
+ // Given:
+ 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);
+
+ // When: all transfers is added to service
+ subject.addAll(List.of(A, B, C));
+
+ // Then
+ assertEquals(List.of(A, B, C), subject.listAll());
+ }
ConstrainedTransfer transfer(TransferPoint from, TransferPoint to) {
var c = TransferConstraint.create().build();
diff --git a/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java b/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java
index 04f4427e350..32544291978 100644
--- a/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java
+++ b/src/test/java/org/opentripplanner/model/transfer/TransferTestData.java
@@ -2,12 +2,25 @@
import org.opentripplanner.model.FeedScopedId;
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;
public interface TransferTestData {
String FEED_ID = "F";
+ Station STATION = new Station(
+ createId(1),
+ "Central Station",
+ null, null, null, null, null,
+ StopTransferPriority.ALLOWED
+ );
+
+ int STOP_POSITION_1 = 1;
+ int STOP_POSITION_2 = 2;
+ int STOP_POSITION_3 = 3;
+
Stop STOP_A = Stop.stopForTest("A", 60.0, 11.0);
Stop STOP_B = Stop.stopForTest("B", 60.0, 11.0);
@@ -17,15 +30,16 @@ public interface TransferTestData {
Trip TRIP_1 = createTrip(1, ROUTE_1);
Trip TRIP_2 = createTrip(2, ROUTE_2);
+ TransferPoint STATION_POINT = new StationTransferPoint(STATION);
+
TransferPoint STOP_POINT_A = new StopTransferPoint(STOP_A);
TransferPoint STOP_POINT_B = new StopTransferPoint(STOP_B);
- TransferPoint ROUTE_POINT_11 = new RouteTransferPoint(ROUTE_1, TRIP_1, 1);
- TransferPoint ROUTE_POINT_22 = new RouteTransferPoint(ROUTE_2, TRIP_2, 2);
-
- TransferPoint TRIP_POINT_11 = new TripTransferPoint(TRIP_1, 1);
- TransferPoint TRIP_POINT_23 = new TripTransferPoint(TRIP_2, 3);
+ TransferPoint ROUTE_POINT_11 = new RouteTransferPoint(ROUTE_1, STOP_POSITION_1);
+ TransferPoint ROUTE_POINT_22 = new RouteTransferPoint(ROUTE_2, STOP_POSITION_2);
+ TransferPoint TRIP_POINT_11 = new TripTransferPoint(TRIP_1, STOP_POSITION_1);
+ TransferPoint TRIP_POINT_23 = new TripTransferPoint(TRIP_2, STOP_POSITION_3);
private static Trip createTrip(int id, Route route) {
Trip t = new Trip(createId(id));
@@ -34,11 +48,10 @@ private static Trip createTrip(int id, Route route) {
}
private static Route createRoute(int id, String name) {
- Route route = new Route(createId(id));
- route.setShortName(name);
- return route;
+ Route r = new Route(createId(id));
+ 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/netex/mapping/StopTransferPriorityMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapperTest.java
index 0f91b91ea9b..d2345598b91 100644
--- a/src/test/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapperTest.java
+++ b/src/test/java/org/opentripplanner/netex/mapping/StopTransferPriorityMapperTest.java
@@ -13,23 +13,23 @@ public class StopTransferPriorityMapperTest {
@Test
public void mapToDomain() {
- assertNull(TransferPriorityMapper.mapToDomain(null));
+ assertNull(StopTransferPriorityMapper.mapToDomain(null));
assertEquals(
StopTransferPriority.DISCOURAGED,
- TransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.NO_INTERCHANGE)
+ StopTransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.NO_INTERCHANGE)
);
assertEquals(
StopTransferPriority.ALLOWED,
- TransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.INTERCHANGE_ALLOWED)
+ StopTransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.INTERCHANGE_ALLOWED)
);
assertEquals(
StopTransferPriority.PREFERRED,
- TransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.PREFERRED_INTERCHANGE)
+ StopTransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.PREFERRED_INTERCHANGE)
);
assertEquals(
StopTransferPriority.RECOMMENDED,
- TransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.RECOMMENDED_INTERCHANGE)
+ StopTransferPriorityMapper.mapToDomain(InterchangeWeightingEnumeration.RECOMMENDED_INTERCHANGE)
);
}
}
\ No newline at end of file
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java
similarity index 58%
rename from src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchTest.java
rename to src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java
index 91654ad57f4..cfa15a13e62 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/ConstrainedBoardingSearchTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/constrainedtransfer/ConstrainedBoardingSearchTest.java
@@ -1,4 +1,4 @@
-package org.opentripplanner.routing.algorithm.raptor.transit.request;
+package org.opentripplanner.routing.algorithm.raptor.transit.constrainedtransfer;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -6,27 +6,33 @@
import static org.opentripplanner.model.transfer.TransferConstraint.REGULAR_TRANSFER;
import gnu.trove.map.hash.TIntObjectHashMap;
+import java.util.Collection;
import java.util.List;
+import java.util.function.Function;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.TransitMode;
import org.opentripplanner.model.transfer.ConstrainedTransfer;
import org.opentripplanner.model.transfer.StopTransferPoint;
import org.opentripplanner.model.transfer.TransferConstraint;
+import org.opentripplanner.model.transfer.TransferPoint;
import org.opentripplanner.model.transfer.TripTransferPoint;
+import org.opentripplanner.routing.algorithm.raptor.transit.StopIndexForRaptor;
+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 {
-
- private static final boolean FORWARD = true;
- private static final boolean REVERSE = false;
private static final int TRIP_1_INDEX = 0;
private static final int TRIP_2_INDEX = 1;
-
private TestRouteData route1;
private TestRouteData route2;
+ private TripPatternWithRaptorStopIndexes pattern1;
+ private TripPatternWithRaptorStopIndexes pattern2;
+ private StopIndexForRaptor stopIndex;
/**
* Create transit data with 2 routes with a trip each.
@@ -48,10 +54,10 @@ public class ConstrainedBoardingSearchTest implements TestTransitCaseData {
* the next trip 'R2-2'.
*
*
- * The transfer at stop C is allow regular transfers between trip R1-2 and R2-1.
+ * The transfer at stop C allow regular transfers between trip R1-2 and R2-1.
*
*
- * R1-1 is the fallback int the reverse search in the same way as R2-2 is the fallback
+ * R1-1 is the fallback in the reverse search in the same way as R2-2 is the fallback
* int the forward search.
*
*
@@ -73,21 +79,35 @@ void setup() {
"10:15 10:30 10:40",
"10:20 10:35 10:45"
);
+
+ this.pattern1 = route1.getRaptorTripPattern();
+ this.pattern2 = route2.getRaptorTripPattern();
+ this.stopIndex = new StopIndexForRaptor(
+ List.of(STOP_A, STOP_B, STOP_C, STOP_D),
+ TransitTuningParameters.FOR_TEST
+ );
}
@Test
void transferExist() {
- var transfers = new TIntObjectHashMap>();
- int targetStopPos = 3;
- transfers.put(targetStopPos, List.of());
+ int fromStopPos = route1.stopPosition(STOP_C);
+ int toStopPos = route2.stopPosition(STOP_C);
+
+ ConstrainedTransfer txAllowed = new ConstrainedTransfer(
+ id("ALLOWED"),
+ new StopTransferPoint(STOP_C),
+ new StopTransferPoint(STOP_C),
+ TransferConstraint.create().guaranteed().build()
+ );
+ generateTransfersForPatterns(List.of(txAllowed));
// Forward
- var subject = new ConstrainedBoardingSearch(true, transfers);
- assertTrue(subject.transferExist(targetStopPos));
+ var subject = route2.getRaptorTripPattern().constrainedTransferForwardSearch();
+ assertTrue(subject.transferExist(toStopPos));
// Reverse
- subject = new ConstrainedBoardingSearch(false, transfers);
- assertTrue(subject.transferExist(targetStopPos));
+ subject = route1.getRaptorTripPattern().constrainedTransferReverseSearch();
+ assertTrue(subject.transferExist(fromStopPos));
}
@Test
@@ -96,8 +116,8 @@ void findGuaranteedTransferWithZeroConnectionTime() {
int sourceStopPos = route1.stopPosition(STOP_B);
int targetStopPos = route2.stopPosition(STOP_B);
- TransferConstraint constraint = TransferConstraint.create().guaranteed().build();
- ConstrainedTransfer txGuaranteed = new ConstrainedTransfer(
+ var constraint = TransferConstraint.create().guaranteed().build();
+ var txGuaranteed = new ConstrainedTransfer(
id("Guaranteed"),
new TripTransferPoint(route1.lastTrip().trip(), sourceStopPos),
new TripTransferPoint(route2.firstTrip().trip(), targetStopPos),
@@ -106,75 +126,66 @@ void findGuaranteedTransferWithZeroConnectionTime() {
List constrainedTransfers = List.of(txGuaranteed);
transfers.put(targetStopPos, constrainedTransfers);
- testTransferSearch(STOP_B, constrainedTransfers, TRIP_1_INDEX, constraint);
+ testTransferSearch(STOP_B, constrainedTransfers, TRIP_1_INDEX, TRIP_2_INDEX, constraint);
}
@Test
- void findNextTransferWhenFirstTripIsNoAllowed() {
- var transfers = new TIntObjectHashMap>();
+ void findNextTransferWhenFirstTransferIsNotAllowed() {
int sourceStopPos = route1.stopPosition(STOP_C);
int targetStopPos = route2.stopPosition(STOP_C);
- TransferConstraint constraint = TransferConstraint.create().notAllowed().build();
- ConstrainedTransfer txGuaranteed = new ConstrainedTransfer(
+ var txNotAllowed = new ConstrainedTransfer(
id("NOT-ALLOWED"),
new TripTransferPoint(route1.lastTrip().trip(), sourceStopPos),
new TripTransferPoint(route2.firstTrip().trip(), targetStopPos),
- constraint
+ TransferConstraint.create().notAllowed().build()
);
- List constrainedTransfers = List.of(txGuaranteed);
- transfers.put(targetStopPos, constrainedTransfers);
- testTransferSearch(STOP_C, constrainedTransfers, TRIP_2_INDEX, REGULAR_TRANSFER);
+ testTransferSearch(STOP_C, List.of(txNotAllowed), TRIP_2_INDEX, TRIP_1_INDEX, REGULAR_TRANSFER);
}
@Test
- @Disabled("This test fail, so we will try to fix the problem in the nex commit")
- void blockTransferWhenNoAllowedMatchesAllTripsInRoute() {
+ void blockTransferWhenNotAllowedApplyToAllTrips() {
var transfers = new TIntObjectHashMap>();
int targetStopPos = route2.stopPosition(STOP_C);
TransferConstraint constraint = TransferConstraint.create().notAllowed().build();
- ConstrainedTransfer txGuaranteed = new ConstrainedTransfer(
+ ConstrainedTransfer transfer = new ConstrainedTransfer(
id("NOT-ALLOWED"),
new StopTransferPoint(STOP_C),
new StopTransferPoint(STOP_C),
constraint
);
- List constrainedTransfers = List.of(txGuaranteed);
+ List constrainedTransfers = List.of(transfer);
transfers.put(targetStopPos, constrainedTransfers);
- testTransferSearch(STOP_C, constrainedTransfers, TRIP_1_INDEX, constraint);
+ testTransferSearch(STOP_C, constrainedTransfers, TRIP_1_INDEX, TRIP_2_INDEX, constraint);
}
void testTransferSearch(
Stop transferStop,
List constraints,
- int expTripIndex,
+ int expTripIndexFwdSearch,
+ int expTripIndexRevSearch,
TransferConstraint expConstraint
) {
- testTransferSearchForward(transferStop, constraints, expTripIndex, expConstraint);
- // Swap expected trip index for reverse search
- int revExpTripIndex = expTripIndex == TRIP_1_INDEX ? TRIP_2_INDEX : TRIP_1_INDEX;
- testTransferSearchReverse(transferStop, constraints, revExpTripIndex, expConstraint);
+ //testTransferSearchForward(transferStop, constraints, expTripIndexFwdSearch, expConstraint);
+ testTransferSearchReverse(transferStop, constraints, expTripIndexRevSearch, expConstraint);
}
void testTransferSearchForward(
Stop transferStop,
- List constraints,
+ List txList,
int expectedTripIndex,
TransferConstraint expectedConstraint
) {
+ generateTransfersForPatterns(txList);
+ var subject = pattern2.constrainedTransferForwardSearch();
+
int targetStopPos = route2.stopPosition(transferStop);
- var transfers = new TIntObjectHashMap>();
int stopIndex = stopIndex(transferStop);
int sourceArrivalTime = route1.lastTrip().getStopTime(transferStop).getArrivalTime();
- transfers.put(targetStopPos, constraints);
-
- // Forward
- var subject = new ConstrainedBoardingSearch(FORWARD, transfers);
-
// Check that transfer exist
assertTrue(subject.transferExist(targetStopPos));
@@ -192,23 +203,19 @@ void testTransferSearchForward(
assertEquals(expectedTripIndex, boarding.getTripIndex());
}
-
void testTransferSearchReverse(
Stop transferStop,
- List constraints,
+ List txList,
int expectedTripIndex,
TransferConstraint expectedConstraint
) {
+ generateTransfersForPatterns(txList);
+ var subject = pattern1.constrainedTransferReverseSearch();
int targetStopPos = route1.stopPosition(transferStop);
- var transfers = new TIntObjectHashMap>();
+
int stopIndex = stopIndex(transferStop);
int sourceArrivalTime = route2.firstTrip().getStopTime(transferStop).getDepartureTime();
- transfers.put(targetStopPos, constraints);
-
- // Forward
- var subject = new ConstrainedBoardingSearch(REVERSE, transfers);
-
// Check that transfer exist
assertTrue(subject.transferExist(targetStopPos));
@@ -225,4 +232,36 @@ void testTransferSearchReverse(
assertEquals(targetStopPos, boarding.getStopPositionInPattern());
assertEquals(expectedTripIndex, boarding.getTripIndex());
}
+
+ TransferForPatternByStopPos createTxAtStopPos(
+ Collection transfers,
+ Function getSource
+ ) {
+ var c = new TransferForPatternByStopPos();
+ for (ConstrainedTransfer tx : transfers) {
+ var source = getSource.apply(tx);
+ var target = source == tx.getFrom() ? tx.getTo() : tx.getFrom();
+ var fromTrip = TransferPoint.getTrip(source);
+ int fromStopPos = TransferPoint.getStopPositionInPattern(source);
+ int toStopPos = TransferPoint.getStopPositionInPattern(source);
+ var toTrip = TransferPoint.getTrip(target);
+
+ //var sourcePoint = TransferForPattern.
+
+ /*
+ c.add(toStopPos, new TransferForPattern(
+ sourcePoint,
+ toTrip,
+ tx.getSpecificityRanking(),
+ tx.getTransferConstraint())
+ );
+ */
+ }
+ return c;
+ }
+
+ private void generateTransfersForPatterns(Collection txList) {
+ new TransferIndexGenerator(txList, List.of(pattern1, pattern2), stopIndex)
+ .generateTransfers();
+ }
}
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/DateMapperTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/DateMapperTest.java
index 9e70cad4790..f42dd1e3246 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/DateMapperTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/mappers/DateMapperTest.java
@@ -1,17 +1,15 @@
package org.opentripplanner.routing.algorithm.raptor.transit.mappers;
-import org.junit.Assert;
-import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.opentripplanner.routing.algorithm.raptor.transit.mappers.DateMapper.asStartOfService;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
-
-import static org.junit.Assert.assertEquals;
-import static org.opentripplanner.routing.algorithm.raptor.transit.mappers.DateMapper.asStartOfService;
+import org.junit.jupiter.api.Test;
public class DateMapperTest {
private static final ZoneId ZONE_ID = ZoneId.of("Europe/Paris");
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 c7aa83c41ce..3df449eca0a 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
@@ -1,10 +1,10 @@
package org.opentripplanner.routing.algorithm.raptor.transit.mappers;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Arrays;
import java.util.List;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitDataCreatorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitDataCreatorTest.java
index 3e7aa1c26ce..ae896989dce 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitDataCreatorTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RaptorRoutingRequestTransitDataCreatorTest.java
@@ -1,7 +1,15 @@
package org.opentripplanner.routing.algorithm.raptor.transit.request;
-import org.junit.Before;
-import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.opentripplanner.model.FeedScopedId;
import org.opentripplanner.model.Route;
import org.opentripplanner.model.StopPattern;
@@ -15,15 +23,6 @@
import org.opentripplanner.routing.trippattern.Deduplicator;
import org.opentripplanner.routing.trippattern.TripTimes;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
public class RaptorRoutingRequestTransitDataCreatorTest {
public static final FeedScopedId TP_ID_1 = new FeedScopedId("F", "1");
@@ -36,7 +35,7 @@ public class RaptorRoutingRequestTransitDataCreatorTest {
new StopPattern(List.of())
);
- @Before
+ @BeforeEach
public void setup() {
TP.getRoute().setMode(TransitMode.BUS);
}
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RoutingRequestTransitDataProviderFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RoutingRequestTransitDataProviderFilterTest.java
index ad7a7f2f383..aac0fa65683 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RoutingRequestTransitDataProviderFilterTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/raptor/transit/request/RoutingRequestTransitDataProviderFilterTest.java
@@ -1,21 +1,29 @@
package org.opentripplanner.routing.algorithm.raptor.transit.request;
-import org.junit.Test;
+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 java.time.LocalDate;
+import java.util.List;
+import java.util.Set;
+import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
-import org.opentripplanner.model.*;
+import org.opentripplanner.model.BikeAccess;
+import org.opentripplanner.model.FeedScopedId;
+import org.opentripplanner.model.Route;
+import org.opentripplanner.model.Stop;
+import org.opentripplanner.model.StopPattern;
+import org.opentripplanner.model.StopTime;
+import org.opentripplanner.model.TransitMode;
+import org.opentripplanner.model.Trip;
+import org.opentripplanner.model.TripAlteration;
+import org.opentripplanner.model.TripPattern;
import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternForDate;
import org.opentripplanner.routing.algorithm.raptor.transit.TripPatternWithRaptorStopIndexes;
import org.opentripplanner.routing.trippattern.Deduplicator;
import org.opentripplanner.routing.trippattern.TripTimes;
-import java.time.LocalDate;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
public class RoutingRequestTransitDataProviderFilterTest {
private static final FeedScopedId TEST_ROUTE_ID = new FeedScopedId("TEST", "ROUTE");
@@ -134,7 +142,7 @@ private TripPatternForDate createTestTripPatternForDate() {
TripPattern pattern = new TripPattern(null, route, stopPattern);
TripPatternWithRaptorStopIndexes tripPattern = new TripPatternWithRaptorStopIndexes(
- new int[0], pattern
+ pattern, new int[0]
);
TripTimes tripTimes = Mockito.mock(TripTimes.class);
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 f14753d6fe0..1a3bd953fe0 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
@@ -31,6 +31,7 @@ public class TestRouteData implements TestTransitCaseData {
private final Map tripTimesByTrip = new HashMap<>();
private final Map tripSchedulesByTrip = new HashMap<>();
private final RaptorTimeTable timetable;
+ private final TripPatternWithRaptorStopIndexes raptorTripPattern;
private Trip currentTrip;
public TestRouteData(String route, TransitMode mode, List stops, String ... times) {
@@ -47,15 +48,19 @@ public TestRouteData(String route, TransitMode mode, List stops, String ..
.map(tripTimesByTrip::get)
.collect(Collectors.toList());
- var tripPattern = new TripPatternWithRaptorStopIndexes(
- stopIndexes(stopTimesFistTrip),
- new TripPattern(id("TP1"), this.route, new StopPattern(stopTimesFistTrip))
+ raptorTripPattern = new TripPatternWithRaptorStopIndexes(
+ new TripPattern(id("TP:"+route), this.route, new StopPattern(stopTimesFistTrip)),
+ stopIndexes(stopTimesFistTrip)
);
+ tripTimes.forEach(t -> raptorTripPattern.getPattern().add(t));
+
var listOfTripPatternForDates = List.of(
- new TripPatternForDate(tripPattern, tripTimes, DATE)
+ new TripPatternForDate(raptorTripPattern, tripTimes, DATE)
);
- var patternForDates = new TripPatternForDates(tripPattern, listOfTripPatternForDates, List.of(OFFSET));
+ var patternForDates = new TripPatternForDates(
+ raptorTripPattern, listOfTripPatternForDates, List.of(OFFSET)
+ );
for (Trip trip : trips) {
var tripSchedule = new TripScheduleWithOffset(
patternForDates, DATE, tripTimesByTrip.get(trip), OFFSET
@@ -75,32 +80,35 @@ private Trip parseTripInfo(String route, String tripTimes, List stops, Ded
return trip;
}
- Trip trip() {
+ public Trip trip() {
return currentTrip;
}
- TestRouteData firstTrip() {
+ public TestRouteData firstTrip() {
this.currentTrip = trips.get(0);
return this;
}
- TestRouteData lastTrip() {
+ public TestRouteData lastTrip() {
this.currentTrip = trips.get(trips.size()-1);
return this;
}
- StopTime getStopTime(Stop stop) {
+ public StopTime getStopTime(Stop stop) {
return stopTimesByTrip.get(currentTrip).get(stopPosition(stop));
}
- RaptorTimeTable getTimetable() {
+ public RaptorTimeTable getTimetable() {
return timetable;
}
- TripSchedule getTripSchedule() {
+ public TripSchedule getTripSchedule() {
return tripSchedulesByTrip.get(currentTrip);
}
+ public TripPatternWithRaptorStopIndexes getRaptorTripPattern() {
+ return raptorTripPattern;
+ }
private List getStopTimes() {
return stopTimesByTrip.get(currentTrip);
@@ -126,7 +134,7 @@ int[] stopIndexes(Collection times) {
return times.stream().mapToInt(it -> stopIndex(it.getStop())).toArray();
}
- int stopPosition(StopLocation stop) {
+ public int stopPosition(StopLocation stop) {
List times = firstTrip().getStopTimes();
for (int i=0; i