From aba7f8088f432825423f768da62ead882d5ef3dc Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 8 Aug 2024 23:24:21 +0200 Subject: [PATCH 01/19] Filter stops by current service week --- .../ext/vectortiles/VectorTilesResource.java | 15 ++++++++- .../vectortiles/layers/stops/Predicates.java | 31 +++++++++++++++++++ .../layers/stops/StopsLayerBuilder.java | 20 ++++++------ .../gtfs/PatternByServiceDatesFilter.java | 8 +++++ .../config/routerconfig/VectorTileConfig.java | 10 +++--- 5 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index 29701ee2307..cbd5b7b082d 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -20,6 +20,7 @@ import org.opentripplanner.apis.support.TileJson; import org.opentripplanner.ext.vectortiles.layers.areastops.AreaStopsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.stations.StationsLayerBuilder; +import org.opentripplanner.ext.vectortiles.layers.stops.Predicates; import org.opentripplanner.ext.vectortiles.layers.stops.StopsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.vehicleparkings.VehicleParkingGroupsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.vehicleparkings.VehicleParkingsLayerBuilder; @@ -122,7 +123,18 @@ private static LayerBuilder createLayerBuilder( OtpServerRequestContext context ) { return switch (layerParameters.type()) { - case Stop -> new StopsLayerBuilder(context.transitService(), layerParameters, locale); + case Stop -> new StopsLayerBuilder( + context.transitService(), + layerParameters, + locale, + Predicates.NO_FILTER + ); + case CurrentServiceWeekStop -> new StopsLayerBuilder( + context.transitService(), + layerParameters, + locale, + Predicates.currentServiceWeek(context.transitService()) + ); case Station -> new StationsLayerBuilder(context.transitService(), layerParameters, locale); case AreaStop -> new AreaStopsLayerBuilder(context.transitService(), layerParameters, locale); case VehicleRental -> new VehicleRentalPlacesLayerBuilder( @@ -154,6 +166,7 @@ private static LayerBuilder createLayerBuilder( public enum LayerType { Stop, + CurrentServiceWeekStop, Station, AreaStop, VehicleRental, diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java new file mode 100644 index 00000000000..9b38587c22d --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java @@ -0,0 +1,31 @@ +package org.opentripplanner.ext.vectortiles.layers.stops; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.temporal.TemporalAdjusters; +import java.util.function.Predicate; +import org.opentripplanner.apis.gtfs.PatternByServiceDatesFilter; +import org.opentripplanner.apis.gtfs.model.LocalDateRange; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.service.TransitService; + +public class Predicates { + + public static final Predicate NO_FILTER = x -> true; + + public static Predicate currentServiceWeek(TransitService transitService) { + var serviceDate = LocalDate.now(transitService.getTimeZone()); + var lastSunday = serviceDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); + var nextSunday = serviceDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).plusDays(1); + var filter = new PatternByServiceDatesFilter( + new LocalDateRange(lastSunday, nextSunday), + transitService + ); + + return regularStop -> { + var patterns = transitService.getPatternsForStop(regularStop); + var patternsInCurrentWeek = filter.filterPatterns(patterns); + return !patternsInCurrentWeek.isEmpty(); + }; + } +} 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 aa664497728..a05851a90db 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 @@ -5,32 +5,28 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.function.BiFunction; -import java.util.stream.Collectors; +import java.util.function.Predicate; import org.locationtech.jts.geom.Envelope; import org.locationtech.jts.geom.Geometry; -import org.opentripplanner.apis.support.mapping.PropertyMapper; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.vector.LayerBuilder; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.service.TransitService; -public class StopsLayerBuilder extends LayerBuilder { +public class StopsLayerBuilder extends LayerBuilder { - static Map>> mappers = Map.of( - MapperType.Digitransit, - DigitransitStopPropertyMapper::create - ); private final TransitService transitService; + private final Predicate filter; public StopsLayerBuilder( TransitService transitService, LayerParameters layerParameters, - Locale locale + Locale locale, + Predicate filter ) { super( - (PropertyMapper) Map + Map .ofEntries( entry(MapperType.Digitransit, new DigitransitStopPropertyMapper(transitService, locale)), entry( @@ -43,12 +39,14 @@ public StopsLayerBuilder( layerParameters.expansionFactor() ); this.transitService = transitService; + this.filter = filter; } protected List getGeometries(Envelope query) { return transitService .findRegularStops(query) .stream() + .filter(filter) .map(stop -> { Geometry point = stop.getGeometry(); @@ -56,7 +54,7 @@ protected List getGeometries(Envelope query) { return point; }) - .collect(Collectors.toList()); + .toList(); } enum MapperType { diff --git a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java b/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java index 8eecfe6273b..fc980da4380 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java @@ -56,6 +56,14 @@ public PatternByServiceDatesFilter( ); } + public PatternByServiceDatesFilter(LocalDateRange range, TransitService transitService) { + this( + range, + transitService::getPatternsForRoute, + trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()) + ); + } + /** * Filter the patterns by the service dates that it operates on. */ diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 96cd49b72bb..d924a5a8328 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -12,14 +12,14 @@ import java.util.Optional; import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; +import org.opentripplanner.ext.vectortiles.VectorTilesResource.LayerType; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; -public class VectorTileConfig - implements VectorTilesResource.LayersParameters { +public class VectorTileConfig implements VectorTilesResource.LayersParameters { public static final VectorTileConfig DEFAULT = new VectorTileConfig(List.of(), null, null); - private final List> layers; + private final List> layers; @Nullable private final String basePath; @@ -28,7 +28,7 @@ public class VectorTileConfig private final String attribution; VectorTileConfig( - Collection> layers, + Collection> layers, @Nullable String basePath, @Nullable String attribution ) { @@ -38,7 +38,7 @@ public class VectorTileConfig } @Override - public List> layers() { + public List> layers() { return layers; } From 526e3f208904a086f681d2708ced7df2fc53878f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Aug 2024 10:22:31 +0200 Subject: [PATCH 02/19] Update example file --- .../examples/ibi/portland/router-config.json | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/doc/user/examples/ibi/portland/router-config.json b/doc/user/examples/ibi/portland/router-config.json index 0bf3547dbfd..d89fc05ec3b 100644 --- a/doc/user/examples/ibi/portland/router-config.json +++ b/doc/user/examples/ibi/portland/router-config.json @@ -59,6 +59,61 @@ "url": "https://gbfs.spin.pm/api/gbfs/v2/portland" } ], + "vectorTiles": { + "basePath": "/rtp/routers/default/vectorTiles", + "attribution": "Regional Partners", + "layers": [ + { + "name": "stops", + "type": "CurrentServiceWeekStop", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + { + "name": "areaStops", + "type": "AreaStop", + "mapper": "OTPRR", + "maxZoom": 30, + "minZoom": 8, + "cacheMaxSeconds": 600 + }, + { + "name": "stations", + "type": "Station", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 2, + "cacheMaxSeconds": 600 + }, + { + "name": "rentalVehicles", + "type": "VehicleRentalVehicle", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 2, + "cacheMaxSeconds": 60 + }, + { + "name": "rentalStations", + "type": "VehicleRentalStation", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 2, + "cacheMaxSeconds": 600 + }, + { + "name": "vehicleParking", + "type": "VehicleParking", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 10, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + } + ] + }, "rideHailingServices": [ { "type": "uber-car-hailing", From 6f1db53bee037b92f91703d93322d6dbf2c04551 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Sep 2024 18:13:28 +0200 Subject: [PATCH 03/19] Introduce vector tile filters --- .../examples/ibi/portland/router-config.json | 5 +++-- doc/user/sandbox/MapboxVectorTilesApi.md | 13 +++++++++++++ .../ext/vectortiles/VectorTilesResource.java | 15 +-------------- .../{Predicates.java => StopPredicates.java} | 14 +++++++++++++- .../layers/stops/StopsLayerBuilder.java | 5 ++--- .../inspector/vector/LayerParameters.java | 5 +++++ .../config/routerconfig/VectorTileConfig.java | 18 ++++++++++++++++-- 7 files changed, 53 insertions(+), 22 deletions(-) rename src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/{Predicates.java => StopPredicates.java} (77%) diff --git a/doc/user/examples/ibi/portland/router-config.json b/doc/user/examples/ibi/portland/router-config.json index d89fc05ec3b..33810d7054e 100644 --- a/doc/user/examples/ibi/portland/router-config.json +++ b/doc/user/examples/ibi/portland/router-config.json @@ -65,11 +65,12 @@ "layers": [ { "name": "stops", - "type": "CurrentServiceWeekStop", + "type": "Stop", "mapper": "Digitransit", "maxZoom": 20, "minZoom": 14, - "cacheMaxSeconds": 600 + "cacheMaxSeconds": 600, + "filter": "CURRENT_TRIMET_SERVICE_WEEK" }, { "name": "areaStops", diff --git a/doc/user/sandbox/MapboxVectorTilesApi.md b/doc/user/sandbox/MapboxVectorTilesApi.md index 62f3bd36c38..9720f4e95f9 100644 --- a/doc/user/sandbox/MapboxVectorTilesApi.md +++ b/doc/user/sandbox/MapboxVectorTilesApi.md @@ -173,6 +173,7 @@ For each layer, the configuration includes: |       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | |       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | |       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [filter](#vectorTiles_layers_0_filter) | `enum` | Reduce the result set of a layer further by a specific filter. | *Optional* | `"none"` | 2.6 | |       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | |       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | |       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | @@ -245,6 +246,18 @@ How far outside its boundaries should the tile contain information. The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. +

filter

+ +**Since version:** `2.6` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"none"` +**Path:** /vectorTiles/layers/[0] +**Enum values:** `none` | `current-trimet-service-week` + +Reduce the result set of a layer further by a specific filter. + +This is useful for when the schema of a layer, say stops, should remain unchanged but some +elements should not be included in the result. + +

mapper

**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index cbd5b7b082d..29701ee2307 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -20,7 +20,6 @@ import org.opentripplanner.apis.support.TileJson; import org.opentripplanner.ext.vectortiles.layers.areastops.AreaStopsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.stations.StationsLayerBuilder; -import org.opentripplanner.ext.vectortiles.layers.stops.Predicates; import org.opentripplanner.ext.vectortiles.layers.stops.StopsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.vehicleparkings.VehicleParkingGroupsLayerBuilder; import org.opentripplanner.ext.vectortiles.layers.vehicleparkings.VehicleParkingsLayerBuilder; @@ -123,18 +122,7 @@ private static LayerBuilder createLayerBuilder( OtpServerRequestContext context ) { return switch (layerParameters.type()) { - case Stop -> new StopsLayerBuilder( - context.transitService(), - layerParameters, - locale, - Predicates.NO_FILTER - ); - case CurrentServiceWeekStop -> new StopsLayerBuilder( - context.transitService(), - layerParameters, - locale, - Predicates.currentServiceWeek(context.transitService()) - ); + case Stop -> new StopsLayerBuilder(context.transitService(), layerParameters, locale); case Station -> new StationsLayerBuilder(context.transitService(), layerParameters, locale); case AreaStop -> new AreaStopsLayerBuilder(context.transitService(), layerParameters, locale); case VehicleRental -> new VehicleRentalPlacesLayerBuilder( @@ -166,7 +154,6 @@ private static LayerBuilder createLayerBuilder( public enum LayerType { Stop, - CurrentServiceWeekStop, Station, AreaStop, VehicleRental, diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java similarity index 77% rename from src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java rename to src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java index 9b38587c22d..55d31c227a6 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/Predicates.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java @@ -9,7 +9,7 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.service.TransitService; -public class Predicates { +public class StopPredicates { public static final Predicate NO_FILTER = x -> true; @@ -28,4 +28,16 @@ public static Predicate currentServiceWeek(TransitService transitSe return !patternsInCurrentWeek.isEmpty(); }; } + + public static Predicate forType(FilterType type, TransitService transitService) { + return switch (type) { + case NONE -> NO_FILTER; + case CURRENT_TRIMET_SERVICE_WEEK -> currentServiceWeek(transitService); + }; + } + + public enum FilterType { + NONE, + CURRENT_TRIMET_SERVICE_WEEK, + } } 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 a05851a90db..1a49c8e3696 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 @@ -22,8 +22,7 @@ public class StopsLayerBuilder extends LayerBuilder { public StopsLayerBuilder( TransitService transitService, LayerParameters layerParameters, - Locale locale, - Predicate filter + Locale locale ) { super( Map @@ -39,7 +38,7 @@ public StopsLayerBuilder( layerParameters.expansionFactor() ); this.transitService = transitService; - this.filter = filter; + this.filter = StopPredicates.forType(layerParameters.filterType(), transitService); } protected List getGeometries(Envelope query) { diff --git a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java index cb849e0f0ac..b37cad615e5 100644 --- a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java +++ b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java @@ -1,6 +1,7 @@ package org.opentripplanner.inspector.vector; import org.opentripplanner.apis.support.mapping.PropertyMapper; +import org.opentripplanner.ext.vectortiles.layers.stops.StopPredicates; /** * Configuration options for a single vector tile layer. @@ -53,4 +54,8 @@ default int cacheMaxSeconds() { default double expansionFactor() { return EXPANSION_FACTOR; } + + default StopPredicates.FilterType filterType() { + return StopPredicates.FilterType.NONE; + } } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index d924a5a8328..70f99a099de 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -6,6 +6,7 @@ import static org.opentripplanner.inspector.vector.LayerParameters.MIN_ZOOM; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_6; import java.util.Collection; import java.util.List; @@ -13,6 +14,7 @@ import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.ext.vectortiles.VectorTilesResource.LayerType; +import org.opentripplanner.ext.vectortiles.layers.stops.StopPredicates; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -144,7 +146,18 @@ public static Layer mapLayer(NodeAdapter node) { "The value is a fraction of the tile size. If you are having problem with icons and " + "shapes being clipped at tile edges, then increase this number." ) - .asDouble(EXPANSION_FACTOR) + .asDouble(EXPANSION_FACTOR), + node + .of("filter") + .since(V2_6) + .summary("Reduce the result set of a layer further by a specific filter.") + .description( + """ + This is useful for when the schema of a layer, say stops, should remain unchanged but some + elements should not be included in the result. + """ + ) + .asEnum(StopPredicates.FilterType.NONE) ); } @@ -155,7 +168,8 @@ record Layer( int maxZoom, int minZoom, int cacheMaxSeconds, - double expansionFactor + double expansionFactor, + StopPredicates.FilterType filterType ) implements LayerParameters {} } From 924fce0b73103803a6ec8dd09f853e795cddd7ad Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Sep 2024 21:51:48 +0200 Subject: [PATCH 04/19] Lowercase the enum name --- doc/user/examples/ibi/portland/router-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/examples/ibi/portland/router-config.json b/doc/user/examples/ibi/portland/router-config.json index 33810d7054e..8e392152dca 100644 --- a/doc/user/examples/ibi/portland/router-config.json +++ b/doc/user/examples/ibi/portland/router-config.json @@ -70,7 +70,7 @@ "maxZoom": 20, "minZoom": 14, "cacheMaxSeconds": 600, - "filter": "CURRENT_TRIMET_SERVICE_WEEK" + "filter": "current-trimet-service-week" }, { "name": "areaStops", From 0f5aaf66e8b2e148218ef3d9de92aa029664393a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 5 Sep 2024 14:22:10 +0200 Subject: [PATCH 05/19] Add documentation --- .../{StopPredicates.java => LayerFilters.java} | 13 ++++++++++++- .../vectortiles/layers/stops/StopsLayerBuilder.java | 2 +- .../inspector/vector/LayerParameters.java | 6 +++--- .../config/routerconfig/VectorTileConfig.java | 6 +++--- 4 files changed, 19 insertions(+), 8 deletions(-) rename src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/{StopPredicates.java => LayerFilters.java} (76%) diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java similarity index 76% rename from src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java rename to src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java index 55d31c227a6..ad0eafd9338 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/StopPredicates.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java @@ -9,10 +9,21 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.service.TransitService; -public class StopPredicates { +/** + * Predicates for filtering elements of vector tile layers. Currently only contains predicates + * for {@link RegularStop}. Once more types need to be filtered, this may need some refactoring. + */ +public class LayerFilters { + /** + * No filter is applied: all stops are included in the result. + */ public static final Predicate NO_FILTER = x -> true; + /** + * Returns a predicate which only includes stop which are visited by a pattern that is in the current + * TriMet service week, namely from Sunday to Sunday. + */ public static Predicate currentServiceWeek(TransitService transitService) { var serviceDate = LocalDate.now(transitService.getTimeZone()); var lastSunday = serviceDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); 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 1a49c8e3696..94497f83d0d 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 @@ -38,7 +38,7 @@ public StopsLayerBuilder( layerParameters.expansionFactor() ); this.transitService = transitService; - this.filter = StopPredicates.forType(layerParameters.filterType(), transitService); + this.filter = LayerFilters.forType(layerParameters.filterType(), transitService); } protected List getGeometries(Envelope query) { diff --git a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java index b37cad615e5..c4e64f39ab8 100644 --- a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java +++ b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java @@ -1,7 +1,7 @@ package org.opentripplanner.inspector.vector; import org.opentripplanner.apis.support.mapping.PropertyMapper; -import org.opentripplanner.ext.vectortiles.layers.stops.StopPredicates; +import org.opentripplanner.ext.vectortiles.layers.stops.LayerFilters; /** * Configuration options for a single vector tile layer. @@ -55,7 +55,7 @@ default double expansionFactor() { return EXPANSION_FACTOR; } - default StopPredicates.FilterType filterType() { - return StopPredicates.FilterType.NONE; + default LayerFilters.FilterType filterType() { + return LayerFilters.FilterType.NONE; } } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 70f99a099de..1eb75c8d394 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -14,7 +14,7 @@ import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.ext.vectortiles.VectorTilesResource.LayerType; -import org.opentripplanner.ext.vectortiles.layers.stops.StopPredicates; +import org.opentripplanner.ext.vectortiles.layers.stops.LayerFilters; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -157,7 +157,7 @@ public static Layer mapLayer(NodeAdapter node) { elements should not be included in the result. """ ) - .asEnum(StopPredicates.FilterType.NONE) + .asEnum(LayerFilters.FilterType.NONE) ); } @@ -169,7 +169,7 @@ record Layer( int minZoom, int cacheMaxSeconds, double expansionFactor, - StopPredicates.FilterType filterType + LayerFilters.FilterType filterType ) implements LayerParameters {} } From 9303ee54a468b318d84c7d281c784c4a15cdb12f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 5 Sep 2024 16:55:42 +0200 Subject: [PATCH 06/19] Add test --- .../layers/stops/LayerFiltersTest.java | 42 ++++++++++++++++++ .../layers/stops/LayerFilters.java | 28 +++++++++--- .../gtfs/PatternByServiceDatesFilter.java | 10 +---- .../gtfs/PatternByServiceDatesFilterTest.java | 38 +--------------- .../apis/gtfs/PatternTestModel.java | 44 +++++++++++++++++++ 5 files changed, 112 insertions(+), 50 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java new file mode 100644 index 00000000000..6021662ab4b --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java @@ -0,0 +1,42 @@ +package org.opentripplanner.ext.vectortiles.layers.stops; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.opentripplanner.apis.gtfs.PatternTestModel; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.site.RegularStop; + +class LayerFiltersTest { + + private static final RegularStop STOP = TransitModelForTest.of().stop("1").build(); + private static final LocalDate DATE = LocalDate.of(2024, 9, 5); + private static final TripPattern PATTERN = PatternTestModel.pattern(); + + @Test + void includeStopWithinServiceWeek() { + var predicate = LayerFilters.currentServiceWeek( + s -> List.of(PATTERN), + trip -> List.of(DATE), + () -> DATE + ); + + assertTrue(predicate.test(STOP)); + } + + @Test + void excludeOutsideServiceWeek() { + var inThreeWeeks = DATE.plusDays(21); + var predicate = LayerFilters.currentServiceWeek( + s -> List.of(PATTERN), + trip -> List.of(inThreeWeeks), + () -> DATE + ); + + assertFalse(predicate.test(STOP)); + } +} diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java index ad0eafd9338..eddb4c6b745 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java @@ -3,10 +3,16 @@ import java.time.DayOfWeek; import java.time.LocalDate; import java.time.temporal.TemporalAdjusters; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import org.opentripplanner.apis.gtfs.PatternByServiceDatesFilter; import org.opentripplanner.apis.gtfs.model.LocalDateRange; +import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.service.TransitService; /** @@ -24,17 +30,24 @@ public class LayerFilters { * Returns a predicate which only includes stop which are visited by a pattern that is in the current * TriMet service week, namely from Sunday to Sunday. */ - public static Predicate currentServiceWeek(TransitService transitService) { - var serviceDate = LocalDate.now(transitService.getTimeZone()); + public static Predicate currentServiceWeek( + Function> getPatternsForStop, + Function> getServiceDatesForTrip, + Supplier nowSupplier + ) { + var serviceDate = nowSupplier.get(); var lastSunday = serviceDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); var nextSunday = serviceDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).plusDays(1); + var filter = new PatternByServiceDatesFilter( new LocalDateRange(lastSunday, nextSunday), - transitService + // not used + route -> List.of(), + getServiceDatesForTrip ); return regularStop -> { - var patterns = transitService.getPatternsForStop(regularStop); + var patterns = getPatternsForStop.apply(regularStop); var patternsInCurrentWeek = filter.filterPatterns(patterns); return !patternsInCurrentWeek.isEmpty(); }; @@ -43,7 +56,12 @@ public static Predicate currentServiceWeek(TransitService transitSe public static Predicate forType(FilterType type, TransitService transitService) { return switch (type) { case NONE -> NO_FILTER; - case CURRENT_TRIMET_SERVICE_WEEK -> currentServiceWeek(transitService); + case CURRENT_TRIMET_SERVICE_WEEK -> currentServiceWeek( + transitService::getPatternsForStop, + trip -> + transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()), + () -> LocalDate.now(transitService.getTimeZone()) + ); }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java b/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java index fc980da4380..8cf72bf9365 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java @@ -29,7 +29,7 @@ public class PatternByServiceDatesFilter { * This method is not private to enable unit testing. *

*/ - PatternByServiceDatesFilter( + public PatternByServiceDatesFilter( LocalDateRange range, Function> getPatternsForRoute, Function> getServiceDatesForTrip @@ -56,14 +56,6 @@ public PatternByServiceDatesFilter( ); } - public PatternByServiceDatesFilter(LocalDateRange range, TransitService transitService) { - this( - range, - transitService::getPatternsForRoute, - trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()) - ); - } - /** * Filter the patterns by the service dates that it operates on. */ diff --git a/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java b/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java index f01bac12006..934bc5a9b1e 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java @@ -6,7 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.opentripplanner.apis.gtfs.PatternByServiceDatesFilterTest.FilterExpectation.NOT_REMOVED; import static org.opentripplanner.apis.gtfs.PatternByServiceDatesFilterTest.FilterExpectation.REMOVED; -import static org.opentripplanner.transit.model._data.TransitModelForTest.id; +import static org.opentripplanner.apis.gtfs.PatternTestModel.ROUTE_1; import java.time.LocalDate; import java.util.List; @@ -14,51 +14,17 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.apis.gtfs.model.LocalDateRange; -import org.opentripplanner.transit.model._data.TransitModelForTest; -import org.opentripplanner.transit.model.framework.FeedScopedId; -import org.opentripplanner.transit.model.network.Route; -import org.opentripplanner.transit.model.network.StopPattern; import org.opentripplanner.transit.model.network.TripPattern; -import org.opentripplanner.transit.model.site.RegularStop; -import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; -import org.opentripplanner.transit.model.timetable.Trip; -import org.opentripplanner.transit.service.StopModel; class PatternByServiceDatesFilterTest { - private static final Route ROUTE_1 = TransitModelForTest.route("1").build(); - private static final FeedScopedId SERVICE_ID = id("service"); - private static final Trip TRIP = TransitModelForTest - .trip("t1") - .withRoute(ROUTE_1) - .withServiceId(SERVICE_ID) - .build(); - private static final TransitModelForTest MODEL = new TransitModelForTest(StopModel.of()); - private static final RegularStop STOP_1 = MODEL.stop("1").build(); - private static final StopPattern STOP_PATTERN = TransitModelForTest.stopPattern(STOP_1, STOP_1); - private static final TripPattern PATTERN_1 = pattern(); + private static final TripPattern PATTERN_1 = PatternTestModel.pattern(); enum FilterExpectation { REMOVED, NOT_REMOVED, } - private static TripPattern pattern() { - var pattern = TransitModelForTest - .tripPattern("1", ROUTE_1) - .withStopPattern(STOP_PATTERN) - .build(); - - var tt = ScheduledTripTimes - .of() - .withTrip(TRIP) - .withArrivalTimes("10:00 10:05") - .withDepartureTimes("10:00 10:05") - .build(); - pattern.add(tt); - return pattern; - } - static List invalidRangeCases() { return List.of( Arguments.of(null, null), diff --git a/src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java b/src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java new file mode 100644 index 00000000000..fda75d9e174 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java @@ -0,0 +1,44 @@ +package org.opentripplanner.apis.gtfs; + +import static org.opentripplanner.transit.model._data.TransitModelForTest.id; + +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.StopPattern; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.service.StopModel; + +public class PatternTestModel { + + public static final Route ROUTE_1 = TransitModelForTest.route("1").build(); + + private static final FeedScopedId SERVICE_ID = id("service"); + private static final Trip TRIP = TransitModelForTest + .trip("t1") + .withRoute(ROUTE_1) + .withServiceId(SERVICE_ID) + .build(); + private static final TransitModelForTest MODEL = new TransitModelForTest(StopModel.of()); + private static final RegularStop STOP_1 = MODEL.stop("1").build(); + private static final StopPattern STOP_PATTERN = TransitModelForTest.stopPattern(STOP_1, STOP_1); + + public static TripPattern pattern() { + var pattern = TransitModelForTest + .tripPattern("1", ROUTE_1) + .withStopPattern(STOP_PATTERN) + .build(); + + var tt = ScheduledTripTimes + .of() + .withTrip(TRIP) + .withArrivalTimes("10:00 10:05") + .withDepartureTimes("10:00 10:05") + .build(); + pattern.add(tt); + return pattern; + } +} From 966a7c9f9797aa2ad2f9b8e5f696fa1d27c7ce49 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 10 Sep 2024 16:40:15 +0200 Subject: [PATCH 07/19] Move filter class into transit.service --- .../layers/stops/LayerFilters.java | 2 +- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 7 ++++-- .../apis/gtfs/datafetchers/RouteImpl.java | 7 ++++-- .../filter/PatternByDateFilterUtil.java | 23 +++++++++++++++++++ .../service}/PatternByServiceDatesFilter.java | 15 +----------- .../PatternByServiceDatesFilterTest.java | 7 +++--- 6 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java rename src/main/java/org/opentripplanner/{apis/gtfs => transit/service}/PatternByServiceDatesFilter.java (82%) rename src/test/java/org/opentripplanner/{apis/gtfs => transit/service}/PatternByServiceDatesFilterTest.java (92%) diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java index eddb4c6b745..54e4052ee63 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java @@ -8,11 +8,11 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import org.opentripplanner.apis.gtfs.PatternByServiceDatesFilter; import org.opentripplanner.apis.gtfs.model.LocalDateRange; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.service.PatternByServiceDatesFilter; import org.opentripplanner.transit.service.TransitService; /** 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 0e70c13074b..d5551a9b902 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -27,12 +27,12 @@ import org.locationtech.jts.geom.Envelope; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.GraphQLUtils; -import org.opentripplanner.apis.gtfs.PatternByServiceDatesFilter; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLQueryTypeStopsByRadiusArgs; import org.opentripplanner.apis.gtfs.mapping.routerequest.LegacyRouteRequestMapper; import org.opentripplanner.apis.gtfs.mapping.routerequest.RouteRequestMapper; +import org.opentripplanner.apis.gtfs.support.filter.PatternByDateFilterUtil; import org.opentripplanner.apis.gtfs.support.time.LocalDateRangeUtil; import org.opentripplanner.ext.fares.impl.DefaultFareService; import org.opentripplanner.ext.fares.impl.GtfsFaresService; @@ -615,7 +615,10 @@ public DataFetcher> routes() { } if (LocalDateRangeUtil.hasServiceDateFilter(args.getGraphQLServiceDates())) { - var filter = new PatternByServiceDatesFilter(args.getGraphQLServiceDates(), transitService); + var filter = PatternByDateFilterUtil.ofGraphQL( + args.getGraphQLServiceDates(), + transitService + ); routeStream = filter.filterRoutes(routeStream).stream(); } return routeStream.toList(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RouteImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RouteImpl.java index a3f557951f0..ae6acb0a297 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RouteImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RouteImpl.java @@ -9,12 +9,12 @@ import java.util.stream.Collectors; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.GraphQLUtils; -import org.opentripplanner.apis.gtfs.PatternByServiceDatesFilter; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLBikesAllowed; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; import org.opentripplanner.apis.gtfs.mapping.BikesAllowedMapper; +import org.opentripplanner.apis.gtfs.support.filter.PatternByDateFilterUtil; import org.opentripplanner.apis.gtfs.support.time.LocalDateRangeUtil; import org.opentripplanner.routing.alertpatch.EntitySelector; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -183,7 +183,10 @@ public DataFetcher> patterns() { var args = new GraphQLTypes.GraphQLRoutePatternsArgs(environment.getArguments()); if (LocalDateRangeUtil.hasServiceDateFilter(args.getGraphQLServiceDates())) { - var filter = new PatternByServiceDatesFilter(args.getGraphQLServiceDates(), transitService); + var filter = PatternByDateFilterUtil.ofGraphQL( + args.getGraphQLServiceDates(), + transitService + ); return filter.filterPatterns(patterns); } else { return patterns; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java b/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java new file mode 100644 index 00000000000..204cdbd0886 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java @@ -0,0 +1,23 @@ +package org.opentripplanner.apis.gtfs.support.filter; + +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; +import org.opentripplanner.apis.gtfs.model.LocalDateRange; +import org.opentripplanner.transit.service.PatternByServiceDatesFilter; +import org.opentripplanner.transit.service.TransitService; + +/** + * Utility methods for instantiating a {@link PatternByServiceDatesFilter}/ + */ +public class PatternByDateFilterUtil { + + public static PatternByServiceDatesFilter ofGraphQL( + GraphQLTypes.GraphQLLocalDateRangeInput range, + TransitService transitService + ) { + return new PatternByServiceDatesFilter( + new LocalDateRange(range.getGraphQLStart(), range.getGraphQLEnd()), + transitService::getPatternsForRoute, + trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()) + ); + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java b/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java similarity index 82% rename from src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java rename to src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java index 8cf72bf9365..30c501af4a0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilter.java +++ b/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java @@ -1,16 +1,14 @@ -package org.opentripplanner.apis.gtfs; +package org.opentripplanner.transit.service; import java.time.LocalDate; import java.util.Collection; import java.util.Objects; import java.util.function.Function; import java.util.stream.Stream; -import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; import org.opentripplanner.apis.gtfs.model.LocalDateRange; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.timetable.Trip; -import org.opentripplanner.transit.service.TransitService; /** * Encapsulates the logic to filter patterns by the service dates that they operate on. It also @@ -45,17 +43,6 @@ public PatternByServiceDatesFilter( } } - public PatternByServiceDatesFilter( - GraphQLTypes.GraphQLLocalDateRangeInput filterInput, - TransitService transitService - ) { - this( - new LocalDateRange(filterInput.getGraphQLStart(), filterInput.getGraphQLEnd()), - transitService::getPatternsForRoute, - trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()) - ); - } - /** * Filter the patterns by the service dates that it operates on. */ diff --git a/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java similarity index 92% rename from src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java rename to src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java index 934bc5a9b1e..55cb2ba9017 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/PatternByServiceDatesFilterTest.java +++ b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java @@ -1,18 +1,19 @@ -package org.opentripplanner.apis.gtfs; +package org.opentripplanner.transit.service; import static java.time.LocalDate.parse; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.opentripplanner.apis.gtfs.PatternByServiceDatesFilterTest.FilterExpectation.NOT_REMOVED; -import static org.opentripplanner.apis.gtfs.PatternByServiceDatesFilterTest.FilterExpectation.REMOVED; import static org.opentripplanner.apis.gtfs.PatternTestModel.ROUTE_1; +import static org.opentripplanner.transit.service.PatternByServiceDatesFilterTest.FilterExpectation.NOT_REMOVED; +import static org.opentripplanner.transit.service.PatternByServiceDatesFilterTest.FilterExpectation.REMOVED; import java.time.LocalDate; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner.apis.gtfs.PatternTestModel; import org.opentripplanner.apis.gtfs.model.LocalDateRange; import org.opentripplanner.transit.model.network.TripPattern; From a6182194d3f17feced1cb6b2e40c50cc6c68ca8c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 10:17:42 +0200 Subject: [PATCH 08/19] Move LayerFilters up one level --- .../ext/vectortiles/layers/{stops => }/LayerFiltersTest.java | 2 +- .../ext/vectortiles/layers/{stops => }/LayerFilters.java | 2 +- .../ext/vectortiles/layers/stops/StopsLayerBuilder.java | 1 + .../org/opentripplanner/inspector/vector/LayerParameters.java | 2 +- .../standalone/config/routerconfig/VectorTileConfig.java | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) rename src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/{stops => }/LayerFiltersTest.java (95%) rename src/ext/java/org/opentripplanner/ext/vectortiles/layers/{stops => }/LayerFilters.java (97%) diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java similarity index 95% rename from src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java rename to src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java index 6021662ab4b..e0418ac0c57 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFiltersTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.vectortiles.layers.stops; +package org.opentripplanner.ext.vectortiles.layers; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java rename to src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java index 54e4052ee63..bdd83a2c020 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.vectortiles.layers.stops; +package org.opentripplanner.ext.vectortiles.layers; import java.time.DayOfWeek; import java.time.LocalDate; 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 94497f83d0d..141157f8f3e 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 @@ -9,6 +9,7 @@ import org.locationtech.jts.geom.Envelope; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.ext.vectortiles.VectorTilesResource; +import org.opentripplanner.ext.vectortiles.layers.LayerFilters; import org.opentripplanner.inspector.vector.LayerBuilder; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.transit.model.site.RegularStop; diff --git a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java index c4e64f39ab8..70cb5a2ce43 100644 --- a/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java +++ b/src/main/java/org/opentripplanner/inspector/vector/LayerParameters.java @@ -1,7 +1,7 @@ package org.opentripplanner.inspector.vector; import org.opentripplanner.apis.support.mapping.PropertyMapper; -import org.opentripplanner.ext.vectortiles.layers.stops.LayerFilters; +import org.opentripplanner.ext.vectortiles.layers.LayerFilters; /** * Configuration options for a single vector tile layer. diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 1eb75c8d394..26d56dc0dba 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -14,7 +14,7 @@ import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.ext.vectortiles.VectorTilesResource.LayerType; -import org.opentripplanner.ext.vectortiles.layers.stops.LayerFilters; +import org.opentripplanner.ext.vectortiles.layers.LayerFilters; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; From 5c76b0b7bae0da6562123194a59bc63d2314d4ef Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 10:21:22 +0200 Subject: [PATCH 09/19] Rename variable --- .../ext/vectortiles/layers/LayerFiltersTest.java | 4 ++-- .../ext/vectortiles/layers/LayerFilters.java | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java index e0418ac0c57..a3c18366d3d 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java @@ -19,7 +19,7 @@ class LayerFiltersTest { @Test void includeStopWithinServiceWeek() { - var predicate = LayerFilters.currentServiceWeek( + var predicate = LayerFilters.buildCurrentServiceWeekPredicate( s -> List.of(PATTERN), trip -> List.of(DATE), () -> DATE @@ -31,7 +31,7 @@ void includeStopWithinServiceWeek() { @Test void excludeOutsideServiceWeek() { var inThreeWeeks = DATE.plusDays(21); - var predicate = LayerFilters.currentServiceWeek( + var predicate = LayerFilters.buildCurrentServiceWeekPredicate( s -> List.of(PATTERN), trip -> List.of(inThreeWeeks), () -> DATE diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java index bdd83a2c020..7b8d939e38c 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java @@ -30,17 +30,18 @@ public class LayerFilters { * Returns a predicate which only includes stop which are visited by a pattern that is in the current * TriMet service week, namely from Sunday to Sunday. */ - public static Predicate currentServiceWeek( + public static Predicate buildCurrentServiceWeekPredicate( Function> getPatternsForStop, Function> getServiceDatesForTrip, Supplier nowSupplier ) { var serviceDate = nowSupplier.get(); var lastSunday = serviceDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)); - var nextSunday = serviceDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).plusDays(1); + var nextSundayPlusOne = serviceDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).plusDays(1); var filter = new PatternByServiceDatesFilter( - new LocalDateRange(lastSunday, nextSunday), + // reminder, the end of the date range is exclusive so it's the next Sunday plus one day + new LocalDateRange(lastSunday, nextSundayPlusOne), // not used route -> List.of(), getServiceDatesForTrip @@ -56,7 +57,7 @@ public static Predicate currentServiceWeek( public static Predicate forType(FilterType type, TransitService transitService) { return switch (type) { case NONE -> NO_FILTER; - case CURRENT_TRIMET_SERVICE_WEEK -> currentServiceWeek( + case CURRENT_TRIMET_SERVICE_WEEK -> buildCurrentServiceWeekPredicate( transitService::getPatternsForStop, trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()), From cc51cb1fa0555379accd751a09dcee9024dda20b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 10:35:32 +0200 Subject: [PATCH 10/19] Move test generation model --- .../ext/vectortiles/layers/LayerFiltersTest.java | 2 +- .../gtfs => transit/model/_data}/PatternTestModel.java | 6 ++++-- .../transit/service/PatternByServiceDatesFilterTest.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) rename src/test/java/org/opentripplanner/{apis/gtfs => transit/model/_data}/PatternTestModel.java (90%) diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java index a3c18366d3d..f12d43b62cf 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/LayerFiltersTest.java @@ -6,7 +6,7 @@ import java.time.LocalDate; import java.util.List; import org.junit.jupiter.api.Test; -import org.opentripplanner.apis.gtfs.PatternTestModel; +import org.opentripplanner.transit.model._data.PatternTestModel; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; diff --git a/src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java b/src/test/java/org/opentripplanner/transit/model/_data/PatternTestModel.java similarity index 90% rename from src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java rename to src/test/java/org/opentripplanner/transit/model/_data/PatternTestModel.java index fda75d9e174..c3afd0ddf61 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/PatternTestModel.java +++ b/src/test/java/org/opentripplanner/transit/model/_data/PatternTestModel.java @@ -1,8 +1,7 @@ -package org.opentripplanner.apis.gtfs; +package org.opentripplanner.transit.model._data; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; -import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.StopPattern; @@ -26,6 +25,9 @@ public class PatternTestModel { private static final RegularStop STOP_1 = MODEL.stop("1").build(); private static final StopPattern STOP_PATTERN = TransitModelForTest.stopPattern(STOP_1, STOP_1); + /** + * Creates a trip pattern that has a stop pattern, trip times and a trip with a service id. + */ public static TripPattern pattern() { var pattern = TransitModelForTest .tripPattern("1", ROUTE_1) diff --git a/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java index 55cb2ba9017..ffc734f6038 100644 --- a/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java +++ b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.opentripplanner.apis.gtfs.PatternTestModel.ROUTE_1; +import static org.opentripplanner.transit.model._data.PatternTestModel.ROUTE_1; import static org.opentripplanner.transit.service.PatternByServiceDatesFilterTest.FilterExpectation.NOT_REMOVED; import static org.opentripplanner.transit.service.PatternByServiceDatesFilterTest.FilterExpectation.REMOVED; @@ -13,8 +13,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.opentripplanner.apis.gtfs.PatternTestModel; import org.opentripplanner.apis.gtfs.model.LocalDateRange; +import org.opentripplanner.transit.model._data.PatternTestModel; import org.opentripplanner.transit.model.network.TripPattern; class PatternByServiceDatesFilterTest { From 8b885dc60079ab157cec2d45434a0d8ca31a9776 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 12:17:49 +0200 Subject: [PATCH 11/19] Rename enum to SUNDAY_TO_SUNDAY_SERVICE_WEEK --- doc/user/examples/ibi/portland/router-config.json | 2 +- doc/user/sandbox/MapboxVectorTilesApi.md | 2 +- .../opentripplanner/ext/vectortiles/layers/LayerFilters.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/user/examples/ibi/portland/router-config.json b/doc/user/examples/ibi/portland/router-config.json index 8e392152dca..acbcbc2e0a0 100644 --- a/doc/user/examples/ibi/portland/router-config.json +++ b/doc/user/examples/ibi/portland/router-config.json @@ -70,7 +70,7 @@ "maxZoom": 20, "minZoom": 14, "cacheMaxSeconds": 600, - "filter": "current-trimet-service-week" + "filter": "sunday-to-sunday-service-week" }, { "name": "areaStops", diff --git a/doc/user/sandbox/MapboxVectorTilesApi.md b/doc/user/sandbox/MapboxVectorTilesApi.md index 9720f4e95f9..4430a398a5d 100644 --- a/doc/user/sandbox/MapboxVectorTilesApi.md +++ b/doc/user/sandbox/MapboxVectorTilesApi.md @@ -250,7 +250,7 @@ The value is a fraction of the tile size. If you are having problem with icons a **Since version:** `2.6` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"none"` **Path:** /vectorTiles/layers/[0] -**Enum values:** `none` | `current-trimet-service-week` +**Enum values:** `none` | `sunday-to-sunday-service-week` Reduce the result set of a layer further by a specific filter. diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java index 7b8d939e38c..9672a9810c1 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java @@ -57,7 +57,7 @@ public static Predicate buildCurrentServiceWeekPredicate( public static Predicate forType(FilterType type, TransitService transitService) { return switch (type) { case NONE -> NO_FILTER; - case CURRENT_TRIMET_SERVICE_WEEK -> buildCurrentServiceWeekPredicate( + case SUNDAY_TO_SUNDAY_SERVICE_WEEK -> buildCurrentServiceWeekPredicate( transitService::getPatternsForStop, trip -> transitService.getCalendarService().getServiceDatesForServiceId(trip.getServiceId()), @@ -68,6 +68,6 @@ public static Predicate forType(FilterType type, TransitService tra public enum FilterType { NONE, - CURRENT_TRIMET_SERVICE_WEEK, + SUNDAY_TO_SUNDAY_SERVICE_WEEK, } } From cd73bd7605a6d03627b8461cc798619ac88636a4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 13 Sep 2024 16:58:27 +0200 Subject: [PATCH 12/19] Extend schema for filtering routes by service dates --- .../apis/gtfs/datafetchers/StopImpl.java | 4 +++- .../org/opentripplanner/apis/gtfs/schema.graphqls | 11 ++++++++++- .../apis/gtfs/GraphQLIntegrationTest.java | 8 ++++++++ .../opentripplanner/apis/gtfs/queries/stops.graphql | 10 ++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java index 0730d2fbc91..b7f9cbce446 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java @@ -243,7 +243,9 @@ public DataFetcher platformCode() { @Override public DataFetcher> routes() { - return this::getRoutes; + return (env) -> { + var routes= this.getRoutes(env); + }; } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 927af19f8b1..844c609b526 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2001,7 +2001,16 @@ type Stop implements Node & PlaceInterface { "Identifier of the platform, usually a number. This value is only present for stops that are part of a station" platformCode: String "Routes which pass through this stop" - routes: [Route!] + routes( + """ + Only include routes whose pattern operates on at least one service date specified by this filter. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + serviceDates: LocalDateRangeInput, + ): [Route!] "Returns timetable of the specified pattern at this stop" stopTimesForPattern( "Id of the pattern" diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 79590ca2775..0e0eb159c1b 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -28,6 +28,7 @@ import java.util.Comparator; import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.stream.Stream; import javax.annotation.Nonnull; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; @@ -86,6 +87,7 @@ import org.opentripplanner.transit.model.framework.Deduplicator; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.BikeAccess; +import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; import org.opentripplanner.transit.model.site.RegularStop; @@ -114,6 +116,7 @@ class GraphQLIntegrationTest { .of(A, B, C, D, E, F, G, H) .map(p -> (RegularStop) p.stop) .toList(); + private static final Route ROUTE = TransitModelForTest.route("a-route").build(); private static VehicleRentalStation VEHICLE_RENTAL_STATION = new TestVehicleRentalStationBuilder() .withVehicles(10) @@ -209,6 +212,11 @@ public List getModesOfStopLocation(StopLocation stop) { public TransitAlertService getTransitAlertService() { return alertService; } + + @Override + public Set getRoutesForStop(StopLocation stop) { + return Set.of(ROUTE); + } }; routes.forEach(transitService::addRoutes); diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql index 5f3df71f8e7..ec320f8b86a 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql @@ -5,5 +5,15 @@ lon name vehicleMode + allRoutes: routes { + gtfsId + longName + shortName + } + routesWithinRange: routes(serviceDates: {start: "2024-09-10", end: "2024-09-10" }) { + gtfsId + longName + shortName + } } } From 7d9033d138d22a5895231ae15fed522a82648cbf Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 13 Sep 2024 17:21:56 +0200 Subject: [PATCH 13/19] Improve implementation --- .../apis/gtfs/datafetchers/StopImpl.java | 16 +++++++++++++-- .../apis/gtfs/generated/GraphQLTypes.java | 20 +++++++++++++++++++ .../apis/gtfs/queries/stops.graphql | 4 +++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java index b7f9cbce446..d8a098b52a5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java @@ -18,6 +18,8 @@ import org.opentripplanner.apis.gtfs.GraphQLUtils; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; +import org.opentripplanner.apis.gtfs.support.filter.PatternByDateFilterUtil; +import org.opentripplanner.apis.gtfs.support.time.LocalDateRangeUtil; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.StopTimesInPattern; import org.opentripplanner.model.TripTimeOnDate; @@ -243,8 +245,18 @@ public DataFetcher platformCode() { @Override public DataFetcher> routes() { - return (env) -> { - var routes= this.getRoutes(env); + return env -> { + var args = new GraphQLTypes.GraphQLStopRoutesArgs(env.getArguments()); + var routes = getRoutes(env); + if (LocalDateRangeUtil.hasServiceDateFilter(args.getGraphQLServiceDates())) { + var filter = PatternByDateFilterUtil.ofGraphQL( + args.getGraphQLServiceDates(), + getTransitService(env) + ); + return filter.filterRoutes(routes.stream()); + } else { + return routes; + } }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 67051444cdf..ed3e9afefc9 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -4231,6 +4231,26 @@ public void setGraphQLLanguage(String language) { } } + public static class GraphQLStopRoutesArgs { + + private GraphQLLocalDateRangeInput serviceDates; + + public GraphQLStopRoutesArgs(Map args) { + if (args != null) { + this.serviceDates = + new GraphQLLocalDateRangeInput((Map) args.get("serviceDates")); + } + } + + public GraphQLLocalDateRangeInput getGraphQLServiceDates() { + return this.serviceDates; + } + + public void setGraphQLServiceDates(GraphQLLocalDateRangeInput serviceDates) { + this.serviceDates = serviceDates; + } + } + public static class GraphQLStopStopTimesForPatternArgs { private String id; diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql index ec320f8b86a..af4fd904096 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/stops.graphql @@ -10,7 +10,9 @@ longName shortName } - routesWithinRange: routes(serviceDates: {start: "2024-09-10", end: "2024-09-10" }) { + routesWithinRange: routes( + serviceDates: { start: "2024-09-10", end: "2024-09-10" } + ) { gtfsId longName shortName From 8f03dbb0a53c39a75527e7645cb7c4e9240b46e8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 15:19:53 +0200 Subject: [PATCH 14/19] Convert from Stream to Collection --- .../opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java | 2 +- .../org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java | 2 +- .../transit/service/PatternByServiceDatesFilter.java | 4 ++-- .../transit/service/PatternByServiceDatesFilterTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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 d5551a9b902..0943fa309fc 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -619,7 +619,7 @@ public DataFetcher> routes() { args.getGraphQLServiceDates(), transitService ); - routeStream = filter.filterRoutes(routeStream).stream(); + routeStream = filter.filterRoutes(routeStream.toList()).stream(); } return routeStream.toList(); }; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java index d8a098b52a5..503899ba21a 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopImpl.java @@ -253,7 +253,7 @@ public DataFetcher> routes() { args.getGraphQLServiceDates(), getTransitService(env) ); - return filter.filterRoutes(routes.stream()); + return filter.filterRoutes(routes); } else { return routes; } diff --git a/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java b/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java index 30c501af4a0..21890975acf 100644 --- a/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java +++ b/src/main/java/org/opentripplanner/transit/service/PatternByServiceDatesFilter.java @@ -4,7 +4,6 @@ import java.util.Collection; import java.util.Objects; import java.util.function.Function; -import java.util.stream.Stream; import org.opentripplanner.apis.gtfs.model.LocalDateRange; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; @@ -54,8 +53,9 @@ public Collection filterPatterns(Collection tripPatter * Filter the routes by listing all their patterns' service dates and checking if they * operate on the specified dates. */ - public Collection filterRoutes(Stream routeStream) { + public Collection filterRoutes(Collection routeStream) { return routeStream + .stream() .filter(r -> { var patterns = getPatternsForRoute.apply(r); return !this.filterPatterns(patterns).isEmpty(); diff --git a/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java index ffc734f6038..93f50ce5b1e 100644 --- a/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java +++ b/src/test/java/org/opentripplanner/transit/service/PatternByServiceDatesFilterTest.java @@ -107,7 +107,7 @@ void filterRoutes(LocalDate start, LocalDate end, FilterExpectation expectation) var filter = defaultFilter(start, end); var filterInput = List.of(ROUTE_1); - var filterOutput = filter.filterRoutes(filterInput.stream()); + var filterOutput = filter.filterRoutes(filterInput); if (expectation == NOT_REMOVED) { assertEquals(filterOutput, filterInput); From 1a2fc413cee637b40be58ec7ce281759abebf2ef Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 16 Sep 2024 15:56:55 +0200 Subject: [PATCH 15/19] Add GraphQL assertion --- .../apis/gtfs/expectations/stops.json | 80 +++++++++++++++++-- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/stops.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/stops.json index 307b07b58aa..4e3d4c8a18c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/stops.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/stops.json @@ -6,56 +6,120 @@ "lat" : 5.0, "lon" : 8.0, "name" : "A", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:B", "lat" : 6.0, "lon" : 8.5, "name" : "B", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:C", "lat" : 7.0, "lon" : 9.0, "name" : "C", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:D", "lat" : 8.0, "lon" : 9.5, "name" : "D", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:E", "lat" : 9.0, "lon" : 10.0, "name" : "E", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:F", "lat" : 9.0, "lon" : 10.5, "name" : "F", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:G", "lat" : 9.5, "lon" : 11.0, "name" : "G", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] }, { "gtfsId" : "F:H", "lat" : 10.0, "lon" : 11.5, "name" : "H", - "vehicleMode" : "BUS" + "vehicleMode" : "BUS", + "allRoutes" : [ + { + "gtfsId" : "F:a-route", + "longName" : null, + "shortName" : "Ra-route" + } + ], + "routesWithinRange" : [ ] } ] } From 1d189236ac21d816120535ee0da21ed402b0e2f5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 17 Sep 2024 09:40:20 +0200 Subject: [PATCH 16/19] Format schema --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 844c609b526..1b944253b05 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2004,12 +2004,12 @@ type Stop implements Node & PlaceInterface { routes( """ Only include routes whose pattern operates on at least one service date specified by this filter. - + **Note**: A service date is a technical term useful for transit planning purposes and might not correspond to a how a passenger thinks of a calendar date. For example, a night bus running on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ - serviceDates: LocalDateRangeInput, + serviceDates: LocalDateRangeInput ): [Route!] "Returns timetable of the specified pattern at this stop" stopTimesForPattern( From 87991acf5bdb8ab73b898b0c0247d25a4eb726c3 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 17 Sep 2024 09:41:34 +0200 Subject: [PATCH 17/19] Update Javadoc --- .../opentripplanner/ext/vectortiles/layers/LayerFilters.java | 2 +- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java index 9672a9810c1..7d63bbe5398 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/LayerFilters.java @@ -28,7 +28,7 @@ public class LayerFilters { /** * Returns a predicate which only includes stop which are visited by a pattern that is in the current - * TriMet service week, namely from Sunday to Sunday. + * "service week", which lasts from Sunday to Sunday. */ public static Predicate buildCurrentServiceWeekPredicate( Function> getPatternsForStop, diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 1b944253b05..63a9829bb19 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2004,7 +2004,7 @@ type Stop implements Node & PlaceInterface { routes( """ Only include routes whose pattern operates on at least one service date specified by this filter. - + **Note**: A service date is a technical term useful for transit planning purposes and might not correspond to a how a passenger thinks of a calendar date. For example, a night bus running on Sunday morning at 1am to 3am, might have the previous Saturday's service date. From 86b48dbc46d95995b7a3e6330cef5f9602d87952 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 17 Sep 2024 16:39:48 +0200 Subject: [PATCH 18/19] Apply review feedback --- .../apis/gtfs/support/filter/PatternByDateFilterUtil.java | 2 +- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java b/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java index 204cdbd0886..f3c0d6d0352 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/support/filter/PatternByDateFilterUtil.java @@ -6,7 +6,7 @@ import org.opentripplanner.transit.service.TransitService; /** - * Utility methods for instantiating a {@link PatternByServiceDatesFilter}/ + * Utility methods for instantiating a {@link PatternByServiceDatesFilter}. */ public class PatternByDateFilterUtil { diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 63a9829bb19..115eacccdfa 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2003,7 +2003,7 @@ type Stop implements Node & PlaceInterface { "Routes which pass through this stop" routes( """ - Only include routes whose pattern operates on at least one service date specified by this filter. + Only include routes whose are operational on at least one service date specified by this filter. **Note**: A service date is a technical term useful for transit planning purposes and might not correspond to a how a passenger thinks of a calendar date. For example, a night bus running From 253bb179d415e4789b859d0080e1a5a4a7f14304 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 18 Sep 2024 07:17:18 +0200 Subject: [PATCH 19/19] Fix spelling Co-authored-by: Joel Lappalainen --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 115eacccdfa..78f18f4e654 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2003,7 +2003,7 @@ type Stop implements Node & PlaceInterface { "Routes which pass through this stop" routes( """ - Only include routes whose are operational on at least one service date specified by this filter. + Only include routes which are operational on at least one service date specified by this filter. **Note**: A service date is a technical term useful for transit planning purposes and might not correspond to a how a passenger thinks of a calendar date. For example, a night bus running