diff --git a/.github/workflows/prune-container-images.yml b/.github/workflows/prune-container-images.yml index c1653701c3b..f3987a064a9 100644 --- a/.github/workflows/prune-container-images.yml +++ b/.github/workflows/prune-container-images.yml @@ -19,4 +19,4 @@ jobs: # remove all snapshot container images that have not been pulled for over a year # --keep-semver makes sure that any image with a x.y.z version scheme is unaffected by this pip install prune-container-repo==0.0.4 - prune-container-repo -u ${CONTAINER_REGISTRY_USER} -r ${CONTAINER_REPO} --days=365 --keep-semver --activate + prune-container-repo -u ${CONTAINER_REGISTRY_USER} -r ${CONTAINER_REPO} --days=90 --keep-semver --activate diff --git a/client-next/.env b/client-next/.env index e8a9667bc23..ca1d71c90e3 100644 --- a/client-next/.env +++ b/client-next/.env @@ -1,2 +1,2 @@ -VITE_API_URL=/otp/routers/default/transmodel/index/graphql +VITE_API_URL=/otp/transmodel/v3 VITE_DEBUG_STYLE_URL=/otp/routers/default/inspector/vectortile/style.json diff --git a/client-next/.env.development b/client-next/.env.development index b10ac31fdf9..35840c239bd 100644 --- a/client-next/.env.development +++ b/client-next/.env.development @@ -1,2 +1,2 @@ -VITE_API_URL=http://localhost:8080/otp/routers/default/transmodel/index/graphql +VITE_API_URL=http://localhost:8080/otp/transmodel/v3 VITE_DEBUG_STYLE_URL=http://localhost:8080/otp/routers/default/inspector/vectortile/style.json \ No newline at end of file diff --git a/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx b/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx index f6df37c2d1d..5f0e2b381aa 100644 --- a/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx +++ b/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx @@ -5,20 +5,27 @@ import { formatDuration } from '../../util/formatDuration.ts'; export function ItineraryLegDetails({ leg, isLast }: { leg: Leg; isLast: boolean }) { return ( -
- -{' '} - {' '} - {leg.mode}{' '} - {leg.line && ( - <> - - {leg.line.publicCode} {leg.toEstimatedCall?.destinationDisplay?.frontText} - - , {leg.authority?.name} - - )}{' '} - {formatDistance(leg.distance)}, {formatDuration(leg.duration)} - {leg.mode !== Mode.Foot && from {leg.fromPlace.name}} {!isLast && to {leg.toPlace.name}} +
+
+ {formatDistance(leg.distance)}, {formatDuration(leg.duration)} +
+
+ -{' '} + +
+
+ {leg.mode}{' '} + {leg.line && ( + <> + + {leg.line.publicCode} {leg.toEstimatedCall?.destinationDisplay?.frontText} + + , {leg.authority?.name} + + )}{' '} +
+ {leg.mode !== Mode.Foot && {leg.fromPlace.name}} {!isLast && → {leg.toPlace.name}} +
); } diff --git a/client-next/src/components/ItineraryList/LegTime.tsx b/client-next/src/components/ItineraryList/LegTime.tsx index 5bd4aa56b1a..1b3d01e0d05 100644 --- a/client-next/src/components/ItineraryList/LegTime.tsx +++ b/client-next/src/components/ItineraryList/LegTime.tsx @@ -11,12 +11,12 @@ export function LegTime({ }) { return aimedTime !== expectedTime ? ( <> - {formatTime(expectedTime)} - {formatTime(aimedTime)} + {formatTime(expectedTime, 'short')} + {formatTime(aimedTime, 'short')} ) : ( - {formatTime(expectedTime)} + {formatTime(expectedTime, 'short')} {hasRealtime && (on time)} ); diff --git a/client-next/src/components/MapView/LayerControl.tsx b/client-next/src/components/MapView/LayerControl.tsx index 237ea8ab150..1517a9ce7c8 100644 --- a/client-next/src/components/MapView/LayerControl.tsx +++ b/client-next/src/components/MapView/LayerControl.tsx @@ -32,6 +32,9 @@ class LayerControl implements IControl { .getLayersOrder() .map((l) => map.getLayer(l)) .filter((s) => s?.type !== 'raster') + // the polylines of the routing result are put in map layers called jsx-1, jsx-2... + // we don't want them to show up in the debug layer selector + .filter((s) => !s?.id.startsWith('jsx')) .reverse() .forEach((layer) => { if (layer) { diff --git a/client-next/src/hooks/useTripQueryVariables.ts b/client-next/src/hooks/useTripQueryVariables.ts new file mode 100644 index 00000000000..ba9ff84c1e2 --- /dev/null +++ b/client-next/src/hooks/useTripQueryVariables.ts @@ -0,0 +1,33 @@ +import { useEffect, useState } from 'react'; +import { TripQueryVariables } from '../gql/graphql.ts'; + +const DEFAULT_VARIABLES: TripQueryVariables = { + from: {}, + to: {}, + dateTime: new Date().toISOString(), +}; + +const getInitialVariables = () => { + const urlParams = new URLSearchParams(window.location.search); + const variablesJson = urlParams.get('variables'); + return variablesJson ? JSON.parse(decodeURIComponent(variablesJson)) : DEFAULT_VARIABLES; +}; + +const updateUrlWithVariables = (variables: TripQueryVariables) => { + const urlParams = new URLSearchParams(window.location.search); + urlParams.set('variables', encodeURIComponent(JSON.stringify(variables))); + history.pushState({}, '', '?' + urlParams.toString() + window.location.hash); +}; + +export const useTripQueryVariables = () => { + const [tripQueryVariables, setTripQueryVariables] = useState(getInitialVariables()); + + useEffect(() => { + updateUrlWithVariables(tripQueryVariables); + }, [tripQueryVariables]); + + return { + tripQueryVariables, + setTripQueryVariables, + }; +}; diff --git a/client-next/src/screens/App.tsx b/client-next/src/screens/App.tsx index df17bb713bf..3e5744e5ad6 100644 --- a/client-next/src/screens/App.tsx +++ b/client-next/src/screens/App.tsx @@ -3,18 +3,12 @@ import { MapView } from '../components/MapView/MapView.tsx'; import { SearchBar } from '../components/SearchBar/SearchBar.tsx'; import { ItineraryListContainer } from '../components/ItineraryList/ItineraryListContainer.tsx'; import { useState } from 'react'; -import { TripQueryVariables } from '../gql/graphql.ts'; import { useTripQuery } from '../hooks/useTripQuery.ts'; import { useServerInfo } from '../hooks/useServerInfo.ts'; - -const INITIAL_VARIABLES: TripQueryVariables = { - from: {}, - to: {}, - dateTime: new Date().toISOString(), -}; +import { useTripQueryVariables } from '../hooks/useTripQueryVariables.ts'; export function App() { - const [tripQueryVariables, setTripQueryVariables] = useState(INITIAL_VARIABLES); + const { tripQueryVariables, setTripQueryVariables } = useTripQueryVariables(); const [tripQueryResult, loading, callback] = useTripQuery(tripQueryVariables); const serverInfo = useServerInfo(); const [selectedTripPatternIndex, setSelectedTripPatternIndex] = useState(0); diff --git a/client-next/src/style.css b/client-next/src/style.css index 79c85d38628..7dd2565c449 100644 --- a/client-next/src/style.css +++ b/client-next/src/style.css @@ -72,6 +72,23 @@ --bs-accordion-active-bg: pink; } +.itinerary-leg-details { + border: 1px solid #80808063; + padding: 10px; + border-radius: 3px; + margin-bottom: 3px; +} + +.itinerary-leg-details .times { + margin-top: 3px; + float: right; + font-size: 11px; +} + +.itinerary-leg-details .mode { + margin-top: 10px; +} + .itinerary-header-itinerary-number { position: absolute; } diff --git a/client-next/src/util/getColorForMode.ts b/client-next/src/util/getColorForMode.ts index 0276a1bce52..79af525e826 100644 --- a/client-next/src/util/getColorForMode.ts +++ b/client-next/src/util/getColorForMode.ts @@ -2,20 +2,20 @@ import { Mode } from '../gql/graphql.ts'; export const getColorForMode = function (mode: Mode) { if (mode === Mode.Foot) return '#444'; - if (mode === Mode.Bicycle) return '#44f'; - if (mode === Mode.Scooter) return '#88f'; + if (mode === Mode.Bicycle) return '#5076D9'; + if (mode === Mode.Scooter) return '#253664'; if (mode === Mode.Car) return '#444'; - if (mode === Mode.Rail) return '#b00'; - if (mode === Mode.Coach) return '#0f0'; - if (mode === Mode.Metro) return '#f00'; - if (mode === Mode.Bus) return '#0f0'; - if (mode === Mode.Tram) return '#f00'; - if (mode === Mode.Trolleybus) return '#0f0'; - if (mode === Mode.Water) return '#f0f'; - if (mode === Mode.Air) return '#f0f'; - if (mode === Mode.Cableway) return '#f0f'; - if (mode === Mode.Funicular) return '#f0f'; - if (mode === Mode.Monorail) return '#f0f'; - if (mode === Mode.Taxi) return '#f0f'; + if (mode === Mode.Rail) return '#86BF8B'; + if (mode === Mode.Coach) return '#25642A'; + if (mode === Mode.Metro) return '#D9B250'; + if (mode === Mode.Bus) return '#25642A'; + if (mode === Mode.Tram) return '#D9B250'; + if (mode === Mode.Trolleybus) return '#25642A'; + if (mode === Mode.Water) return '#81304C'; + if (mode === Mode.Air) return '#81304C'; + if (mode === Mode.Cableway) return '#81304C'; + if (mode === Mode.Funicular) return '#81304C'; + if (mode === Mode.Monorail) return '#81304C'; + if (mode === Mode.Taxi) return '#81304C'; return '#aaa'; }; diff --git a/docs/Changelog.md b/docs/Changelog.md index a95d931ae51..d0db11c2f2c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,6 +33,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add plan query that follows the relay connection specification [#5185](https://github.com/opentripplanner/OpenTripPlanner/pull/5185) - Fix debug client after breaking change in dependency graphql-request [#5899](https://github.com/opentripplanner/OpenTripPlanner/pull/5899) - Remove TravelTime API [#5890](https://github.com/opentripplanner/OpenTripPlanner/pull/5890) +- Improve cancellation of large response in TransModel API [#5908](https://github.com/opentripplanner/OpenTripPlanner/pull/5908) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.5.0 (2024-03-13) diff --git a/pom.xml b/pom.xml index c286cdd372e..444847a1532 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.4.1 + 3.4.2 diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html index 8f654dfb40e..77fc8ebbe8d 100644 --- a/src/client/debug-client-preview/index.html +++ b/src/client/debug-client-preview/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java index 7493c33bbb2..e7a2610b42f 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java @@ -134,7 +134,7 @@ private static void assertLegFareEquals( void calculateFareForSingleAgency() { List rides = List.of(getLeg(COMM_TRANS_AGENCY_ID, "400", 0)); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE); + calculateFare(rides, FareType.senior, TWO_DOLLARS); calculateFare(rides, FareType.youth, ZERO_USD); calculateFare(rides, FareType.electronicSpecial, TWO_DOLLARS); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); @@ -154,18 +154,14 @@ void calculateFareWithNoFreeTransfer() { getLeg(COMM_TRANS_AGENCY_ID, 2) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.plus(usDollars(2.25f))); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare( rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE.plus(usDollars(1.25f)) ); - calculateFare( - rides, - FareType.electronicRegular, - DEFAULT_TEST_RIDE_PRICE.plus(DEFAULT_TEST_RIDE_PRICE) - ); + calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); calculateFare(rides, FareType.electronicSenior, DEFAULT_TEST_RIDE_PRICE.plus(usDollars(1.25f))); calculateFare(rides, FareType.electronicYouth, Money.ZERO_USD); } @@ -200,7 +196,7 @@ void calculateFareThatExceedsTwoHourFreeTransferWindow() { ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, TWO_DOLLARS); calculateFare(rides, FareType.youth, ZERO_USD); calculateFare(rides, FareType.electronicSpecial, TWO_DOLLARS); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); @@ -227,7 +223,7 @@ void calculateFareThatIncludesNoFreeTransfers() { calculateFare( rides, FareType.senior, - DEFAULT_TEST_RIDE_PRICE.times(2).plus(usDollars(.50f)).plus(HALF_FERRY_FARE) + ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE).plus(usDollars(0.5f)) ); calculateFare(rides, FareType.youth, Money.ZERO_USD); // We don't get any fares for the skagit transit leg below here because they don't accept ORCA (electronic) @@ -263,7 +259,7 @@ void calculateFareThatExceedsTwoHourFreeTransferWindowTwice() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 270) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); + calculateFare(rides, FareType.senior, usDollars(3)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(3)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(3)); @@ -286,7 +282,7 @@ void calculateFareThatStartsWithACashFare() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 149) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.plus(ONE_DOLLAR)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE.plus(ONE_DOLLAR)); calculateFare( @@ -305,7 +301,7 @@ void calculateFareThatStartsWithACashFare() { void calculateFareForKitsapFastFerry() { List rides = List.of(getLeg(KITSAP_TRANSIT_AGENCY_ID, 0, 4, "404", "east")); calculateFare(rides, regular, TWO_DOLLARS); - calculateFare(rides, FareType.senior, TWO_DOLLARS); + calculateFare(rides, FareType.senior, ONE_DOLLAR); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR); calculateFare(rides, FareType.electronicRegular, TWO_DOLLARS); @@ -314,7 +310,7 @@ void calculateFareForKitsapFastFerry() { rides = List.of(getLeg(KITSAP_TRANSIT_AGENCY_ID, 0, 4, "404", "west")); calculateFare(rides, regular, usDollars(10f)); - calculateFare(rides, FareType.senior, usDollars(10f)); + calculateFare(rides, FareType.senior, usDollars(5f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(5f)); calculateFare(rides, FareType.electronicRegular, usDollars(10f)); @@ -349,7 +345,7 @@ void calculateFareForSTRail() { getLeg(SOUND_TRANSIT_AGENCY_ID, "S Line", 100, "King Street Station", "Auburn Station") ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, TWO_DOLLARS); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, ORCA_SPECIAL_FARE); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); @@ -364,7 +360,7 @@ void calculateFareForSTRail() { void calculateWaterTaxiFares() { List rides = List.of(getLeg(KC_METRO_AGENCY_ID, "973", 1)); calculateFare(rides, regular, WEST_SEATTLE_WATER_TAXI_CASH_FARE); - calculateFare(rides, FareType.senior, WEST_SEATTLE_WATER_TAXI_CASH_FARE); + calculateFare(rides, FareType.senior, usDollars(2.50f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(3.75f)); calculateFare(rides, FareType.electronicRegular, usDollars(5f)); @@ -374,7 +370,7 @@ void calculateWaterTaxiFares() { rides = List.of(getLeg(KC_METRO_AGENCY_ID, "975", 1)); calculateFare(rides, regular, VASHON_WATER_TAXI_CASH_FARE); - calculateFare(rides, FareType.senior, VASHON_WATER_TAXI_CASH_FARE); + calculateFare(rides, FareType.senior, usDollars(3f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(4.50f)); calculateFare(rides, FareType.electronicRegular, usDollars(5.75f)); @@ -395,8 +391,7 @@ void calculateSoundTransitBusFares() { getLeg(KC_METRO_AGENCY_ID, "550", 240) ); calculateFare(rides, regular, usDollars(9.75f)); - // Sound Transit does not accept senior fares in cash - calculateFare(rides, FareType.senior, usDollars(9.75f)); + calculateFare(rides, FareType.senior, usDollars(3.00f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(3f)); calculateFare(rides, FareType.electronicRegular, usDollars(9.75f)); @@ -410,7 +405,7 @@ void calculateSoundTransitBusFares() { getLeg(PIERCE_COUNTY_TRANSIT_AGENCY_ID, "501", 60) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(2)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2)); + calculateFare(rides, FareType.senior, TWO_DOLLARS); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(1f)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); @@ -430,7 +425,7 @@ void calculateCashFreeTransferKCMetroAndKitsap() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 132) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(4)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(4)); + calculateFare(rides, FareType.senior, usDollars(4.25f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(1.25f)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); @@ -442,12 +437,12 @@ void calculateCashFreeTransferKCMetroAndKitsap() { void calculateTransferExtension() { List rides = List.of( getLeg(KITSAP_TRANSIT_AGENCY_ID, 0, 4, "Kitsap Fast Ferry", "east"), // 2.00 - getLeg(KC_METRO_AGENCY_ID, 100), // Default ride price, extends transfer + getLeg(KC_METRO_AGENCY_ID, 100), // Default ride price, extends transfer for regular fare getLeg(KITSAP_TRANSIT_AGENCY_ID, 150, 4, "Kitsap Fast Ferry", "west") // 10.00 ); var regularFare = usDollars(2.00f).plus(DEFAULT_TEST_RIDE_PRICE).plus(usDollars(10f)); calculateFare(rides, regular, regularFare); - calculateFare(rides, FareType.senior, regularFare); + calculateFare(rides, FareType.senior, usDollars(7f)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(6f)); calculateFare(rides, FareType.electronicRegular, usDollars(10f)); // transfer extended on second leg diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 8f961b0b01b..c3c1873ad6d 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -352,10 +352,10 @@ private Optional getSeniorFare( var regularFare = getRegularFare(fareType, rideType, defaultFare, leg); // Many agencies only provide senior discount if using ORCA return switch (rideType) { - case COMM_TRANS_LOCAL_SWIFT -> usesOrca(fareType) ? optionalUSD(1.25f) : regularFare; - case COMM_TRANS_COMMUTER_EXPRESS -> usesOrca(fareType) ? optionalUSD(2f) : regularFare; + case COMM_TRANS_LOCAL_SWIFT -> optionalUSD(1.25f); + case COMM_TRANS_COMMUTER_EXPRESS -> optionalUSD(2f); case SKAGIT_TRANSIT, WHATCOM_LOCAL, SKAGIT_LOCAL -> optionalUSD(0.5f); - case EVERETT_TRANSIT -> usesOrca(fareType) ? optionalUSD(0.5f) : regularFare; + case EVERETT_TRANSIT -> optionalUSD(0.5f); case KITSAP_TRANSIT_FAST_FERRY_EASTBOUND, SOUND_TRANSIT, SOUND_TRANSIT_BUS, @@ -365,14 +365,10 @@ private Optional getSeniorFare( KC_METRO, PIERCE_COUNTY_TRANSIT, SEATTLE_STREET_CAR, - KITSAP_TRANSIT -> fareType.equals(FareType.electronicSenior) - ? optionalUSD(1f) - : regularFare; - case KC_WATER_TAXI_VASHON_ISLAND -> usesOrca(fareType) ? optionalUSD(3f) : regularFare; - case KC_WATER_TAXI_WEST_SEATTLE -> usesOrca(fareType) ? optionalUSD(2.5f) : regularFare; - case KITSAP_TRANSIT_FAST_FERRY_WESTBOUND -> fareType.equals(FareType.electronicSenior) - ? optionalUSD(5f) - : regularFare; + KITSAP_TRANSIT -> optionalUSD(1f); + case KC_WATER_TAXI_VASHON_ISLAND -> optionalUSD(3f); + case KC_WATER_TAXI_WEST_SEATTLE -> optionalUSD(2.5f); + case KITSAP_TRANSIT_FAST_FERRY_WESTBOUND -> optionalUSD(5f); // Discount specific to Skagit transit and not Orca. case WASHINGTON_STATE_FERRIES -> Optional.of( getWashingtonStateFerriesFare(route.getLongName(), fareType, defaultFare) diff --git a/src/ext/java/org/opentripplanner/ext/restapi/resources/PlannerResource.java b/src/ext/java/org/opentripplanner/ext/restapi/resources/PlannerResource.java index 38c70851b76..9c58c1c719d 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/resources/PlannerResource.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/resources/PlannerResource.java @@ -12,6 +12,7 @@ import org.opentripplanner.api.common.Message; import org.opentripplanner.api.error.PlannerError; import org.opentripplanner.apis.support.mapping.PlannerErrorMapper; +import org.opentripplanner.apis.transmodel.ResponseTooLargeException; import org.opentripplanner.ext.restapi.mapping.TripPlanMapper; import org.opentripplanner.ext.restapi.mapping.TripSearchMetadataMapper; import org.opentripplanner.ext.restapi.model.ElevationMetadata; @@ -104,8 +105,8 @@ public Response plan(@Context UriInfo uriInfo, @Context Request grizzlyRequest) LOG.error("System error - unhandled error case?", e); response.setError(new PlannerError(Message.SYSTEM_ERROR)); } - } catch (OTPRequestTimeoutException e) { - response.setError(new PlannerError(Message.PROCESSING_TIMEOUT)); + } catch (OTPRequestTimeoutException | ResponseTooLargeException e) { + response.setError(new PlannerError(Message.UNPROCESSABLE_REQUEST)); } catch (Exception e) { LOG.error("System error", e); response.setError(new PlannerError(Message.SYSTEM_ERROR)); diff --git a/src/main/java/org/opentripplanner/api/common/Message.java b/src/main/java/org/opentripplanner/api/common/Message.java index 9a07d8c33d6..3e568d57940 100644 --- a/src/main/java/org/opentripplanner/api/common/Message.java +++ b/src/main/java/org/opentripplanner/api/common/Message.java @@ -15,7 +15,7 @@ public enum Message { PLAN_OK(200), SYSTEM_ERROR(500), - PROCESSING_TIMEOUT(422), + UNPROCESSABLE_REQUEST(422), GRAPH_UNAVAILABLE(503), diff --git a/src/main/java/org/opentripplanner/apis/transmodel/MaxFieldsInResultInstrumentation.java b/src/main/java/org/opentripplanner/apis/transmodel/MaxFieldsInResultInstrumentation.java index 6d22f18783c..7cc356e5f6b 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/MaxFieldsInResultInstrumentation.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/MaxFieldsInResultInstrumentation.java @@ -3,7 +3,6 @@ import static graphql.execution.instrumentation.SimpleInstrumentationContext.noOp; import graphql.ExecutionResult; -import graphql.execution.AbortExecutionException; import graphql.execution.instrumentation.Instrumentation; import graphql.execution.instrumentation.InstrumentationContext; import graphql.execution.instrumentation.InstrumentationState; @@ -47,7 +46,7 @@ public InstrumentationContext beginFieldFetch( if (fetched % 10000 == 0) { LOG.debug("Fetched {} fields", fetched); if (fetched > maxFieldFetch) { - throw new AbortExecutionException( + throw new ResponseTooLargeException( "The number of fields in the GraphQL result exceeds the maximum allowed: " + maxFieldFetch ); } diff --git a/src/main/java/org/opentripplanner/apis/transmodel/ResponseTooLargeException.java b/src/main/java/org/opentripplanner/apis/transmodel/ResponseTooLargeException.java new file mode 100644 index 00000000000..a6b070e8fdd --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/transmodel/ResponseTooLargeException.java @@ -0,0 +1,11 @@ +package org.opentripplanner.apis.transmodel; + +/** + * Exception thrown when the API response exceeds a configurable limit. + */ +public class ResponseTooLargeException extends RuntimeException { + + public ResponseTooLargeException(String message) { + super(message); + } +} diff --git a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java index 1bff91638fd..d755c509989 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java @@ -16,7 +16,7 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.opentripplanner.apis.transmodel.support.AbortOnTimeoutExecutionStrategy; +import org.opentripplanner.apis.transmodel.support.AbortOnUnprocessableRequestExecutionStrategy; import org.opentripplanner.apis.transmodel.support.ExecutionResultMapper; import org.opentripplanner.ext.actuator.MicrometerGraphQLInstrumentation; import org.opentripplanner.framework.application.OTPFeature; @@ -50,7 +50,7 @@ Response executeGraphQL( int maxNumberOfResultFields, Iterable tracingTags ) { - try (var executionStrategy = new AbortOnTimeoutExecutionStrategy()) { + try (var executionStrategy = new AbortOnUnprocessableRequestExecutionStrategy()) { variables = ObjectUtils.ifNotNull(variables, new HashMap<>()); var instrumentation = createInstrumentation(maxNumberOfResultFields, tracingTags); var transmodelRequestContext = createRequestContext(serverContext); @@ -69,6 +69,8 @@ Response executeGraphQL( return ExecutionResultMapper.okResponse(result); } catch (OTPRequestTimeoutException te) { return ExecutionResultMapper.timeoutResponse(); + } catch (ResponseTooLargeException rtle) { + return ExecutionResultMapper.tooLargeResponse(rtle.getMessage()); } catch (CoercingParseValueException | UnknownOperationException e) { return ExecutionResultMapper.badRequestResponse(e.getMessage()); } catch (Exception systemError) { diff --git a/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java b/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnUnprocessableRequestExecutionStrategy.java similarity index 62% rename from src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java rename to src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnUnprocessableRequestExecutionStrategy.java index a925aff0a1d..a8a664fc18d 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnUnprocessableRequestExecutionStrategy.java @@ -5,22 +5,28 @@ import graphql.schema.DataFetchingEnvironment; import java.io.Closeable; import java.util.concurrent.CompletableFuture; +import org.opentripplanner.apis.transmodel.ResponseTooLargeException; import org.opentripplanner.framework.application.OTPRequestTimeoutException; import org.opentripplanner.framework.logging.ProgressTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * To abort fetching data when a timeout occurs we have to rethrow the time-out-exception. + * To abort fetching data when a request is unprocessable (either because the execution times + * out or because the response is too large) we have to rethrow the exception. * This will prevent unresolved data-fetchers to be called. The exception is not handled * gracefully. */ -public class AbortOnTimeoutExecutionStrategy extends AsyncExecutionStrategy implements Closeable { +public class AbortOnUnprocessableRequestExecutionStrategy + extends AsyncExecutionStrategy + implements Closeable { - private static final Logger LOG = LoggerFactory.getLogger(AbortOnTimeoutExecutionStrategy.class); + private static final Logger LOG = LoggerFactory.getLogger( + AbortOnUnprocessableRequestExecutionStrategy.class + ); public static final int LOG_STEPS = 25_000; private final ProgressTracker timeoutProgressTracker = ProgressTracker.track( - "TIMEOUT! Abort GraphQL query", + "Unprocessable request. Abort GraphQL query", LOG_STEPS, -1 ); @@ -31,15 +37,15 @@ protected CompletableFuture handleFetchingException( ExecutionStrategyParameters params, Throwable e ) { - if (e instanceof OTPRequestTimeoutException te) { - logTimeoutProgress(); - throw te; + if (e instanceof OTPRequestTimeoutException || e instanceof ResponseTooLargeException) { + logCancellationProgress(); + throw (RuntimeException) e; } return super.handleFetchingException(environment, params, e); } @SuppressWarnings("Convert2MethodRef") - private void logTimeoutProgress() { + private void logCancellationProgress() { timeoutProgressTracker.startOrStep(m -> LOG.info(m)); } diff --git a/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java index d0ccb198e16..aac9cb1bb7c 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java @@ -16,6 +16,11 @@ public class ExecutionResultMapper { private static final ErrorClassification API_PROCESSING_TIMEOUT = ErrorClassification.errorClassification( "ApiProcessingTimeout" ); + + private static final ErrorClassification RESPONSE_TOO_LARGE = ErrorClassification.errorClassification( + "ResponseTooLarge" + ); + private static final ErrorClassification BAD_REQUEST_ERROR = ErrorClassification.errorClassification( "BadRequestError" ); @@ -29,13 +34,11 @@ public static Response okResponse(ExecutionResult result) { } public static Response timeoutResponse() { - var error = GraphQLError - .newError() - .errorType(API_PROCESSING_TIMEOUT) - .message(OTPRequestTimeoutException.MESSAGE) - .build(); - var result = ExecutionResult.newExecutionResult().addError(error).build(); - return response(result, OtpHttpStatus.STATUS_UNPROCESSABLE_ENTITY); + return unprocessableResponse(API_PROCESSING_TIMEOUT, OTPRequestTimeoutException.MESSAGE); + } + + public static Response tooLargeResponse(String message) { + return unprocessableResponse(RESPONSE_TOO_LARGE, message); } public static Response badRequestResponse(String message) { @@ -56,4 +59,13 @@ public static Response response(ExecutionResult result, Response.StatusType stat .entity(GraphQLResponseSerializer.serialize(result)) .build(); } + + private static Response unprocessableResponse( + ErrorClassification errorClassification, + String message + ) { + var error = GraphQLError.newError().errorType(errorClassification).message(message).build(); + var result = ExecutionResult.newExecutionResult().addError(error).build(); + return response(result, OtpHttpStatus.STATUS_UNPROCESSABLE_ENTITY); + } } diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 92d577480e2..da612c5ea20 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -85,7 +85,7 @@ static StyleSpec build( .lineColor(MAGENTA) .edgeFilter(EDGES_TO_DISPLAY) .lineWidth(LINE_WIDTH) - .minZoom(13) + .minZoom(6) .maxZoom(MAX_ZOOM) .intiallyHidden(), StyleBuilder diff --git a/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java b/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java index 9d798554f20..287a1a71c21 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/DirectTransferGenerator.java @@ -12,6 +12,10 @@ import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.graph_builder.issues.StopNotLinkedForTransfers; import org.opentripplanner.graph_builder.model.GraphBuilderModule; +import org.opentripplanner.graph_builder.module.nearbystops.NearbyStopFinder; +import org.opentripplanner.graph_builder.module.nearbystops.PatternConsideringNearbyStopFinder; +import org.opentripplanner.graph_builder.module.nearbystops.StraightLineNearbyStopFinder; +import org.opentripplanner.graph_builder.module.nearbystops.StreetNearbyStopFinder; import org.opentripplanner.model.PathTransfer; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.request.StreetRequest; @@ -68,20 +72,7 @@ public void buildGraph() { } /* The linker will use streets if they are available, or straight-line distance otherwise. */ - NearbyStopFinder nearbyStopFinder = new NearbyStopFinder( - new DefaultTransitService(transitModel), - radiusByDuration, - 0, - null, - graph.hasStreets - ); - if (nearbyStopFinder.useStreets) { - LOG.info("Creating direct transfer edges between stops using the street network from OSM..."); - } else { - LOG.info( - "Creating direct transfer edges between stops using straight line distance (not streets)..." - ); - } + NearbyStopFinder nearbyStopFinder = createNearbyStopFinder(); List stops = graph.getVerticesOfType(TransitStopVertex.class); @@ -189,6 +180,31 @@ public void buildGraph() { ); } + /** + * Factory method for creating a NearbyStopFinder. Will create different finders depending on + * whether the graph has a street network and if ConsiderPatternsForDirectTransfers feature is + * enabled. + */ + private NearbyStopFinder createNearbyStopFinder() { + var transitService = new DefaultTransitService(transitModel); + NearbyStopFinder finder; + if (!graph.hasStreets) { + LOG.info( + "Creating direct transfer edges between stops using straight line distance (not streets)..." + ); + finder = new StraightLineNearbyStopFinder(transitService, radiusByDuration); + } else { + LOG.info("Creating direct transfer edges between stops using the street network from OSM..."); + finder = new StreetNearbyStopFinder(radiusByDuration, 0, null); + } + + if (OTPFeature.ConsiderPatternsForDirectTransfers.isOn()) { + return new PatternConsideringNearbyStopFinder(transitService, finder); + } else { + return finder; + } + } + private static Iterable findNearbyStops( NearbyStopFinder nearbyStopFinder, Vertex vertex, @@ -196,14 +212,7 @@ private static Iterable findNearbyStops( StreetRequest streetRequest, boolean reverseDirection ) { - return OTPFeature.ConsiderPatternsForDirectTransfers.isOn() - ? nearbyStopFinder.findNearbyStopsConsideringPatterns( - vertex, - request, - streetRequest, - reverseDirection - ) - : nearbyStopFinder.findNearbyStops(vertex, request, streetRequest, reverseDirection); + return nearbyStopFinder.findNearbyStops(vertex, request, streetRequest, reverseDirection); } private record TransferKey(StopLocation source, StopLocation target, List edges) {} diff --git a/src/main/java/org/opentripplanner/graph_builder/module/MinMap.java b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/MinMap.java similarity index 95% rename from src/main/java/org/opentripplanner/graph_builder/module/MinMap.java rename to src/main/java/org/opentripplanner/graph_builder/module/nearbystops/MinMap.java index 6db53e39fc6..6492a134474 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/MinMap.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/MinMap.java @@ -1,4 +1,4 @@ -package org.opentripplanner.graph_builder.module; +package org.opentripplanner.graph_builder.module.nearbystops; import java.util.HashMap; diff --git a/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/NearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/NearbyStopFinder.java new file mode 100644 index 00000000000..13cc765987c --- /dev/null +++ b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/NearbyStopFinder.java @@ -0,0 +1,23 @@ +package org.opentripplanner.graph_builder.module.nearbystops; + +import java.util.Collection; +import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.routing.api.request.request.StreetRequest; +import org.opentripplanner.routing.graphfinder.NearbyStop; +import org.opentripplanner.street.model.vertex.Vertex; + +/** + * Interface for finding nearby stops from a given vertex. It is used by access + * and egress searches, and in transfer generation. + */ +public interface NearbyStopFinder { + /** + * Return all stops within a certain distance from the given vertex. + */ + Collection findNearbyStops( + Vertex vertex, + RouteRequest routingRequest, + StreetRequest streetRequest, + boolean reverseDirection + ); +} diff --git a/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/PatternConsideringNearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/PatternConsideringNearbyStopFinder.java new file mode 100644 index 00000000000..9abf759d076 --- /dev/null +++ b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/PatternConsideringNearbyStopFinder.java @@ -0,0 +1,94 @@ +package org.opentripplanner.graph_builder.module.nearbystops; + +import java.time.Duration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.opentripplanner.ext.dataoverlay.routing.DataOverlayContext; +import org.opentripplanner.ext.flex.trip.FlexTrip; +import org.opentripplanner.framework.application.OTPFeature; +import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.routing.api.request.request.StreetRequest; +import org.opentripplanner.routing.graphfinder.NearbyStop; +import org.opentripplanner.street.model.vertex.Vertex; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.service.TransitService; + +public class PatternConsideringNearbyStopFinder implements NearbyStopFinder { + + private final NearbyStopFinder delegateNearbyStopFinder; + private final TransitService transitService; + + public PatternConsideringNearbyStopFinder( + TransitService transitService, + NearbyStopFinder delegateNearbyStopFinder + ) { + this.transitService = transitService; + this.delegateNearbyStopFinder = delegateNearbyStopFinder; + } + + /** + * Find all unique nearby stops that are the closest stop on some trip pattern or flex trip. Note + * that the result will include the origin vertex if it is an instance of StopVertex. This is + * intentional: we don't want to return the next stop down the line for trip patterns that pass + * through the origin vertex. Taking the patterns into account reduces the number of transfers + * significantly compared to simple traverse-duration-constrained all-to-all stop linkage. + */ + @Override + public List findNearbyStops( + Vertex vertex, + RouteRequest routingRequest, + StreetRequest streetRequest, + boolean reverseDirection + ) { + /* Track the closest stop on each pattern passing nearby. */ + MinMap closestStopForPattern = new MinMap<>(); + + /* Track the closest stop on each flex trip nearby. */ + MinMap, NearbyStop> closestStopForFlexTrip = new MinMap<>(); + + /* Iterate over nearby stops via the street network or using straight-line distance. */ + for (NearbyStop nearbyStop : delegateNearbyStopFinder.findNearbyStops( + vertex, + routingRequest, + streetRequest, + reverseDirection + )) { + StopLocation ts1 = nearbyStop.stop; + + if (ts1 instanceof RegularStop) { + /* Consider this destination stop as a candidate for every trip pattern passing through it. */ + for (TripPattern pattern : transitService.getPatternsForStop(ts1)) { + if ( + reverseDirection + ? pattern.canAlight(nearbyStop.stop) + : pattern.canBoard(nearbyStop.stop) + ) { + closestStopForPattern.putMin(pattern, nearbyStop); + } + } + } + + if (OTPFeature.FlexRouting.isOn()) { + for (FlexTrip trip : transitService.getFlexIndex().getFlexTripsByStop(ts1)) { + if ( + reverseDirection + ? trip.isAlightingPossible(nearbyStop.stop) + : trip.isBoardingPossible(nearbyStop.stop) + ) { + closestStopForFlexTrip.putMin(trip, nearbyStop); + } + } + } + } + + /* Make a transfer from the origin stop to each destination stop that was the closest stop on any pattern. */ + Set uniqueStops = new HashSet<>(); + uniqueStops.addAll(closestStopForFlexTrip.values()); + uniqueStops.addAll(closestStopForPattern.values()); + // TODO: don't convert to list + return uniqueStops.stream().toList(); + } +} diff --git a/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java new file mode 100644 index 00000000000..5b304d0d20c --- /dev/null +++ b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StraightLineNearbyStopFinder.java @@ -0,0 +1,47 @@ +package org.opentripplanner.graph_builder.module.nearbystops; + +import java.time.Duration; +import java.util.List; +import org.locationtech.jts.geom.Coordinate; +import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.routing.api.request.preference.WalkPreferences; +import org.opentripplanner.routing.api.request.request.StreetRequest; +import org.opentripplanner.routing.graphfinder.DirectGraphFinder; +import org.opentripplanner.routing.graphfinder.NearbyStop; +import org.opentripplanner.street.model.vertex.Vertex; +import org.opentripplanner.transit.service.TransitService; + +public class StraightLineNearbyStopFinder implements NearbyStopFinder { + + private final Duration durationLimit; + private final DirectGraphFinder directGraphFinder; + + public StraightLineNearbyStopFinder(TransitService transitService, Duration durationLimit) { + this.durationLimit = durationLimit; + + // 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::findRegularStops); + } + + /** + * Find nearby stops using straight line distance. + */ + @Override + public List findNearbyStops( + Vertex vertex, + RouteRequest routingRequest, + StreetRequest streetRequest, + boolean reverseDirection + ) { + return findNearbyStopsViaDirectTransfers(vertex); + } + + private List findNearbyStopsViaDirectTransfers(Vertex vertex) { + // It make sense for the directGraphFinder to use meters as a limit, so we convert first + double limitMeters = durationLimit.toSeconds() * WalkPreferences.DEFAULT.speed(); + Coordinate c0 = vertex.getCoordinate(); + return directGraphFinder.findClosestStops(c0, limitMeters); + } +} diff --git a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StreetNearbyStopFinder.java similarity index 60% rename from src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java rename to src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StreetNearbyStopFinder.java index aca6e8a94cf..baf528a739f 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/NearbyStopFinder.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/nearbystops/StreetNearbyStopFinder.java @@ -1,4 +1,4 @@ -package org.opentripplanner.graph_builder.module; +package org.opentripplanner.graph_builder.module.nearbystops; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; @@ -7,24 +7,19 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Set; -import org.locationtech.jts.geom.Coordinate; import org.opentripplanner.astar.model.ShortestPathTree; import org.opentripplanner.astar.spi.SkipEdgeStrategy; import org.opentripplanner.astar.strategy.ComposingSkipEdgeStrategy; import org.opentripplanner.astar.strategy.DurationSkipEdgeStrategy; import org.opentripplanner.astar.strategy.MaxCountSkipEdgeStrategy; import org.opentripplanner.ext.dataoverlay.routing.DataOverlayContext; -import org.opentripplanner.ext.flex.trip.FlexTrip; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.application.OTPRequestTimeoutException; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.api.request.preference.WalkPreferences; import org.opentripplanner.routing.api.request.request.StreetRequest; -import org.opentripplanner.routing.graphfinder.DirectGraphFinder; import org.opentripplanner.routing.graphfinder.NearbyStop; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; @@ -38,139 +33,40 @@ import org.opentripplanner.street.search.request.StreetSearchRequestMapper; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.strategy.DominanceFunctions; -import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.AreaStop; -import org.opentripplanner.transit.model.site.RegularStop; -import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.service.TransitService; -/** - * This class contains code for finding nearby stops from a given vertex. It is being used by access - * and egress searches as well as transfer generation. - */ -public class NearbyStopFinder { - - public final boolean useStreets; - - private final TransitService transitService; +public class StreetNearbyStopFinder implements NearbyStopFinder { private final Duration durationLimit; private final int maxStopCount; private final DataOverlayContext dataOverlayContext; - private DirectGraphFinder directGraphFinder; - /** * Construct a NearbyStopFinder for the given graph and search radius. - * - * @param useStreets if true, search via the street network instead of using straight-line - * distance. */ - public NearbyStopFinder( - TransitService transitService, + public StreetNearbyStopFinder( Duration durationLimit, int maxStopCount, - DataOverlayContext dataOverlayContext, - boolean useStreets + DataOverlayContext dataOverlayContext ) { - this.transitService = transitService; this.dataOverlayContext = dataOverlayContext; - this.useStreets = useStreets; this.durationLimit = durationLimit; this.maxStopCount = maxStopCount; - - if (!useStreets) { - // 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::findRegularStops); - } - } - - /** - * Find all unique nearby stops that are the closest stop on some trip pattern or flex trip. Note - * that the result will include the origin vertex if it is an instance of StopVertex. This is - * intentional: we don't want to return the next stop down the line for trip patterns that pass - * through the origin vertex. - * Taking the patterns into account reduces the number of transfers significantly compared to - * simple traverse-duration-constrained all-to-all stop linkage. - */ - public Set findNearbyStopsConsideringPatterns( - Vertex vertex, - RouteRequest routingRequest, - StreetRequest streetRequest, - boolean reverseDirection - ) { - /* Track the closest stop on each pattern passing nearby. */ - MinMap closestStopForPattern = new MinMap<>(); - - /* Track the closest stop on each flex trip nearby. */ - MinMap, NearbyStop> closestStopForFlexTrip = new MinMap<>(); - - /* Iterate over nearby stops via the street network or using straight-line distance, depending on the graph. */ - for (NearbyStop nearbyStop : findNearbyStops( - vertex, - routingRequest, - streetRequest, - reverseDirection - )) { - StopLocation ts1 = nearbyStop.stop; - - if (ts1 instanceof RegularStop) { - /* Consider this destination stop as a candidate for every trip pattern passing through it. */ - for (TripPattern pattern : transitService.getPatternsForStop(ts1)) { - if ( - reverseDirection - ? pattern.canAlight(nearbyStop.stop) - : pattern.canBoard(nearbyStop.stop) - ) { - closestStopForPattern.putMin(pattern, nearbyStop); - } - } - } - - if (OTPFeature.FlexRouting.isOn()) { - for (FlexTrip trip : transitService.getFlexIndex().getFlexTripsByStop(ts1)) { - if ( - reverseDirection - ? trip.isAlightingPossible(nearbyStop.stop) - : trip.isBoardingPossible(nearbyStop.stop) - ) { - closestStopForFlexTrip.putMin(trip, nearbyStop); - } - } - } - } - - /* Make a transfer from the origin stop to each destination stop that was the closest stop on any pattern. */ - Set uniqueStops = new HashSet<>(); - uniqueStops.addAll(closestStopForFlexTrip.values()); - uniqueStops.addAll(closestStopForPattern.values()); - return uniqueStops; } /** * Return all stops within a certain radius of the given vertex, using network distance along - * streets. Use the correct method depending on whether the graph has street data or not. If the - * origin vertex is a StopVertex, the result will include it; this characteristic is essential for - * associating the correct stop with each trip pattern in the vicinity. + * streets. If the origin vertex is a StopVertex, the result will include it; this characteristic + * is essential for associating the correct stop with each trip pattern in the vicinity. */ - public List findNearbyStops( + @Override + public Collection findNearbyStops( Vertex vertex, RouteRequest routingRequest, StreetRequest streetRequest, boolean reverseDirection ) { - if (useStreets) { - return findNearbyStopsViaStreets( - Set.of(vertex), - reverseDirection, - routingRequest, - streetRequest - ); - } else { - return findNearbyStopsViaDirectTransfers(vertex); - } + return findNearbyStops(Set.of(vertex), reverseDirection, routingRequest, streetRequest); } /** @@ -181,7 +77,7 @@ public List findNearbyStops( * @param reverseDirection if true the paths returned instead originate at the nearby stops and * have the originVertex as the destination */ - public List findNearbyStopsViaStreets( + public Collection findNearbyStops( Set originVertices, boolean reverseDirection, RouteRequest request, @@ -262,18 +158,14 @@ public List findNearbyStopsViaStreets( return stopsFound; } - private List findNearbyStopsViaDirectTransfers(Vertex vertex) { - // It make sense for the directGraphFinder to use meters as a limit, so we convert first - double limitMeters = durationLimit.toSeconds() * WalkPreferences.DEFAULT.speed(); - Coordinate c0 = vertex.getCoordinate(); - return directGraphFinder.findClosestStops(c0, limitMeters); - } - private SkipEdgeStrategy getSkipEdgeStrategy() { var durationSkipEdgeStrategy = new DurationSkipEdgeStrategy(durationLimit); if (maxStopCount > 0) { - var strategy = new MaxCountSkipEdgeStrategy<>(maxStopCount, NearbyStopFinder::hasReachedStop); + var strategy = new MaxCountSkipEdgeStrategy<>( + maxStopCount, + StreetNearbyStopFinder::hasReachedStop + ); return new ComposingSkipEdgeStrategy<>(strategy, durationSkipEdgeStrategy); } return durationSkipEdgeStrategy; @@ -328,10 +220,9 @@ private boolean canBoardFlex(State state, boolean reverse) { * can dominate those that can thereby leading to zero found stops when this predicate is used with * the {@link MaxCountSkipEdgeStrategy}. *

- * An example of this would be an egress/reverse search with a very high walk reluctance where - * the states that speculatively rent a vehicle move the walk states down the A* priority queue - * until the required number of stops are reached to abort the search, leading to zero egress - * results. + * An example of this would be an egress/reverse search with a very high walk reluctance where the + * states that speculatively rent a vehicle move the walk states down the A* priority queue until + * the required number of stops are reached to abort the search, leading to zero egress results. */ public static boolean hasReachedStop(State state) { return state.getVertex() instanceof TransitStopVertex && state.isFinal(); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java index 6a1404c3039..06f4ff1cf45 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java @@ -247,7 +247,6 @@ private Collection fetchAccessEgresses(AccessEgre var nearbyStops = AccessEgressRouter.streetSearch( accessRequest, temporaryVerticesContainer, - serverContext.transitService(), streetRequest, serverContext.dataOverlayContext(accessRequest), type.isEgress(), diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressRouter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressRouter.java index d8b4132ba66..f6a0526fa66 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressRouter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressRouter.java @@ -2,10 +2,9 @@ import java.time.Duration; import java.util.Collection; -import java.util.List; import org.opentripplanner.ext.dataoverlay.routing.DataOverlayContext; import org.opentripplanner.framework.application.OTPRequestTimeoutException; -import org.opentripplanner.graph_builder.module.NearbyStopFinder; +import org.opentripplanner.graph_builder.module.nearbystops.StreetNearbyStopFinder; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.request.StreetRequest; import org.opentripplanner.routing.graphfinder.NearbyStop; @@ -31,7 +30,6 @@ private AccessEgressRouter() {} public static Collection streetSearch( RouteRequest request, TemporaryVerticesContainer verticesContainer, - TransitService transitService, StreetRequest streetRequest, DataOverlayContext dataOverlayContext, boolean fromTarget, @@ -39,14 +37,12 @@ public static Collection streetSearch( int maxStopCount ) { OTPRequestTimeoutException.checkForTimeout(); - NearbyStopFinder nearbyStopFinder = new NearbyStopFinder( - transitService, + var nearbyStopFinder = new StreetNearbyStopFinder( durationLimit, maxStopCount, - dataOverlayContext, - true + dataOverlayContext ); - List nearbyStopList = nearbyStopFinder.findNearbyStopsViaStreets( + Collection nearbyStopList = nearbyStopFinder.findNearbyStops( fromTarget ? verticesContainer.getToVertices() : verticesContainer.getFromVertices(), fromTarget, request, diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/DirectFlexRouter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/DirectFlexRouter.java index ff60138d77d..8e4cf1b222f 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/DirectFlexRouter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/DirectFlexRouter.java @@ -37,7 +37,6 @@ public static List route( Collection accessStops = AccessEgressRouter.streetSearch( request, temporaryVertices, - serverContext.transitService(), request.journey().direct(), serverContext.dataOverlayContext(request), false, @@ -47,7 +46,6 @@ public static List route( Collection egressStops = AccessEgressRouter.streetSearch( request, temporaryVertices, - serverContext.transitService(), request.journey().direct(), serverContext.dataOverlayContext(request), true, diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/FlexAccessEgressRouter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/FlexAccessEgressRouter.java index 5023e595678..68dda38211a 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/FlexAccessEgressRouter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/FlexAccessEgressRouter.java @@ -37,7 +37,6 @@ public static Collection routeAccessEgress( ? AccessEgressRouter.streetSearch( request, verticesContainer, - transitService, new StreetRequest(StreetMode.WALK), dataOverlayContext, false, @@ -50,7 +49,6 @@ public static Collection routeAccessEgress( ? AccessEgressRouter.streetSearch( request, verticesContainer, - transitService, new StreetRequest(StreetMode.WALK), dataOverlayContext, true, diff --git a/src/main/resources/Message.properties b/src/main/resources/Message.properties index 5c6011e3d3d..eafca543bd4 100644 --- a/src/main/resources/Message.properties +++ b/src/main/resources/Message.properties @@ -8,7 +8,8 @@ SYSTEM_ERROR = We're sorry. The trip planner is temporarily unavailable. Please GRAPH_UNAVAILABLE = We're sorry. The trip planner is temporarily unavailable. Please try again later. OUTSIDE_BOUNDS = Trip is not possible. You might be trying to plan a trip outside the map data boundary. -PROCESSING_TIMEOUT = The trip planner is taking too long to process your request. +UNPROCESSABLE_REQUEST = The trip planner is taking too long time or consuming too many resources to process your request. + BOGUS_PARAMETER = The request has errors that the server is not willing or able to process. LOCATION_NOT_ACCESSIBLE = The location was found, but no stops could be found within the search radius. PATH_NOT_FOUND = No trip found. There may be no transit service within the maximum specified distance or at the specified time, or your start or end point might not be safely accessible. diff --git a/src/main/resources/Message_de.properties b/src/main/resources/Message_de.properties index 1b0d8a2322e..7bace521ee8 100644 --- a/src/main/resources/Message_de.properties +++ b/src/main/resources/Message_de.properties @@ -2,7 +2,8 @@ PLAN_OK = Success SYSTEM_ERROR = Es tut uns leid, leider steht der Trip-Planer momentan nicht zur Verfügung. Bitte versuchen Sie es zu einem späteren Zeitpunkt nochmal. OUTSIDE_BOUNDS = Planung nicht möglich. Vielleicht versuchen sie einen Plan außerhalb der Kartengrenzen zu planen. -PROCESSING_TIMEOUT = Der Trip-Planner braucht zu lange um die Anfrage zu bearbeiten +UNPROCESSABLE_REQUEST = Der Trip-Planner braucht zu lange oder verbraucht zu viele Ressourcen, um die Anfrage zu bearbeiten + BOGUS_PARAMETER = Die Anfrage ist fehlerhaft so dass sie der Server nicht bearbeiten möchte oder kann. PATH_NOT_FOUND = Planung nicht möglich. Ihr Start- oder Endpunkt könnte nicht erreichbar sein. Bitte stellen sie sicher, dass ihre Anfrage innerhalb der Kartendaten ist. NO_TRANSIT_TIMES = Keine Fahrzeiten verfügbar. Das Datum kann zu weit in der Vergangenheit oder zu weit in der Zukunft liegen oder es gibt keinen Verkehrsbetrieb zu dem von Ihnen gewählten Zeitpunkt. diff --git a/src/main/resources/Message_es.properties b/src/main/resources/Message_es.properties index 0c5fe7a9395..1cdf7980252 100644 --- a/src/main/resources/Message_es.properties +++ b/src/main/resources/Message_es.properties @@ -8,7 +8,8 @@ SYSTEM_ERROR = ES-We're sorry. The trip planner is temporarily unavailable. Plea GRAPH_UNAVAILABLE = ES-We're sorry. The trip planner is temporarily unavailable. Please try again later. OUTSIDE_BOUNDS = ES-los trip is not possible. You might be trying to plan a trip outside the map data boundary. -PROCESSING_TIMEOUT = ES-los trip planner is taking too long to process your request. +UNPROCESSABLE_REQUEST = ES-los trip planner is taking too long time or consuming many resources to process your request. + BOGUS_PARAMETER = ES-los request has errors that the server is not willing or able to process. PATH_NOT_FOUND = ES-los trip is not possible. Please check that you plan is within the bound of the map. NO_TRANSIT_TIMES = ES-Non transit times available. The date may be past or too far in the future or there may not be transit service for your trip at the time you chose. diff --git a/src/main/resources/Message_fr.properties b/src/main/resources/Message_fr.properties index 6f7b73c1997..66ff82bbc59 100644 --- a/src/main/resources/Message_fr.properties +++ b/src/main/resources/Message_fr.properties @@ -8,7 +8,7 @@ SYSTEM_ERROR = Désolé: le calculateur d'itinéraires est temporairement indisp GRAPH_UNAVAILABLE = Désolé: le calculateur d'itinéraires est temporairement indisponible. Veuillez recommencer ultérieurement. OUTSIDE_BOUNDS = Impossible de calculer un itinéraire. Vous essayez de planifier un itinéraire hors des limites de la zone couverte. -PROCESSING_TIMEOUT = Le calculateur d'itinéraires prend trop de temps pour gérer votre demande. +UNPROCESSABLE_REQUEST = Le calculateur d'itinéraires prend trop de temps ou de resources pour gérer votre demande. BOGUS_PARAMETER = Le serveur ne peut pas prendre en compte la requête, elle contient des paramètres erronés. PATH_NOT_FOUND = Impossible de calculer un itinéraire. Veuillez vérifier que le trajet demandé est inclus dans la zone couverte. NO_TRANSIT_TIMES = Aucun voyage disponible. Soit la date est trop loin dans le futur, soit il n'y a pas de service ce jour. diff --git a/src/main/resources/Message_hu.properties b/src/main/resources/Message_hu.properties index eca5fad9b10..f72f2295581 100644 --- a/src/main/resources/Message_hu.properties +++ b/src/main/resources/Message_hu.properties @@ -8,7 +8,7 @@ SYSTEM_ERROR = Sajn\u00E1ljuk. Az \u00FAtvonaltervez\u0151 \u00E1tmenetileg GRAPH_UNAVAILABLE = Sajn\u00E1ljuk. Az \u00FAtvonaltervez\u0151 \u00E1tmenetileg nem el\u00E9rhet\u0151. K\u00E9rj\u00FCk, pr\u00F3b\u00E1lja \u00FAjra k\u00E9s\u0151bb. OUTSIDE_BOUNDS = Az utaz\u00E1s nem lehets\u00E9ges. Lehet, hogy a t\u00E9rk\u00E9padat-hat\u00E1ron k\u00EDv\u00FCli utat pr\u00F3b\u00E1l megtervezni. -PROCESSING_TIMEOUT = Az utaz\u00E1stervez\u0151 t\u00FAl sok\u00E1ig tart a k\u00E9r\u00E9s feldolgoz\u00E1s\u00E1hoz. +UNPROCESSABLE_REQUEST = Az utaz\u00E1stervez\u0151 t\u00FAl sok\u00E1ig tart a k\u00E9r\u00E9s feldolgoz\u00E1s\u00E1hoz. BOGUS_PARAMETER = A k\u00E9r\u00E9s olyan hib\u00E1kat tartalmaz, amelyeket a szerver nem hajland\u00F3 vagy nem k\u00E9pes feldolgozni. LOCATION_NOT_ACCESSIBLE = A helyek megtal\u00E1lhat\u00F3ak, de meg\u00E1ll\u00F3k nem tal\u00E1lhat\u00F3 a keres\u00E9si k\u00F6rzetben. PATH_NOT_FOUND = Nem tal\u00E1lhat\u00F3 utaz\u00E1s. El\u0151fordulhat, hogy a megadott maxim\u00E1lis t\u00E1vols\u00E1gon bel\u00FCl vagy a megadott id\u0151pontban nincs t\u00F6megk\u00F6zleked\u00E9si szolg\u00E1ltat\u00E1s, vagy a kezd\u0151- vagy v\u00E9gpont nem \u00E9rhet\u0151 el biztons\u00E1gosan. diff --git a/src/main/resources/Message_nl.properties b/src/main/resources/Message_nl.properties index 1e18c998264..2a7a1b7700b 100644 --- a/src/main/resources/Message_nl.properties +++ b/src/main/resources/Message_nl.properties @@ -8,7 +8,7 @@ SYSTEM_ERROR = Onze excuses. De routeplanner is momenteel niet beschikbaar. Prob GRAPH_UNAVAILABLE = Onze excuses. De routeplanner is momenteel niet beschikbaar. Probeer later opnieuw. OUTSIDE_BOUNDS = Deze reis is niet mogelijk. Mogelijk probeert u een reis te plannen buiten het beschikbare gebied -PROCESSING_TIMEOUT = De routeplanner is te lang bezig met uw verzoek. +UNPROCESSABLE_REQUEST = De routeplanner is te lang bezig met uw verzoek. BOGUS_PARAMETER = Uw verzoek bevat fouten die de server niet wil or kan verwerken. PATH_NOT_FOUND = Reis is niet mogelijk. Misschien is het startpunt of de bestemming niet veilig toegankelijk. Bijvoorbeeld een straat alleen verbonden met een snelweg. NO_TRANSIT_TIMES = Geen OV-informatie beschikbaar. De datum is mogelijk te ver in het verleden of te ver in de toekomst. Of er is geen dienst voor uw reis op het moment dat u wilt. diff --git a/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java index bce971e9f1e..b697adc9288 100644 --- a/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java @@ -34,6 +34,21 @@ class ExecutionResultMapperTest { "}" ); + public static final String TOO_LARGE_MESSAGE = + "The number of fields in the GraphQL result exceeds the maximum allowed: 100000"; + + private static final String TOO_LARGE_RESPONSE = quoteReplace( + "{'" + + "errors':[{" + + "'message':'" + + TOO_LARGE_MESSAGE + + "'," + + "'locations':[]," + + "'extensions':{'classification':'ResponseTooLarge'}" + + "}]" + + "}" + ); + public static final String SYSTEM_ERROR_MESSAGE = "A system error!"; public static final String SYSTEM_ERROR_RESPONSE = quoteReplace( @@ -62,6 +77,13 @@ void timeoutResponse() { assertEquals(TIMEOUT_RESPONSE, response.getEntity().toString()); } + @Test + void tooLargeResponse() { + var response = ExecutionResultMapper.tooLargeResponse(TOO_LARGE_MESSAGE); + assertEquals(422, response.getStatus()); + assertEquals(TOO_LARGE_RESPONSE, response.getEntity().toString()); + } + @Test void systemErrorResponse() { var response = ExecutionResultMapper.systemErrorResponse(SYSTEM_ERROR_MESSAGE); diff --git a/src/test/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategyTest.java b/src/test/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategyTest.java index 17dc26a4c5e..88976591ea1 100644 --- a/src/test/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategyTest.java +++ b/src/test/java/org/opentripplanner/astar/strategy/MaxCountSkipEdgeStrategyTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; -import org.opentripplanner.graph_builder.module.NearbyStopFinder; +import org.opentripplanner.graph_builder.module.nearbystops.StreetNearbyStopFinder; import org.opentripplanner.street.search.state.TestStateBuilder; class MaxCountSkipEdgeStrategyTest { @@ -12,7 +12,7 @@ class MaxCountSkipEdgeStrategyTest { @Test void countStops() { var state = TestStateBuilder.ofWalking().stop().build(); - var strategy = new MaxCountSkipEdgeStrategy<>(1, NearbyStopFinder::hasReachedStop); + var strategy = new MaxCountSkipEdgeStrategy<>(1, StreetNearbyStopFinder::hasReachedStop); assertFalse(strategy.shouldSkipEdge(state, null)); assertTrue(strategy.shouldSkipEdge(state, null)); } @@ -20,7 +20,7 @@ void countStops() { @Test void doNotCountStop() { var state = TestStateBuilder.ofWalking().build(); - var strategy = new MaxCountSkipEdgeStrategy<>(1, NearbyStopFinder::hasReachedStop); + var strategy = new MaxCountSkipEdgeStrategy<>(1, StreetNearbyStopFinder::hasReachedStop); assertFalse(strategy.shouldSkipEdge(state, null)); assertFalse(strategy.shouldSkipEdge(state, null)); assertFalse(strategy.shouldSkipEdge(state, null)); @@ -30,7 +30,7 @@ void doNotCountStop() { void nonFinalState() { var state = TestStateBuilder.ofScooterRentalArriveBy().stop().build(); assertFalse(state.isFinal()); - var strategy = new MaxCountSkipEdgeStrategy<>(1, NearbyStopFinder::hasReachedStop); + var strategy = new MaxCountSkipEdgeStrategy<>(1, StreetNearbyStopFinder::hasReachedStop); assertFalse(strategy.shouldSkipEdge(state, null)); } } diff --git a/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index c0e31a26f5d..d0aed828f6f 100644 --- a/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -29,7 +29,7 @@ "type" : "line", "source" : "vectorSource", "source-layer" : "edges", - "minzoom" : 13, + "minzoom" : 6, "maxzoom" : 23, "paint" : { "line-color" : "#f21d52",