getStopsInRadius(
new Coordinate(maxLon, maxLat)
);
- var stops = transitService().findRegularStop(envelope);
+ var stops = transitService().findRegularStops(envelope);
return stops
.stream()
.filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
diff --git a/src/ext/java/org/opentripplanner/ext/restapi/resources/RequestToPreferencesMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/resources/RequestToPreferencesMapper.java
index bfac498ff8c..bf44da6be00 100644
--- a/src/ext/java/org/opentripplanner/ext/restapi/resources/RequestToPreferencesMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/restapi/resources/RequestToPreferencesMapper.java
@@ -89,8 +89,8 @@ private void mapBike() {
bike.withWalking(walk -> {
setIfNotNull(req.bikeWalkingSpeed, walk::withSpeed);
setIfNotNull(req.bikeWalkingReluctance, walk::withReluctance);
- setIfNotNull(req.bikeSwitchTime, walk::withHopTime);
- setIfNotNull(req.bikeSwitchCost, walk::withHopCost);
+ setIfNotNull(req.bikeSwitchTime, walk::withMountDismountTime);
+ setIfNotNull(req.bikeSwitchCost, walk::withMountDismountCost);
});
});
}
diff --git a/src/ext/java/org/opentripplanner/ext/stopconsolidation/DecorateConsolidatedStopNames.java b/src/ext/java/org/opentripplanner/ext/stopconsolidation/DecorateConsolidatedStopNames.java
index 8fcba82a357..a287e6a7d66 100644
--- a/src/ext/java/org/opentripplanner/ext/stopconsolidation/DecorateConsolidatedStopNames.java
+++ b/src/ext/java/org/opentripplanner/ext/stopconsolidation/DecorateConsolidatedStopNames.java
@@ -7,9 +7,9 @@
import org.opentripplanner.routing.algorithm.filterchain.framework.spi.ItineraryDecorator;
/**
- * A decorating filter that checks if a transit leg contains any primary stops and if it does,
- * then replaces it with the secondary, agency-specific stop name. This is so that the in-vehicle
- * display matches what OTP returns as a board/alight stop name.
+ * A decorating filter that checks if a transit leg contains any consolidated stops and if it does,
+ * then replaces it with the appropriate, agency-specific stop name. This is so that the physical
+ * signage and in-vehicle display matches what OTP returns as a board/alight stop name.
*/
public class DecorateConsolidatedStopNames implements ItineraryDecorator {
@@ -21,31 +21,45 @@ public DecorateConsolidatedStopNames(StopConsolidationService service) {
@Override
public void decorate(Itinerary itinerary) {
- replacePrimaryNamesWithSecondary(itinerary);
+ replaceConsolidatedStops(itinerary);
}
/**
- * If the itinerary has a from/to that is the primary stop of a {@link org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup}
- * then we replace its name with the secondary name of the agency that is
- * operating the route, so that the name in the result matches the name in the in-vehicle
- * display.
+ * If the itinerary has a "from" stop that is the secondary stop of a
+ * {@link org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup}
+ * then we replace its name with the primary name of the agency that is
+ * operating the route, so that the name in the result matches the physical signage on the stop.
+ *
+ * If the leg has a "to" stop that is a primary stop, then we don't want to show the stop that's on
+ * the signage but what is shown _inside_ the vehicle. That's why we use the agency-specific (aka
+ * secondary) stop.
+ *
+ * This follows the somewhat idiosyncratic logic of the consolidated stops feature.
*/
- private void replacePrimaryNamesWithSecondary(Itinerary i) {
+ private void replaceConsolidatedStops(Itinerary i) {
i.transformTransitLegs(leg -> {
if (leg instanceof ScheduledTransitLeg stl && needsToRenameStops(stl)) {
var agency = leg.getAgency();
- return new ConsolidatedStopLeg(
- stl,
- service.agencySpecificName(stl.getFrom().stop, agency),
- service.agencySpecificName(stl.getTo().stop, agency)
- );
+ // to show the name on the stop signage we use the primary stop's name
+ var from = service.primaryStop(stl.getFrom().stop.getId());
+ // to show the name that's on the display inside the vehicle we use the agency-specific name
+ var to = service.agencySpecificStop(stl.getTo().stop, agency);
+ return new ConsolidatedStopLeg(stl, from, to);
} else {
return leg;
}
});
}
+ /**
+ * Figures out if the from/to stops are part of a consolidated stop group and therefore
+ * some stops need to be replaced.
+ *
+ * Please consult the Javadoc of {@link DecorateConsolidatedStopNames#replaceConsolidatedStops(Itinerary)}
+ * for details of this idiosyncratic business logic and in particular why the logic is not the same
+ * for the from/to stops.
+ */
private boolean needsToRenameStops(ScheduledTransitLeg stl) {
- return (service.isPrimaryStop(stl.getFrom().stop) || service.isPrimaryStop(stl.getTo().stop));
+ return (service.isSecondaryStop(stl.getFrom().stop) || service.isPrimaryStop(stl.getTo().stop));
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationService.java b/src/ext/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationService.java
index 2418d8f5625..a829a905e27 100644
--- a/src/ext/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationService.java
+++ b/src/ext/java/org/opentripplanner/ext/stopconsolidation/StopConsolidationService.java
@@ -2,7 +2,6 @@
import java.util.List;
import org.opentripplanner.ext.stopconsolidation.model.StopReplacement;
-import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.organization.Agency;
import org.opentripplanner.transit.model.site.StopLocation;
@@ -24,13 +23,23 @@ public interface StopConsolidationService {
*/
boolean isPrimaryStop(StopLocation stop);
+ /**
+ * Is the given stop a secondary stop as defined by the stop consolidation configuration?
+ */
+ boolean isSecondaryStop(StopLocation stop);
+
/**
* Are any stop consolidations defined?
*/
boolean isActive();
/**
- * For a given primary stop look up the name as it was originally defined in the agency's feed.
+ * For a given primary stop look up secondary feed as it was originally defined in the agency's feed.
+ */
+ StopLocation agencySpecificStop(StopLocation stop, Agency agency);
+
+ /**
+ * For a given stop id return the primary stop if it is part of a consolidated stop group.
*/
- I18NString agencySpecificName(StopLocation stop, Agency agency);
+ StopLocation primaryStop(FeedScopedId id);
}
diff --git a/src/ext/java/org/opentripplanner/ext/stopconsolidation/internal/DefaultStopConsolidationService.java b/src/ext/java/org/opentripplanner/ext/stopconsolidation/internal/DefaultStopConsolidationService.java
index 54bd960d078..51a57028121 100644
--- a/src/ext/java/org/opentripplanner/ext/stopconsolidation/internal/DefaultStopConsolidationService.java
+++ b/src/ext/java/org/opentripplanner/ext/stopconsolidation/internal/DefaultStopConsolidationService.java
@@ -2,14 +2,15 @@
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.stream.Stream;
+import javax.annotation.Nonnull;
import org.opentripplanner.ext.stopconsolidation.StopConsolidationRepository;
import org.opentripplanner.ext.stopconsolidation.StopConsolidationService;
+import org.opentripplanner.ext.stopconsolidation.model.ConsolidatedStopGroup;
import org.opentripplanner.ext.stopconsolidation.model.StopReplacement;
-import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.organization.Agency;
-import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.service.TransitModel;
import org.slf4j.Logger;
@@ -61,26 +62,46 @@ public boolean isPrimaryStop(StopLocation stop) {
return repo.groups().stream().anyMatch(r -> r.primary().equals(stop.getId()));
}
+ @Override
+ public boolean isSecondaryStop(StopLocation stop) {
+ return repo.groups().stream().anyMatch(r -> r.secondaries().contains(stop.getId()));
+ }
+
@Override
public boolean isActive() {
return !repo.groups().isEmpty();
}
@Override
- public I18NString agencySpecificName(StopLocation stop, Agency agency) {
+ public StopLocation agencySpecificStop(StopLocation stop, Agency agency) {
if (agency.getId().getFeedId().equals(stop.getId().getFeedId())) {
- return stop.getName();
+ return stop;
} else {
- return repo
- .groups()
- .stream()
- .filter(r -> r.primary().equals(stop.getId()))
- .flatMap(g -> g.secondaries().stream())
- .filter(secondary -> secondary.getFeedId().equals(agency.getId().getFeedId()))
- .findAny()
- .map(id -> transitModel.getStopModel().getRegularStop(id))
- .map(RegularStop::getName)
- .orElseGet(stop::getName);
+ return findAgencySpecificStop(stop, agency).orElse(stop);
}
}
+
+ @Nonnull
+ private Optional findAgencySpecificStop(StopLocation stop, Agency agency) {
+ return repo
+ .groups()
+ .stream()
+ .filter(r -> r.primary().equals(stop.getId()))
+ .flatMap(g -> g.secondaries().stream())
+ .filter(secondary -> secondary.getFeedId().equals(agency.getId().getFeedId()))
+ .findAny()
+ .map(id -> transitModel.getStopModel().getRegularStop(id));
+ }
+
+ @Override
+ public StopLocation primaryStop(FeedScopedId id) {
+ var primaryId = repo
+ .groups()
+ .stream()
+ .filter(g -> g.secondaries().contains(id))
+ .map(ConsolidatedStopGroup::primary)
+ .findAny()
+ .orElse(id);
+ return transitModel.getStopModel().getRegularStop(primaryId);
+ }
}
diff --git a/src/ext/java/org/opentripplanner/ext/stopconsolidation/model/ConsolidatedStopLeg.java b/src/ext/java/org/opentripplanner/ext/stopconsolidation/model/ConsolidatedStopLeg.java
index e201c7ed805..39f06bd6347 100644
--- a/src/ext/java/org/opentripplanner/ext/stopconsolidation/model/ConsolidatedStopLeg.java
+++ b/src/ext/java/org/opentripplanner/ext/stopconsolidation/model/ConsolidatedStopLeg.java
@@ -1,28 +1,28 @@
package org.opentripplanner.ext.stopconsolidation.model;
-import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.model.plan.Place;
import org.opentripplanner.model.plan.ScheduledTransitLeg;
import org.opentripplanner.model.plan.ScheduledTransitLegBuilder;
+import org.opentripplanner.transit.model.site.StopLocation;
public class ConsolidatedStopLeg extends ScheduledTransitLeg {
- private final I18NString fromName;
- private final I18NString toName;
+ private final StopLocation from;
+ private final StopLocation to;
- public ConsolidatedStopLeg(ScheduledTransitLeg original, I18NString fromName, I18NString toName) {
+ public ConsolidatedStopLeg(ScheduledTransitLeg original, StopLocation from, StopLocation to) {
super(new ScheduledTransitLegBuilder<>(original));
- this.fromName = fromName;
- this.toName = toName;
+ this.from = from;
+ this.to = to;
}
@Override
public Place getFrom() {
- return Place.forStop(super.getFrom().stop, fromName);
+ return Place.forStop(from);
}
@Override
public Place getTo() {
- return Place.forStop(super.getTo().stop, toName);
+ return Place.forStop(to);
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
index 6d15816669e..2ad85587fe5 100644
--- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
+++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerBuilder.java
@@ -37,7 +37,7 @@ public StopsLayerBuilder(
protected List getGeometries(Envelope query) {
return transitService
- .findRegularStop(query)
+ .findRegularStops(query)
.stream()
.map(stop -> {
Geometry point = stop.getGeometry();
diff --git a/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/BikeToStopSkipEdgeStrategy.java b/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/BikeToStopSkipEdgeStrategy.java
deleted file mode 100644
index ad503b1212d..00000000000
--- a/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/BikeToStopSkipEdgeStrategy.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.opentripplanner.ext.vehicletostopheuristics;
-
-import java.util.Collection;
-import java.util.function.Function;
-import org.opentripplanner.astar.spi.SkipEdgeStrategy;
-import org.opentripplanner.street.model.edge.Edge;
-import org.opentripplanner.street.model.vertex.TransitStopVertex;
-import org.opentripplanner.street.search.state.State;
-import org.opentripplanner.transit.model.network.BikeAccess;
-import org.opentripplanner.transit.model.site.RegularStop;
-import org.opentripplanner.transit.model.timetable.Trip;
-
-/**
- * When wanting to take a bike onto transit we want to improve the performance by limiting the
- * number of accesses to those stops which actually have trips where you can take the bike on. Once
- * we have reached enough of trips we skip all further edges.
- */
-public class BikeToStopSkipEdgeStrategy implements SkipEdgeStrategy {
-
- private static final int LIMIT = 100;
- private static final double MAX_FACTOR = 1.2;
-
- private final Function> getTripsForStop;
-
- int numberOfBikeableTripsReached = 0;
- double distanceLimit = Double.MAX_VALUE;
-
- public BikeToStopSkipEdgeStrategy(Function> getTripsForStop) {
- this.getTripsForStop = getTripsForStop;
- }
-
- public static boolean bikeAccessForTrip(Trip trip) {
- if (trip.getBikesAllowed() != BikeAccess.UNKNOWN) {
- return trip.getBikesAllowed() == BikeAccess.ALLOWED;
- }
-
- return trip.getRoute().getBikesAllowed() == BikeAccess.ALLOWED;
- }
-
- @Override
- public boolean shouldSkipEdge(State current, Edge edge) {
- if (
- current.getVertex() instanceof TransitStopVertex stopVertex &&
- distanceLimit == Double.MAX_VALUE
- ) {
- numberOfBikeableTripsReached +=
- getTripsForStop
- .apply(stopVertex.getStop())
- .stream()
- .filter(BikeToStopSkipEdgeStrategy::bikeAccessForTrip)
- .count();
- if (numberOfBikeableTripsReached >= LIMIT) {
- distanceLimit = current.getWalkDistance() * MAX_FACTOR;
- }
- }
- return current.getWalkDistance() > distanceLimit;
- }
-}
diff --git a/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/VehicleToStopSkipEdgeStrategy.java b/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/VehicleToStopSkipEdgeStrategy.java
deleted file mode 100644
index 3eb466f97b9..00000000000
--- a/src/ext/java/org/opentripplanner/ext/vehicletostopheuristics/VehicleToStopSkipEdgeStrategy.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.opentripplanner.ext.vehicletostopheuristics;
-
-import static org.opentripplanner.routing.api.request.StreetMode.BIKE_RENTAL;
-import static org.opentripplanner.routing.api.request.StreetMode.BIKE_TO_PARK;
-import static org.opentripplanner.routing.api.request.StreetMode.CAR_HAILING;
-import static org.opentripplanner.routing.api.request.StreetMode.CAR_PICKUP;
-import static org.opentripplanner.routing.api.request.StreetMode.CAR_RENTAL;
-import static org.opentripplanner.routing.api.request.StreetMode.CAR_TO_PARK;
-import static org.opentripplanner.routing.api.request.StreetMode.SCOOTER_RENTAL;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-import org.opentripplanner.astar.spi.SkipEdgeStrategy;
-import org.opentripplanner.routing.api.request.StreetMode;
-import org.opentripplanner.routing.api.request.request.filter.TransitFilter;
-import org.opentripplanner.street.model.edge.Edge;
-import org.opentripplanner.street.model.vertex.TransitStopVertex;
-import org.opentripplanner.street.search.state.State;
-import org.opentripplanner.transit.model.basic.TransitMode;
-import org.opentripplanner.transit.model.framework.FeedScopedId;
-import org.opentripplanner.transit.model.network.TripPattern;
-import org.opentripplanner.transit.model.site.RegularStop;
-
-/**
- * This strategy terminates when enough "important" stops are found.
- *
- * The definition of important is a stop where many routes of mode RAIL, SUBWAY or FERRY depart.
- *
- * This means that the search radius scales with density of "important" stops:
- *
- *
in a city the radius is quite small
- * in more rural regions the radius is bigger and stops further away are considered
- *
- * The strategy is useful when you want to limit the number of accesses of Park+Ride, Bike+Ride and
- * Bike+Transit: it improves both performance the quality of results.
- *
- * {@see https://github.com/opentripplanner/OpenTripPlanner/pull/3906}
- */
-public class VehicleToStopSkipEdgeStrategy implements SkipEdgeStrategy {
-
- public static final Set applicableModes = Set.of(
- BIKE_TO_PARK,
- BIKE_RENTAL,
- CAR_TO_PARK,
- CAR_PICKUP,
- CAR_HAILING,
- CAR_RENTAL,
- SCOOTER_RENTAL
- );
- private final Function> getPatternsForStop;
- private final int maxScore;
- private final List filters;
- private double sumOfScores;
-
- private final Set stopsCounted = new HashSet<>();
-
- public VehicleToStopSkipEdgeStrategy(
- Function> getPatternsForStop,
- Collection filters
- ) {
- this.filters = new ArrayList<>(filters);
- this.maxScore = 300;
- this.getPatternsForStop = getPatternsForStop;
- }
-
- @Override
- public boolean shouldSkipEdge(State current, Edge edge) {
- if (current.currentMode().isWalking()) {
- if (
- current.getVertex() instanceof TransitStopVertex stopVertex &&
- !stopsCounted.contains(stopVertex.getStop().getId())
- ) {
- // TODO: 2022-12-05 filters: check performance on that and verify that this is right. Previously we were filtering just on modes
- var stop = stopVertex.getStop();
-
- // Not using streams. Performance is important here
- var patterns = getPatternsForStop.apply(stop);
- var score = 0;
- for (var pattern : patterns) {
- for (var filter : filters) {
- if (filter.matchTripPattern(pattern)) {
- score += VehicleToStopSkipEdgeStrategy.score(pattern.getMode());
- break;
- }
- }
- }
-
- stopsCounted.add(stop.getId());
-
- sumOfScores = sumOfScores + score;
- }
- return false;
- } else {
- return sumOfScores >= maxScore;
- }
- }
-
- private static int score(TransitMode mode) {
- return switch (mode) {
- case RAIL, FERRY, SUBWAY -> 20;
- case BUS -> 1;
- default -> 2;
- };
- }
-}
diff --git a/src/main/java/org/opentripplanner/apis/APIEndpoints.java b/src/main/java/org/opentripplanner/apis/APIEndpoints.java
index 959815f1716..b6b70eb238e 100644
--- a/src/main/java/org/opentripplanner/apis/APIEndpoints.java
+++ b/src/main/java/org/opentripplanner/apis/APIEndpoints.java
@@ -63,6 +63,8 @@ private APIEndpoints() {
addIfEnabled(SandboxAPIMapboxVectorTilesApi, VectorTilesResource.class);
addIfEnabled(SandboxAPIParkAndRideApi, ParkAndRideResource.class);
addIfEnabled(SandboxAPIGeocoder, GeocoderResource.class);
+ // scheduled to be removed and only here for backwards compatibility
+ addIfEnabled(SandboxAPIGeocoder, GeocoderResource.GeocoderResourceOldPath.class);
addIfEnabled(SandboxAPITravelTime, TravelTimeResource.class);
// scheduled to be removed
diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
index d749987384c..a4f5cb00e2f 100644
--- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
+++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java
@@ -21,7 +21,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.locationtech.jts.geom.Coordinate;
@@ -710,7 +709,7 @@ public DataFetcher> stopsByBbox() {
);
Stream stopStream = getTransitService(environment)
- .findRegularStop(envelope)
+ .findRegularStops(envelope)
.stream()
.filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()));
diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/package.json b/src/main/java/org/opentripplanner/apis/gtfs/generated/package.json
index 6a2eb3343b9..db865eaa003 100644
--- a/src/main/java/org/opentripplanner/apis/gtfs/generated/package.json
+++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/package.json
@@ -10,8 +10,8 @@
},
"license": "LGPL-3.0",
"dependencies": {
- "@graphql-codegen/add": "5.0.0",
- "@graphql-codegen/cli": "5.0.0",
+ "@graphql-codegen/add": "5.0.2",
+ "@graphql-codegen/cli": "5.0.2",
"@graphql-codegen/java": "4.0.0",
"@graphql-codegen/java-resolvers": "3.0.0",
"graphql": "16.8.1"
diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/yarn.lock b/src/main/java/org/opentripplanner/apis/gtfs/generated/yarn.lock
index 7e3c815cfb1..fffe602db18 100644
--- a/src/main/java/org/opentripplanner/apis/gtfs/generated/yarn.lock
+++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/yarn.lock
@@ -264,7 +264,7 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
-"@babel/helper-plugin-utils@^7.22.5":
+"@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
@@ -699,24 +699,25 @@
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
-"@graphql-codegen/add@5.0.0":
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-5.0.0.tgz#578ebaf4fa87c1e934c381cd679bcedcf79feaba"
- integrity sha512-ynWDOsK2yxtFHwcJTB9shoSkUd7YXd6ZE57f0nk7W5cu/nAgxZZpEsnTPEpZB/Mjf14YRGe2uJHQ7AfElHjqUQ==
+"@graphql-codegen/add@5.0.2", "@graphql-codegen/add@^5.0.2":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-5.0.2.tgz#71b3ae0465a4537172dddb84531b6967ca5545f2"
+ integrity sha512-ouBkSvMFUhda5VoKumo/ZvsZM9P5ZTyDsI8LW18VxSNWOjrTeLXBWHG8Gfaai0HwhflPtCYVABbriEcOmrRShQ==
dependencies:
- "@graphql-codegen/plugin-helpers" "^5.0.0"
- tslib "~2.5.0"
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ tslib "~2.6.0"
-"@graphql-codegen/cli@5.0.0":
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-5.0.0.tgz#761dcf08cfee88bbdd9cdf8097b2343445ec6f0a"
- integrity sha512-A7J7+be/a6e+/ul2KI5sfJlpoqeqwX8EzktaKCeduyVKgOLA6W5t+NUGf6QumBDXU8PEOqXk3o3F+RAwCWOiqA==
+"@graphql-codegen/cli@5.0.2":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-5.0.2.tgz#07ff691c16da4c3dcc0e1995d3231530379ab317"
+ integrity sha512-MBIaFqDiLKuO4ojN6xxG9/xL9wmfD3ZjZ7RsPjwQnSHBCUXnEkdKvX+JVpx87Pq29Ycn8wTJUguXnTZ7Di0Mlw==
dependencies:
"@babel/generator" "^7.18.13"
"@babel/template" "^7.18.10"
"@babel/types" "^7.18.13"
- "@graphql-codegen/core" "^4.0.0"
- "@graphql-codegen/plugin-helpers" "^5.0.1"
+ "@graphql-codegen/client-preset" "^4.2.2"
+ "@graphql-codegen/core" "^4.0.2"
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
"@graphql-tools/apollo-engine-loader" "^8.0.0"
"@graphql-tools/code-file-loader" "^8.0.0"
"@graphql-tools/git-loader" "^8.0.0"
@@ -747,15 +748,45 @@
yaml "^2.3.1"
yargs "^17.0.0"
-"@graphql-codegen/core@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-4.0.0.tgz#b29c911746a532a675e33720acb4eb2119823e01"
- integrity sha512-JAGRn49lEtSsZVxeIlFVIRxts2lWObR+OQo7V2LHDJ7ohYYw3ilv7nJ8pf8P4GTg/w6ptcYdSdVVdkI8kUHB/Q==
+"@graphql-codegen/client-preset@^4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/client-preset/-/client-preset-4.2.2.tgz#545c62789a5687bee5df8b4738b4911e72ea8051"
+ integrity sha512-DF9pNWj3TEdA90E9FH5SsUIqiZfr872vqaQOspLVuVXGsaDx8F/JLLzaN+7ucmoo0ff/bLW8munVXYXTmgwwEA==
dependencies:
- "@graphql-codegen/plugin-helpers" "^5.0.0"
+ "@babel/helper-plugin-utils" "^7.20.2"
+ "@babel/template" "^7.20.7"
+ "@graphql-codegen/add" "^5.0.2"
+ "@graphql-codegen/gql-tag-operations" "4.0.4"
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-codegen/typed-document-node" "^5.0.4"
+ "@graphql-codegen/typescript" "^4.0.4"
+ "@graphql-codegen/typescript-operations" "^4.1.2"
+ "@graphql-codegen/visitor-plugin-common" "^4.1.2"
+ "@graphql-tools/documents" "^1.0.0"
+ "@graphql-tools/utils" "^10.0.0"
+ "@graphql-typed-document-node/core" "3.2.0"
+ tslib "~2.6.0"
+
+"@graphql-codegen/core@^4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-4.0.2.tgz#7e6ec266276f54bbf02f60599d9e518f4a59d85e"
+ integrity sha512-IZbpkhwVqgizcjNiaVzNAzm/xbWT6YnGgeOLwVjm4KbJn3V2jchVtuzHH09G5/WkkLSk2wgbXNdwjM41JxO6Eg==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
"@graphql-tools/schema" "^10.0.0"
"@graphql-tools/utils" "^10.0.0"
- tslib "~2.5.0"
+ tslib "~2.6.0"
+
+"@graphql-codegen/gql-tag-operations@4.0.4":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.4.tgz#572be5db804af5efdc3ca24e4bcac815448730c5"
+ integrity sha512-dypul0iDLjb07yv+/cRb6qPbn42cFPcwlsJertVl9G6qkS4+3V4806WwSfUht4QVMWnvGfgDkJJqG0yUVKOHwA==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-codegen/visitor-plugin-common" "4.1.2"
+ "@graphql-tools/utils" "^10.0.0"
+ auto-bind "~4.0.0"
+ tslib "~2.6.0"
"@graphql-codegen/java-common@^3.0.0":
version "3.0.0"
@@ -813,29 +844,59 @@
lodash "~4.17.0"
tslib "~2.4.0"
-"@graphql-codegen/plugin-helpers@^5.0.0":
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.0.tgz#40c18217454af5cf8317e5f46cf4d38e8cc78ae4"
- integrity sha512-suL2ZMkBAU2a4YbBHaZvUPsV1z0q3cW6S96Z/eYYfkRIsJoe2vN+wNZ9Xdzmqx0JLmeeFCBSoBGC0imFyXlkDQ==
+"@graphql-codegen/plugin-helpers@^5.0.3":
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.3.tgz#7027b9d911d7cb594663590fcf5d63e9cf7ec2ff"
+ integrity sha512-yZ1rpULIWKBZqCDlvGIJRSyj1B2utkEdGmXZTBT/GVayP4hyRYlkd36AJV/LfEsVD8dnsKL5rLz2VTYmRNlJ5Q==
dependencies:
"@graphql-tools/utils" "^10.0.0"
change-case-all "1.0.15"
common-tags "1.8.2"
import-from "4.0.0"
lodash "~4.17.0"
- tslib "~2.5.0"
+ tslib "~2.6.0"
-"@graphql-codegen/plugin-helpers@^5.0.1":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.1.tgz#e2429fcfba3f078d5aa18aa062d46c922bbb0d55"
- integrity sha512-6L5sb9D8wptZhnhLLBcheSPU7Tg//DGWgc5tQBWX46KYTOTQHGqDpv50FxAJJOyFVJrveN9otWk9UT9/yfY4ww==
+"@graphql-codegen/schema-ast@^4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-4.0.2.tgz#aeaa104e4555cca73a058f0a9350b4b0e290b377"
+ integrity sha512-5mVAOQQK3Oz7EtMl/l3vOQdc2aYClUzVDHHkMvZlunc+KlGgl81j8TLa+X7ANIllqU4fUEsQU3lJmk4hXP6K7Q==
dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
"@graphql-tools/utils" "^10.0.0"
+ tslib "~2.6.0"
+
+"@graphql-codegen/typed-document-node@^5.0.4":
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.4.tgz#06e286caacdd66c3566f98433dcb8f1a9c9a9f1d"
+ integrity sha512-t66Z6erQ4Dh1j6f9pRZmc8uYtHoUI3A49tLmJAlg9/3IV0kCmwrWKJut/G8SeOefDLG8cXBTVtI/YuZOe1Te+w==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-codegen/visitor-plugin-common" "4.1.2"
+ auto-bind "~4.0.0"
change-case-all "1.0.15"
- common-tags "1.8.2"
- import-from "4.0.0"
- lodash "~4.17.0"
- tslib "~2.5.0"
+ tslib "~2.6.0"
+
+"@graphql-codegen/typescript-operations@^4.1.2":
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-4.1.2.tgz#a0f455ae19e16961e5870420ca7515bbe51b5568"
+ integrity sha512-CtCWK+gW7hS+Ely3lohr8CL1HVLswQzMcaUk3k1sxdWCWKTNq7abMsWa31rTVwRCJ+WNEkM/7S8sIBTpEG683A==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-codegen/typescript" "^4.0.4"
+ "@graphql-codegen/visitor-plugin-common" "4.1.2"
+ auto-bind "~4.0.0"
+ tslib "~2.6.0"
+
+"@graphql-codegen/typescript@^4.0.4":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-4.0.4.tgz#e791c61f675ae454951ea077b0ae519ae352cc3e"
+ integrity sha512-x79CKLfP9UQCX+/I78qxQlMs2Mmq3pF1lKafZo7lAno0f/fvJ+qWUduzdgjRNz+YL+5blGeWcC0pWEDxniO7hw==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-codegen/schema-ast" "^4.0.2"
+ "@graphql-codegen/visitor-plugin-common" "4.1.2"
+ auto-bind "~4.0.0"
+ tslib "~2.6.0"
"@graphql-codegen/visitor-plugin-common@2.13.1":
version "2.13.1"
@@ -853,6 +914,22 @@
parse-filepath "^1.0.2"
tslib "~2.4.0"
+"@graphql-codegen/visitor-plugin-common@4.1.2", "@graphql-codegen/visitor-plugin-common@^4.1.2":
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.1.2.tgz#674c5d5813f6c00dd65e1ee148a62536879e65e2"
+ integrity sha512-yk7iEAL1kYZ2Gi/pvVjdsZhul5WsYEM4Zcgh2Ev15VicMdJmPHsMhNUsZWyVJV0CaQCYpNOFlGD/11Ea3pn4GA==
+ dependencies:
+ "@graphql-codegen/plugin-helpers" "^5.0.3"
+ "@graphql-tools/optimize" "^2.0.0"
+ "@graphql-tools/relay-operation-optimizer" "^7.0.0"
+ "@graphql-tools/utils" "^10.0.0"
+ auto-bind "~4.0.0"
+ change-case-all "1.0.15"
+ dependency-graph "^0.11.0"
+ graphql-tag "^2.11.0"
+ parse-filepath "^1.0.2"
+ tslib "~2.6.0"
+
"@graphql-tools/apollo-engine-loader@^8.0.0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489"
@@ -897,6 +974,14 @@
tslib "^2.5.0"
value-or-promise "^1.0.12"
+"@graphql-tools/documents@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@graphql-tools/documents/-/documents-1.0.0.tgz#e3ed97197cc22ec830ca227fd7d17e86d8424bdf"
+ integrity sha512-rHGjX1vg/nZ2DKqRGfDPNC55CWZBMldEVcH+91BThRa6JeT80NqXknffLLEZLRUxyikCfkwMsk6xR3UNMqG0Rg==
+ dependencies:
+ lodash.sortby "^4.7.0"
+ tslib "^2.4.0"
+
"@graphql-tools/executor-graphql-ws@^1.0.0":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.0.2.tgz#29890f9370c5bebd4a2380e29904f8eaf9f013ca"
@@ -1036,6 +1121,13 @@
dependencies:
tslib "^2.4.0"
+"@graphql-tools/optimize@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-2.0.0.tgz#7a9779d180824511248a50c5a241eff6e7a2d906"
+ integrity sha512-nhdT+CRGDZ+bk68ic+Jw1OZ99YCDIKYA5AlVAnBHJvMawSx9YQqQAIj4refNc1/LRieGiuWvhbG3jvPVYho0Dg==
+ dependencies:
+ tslib "^2.4.0"
+
"@graphql-tools/prisma-loader@^8.0.0":
version "8.0.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/prisma-loader/-/prisma-loader-8.0.1.tgz#0a013c69b04e0779b5be15757173d458cdf94e35"
@@ -1069,6 +1161,15 @@
"@graphql-tools/utils" "9.1.1"
tslib "^2.4.0"
+"@graphql-tools/relay-operation-optimizer@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.0.tgz#24367666af87bc5a81748de5e8e9b3c523fd4207"
+ integrity sha512-UNlJi5y3JylhVWU4MBpL0Hun4Q7IoJwv9xYtmAz+CgRa066szzY7dcuPfxrA7cIGgG/Q6TVsKsYaiF4OHPs1Fw==
+ dependencies:
+ "@ardatan/relay-compiler" "12.0.0"
+ "@graphql-tools/utils" "^10.0.0"
+ tslib "^2.4.0"
+
"@graphql-tools/schema@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.0.tgz#7b5f6b6a59f51c927de8c9069bde4ebbfefc64b3"
@@ -2374,6 +2475,11 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
+lodash.sortby@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+ integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==
+
lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@@ -3049,7 +3155,7 @@ ts-log@^2.2.3:
resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.3.tgz#4da5640fe25a9fb52642cd32391c886721318efb"
integrity sha512-XvB+OdKSJ708Dmf9ore4Uf/q62AYDTzFcAdxc8KNML1mmAWywRFVt/dn1KYJH8Agt5UJNujfM3znU5PxgAzA2w==
-tslib@^2.0.0, tslib@^2.3.1, tslib@^2.4.1, tslib@~2.5.0:
+tslib@^2.0.0, tslib@^2.3.1, tslib@^2.4.1:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java
index 212bfbcf380..5bc00cb7a85 100644
--- a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java
+++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java
@@ -340,8 +340,8 @@ private static void setVehicleWalkingPreferences(
) {
callWith.argument("bikeWalkingReluctance", walking::withReluctance);
callWith.argument("bikeWalkingSpeed", walking::withSpeed);
- callWith.argument("bikeSwitchTime", time -> walking.withHopTime((int) time));
- callWith.argument("bikeSwitchCost", cost -> walking.withHopCost((int) cost));
+ callWith.argument("bikeSwitchTime", time -> walking.withMountDismountTime((int) time));
+ callWith.argument("bikeSwitchCost", cost -> walking.withMountDismountCost((int) cost));
}
private static class CallerWithEnvironment {
diff --git a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
index 00bf98c703f..638d7783e9a 100644
--- a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
+++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java
@@ -687,7 +687,7 @@ private GraphQLSchema create() {
);
return GqlUtil
.getTransitService(environment)
- .findRegularStop(envelope)
+ .findRegularStops(envelope)
.stream()
.filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
.filter(stop ->
diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
index accaf1e35fb..d178e5125b5 100644
--- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
+++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java
@@ -531,7 +531,7 @@ public static Collection fetchStopPlaces(
);
Stream stations = transitService
- .findRegularStop(envelope)
+ .findRegularStops(envelope)
.stream()
.filter(stop -> envelope.contains(stop.getCoordinate().asJtsCoordinate()))
.map(StopLocation::getParentStation)
diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
index 03f4357e540..dc6ba627e0e 100644
--- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
+++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java
@@ -179,7 +179,7 @@ private static LayerBuilder> createLayerBuilder(
case RegularStop -> new StopLayerBuilder<>(
layerParameters,
locale,
- e -> context.transitService().findRegularStop(e)
+ e -> context.transitService().findRegularStops(e)
);
case AreaStop -> new StopLayerBuilder<>(
layerParameters,
diff --git a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
index 4847b204077..4ae5004cf6b 100644
--- a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
+++ b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java
@@ -105,8 +105,7 @@ public enum OTPFeature {
SandboxAPIMapboxVectorTilesApi(false, true, "Enable Mapbox vector tiles API."),
SandboxAPIParkAndRideApi(false, true, "Enable park-and-ride endpoint."),
SandboxAPITravelTime(false, true, "Enable the isochrone/travel time surface API."),
- TransferAnalyzer(false, true, "Analyze transfers during graph build."),
- VehicleToStopHeuristics(false, true, "Enable improved heuristic for park-and-ride queries.");
+ TransferAnalyzer(false, true, "Analyze transfers during graph build.");
private static final Object TEST_LOCK = new Object();
diff --git a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java
index c726d03c66c..cbb32b9eaca 100644
--- a/src/main/java/org/opentripplanner/framework/lang/StringUtils.java
+++ b/src/main/java/org/opentripplanner/framework/lang/StringUtils.java
@@ -110,4 +110,13 @@ public static String padRight(String value, char ch, int width) {
public static String quoteReplace(@Nonnull String text) {
return text.replace('\'', '\"');
}
+
+ /**
+ * Convert "HELLO_WORLD" or "HellO_WorlD" to "hello-world".
+ *
+ * https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case
+ */
+ public static String kebabCase(String input) {
+ return input.toLowerCase().replace('_', '-');
+ }
}
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
index 360cdaee363..7386b60b452 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java
@@ -18,8 +18,6 @@
import org.opentripplanner.astar.strategy.MaxCountSkipEdgeStrategy;
import org.opentripplanner.ext.dataoverlay.routing.DataOverlayContext;
import org.opentripplanner.ext.flex.trip.FlexTrip;
-import org.opentripplanner.ext.vehicletostopheuristics.BikeToStopSkipEdgeStrategy;
-import org.opentripplanner.ext.vehicletostopheuristics.VehicleToStopSkipEdgeStrategy;
import org.opentripplanner.framework.application.OTPFeature;
import org.opentripplanner.framework.application.OTPRequestTimeoutException;
import org.opentripplanner.routing.api.request.RouteRequest;
@@ -85,7 +83,7 @@ public NearbyStopFinder(
// We need to accommodate straight line distance (in meters) but when streets are present we
// use an earliest arrival search, which optimizes on time. Ideally we'd specify in meters,
// but we don't have much of a choice here. Use the default walking speed to convert.
- this.directGraphFinder = new DirectGraphFinder(transitService::findRegularStop);
+ this.directGraphFinder = new DirectGraphFinder(transitService::findRegularStops);
}
}
@@ -205,7 +203,7 @@ public List findNearbyStopsViaStreets(
ShortestPathTree spt = StreetSearchBuilder
.of()
- .setSkipEdgeStrategy(getSkipEdgeStrategy(reverseDirection, request))
+ .setSkipEdgeStrategy(getSkipEdgeStrategy())
.setDominanceFunction(new DominanceFunctions.MinimumWeight())
.setRequest(request)
.setArriveBy(reverseDirection)
@@ -271,48 +269,14 @@ private List findNearbyStopsViaDirectTransfers(Vertex vertex) {
return directGraphFinder.findClosestStops(c0, limitMeters);
}
- private SkipEdgeStrategy getSkipEdgeStrategy(
- boolean reverseDirection,
- RouteRequest routingRequest
- ) {
+ private SkipEdgeStrategy getSkipEdgeStrategy() {
var durationSkipEdgeStrategy = new DurationSkipEdgeStrategy(durationLimit);
- // if we compute the accesses for Park+Ride, Bike+Ride and Bike+Transit we don't want to
- // search the full durationLimit as this returns way too many stops.
- // this is both slow and returns suboptimal results as it favours long drives with short
- // transit legs.
- // therefore, we use a heuristic based on the number of routes and their mode to determine
- // what are "good" stops for those accesses. if we have reached a threshold of "good" stops
- // we stop the access search.
- if (
- !reverseDirection &&
- OTPFeature.VehicleToStopHeuristics.isOn() &&
- VehicleToStopSkipEdgeStrategy.applicableModes.contains(
- routingRequest.journey().access().mode()
- )
- ) {
- var strategy = new VehicleToStopSkipEdgeStrategy(
- transitService::getPatternsForStop,
- routingRequest.journey().transit().filters()
- );
-
+ if (maxStopCount > 0) {
+ var strategy = new MaxCountSkipEdgeStrategy<>(maxStopCount, NearbyStopFinder::hasReachedStop);
return new ComposingSkipEdgeStrategy<>(strategy, durationSkipEdgeStrategy);
- } else if (
- OTPFeature.VehicleToStopHeuristics.isOn() &&
- routingRequest.journey().access().mode() == StreetMode.BIKE
- ) {
- var strategy = new BikeToStopSkipEdgeStrategy(transitService::getTripsForStop);
- return new ComposingSkipEdgeStrategy<>(strategy, durationSkipEdgeStrategy);
- } else {
- if (maxStopCount > 0) {
- var strategy = new MaxCountSkipEdgeStrategy<>(
- maxStopCount,
- NearbyStopFinder::hasReachedStop
- );
- return new ComposingSkipEdgeStrategy<>(strategy, durationSkipEdgeStrategy);
- }
- return durationSkipEdgeStrategy;
}
+ return durationSkipEdgeStrategy;
}
private static List createDirectlyConnectedStops(
diff --git a/src/main/java/org/opentripplanner/model/plan/Place.java b/src/main/java/org/opentripplanner/model/plan/Place.java
index 71c6d9bc188..fe3a9dee420 100644
--- a/src/main/java/org/opentripplanner/model/plan/Place.java
+++ b/src/main/java/org/opentripplanner/model/plan/Place.java
@@ -90,11 +90,7 @@ public static Place normal(Vertex vertex, I18NString name) {
}
public static Place forStop(StopLocation stop) {
- return forStop(stop, stop.getName());
- }
-
- public static Place forStop(StopLocation stop, I18NString nameOverride) {
- return new Place(nameOverride, stop.getCoordinate(), VertexType.TRANSIT, stop, null, null);
+ return new Place(stop.getName(), stop.getCoordinate(), VertexType.TRANSIT, stop, null, null);
}
public static Place forFlexStop(StopLocation stop, Vertex vertex) {
diff --git a/src/main/java/org/opentripplanner/routing/api/request/framework/TimeAndCostPenaltyForEnum.java b/src/main/java/org/opentripplanner/routing/api/request/framework/TimeAndCostPenaltyForEnum.java
index 60bd4d4c769..c45fc3e33a8 100644
--- a/src/main/java/org/opentripplanner/routing/api/request/framework/TimeAndCostPenaltyForEnum.java
+++ b/src/main/java/org/opentripplanner/routing/api/request/framework/TimeAndCostPenaltyForEnum.java
@@ -81,6 +81,13 @@ private EnumMap copyValues() {
return values.isEmpty() ? new EnumMap<>(type) : new EnumMap<>(values);
}
+ /**
+ * Convert the values to an {@link EnumMap}.
+ */
+ public EnumMap asEnumMap() {
+ return copyValues();
+ }
+
private static > String toString(
Class> clazz,
Map values
diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/AccessEgressPreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/AccessEgressPreferences.java
index db8845e7c41..ada495b19ba 100644
--- a/src/main/java/org/opentripplanner/routing/api/request/preference/AccessEgressPreferences.java
+++ b/src/main/java/org/opentripplanner/routing/api/request/preference/AccessEgressPreferences.java
@@ -7,12 +7,12 @@
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
-import org.opentripplanner.framework.model.Units;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.api.request.framework.DurationForEnum;
import org.opentripplanner.routing.api.request.framework.TimeAndCostPenalty;
import org.opentripplanner.routing.api.request.framework.TimeAndCostPenaltyForEnum;
+import org.opentripplanner.routing.api.request.framework.TimePenalty;
/**
* Preferences for access/egress routing on street network
@@ -21,14 +21,27 @@
*/
public final class AccessEgressPreferences implements Serializable {
+ private static final TimeAndCostPenalty DEFAULT_PENALTY = TimeAndCostPenalty.of(
+ TimePenalty.of(ofMinutes(20), 2f),
+ 1.5
+ );
+ private static final TimeAndCostPenaltyForEnum DEFAULT_TIME_AND_COST = TimeAndCostPenaltyForEnum
+ .of(StreetMode.class)
+ .with(StreetMode.CAR_TO_PARK, DEFAULT_PENALTY)
+ .with(StreetMode.CAR_HAILING, DEFAULT_PENALTY)
+ .with(StreetMode.CAR_RENTAL, DEFAULT_PENALTY)
+ .with(StreetMode.FLEXIBLE, DEFAULT_PENALTY)
+ .build();
+
public static final AccessEgressPreferences DEFAULT = new AccessEgressPreferences();
+
private final TimeAndCostPenaltyForEnum penalty;
private final DurationForEnum maxDuration;
private final int maxStopCount;
private AccessEgressPreferences() {
this.maxDuration = durationForStreetModeOf(ofMinutes(45));
- this.penalty = TimeAndCostPenaltyForEnum.ofDefault(StreetMode.class);
+ this.penalty = DEFAULT_TIME_AND_COST;
this.maxStopCount = 500;
}
diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferences.java
index aa3631e1c6b..b7adc04df1c 100644
--- a/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferences.java
+++ b/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferences.java
@@ -19,15 +19,15 @@ public class VehicleWalkingPreferences implements Serializable {
private final double speed;
private final double reluctance;
- private final Duration hopTime;
- private final Cost hopCost;
+ private final Duration mountDismountTime;
+ private final Cost mountDismountCost;
private final double stairsReluctance;
private VehicleWalkingPreferences() {
this.speed = 1.33;
this.reluctance = 5.0;
- this.hopTime = Duration.ZERO;
- this.hopCost = Cost.ZERO;
+ this.mountDismountTime = Duration.ZERO;
+ this.mountDismountCost = Cost.ZERO;
// very high reluctance to carry the bike up/down a flight of stairs
this.stairsReluctance = 10;
}
@@ -39,8 +39,8 @@ private VehicleWalkingPreferences() {
private VehicleWalkingPreferences(Builder builder) {
this.speed = Units.speed(builder.speed);
this.reluctance = Units.reluctance(builder.reluctance);
- this.hopTime = Duration.ofSeconds(Units.duration(builder.hopTime));
- this.hopCost = Cost.costOfSeconds(builder.hopCost);
+ this.mountDismountTime = Duration.ofSeconds(Units.duration(builder.mountDismountTime));
+ this.mountDismountCost = Cost.costOfSeconds(builder.mountDismountCost);
this.stairsReluctance = Units.reluctance(builder.stairsReluctance);
}
@@ -73,13 +73,13 @@ public double reluctance() {
}
/** Time to get on and off your own vehicle. */
- public Duration hopTime() {
- return hopTime;
+ public Duration mountDismountTime() {
+ return mountDismountTime;
}
/** Cost of getting on and off your own vehicle. */
- public Cost hopCost() {
- return hopCost;
+ public Cost mountDismountCost() {
+ return mountDismountCost;
}
/** Reluctance of walking carrying a vehicle up a flight of stairs. */
@@ -95,15 +95,15 @@ public boolean equals(Object o) {
return (
speed == that.speed &&
reluctance == that.reluctance &&
- Objects.equals(hopTime, that.hopTime) &&
- Objects.equals(hopCost, that.hopCost) &&
+ Objects.equals(mountDismountTime, that.mountDismountTime) &&
+ Objects.equals(mountDismountCost, that.mountDismountCost) &&
stairsReluctance == that.stairsReluctance
);
}
@Override
public int hashCode() {
- return Objects.hash(speed, reluctance, hopTime, hopCost, stairsReluctance);
+ return Objects.hash(speed, reluctance, mountDismountTime, mountDismountCost, stairsReluctance);
}
@Override
@@ -112,8 +112,8 @@ public String toString() {
.of(VehicleWalkingPreferences.class)
.addNum("speed", speed, DEFAULT.speed)
.addNum("reluctance", reluctance, DEFAULT.reluctance)
- .addObj("hopTime", hopTime, DEFAULT.hopTime)
- .addObj("hopCost", hopCost, DEFAULT.hopCost)
+ .addObj("mountDismountTime", mountDismountTime, DEFAULT.mountDismountTime)
+ .addObj("mountDismountCost", mountDismountCost, DEFAULT.mountDismountCost)
.addNum("stairsReluctance", stairsReluctance, DEFAULT.stairsReluctance)
.toString();
}
@@ -123,16 +123,16 @@ public static class Builder {
private final VehicleWalkingPreferences original;
private double speed;
private double reluctance;
- private int hopTime;
- private int hopCost;
+ private int mountDismountTime;
+ private int mountDismountCost;
private double stairsReluctance;
private Builder(VehicleWalkingPreferences original) {
this.original = original;
this.speed = original.speed;
this.reluctance = original.reluctance;
- this.hopTime = (int) original.hopTime.toSeconds();
- this.hopCost = original.hopCost.toSeconds();
+ this.mountDismountTime = (int) original.mountDismountTime.toSeconds();
+ this.mountDismountCost = original.mountDismountCost.toSeconds();
this.stairsReluctance = original.stairsReluctance;
}
@@ -146,18 +146,18 @@ public VehicleWalkingPreferences.Builder withReluctance(double reluctance) {
return this;
}
- public VehicleWalkingPreferences.Builder withHopTime(Duration hopTime) {
- this.hopTime = (int) hopTime.toSeconds();
+ public VehicleWalkingPreferences.Builder withMountDismountTime(Duration mountDismountTime) {
+ this.mountDismountTime = (int) mountDismountTime.toSeconds();
return this;
}
- public VehicleWalkingPreferences.Builder withHopTime(int hopTime) {
- this.hopTime = hopTime;
+ public VehicleWalkingPreferences.Builder withMountDismountTime(int mountDismountTime) {
+ this.mountDismountTime = mountDismountTime;
return this;
}
- public VehicleWalkingPreferences.Builder withHopCost(int hopCost) {
- this.hopCost = hopCost;
+ public VehicleWalkingPreferences.Builder withMountDismountCost(int mountDismountCost) {
+ this.mountDismountCost = mountDismountCost;
return this;
}
diff --git a/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java b/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java
index 830a80c39a5..047e44f229a 100644
--- a/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java
+++ b/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java
@@ -16,7 +16,7 @@ static void addFlexLocations(StreetEdge edge, IntersectionVertex v0, StopModel s
if (edge.getPermission().allows(StreetTraversalPermission.PEDESTRIAN_AND_CAR)) {
Point p = GeometryUtils.getGeometryFactory().createPoint(v0.getCoordinate());
Envelope env = p.getEnvelopeInternal();
- for (AreaStop areaStop : stopModel.queryLocationIndex(env)) {
+ for (AreaStop areaStop : stopModel.findAreaStops(env)) {
if (!areaStop.getGeometry().disjoint(p)) {
v0.addAreaStops(Set.of(areaStop));
}
diff --git a/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
index fa3a7069e2d..bbc6733a40c 100644
--- a/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
+++ b/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java
@@ -114,7 +114,7 @@ public interface OtpServerRequestContext {
TraverseVisitor traverseVisitor();
default GraphFinder graphFinder() {
- return GraphFinder.getInstance(graph(), transitService()::findRegularStop);
+ return GraphFinder.getInstance(graph(), transitService()::findRegularStops);
}
FlexConfig flexConfig();
diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/EnumMapper.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/EnumMapper.java
index ce880058005..0e048a2e3e7 100644
--- a/src/main/java/org/opentripplanner/standalone/config/framework/json/EnumMapper.java
+++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/EnumMapper.java
@@ -3,6 +3,7 @@
import java.util.Arrays;
import java.util.Optional;
import org.opentripplanner.framework.doc.DocumentedEnum;
+import org.opentripplanner.framework.lang.StringUtils;
public class EnumMapper {
@@ -23,11 +24,7 @@ public static Optional extends Enum>> mapToEnum2(String text, Class extend
}
public static String toString(Enum> en) {
- return kebabCase(en.name());
- }
-
- public static String kebabCase(String input) {
- return input.toLowerCase().replace('_', '-');
+ return StringUtils.kebabCase(en.name());
}
/**
diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeInfo.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeInfo.java
index 296c07805f9..06675475fd1 100644
--- a/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeInfo.java
+++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/NodeInfo.java
@@ -7,6 +7,7 @@
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opentripplanner.framework.lang.StringUtils;
import org.opentripplanner.framework.tostring.ValueObjectToStringBuilder;
/**
@@ -137,7 +138,7 @@ public List extends Enum>> enumTypeValues() {
*/
public String toMarkdownString(Object value) {
if (enumType != null) {
- value = EnumMapper.kebabCase(value.toString());
+ value = StringUtils.kebabCase(value.toString());
}
return type.quote(value);
}
diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java
index f1d90d0ec40..088a7794585 100644
--- a/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java
+++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/ParameterBuilder.java
@@ -303,14 +303,15 @@ public > Map asEnumMap(Class enumType, Class el
*/
public > Map asEnumMap(
Class enumType,
- Function typeMapper
+ Function typeMapper,
+ Map defaultValue
) {
info.withOptional().withEnumMap(enumType, OBJECT);
var mapNode = buildObject();
if (mapNode.isEmpty()) {
- return Map.of();
+ return defaultValue;
}
EnumMap result = new EnumMap<>(enumType);
diff --git a/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java
index 4538f6de84d..c4b0b0bd8cb 100644
--- a/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java
+++ b/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java
@@ -15,12 +15,16 @@
import static org.opentripplanner.standalone.config.routerequest.WheelchairConfig.mapWheelchairPreferences;
import java.time.Duration;
+import java.util.List;
+import java.util.stream.Collectors;
import org.opentripplanner.api.parameter.QualifiedModeSet;
import org.opentripplanner.framework.application.OTPFeature;
+import org.opentripplanner.framework.lang.StringUtils;
import org.opentripplanner.routing.api.request.RequestModes;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.api.request.framework.CostLinearFunction;
+import org.opentripplanner.routing.api.request.preference.AccessEgressPreferences;
import org.opentripplanner.routing.api.request.preference.BikePreferences;
import org.opentripplanner.routing.api.request.preference.CarPreferences;
import org.opentripplanner.routing.api.request.preference.RoutingPreferences;
@@ -455,7 +459,9 @@ private static void mapStreetPreferences(NodeAdapter c, StreetPreferences.Builde
the access legs used. In other cases where the access(CAR) is faster than transit the
performance will be better.
- The default is no penalty, if not configured.
+ The default values are
+
+ %s
Example: `"car-to-park" : { "timePenalty": "10m + 1.5t", "costFactor": 2.5 }`
@@ -470,9 +476,15 @@ the access legs used. In other cases where the access(CAR) is faster than transi
The `costFactor` is used to add an additional cost to the leg´s generalized-cost. The
time-penalty is multiplied with the cost-factor. A cost-factor of zero, gives no
extra cost, while 1.0 will add the same amount to both time and cost.
- """
+ """.formatted(
+ formatPenaltyDefaultValues(dftAccessEgress)
+ )
+ )
+ .asEnumMap(
+ StreetMode.class,
+ TimeAndCostPenaltyMapper::map,
+ dftAccessEgress.penalty().asEnumMap()
)
- .asEnumMap(StreetMode.class, TimeAndCostPenaltyMapper::map)
)
.withMaxDuration(
cae
@@ -569,6 +581,16 @@ The street search(AStar) aborts after this duration and any paths found are retu
);
}
+ private static String formatPenaltyDefaultValues(AccessEgressPreferences dftAccessEgress) {
+ return dftAccessEgress
+ .penalty()
+ .asEnumMap()
+ .entrySet()
+ .stream()
+ .map(s -> "- `%s` = %s".formatted(StringUtils.kebabCase(s.getKey().toString()), s.getValue()))
+ .collect(Collectors.joining("\n"));
+ }
+
private static void mapCarPreferences(NodeAdapter root, CarPreferences.Builder builder) {
var dft = builder.original();
NodeAdapter c = root.of("car").since(V2_5).summary("Car preferences.").asObject();
diff --git a/src/main/java/org/opentripplanner/standalone/config/routerequest/VehicleWalkingConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerequest/VehicleWalkingConfig.java
index f2ba922c8e3..2b20e12f755 100644
--- a/src/main/java/org/opentripplanner/standalone/config/routerequest/VehicleWalkingConfig.java
+++ b/src/main/java/org/opentripplanner/standalone/config/routerequest/VehicleWalkingConfig.java
@@ -43,9 +43,9 @@ private static void mapVehicleWalkingPreferences(
)
.asDouble(dft.reluctance())
)
- .withHopTime(
+ .withMountDismountTime(
c
- .of("hopTime")
+ .of("mountDismountTime")
.since(V2_0)
.summary("The time it takes the user to hop on or off a vehicle.")
.description(
@@ -54,11 +54,11 @@ private static void mapVehicleWalkingPreferences(
for controlling the duration of those events.
"""
)
- .asDuration(dft.hopTime())
+ .asDuration(dft.mountDismountTime())
)
- .withHopCost(
+ .withMountDismountCost(
c
- .of("hopCost")
+ .of("mountDismountCost")
.since(V2_0)
.summary("The cost of hopping on or off a vehicle.")
.description(
@@ -67,7 +67,7 @@ private static void mapVehicleWalkingPreferences(
not meant for controlling the cost of those events.
"""
)
- .asInt(dft.hopCost().toSeconds())
+ .asInt(dft.mountDismountCost().toSeconds())
)
.withStairsReluctance(
c
diff --git a/src/main/java/org/opentripplanner/street/model/edge/BikeWalkableEdge.java b/src/main/java/org/opentripplanner/street/model/edge/BikeWalkableEdge.java
index 799a5b006e6..7f61982434d 100644
--- a/src/main/java/org/opentripplanner/street/model/edge/BikeWalkableEdge.java
+++ b/src/main/java/org/opentripplanner/street/model/edge/BikeWalkableEdge.java
@@ -17,8 +17,10 @@ default void switchToWalkingBike(RoutingPreferences preferences, StateEditor edi
editor.setBackWalkingBike(true);
if (shouldIncludeCost) {
- editor.incrementWeight(preferences.bike().walking().hopCost().toSeconds());
- editor.incrementTimeInSeconds((int) preferences.bike().walking().hopTime().toSeconds());
+ editor.incrementWeight(preferences.bike().walking().mountDismountCost().toSeconds());
+ editor.incrementTimeInSeconds(
+ (int) preferences.bike().walking().mountDismountTime().toSeconds()
+ );
}
}
@@ -28,8 +30,10 @@ default void switchToBiking(RoutingPreferences preferences, StateEditor editor)
editor.setBackWalkingBike(false);
if (shouldIncludeCost) {
- editor.incrementWeight(preferences.bike().walking().hopCost().toSeconds());
- editor.incrementTimeInSeconds((int) preferences.bike().walking().hopTime().toSeconds());
+ editor.incrementWeight(preferences.bike().walking().mountDismountCost().toSeconds());
+ editor.incrementTimeInSeconds(
+ (int) preferences.bike().walking().mountDismountTime().toSeconds()
+ );
}
}
diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java
index edee00e27e1..c674d588238 100644
--- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java
+++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java
@@ -94,13 +94,12 @@ public Geometry getGeometry() {
/**
* Returns the geometry of the area that encompasses the bounds of this StopLocation group. If the
- * group is defined only as a list of stops, this will return the same as getGeometry. If on the
- * other hand the group is defined as an area and the stops are inferred from that area, then this
- * will return the geometry of the area.
+ * group is defined as all the stops within an area, then this will return the geometry of the
+ * area. If the group is defined simply as a list of stops, this will return an empty optional.
*/
@Override
public Optional extends Geometry> getEncompassingAreaGeometry() {
- return Optional.ofNullable(encompassingAreaGeometry).or(() -> Optional.of(geometry));
+ return Optional.ofNullable(encompassingAreaGeometry);
}
@Override
diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java
index 8873e6ede99..64cad9325d1 100644
--- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java
+++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java
@@ -4,7 +4,6 @@
import java.util.List;
import java.util.function.IntSupplier;
import javax.annotation.Nonnull;
-import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.opentripplanner.framework.geometry.GeometryUtils;
@@ -69,6 +68,22 @@ public I18NString name() {
}
public GroupStopBuilder addLocation(StopLocation location) {
+ if (
+ !(
+ location.getStopType() == StopType.REGULAR ||
+ location.getStopType() == StopType.FLEXIBLE_AREA
+ )
+ ) {
+ throw new RuntimeException(
+ String.format(
+ "Unsupported location for %s. Must be %s or %s.",
+ GroupStop.class.getSimpleName(),
+ StopType.REGULAR,
+ StopType.FLEXIBLE_AREA
+ )
+ );
+ }
+
stopLocations.add(location);
int numGeometries = geometry.getNumGeometries();
@@ -76,17 +91,8 @@ public GroupStopBuilder addLocation(StopLocation location) {
for (int i = 0; i < numGeometries; i++) {
newGeometries[i] = geometry.getGeometryN(i);
}
- if (location instanceof RegularStop) {
- WgsCoordinate coordinate = location.getCoordinate();
- Envelope envelope = new Envelope(coordinate.asJtsCoordinate());
- double xscale = Math.cos(coordinate.latitude() * Math.PI / 180);
- envelope.expandBy(100 / xscale, 100);
- newGeometries[numGeometries] = GeometryUtils.getGeometryFactory().toGeometry(envelope);
- } else if (location instanceof AreaStop) {
- newGeometries[numGeometries] = location.getGeometry();
- } else {
- throw new RuntimeException("Unknown location type");
- }
+ newGeometries[numGeometries] = location.getGeometry();
+
geometry = new GeometryCollection(newGeometries, GeometryUtils.getGeometryFactory());
centroid = new WgsCoordinate(geometry.getCentroid());
diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
index 0d08bcf34b2..3050fca6a3d 100644
--- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
+++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java
@@ -543,7 +543,7 @@ public ZonedDateTime getTransitServiceStarts() {
}
@Override
- public Collection findRegularStop(Envelope envelope) {
+ public Collection findRegularStops(Envelope envelope) {
OTPRequestTimeoutException.checkForTimeout();
return transitModel.getStopModel().findRegularStops(envelope);
}
@@ -551,7 +551,7 @@ public Collection findRegularStop(Envelope envelope) {
@Override
public Collection findAreaStops(Envelope envelope) {
OTPRequestTimeoutException.checkForTimeout();
- return transitModel.getStopModel().queryLocationIndex(envelope);
+ return transitModel.getStopModel().findAreaStops(envelope);
}
@Override
diff --git a/src/main/java/org/opentripplanner/transit/service/StopModel.java b/src/main/java/org/opentripplanner/transit/service/StopModel.java
index dd6b65e5b33..763aa504c40 100644
--- a/src/main/java/org/opentripplanner/transit/service/StopModel.java
+++ b/src/main/java/org/opentripplanner/transit/service/StopModel.java
@@ -108,7 +108,7 @@ public StopModelBuilder withContext() {
}
/**
- * Return a regular transit stop if found(not flex stops).
+ * Return a regular transit stop if found (not flex stops).
*/
public RegularStop getRegularStop(FeedScopedId id) {
return regularStopById.get(id);
@@ -121,6 +121,9 @@ public Collection listRegularStops() {
return regularStopById.values();
}
+ /**
+ * Find regular stops within a geographical area.
+ */
public Collection findRegularStops(Envelope envelope) {
return index.findRegularStops(envelope);
}
@@ -131,21 +134,30 @@ public boolean hasAreaStops() {
/**
* Flex locations are generated by GTFS graph builder, but consumed only after the street graph is
- * built
+ * built.
*/
@Nullable
public AreaStop getAreaStop(FeedScopedId id) {
return areaStopById.get(id);
}
+ /**
+ * Return all flex stops, not regular transit stops and flex group of stops.
+ */
public Collection listAreaStops() {
return areaStopById.values();
}
- public Collection queryLocationIndex(Envelope envelope) {
+ /**
+ * Find flex stops within a geographical area.
+ */
+ public Collection findAreaStops(Envelope envelope) {
return index.findAreaStops(envelope);
}
+ /**
+ * Return all flex groups of stops.
+ */
public Collection listGroupStops() {
return groupStopById.values();
}
diff --git a/src/main/java/org/opentripplanner/transit/service/TransitService.java b/src/main/java/org/opentripplanner/transit/service/TransitService.java
index d0664aa292d..fdb6dda8749 100644
--- a/src/main/java/org/opentripplanner/transit/service/TransitService.java
+++ b/src/main/java/org/opentripplanner/transit/service/TransitService.java
@@ -187,7 +187,7 @@ List stopTimesForPatternAtStop(
boolean transitFeedCovers(Instant dateTime);
- Collection findRegularStop(Envelope envelope);
+ Collection findRegularStops(Envelope envelope);
Collection findAreaStops(Envelope envelope);
diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
index 25cf95ca2f9..dad106418fe 100644
--- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
+++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql
@@ -774,7 +774,7 @@ type QueryType {
"Input type for executing a travel search for a trip between two locations. Returns trip patterns describing suggested alternatives for the trip."
trip(
"Time and cost penalty on access/egress modes."
- accessEgressPenalty: [PenaltyForStreetMode!] = [],
+ accessEgressPenalty: [PenaltyForStreetMode!] = [{streetMode : car_park, timePenalty : "20m + 2.0 t", costFactor : 1.5}, {streetMode : flexible, timePenalty : "20m + 2.0 t", costFactor : 1.5}],
"The alightSlack is the minimum extra time after exiting a public transport vehicle. This is the default value used, if not overridden by the 'alightSlackList'."
alightSlackDefault: Int = 0,
"List of alightSlack for a given set of modes. Defaults: []"
diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java
index b05dd77e2a9..85736291ada 100644
--- a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java
+++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java
@@ -55,7 +55,7 @@ class RouteRequestMapperTest implements PlanTestConstants {
graph.getVehicleParkingService(),
new DefaultVehicleRentalService(),
new DefaultRealtimeVehicleService(transitService),
- GraphFinder.getInstance(graph, transitService::findRegularStop),
+ GraphFinder.getInstance(graph, transitService::findRegularStops),
new RouteRequest()
);
}
diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/StreetPreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/StreetPreferencesTest.java
index 1d47337a312..0289c24e837 100644
--- a/src/test/java/org/opentripplanner/routing/api/request/preference/StreetPreferencesTest.java
+++ b/src/test/java/org/opentripplanner/routing/api/request/preference/StreetPreferencesTest.java
@@ -109,10 +109,10 @@ void testToString() {
"routingTimeout: 3s, " +
"elevator: ElevatorPreferences{boardTime: 2m}, " +
"intersectionTraversalModel: CONSTANT, " +
- "accessEgress: AccessEgressPreferences{" +
- "penalty: TimeAndCostPenaltyForEnum{CAR_TO_PARK: " +
+ "accessEgress: AccessEgressPreferences{penalty: TimeAndCostPenaltyForEnum{CAR_TO_PARK: " +
CAR_PENALTY +
- "}, " +
+ ", CAR_RENTAL: (timePenalty: 20m + 2.0 t, costFactor: 1.50), CAR_HAILING: (timePenalty: 20m + 2.0 t, costFactor: 1.50), " +
+ "FLEXIBLE: (timePenalty: 20m + 2.0 t, costFactor: 1.50)}, " +
"maxDuration: DurationForStreetMode{default:5m}" +
"}, " +
"maxDirectDuration: DurationForStreetMode{default:10m}" +
diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferencesTest.java
index 9571eee8cc5..fdc416d7c0f 100644
--- a/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferencesTest.java
+++ b/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleWalkingPreferencesTest.java
@@ -11,8 +11,8 @@ class VehicleWalkingPreferencesTest {
private static final double SPEED = 1.45;
private static final double RELUCTANCE = 5.5;
- private static final Duration HOP_TIME = Duration.ofSeconds(15);
- private static final Cost HOP_COST = Cost.costOfSeconds(20);
+ private static final Duration MOUNT_DISMOUNT_TIME = Duration.ofSeconds(15);
+ private static final Cost MOUNT_DISMOUNT_COST = Cost.costOfSeconds(20);
private static final double STAIRS_RELUCTANCE = 11;
private final VehicleWalkingPreferences subject = createPreferences();
@@ -28,13 +28,13 @@ void reluctance() {
}
@Test
- void hopTime() {
- assertEquals(HOP_TIME, subject.hopTime());
+ void mountDismountTime() {
+ assertEquals(MOUNT_DISMOUNT_TIME, subject.mountDismountTime());
}
@Test
- void hopCost() {
- assertEquals(HOP_COST, subject.hopCost());
+ void mountDismountCost() {
+ assertEquals(MOUNT_DISMOUNT_COST, subject.mountDismountCost());
}
@Test
@@ -57,8 +57,8 @@ void testToString() {
"VehicleWalkingPreferences{" +
"speed: 1.45, " +
"reluctance: 5.5, " +
- "hopTime: PT15S, " +
- "hopCost: $20, " +
+ "mountDismountTime: PT15S, " +
+ "mountDismountCost: $20, " +
"stairsReluctance: 11.0}",
subject.toString()
);
@@ -69,8 +69,8 @@ private VehicleWalkingPreferences createPreferences() {
.of()
.withSpeed(SPEED)
.withReluctance(RELUCTANCE)
- .withHopTime(HOP_TIME)
- .withHopCost(HOP_COST.toSeconds())
+ .withMountDismountTime(MOUNT_DISMOUNT_TIME)
+ .withMountDismountCost(MOUNT_DISMOUNT_COST.toSeconds())
.withStairsReluctance(STAIRS_RELUCTANCE)
.build();
}
diff --git a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java
index f975579cbf5..be44d1ea86f 100644
--- a/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java
+++ b/src/test/java/org/opentripplanner/standalone/config/framework/json/NodeAdapterTest.java
@@ -225,15 +225,23 @@ public void asEnumMapWithCustomType() {
NodeAdapter subject = newNodeAdapterForTest("{ key : { A: {a:'Foo'} } }");
assertEquals(
Map.of(AnEnum.A, new ARecord("Foo")),
- subject.of("key").asEnumMap(AnEnum.class, ARecord::fromJson)
+ subject.of("key").asEnumMap(AnEnum.class, ARecord::fromJson, Map.of())
);
assertEquals(
Collections.emptyMap(),
- subject.of("missing-key").asEnumMap(AnEnum.class, ARecord::fromJson)
+ subject.of("missing-key").asEnumMap(AnEnum.class, ARecord::fromJson, Map.of())
);
assertEquals(NON_UNUSED_PARAMETERS, unusedParams(subject));
}
+ @Test
+ public void asEnumMapWithDefaultValue() {
+ var subject = newNodeAdapterForTest("{}");
+ final Map dflt = Map.of(AnEnum.A, new ARecord("Foo"));
+ assertEquals(dflt, subject.of("key").asEnumMap(AnEnum.class, ARecord::fromJson, dflt));
+ assertEquals(NON_UNUSED_PARAMETERS, unusedParams(subject));
+ }
+
@Test
public void asEnumMapWithUnknownKey() {
NodeAdapter subject = newNodeAdapterForTest("{ enumMap : { unknown : 7 } }");
diff --git a/src/test/java/org/opentripplanner/street/integration/BikeWalkingTest.java b/src/test/java/org/opentripplanner/street/integration/BikeWalkingTest.java
index 417f1b87347..41ec677b3bb 100644
--- a/src/test/java/org/opentripplanner/street/integration/BikeWalkingTest.java
+++ b/src/test/java/org/opentripplanner/street/integration/BikeWalkingTest.java
@@ -375,7 +375,10 @@ private List runStreetSearchAndCreateDescriptor(
preferences
.withWalk(w -> w.withSpeed(10))
.withBike(it ->
- it.withSpeed(20d).withWalking(w -> w.withSpeed(5d).withHopTime(100).withHopCost(1000))
+ it
+ .withSpeed(20d)
+ .withWalking(w -> w.withSpeed(5d).withMountDismountTime(100).withMountDismountCost(1000)
+ )
)
);
request.setArriveBy(arriveBy);
diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java
index 42d841b9fa3..ed5768d4a1a 100644
--- a/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java
+++ b/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java
@@ -221,7 +221,7 @@ public void testBikeSwitch() {
StreetSearchRequestBuilder noPenalty = StreetSearchRequest.copyOf(proto);
noPenalty.withPreferences(p ->
- p.withBike(it -> it.withWalking(w -> w.withHopTime(0).withHopCost(0)))
+ p.withBike(it -> it.withWalking(w -> w.withMountDismountTime(0).withMountDismountCost(0)))
);
State s0 = new State(v0, noPenalty.withMode(StreetMode.BIKE).build());
@@ -231,7 +231,7 @@ public void testBikeSwitch() {
StreetSearchRequestBuilder withPenalty = StreetSearchRequest.copyOf(proto);
withPenalty.withPreferences(p ->
- p.withBike(it -> it.withWalking(w -> w.withHopTime(42).withHopCost(23)))
+ p.withBike(it -> it.withWalking(w -> w.withMountDismountTime(42).withMountDismountCost(23)))
);
State s4 = new State(v0, withPenalty.withMode(StreetMode.BIKE).build());
diff --git a/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java b/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java
index 17938131eef..b57566b68ed 100644
--- a/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java
+++ b/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java
@@ -6,7 +6,12 @@
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.List;
+import java.util.Objects;
import org.junit.jupiter.api.Test;
+import org.locationtech.jts.geom.Geometry;
+import org.opentripplanner._support.geometry.Coordinates;
+import org.opentripplanner._support.geometry.Polygons;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.transit.model._data.TransitModelForTest;
@@ -14,12 +19,14 @@
class GroupStopTest {
- private static TransitModelForTest TEST_MODEL = TransitModelForTest.of();
+ private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();
private static final String ID = "1";
private static final I18NString NAME = new NonLocalizedString("name");
- private static final StopLocation STOP_LOCATION = TEST_MODEL.stop("1:stop", 1d, 1d).build();
+ private static final StopLocation STOP_LOCATION = TEST_MODEL
+ .stop("1:stop", Coordinates.BERLIN.getX(), Coordinates.BERLIN.getY())
+ .build();
private static final GroupStop subject = StopModel
.of()
.groupStop(TransitModelForTest.id(ID))
@@ -27,6 +34,53 @@ class GroupStopTest {
.addLocation(STOP_LOCATION)
.build();
+ @Test
+ void testGroupStopGeometry() {
+ StopLocation stopLocation1 = TEST_MODEL
+ .stop("1:stop", Coordinates.BERLIN.getX(), Coordinates.BERLIN.getY())
+ .build();
+ StopLocation stopLocation2 = TEST_MODEL
+ .stop("2:stop", Coordinates.HAMBURG.getX(), Coordinates.HAMBURG.getY())
+ .build();
+
+ GroupStop groupStop = StopModel
+ .of()
+ .groupStop(TransitModelForTest.id(ID))
+ .withName(NAME)
+ .addLocation(stopLocation1)
+ .addLocation(stopLocation2)
+ .build();
+
+ Geometry groupStopGeometry1 = Objects.requireNonNull(groupStop.getGeometry()).getGeometryN(0);
+ assertEquals(stopLocation1.getGeometry(), groupStopGeometry1);
+
+ Geometry groupStopGeometry2 = Objects.requireNonNull(groupStop.getGeometry()).getGeometryN(1);
+ assertEquals(stopLocation2.getGeometry(), groupStopGeometry2);
+ }
+
+ @Test
+ void testGroupStopEncompassingAreaGeometry() {
+ StopLocation stopLocation = TEST_MODEL
+ .stop("1:stop", Coordinates.BERLIN.getX(), Coordinates.BERLIN.getY())
+ .build();
+
+ GroupStop groupStop = StopModel
+ .of()
+ .groupStop(TransitModelForTest.id(ID))
+ .withName(NAME)
+ .addLocation(stopLocation)
+ .withEncompassingAreaGeometries(List.of(Polygons.BERLIN))
+ .build();
+
+ Geometry groupStopGeometry = Objects.requireNonNull(groupStop.getGeometry()).getGeometryN(0);
+ assertEquals(stopLocation.getGeometry(), groupStopGeometry);
+
+ assertEquals(
+ Polygons.BERLIN,
+ groupStop.getEncompassingAreaGeometry().orElseThrow().getGeometryN(0)
+ );
+ }
+
@Test
void copy() {
assertEquals(ID, subject.getId().getId());
diff --git a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java
index 2a26dc681be..f04fe782a0a 100644
--- a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java
+++ b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java
@@ -43,6 +43,8 @@ static void setup() {
.build();
var transitModel = new TransitModel(stopModel, new Deduplicator());
+ transitModel.addTripPattern(RAIL_PATTERN.getId(), RAIL_PATTERN);
+ transitModel.index();
service =
new DefaultTransitService(transitModel) {