diff --git a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/RelativeDirectionMapper.java b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/RelativeDirectionMapper.java index a1bdd145a55..708da1fd6c3 100644 --- a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/RelativeDirectionMapper.java +++ b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/RelativeDirectionMapper.java @@ -25,6 +25,7 @@ public static ApiRelativeDirection mapRelativeDirection(RelativeDirection domain case UTURN_RIGHT -> ApiRelativeDirection.UTURN_RIGHT; case ENTER_STATION -> ApiRelativeDirection.ENTER_STATION; case EXIT_STATION -> ApiRelativeDirection.EXIT_STATION; + case ENTER_OR_EXIT_STATION -> ApiRelativeDirection.ENTER_OR_EXIT_STATION; case FOLLOW_SIGNS -> ApiRelativeDirection.FOLLOW_SIGNS; }; } diff --git a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/WalkStepMapper.java b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/WalkStepMapper.java index c5c59e4dc37..1df3d7e6fa7 100644 --- a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/WalkStepMapper.java +++ b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/WalkStepMapper.java @@ -39,7 +39,7 @@ public ApiWalkStep mapWalkStep(WalkStep domain) { api.streetName = domain.getDirectionText().toString(locale); api.absoluteDirection = domain.getAbsoluteDirection().map(AbsoluteDirectionMapper::mapAbsoluteDirection).orElse(null); - api.exit = domain.getExit(); + api.exit = domain.getHighwayExit(); api.stayOn = domain.isStayOn(); api.area = domain.getArea(); api.bogusName = domain.getBogusName(); diff --git a/application/src/ext/java/org/opentripplanner/ext/restapi/model/ApiRelativeDirection.java b/application/src/ext/java/org/opentripplanner/ext/restapi/model/ApiRelativeDirection.java index 02a530f06de..eb624df5ea6 100644 --- a/application/src/ext/java/org/opentripplanner/ext/restapi/model/ApiRelativeDirection.java +++ b/application/src/ext/java/org/opentripplanner/ext/restapi/model/ApiRelativeDirection.java @@ -21,5 +21,6 @@ public enum ApiRelativeDirection { UTURN_RIGHT, ENTER_STATION, EXIT_STATION, + ENTER_OR_EXIT_STATION, FOLLOW_SIGNS, } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 43a8399e70c..22e8f2e6fa7 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -37,6 +37,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; +import org.opentripplanner.apis.gtfs.datafetchers.EntranceImpl; import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; @@ -58,6 +59,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.RouteImpl; import org.opentripplanner.apis.gtfs.datafetchers.RouteTypeImpl; import org.opentripplanner.apis.gtfs.datafetchers.RoutingErrorImpl; +import org.opentripplanner.apis.gtfs.datafetchers.StepFeatureTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.StopGeometriesImpl; import org.opentripplanner.apis.gtfs.datafetchers.StopImpl; import org.opentripplanner.apis.gtfs.datafetchers.StopOnRouteImpl; @@ -126,6 +128,7 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) + .type("StepFeature", type -> type.typeResolver(new StepFeatureTypeResolver())) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) @@ -179,6 +182,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) + .type(typeWiring.build(EntranceImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EntranceImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EntranceImpl.java new file mode 100644 index 00000000000..9891d107479 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EntranceImpl.java @@ -0,0 +1,45 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import org.opentripplanner.apis.gtfs.GraphQLUtils; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; +import org.opentripplanner.transit.model.site.Entrance; + +public class EntranceImpl implements GraphQLDataFetchers.GraphQLEntrance { + + @Override + public DataFetcher code() { + return environment -> { + Entrance entrance = environment.getSource(); + return entrance.getCode(); + }; + } + + @Override + public DataFetcher entranceId() { + return environment -> { + Entrance entrance = environment.getSource(); + return entrance.getId().toString(); + }; + } + + @Override + public DataFetcher name() { + return environment -> { + Entrance entrance = environment.getSource(); + return org.opentripplanner.framework.graphql.GraphQLUtils.getTranslation( + entrance.getName(), + environment + ); + }; + } + + @Override + public DataFetcher wheelchairAccessible() { + return environment -> { + Entrance entrance = environment.getSource(); + return GraphQLUtils.toGraphQL(entrance.getWheelchairAccessibility()); + }; + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StepFeatureTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StepFeatureTypeResolver.java new file mode 100644 index 00000000000..714518cb9ea --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StepFeatureTypeResolver.java @@ -0,0 +1,21 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.TypeResolutionEnvironment; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLSchema; +import graphql.schema.TypeResolver; +import org.opentripplanner.transit.model.site.Entrance; + +public class StepFeatureTypeResolver implements TypeResolver { + + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment environment) { + Object o = environment.getObject(); + GraphQLSchema schema = environment.getSchema(); + + if (o instanceof Entrance) { + return schema.getObjectType("Entrance"); + } + return null; + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/stepImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/stepImpl.java index 6bd51ae5f29..c98237f78c5 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/stepImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/stepImpl.java @@ -7,6 +7,7 @@ import org.opentripplanner.apis.gtfs.mapping.DirectionMapper; import org.opentripplanner.apis.gtfs.mapping.StreetNoteMapper; import org.opentripplanner.model.plan.ElevationProfile.Step; +import org.opentripplanner.model.plan.RelativeDirection; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -50,7 +51,18 @@ public DataFetcher> elevationProfile() { @Override public DataFetcher exit() { - return environment -> getSource(environment).getExit(); + return environment -> getSource(environment).getHighwayExit(); + } + + @Override + public DataFetcher feature() { + return environment -> { + WalkStep source = getSource(environment); + if (source.getRelativeDirection() == RelativeDirection.ENTER_OR_EXIT_STATION) { + return source.getEntrance(); + } + return null; + }; } @Override diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 7532faf28bd..b7889c8be3a 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -357,6 +357,17 @@ public interface GraphQLEmissions { public DataFetcher co2(); } + /** Station entrance or exit, originating from OSM or GTFS data. */ + public interface GraphQLEntrance { + public DataFetcher code(); + + public DataFetcher entranceId(); + + public DataFetcher name(); + + public DataFetcher wheelchairAccessible(); + } + /** A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'. */ public interface GraphQLFareMedium { public DataFetcher id(); @@ -973,6 +984,8 @@ public interface GraphQLRoutingError { public DataFetcher inputField(); } + public interface GraphQLStepFeature extends TypeResolver {} + /** * Stop can represent either a single public transport stop, where passengers can * board and/or disembark vehicles, or a station, which contains multiple stops. @@ -1426,6 +1439,8 @@ public interface GraphQLStep { public DataFetcher exit(); + public DataFetcher feature(); + public DataFetcher lat(); public DataFetcher lon(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 48d60701a96..2b8ca4521a0 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -3994,6 +3994,7 @@ public enum GraphQLRelativeDirection { CONTINUE, DEPART, ELEVATOR, + ENTER_OR_EXIT_STATION, ENTER_STATION, EXIT_STATION, FOLLOW_SIGNS, diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/DirectionMapper.java b/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/DirectionMapper.java index 69a78b05f55..1439cdd34c3 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/DirectionMapper.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/DirectionMapper.java @@ -38,6 +38,7 @@ public static GraphQLRelativeDirection map(RelativeDirection relativeDirection) case UTURN_RIGHT -> GraphQLRelativeDirection.UTURN_RIGHT; case ENTER_STATION -> GraphQLRelativeDirection.ENTER_STATION; case EXIT_STATION -> GraphQLRelativeDirection.EXIT_STATION; + case ENTER_OR_EXIT_STATION -> GraphQLRelativeDirection.ENTER_OR_EXIT_STATION; case FOLLOW_SIGNS -> GraphQLRelativeDirection.FOLLOW_SIGNS; }; } diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java b/application/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java index c52baa0be4c..12eaa089a50 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java @@ -65,7 +65,7 @@ public static GraphQLObjectType create(GraphQLObjectType elevationStepType) { .name("exit") .description("When exiting a highway or traffic circle, the exit name/number.") .type(Scalars.GraphQLString) - .dataFetcher(environment -> ((WalkStep) environment.getSource()).getExit()) + .dataFetcher(environment -> ((WalkStep) environment.getSource()).getHighwayExit()) .build() ) .field( diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java b/application/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java index c4acabefd6c..2557b344d83 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/OsmBoardingLocationsModule.java @@ -22,8 +22,8 @@ import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.edge.StreetTransitStopLink; import org.opentripplanner.street.model.vertex.OsmBoardingLocationVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TransitStopVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexFactory; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.TraverseModeSet; @@ -182,7 +182,7 @@ private boolean connectVertexToStop(TransitStopVertex ts, StreetIndex index) { return false; } - private StreetEdge linkBoardingLocationToStreetNetwork(StreetVertex from, StreetVertex to) { + private StreetEdge linkBoardingLocationToStreetNetwork(Vertex from, Vertex to) { var line = GeometryUtils.makeLineString(List.of(from.getCoordinate(), to.getCoordinate())); return new StreetEdgeBuilder<>() .withFromVertex(from) diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java b/application/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java index 98b2287542e..c9a22819e6d 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java @@ -20,14 +20,12 @@ import org.opentripplanner.street.model.edge.StreetVehicleParkingLink; import org.opentripplanner.street.model.edge.VehicleParkingEdge; import org.opentripplanner.street.model.vertex.StationCentroidVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TransitEntranceVertex; import org.opentripplanner.street.model.vertex.TransitStopVertex; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.TraverseModeSet; -import org.opentripplanner.transit.model.network.CarAccess; import org.opentripplanner.transit.model.site.GroupStop; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; @@ -170,10 +168,7 @@ private void linkToDriveableEdge(TransitStopVertex tStop) { ); } - private static List createStopLinkEdges( - TransitStopVertex vertex, - StreetVertex streetVertex - ) { + private static List createStopLinkEdges(TransitStopVertex vertex, Vertex streetVertex) { return List.of( StreetTransitStopLink.createStreetTransitStopLink(vertex, streetVertex), StreetTransitStopLink.createStreetTransitStopLink(streetVertex, vertex) @@ -230,6 +225,9 @@ private static void linkVehicleParkingWithLinker( private void linkTransitEntrances(Graph graph) { LOG.info("Linking transit entrances to graph..."); for (TransitEntranceVertex tEntrance : graph.getVerticesOfType(TransitEntranceVertex.class)) { + if (tEntrance.isConnectedToGraph()) { + continue; + } graph .getLinker() .linkVertexPermanently( @@ -252,7 +250,7 @@ private void linkTransitEntrances(Graph graph) { } private void linkStationCentroids(Graph graph) { - BiFunction> stationAndStreetVertexLinker = ( + BiFunction> stationAndStreetVertexLinker = ( theStation, streetVertex ) -> diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/configure/GraphBuilderModules.java b/application/src/main/java/org/opentripplanner/graph_builder/module/configure/GraphBuilderModules.java index 080d69c571e..03be3a85489 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/configure/GraphBuilderModules.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/configure/GraphBuilderModules.java @@ -69,6 +69,7 @@ static OsmModule provideOsmModule( osmConfiguredDataSource.dataSource(), osmConfiguredDataSource.config().osmTagMapper(), osmConfiguredDataSource.config().timeZone(), + osmConfiguredDataSource.config().includeOsmSubwayEntrances(), config.osmCacheDataInMem, issueStore ) @@ -84,6 +85,7 @@ static OsmModule provideOsmModule( .withStaticBikeParkAndRide(config.staticBikeParkAndRide) .withMaxAreaNodes(config.maxAreaNodes) .withBoardingAreaRefTags(config.boardingLocationTags) + .withIncludeOsmSubwayEntrances(config.osmDefaults.includeOsmSubwayEntrances()) .withIssueStore(issueStore) .withStreetLimitationParameters(streetLimitationParameters) .build(); diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ElevatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ElevatorProcessor.java index 490d6a266b9..d8dad03da57 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ElevatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ElevatorProcessor.java @@ -22,7 +22,6 @@ import org.opentripplanner.street.model.edge.FreeEdge; import org.opentripplanner.street.model.vertex.ElevatorOffboardVertex; import org.opentripplanner.street.model.vertex.ElevatorOnboardVertex; -import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.OsmVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexFactory; @@ -154,7 +153,7 @@ public void buildElevatorEdges(Graph graph) { private static void createElevatorVertices( Graph graph, ArrayList onboardVertices, - IntersectionVertex sourceVertex, + Vertex sourceVertex, String label, String levelName ) { diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 75e0965d82f..b160b01af68 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -5,16 +5,16 @@ import java.util.Map; import org.opentripplanner.osm.model.OsmWay; import org.opentripplanner.street.model.edge.EscalatorEdge; -import org.opentripplanner.street.model.vertex.IntersectionVertex; +import org.opentripplanner.street.model.vertex.Vertex; /** * Contains the logic for extracting escalators out of OSM data */ class EscalatorProcessor { - private final Map intersectionNodes; + private final Map intersectionNodes; - public EscalatorProcessor(Map intersectionNodes) { + public EscalatorProcessor(Map intersectionNodes) { this.intersectionNodes = intersectionNodes; } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java index 08d23087a45..19bbaec14fe 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java @@ -31,7 +31,6 @@ import org.opentripplanner.street.model.edge.StreetEdge; import org.opentripplanner.street.model.edge.StreetEdgeBuilder; import org.opentripplanner.street.model.vertex.BarrierVertex; -import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.utils.logging.ProgressTracker; import org.slf4j.Logger; @@ -70,7 +69,13 @@ public class OsmModule implements GraphBuilderModule { this.issueStore = issueStore; this.params = params; this.osmdb = new OsmDatabase(issueStore); - this.vertexGenerator = new VertexGenerator(osmdb, graph, params.boardingAreaRefTags()); + this.vertexGenerator = + new VertexGenerator( + osmdb, + graph, + params.boardingAreaRefTags(), + params.includeOsmSubwayEntrances() + ); this.normalizer = new SafetyValueNormalizer(graph, issueStore); this.streetLimitationParameters = Objects.requireNonNull(streetLimitationParameters); } @@ -289,8 +294,8 @@ private void buildBasicGraph() { lastLevel = level; } - IntersectionVertex startEndpoint = null; - IntersectionVertex endEndpoint = null; + Vertex startEndpoint = null; + Vertex endEndpoint = null; ArrayList segmentCoordinates = new ArrayList<>(); @@ -459,8 +464,8 @@ private void applyEdgesToTurnRestrictions( * http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing#Oneway. */ private StreetEdgePair getEdgesForStreet( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, + Vertex startEndpoint, + Vertex endEndpoint, OsmWay way, int index, StreetTraversalPermission permissions, @@ -513,8 +518,8 @@ private StreetEdgePair getEdgesForStreet( } private StreetEdge getEdgeForStreet( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, + Vertex startEndpoint, + Vertex endEndpoint, OsmWay way, int index, double length, diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModuleBuilder.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModuleBuilder.java index 6e90fb20b1c..af89eab0dd7 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModuleBuilder.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModuleBuilder.java @@ -24,6 +24,7 @@ public class OsmModuleBuilder { private boolean platformEntriesLinking = false; private boolean staticParkAndRide = false; private boolean staticBikeParkAndRide = false; + private boolean includeOsmSubwayEntrances = false; private int maxAreaNodes; private StreetLimitationParameters streetLimitationParameters = new StreetLimitationParameters(); @@ -72,6 +73,11 @@ public OsmModuleBuilder withMaxAreaNodes(int maxAreaNodes) { return this; } + public OsmModuleBuilder withIncludeOsmSubwayEntrances(boolean includeOsmSubwayEntrances) { + this.includeOsmSubwayEntrances = includeOsmSubwayEntrances; + return this; + } + public OsmModuleBuilder withStreetLimitationParameters(StreetLimitationParameters parameters) { this.streetLimitationParameters = parameters; return this; @@ -90,7 +96,8 @@ public OsmModule build() { areaVisibility, platformEntriesLinking, staticParkAndRide, - staticBikeParkAndRide + staticBikeParkAndRide, + includeOsmSubwayEntrances ) ); } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ParkingProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ParkingProcessor.java index f372f0c82e2..37a6e9fd714 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ParkingProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/ParkingProcessor.java @@ -30,8 +30,8 @@ import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; import org.opentripplanner.street.model.edge.VehicleParkingEdge; -import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexFactory; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.transit.model.framework.FeedScopedId; @@ -44,14 +44,14 @@ class ParkingProcessor { private static final String VEHICLE_PARKING_OSM_FEED_ID = "OSM"; private final DataImportIssueStore issueStore; private final OsmOpeningHoursParser osmOpeningHoursParser; - private final BiFunction getVertexForOsmNode; + private final BiFunction getVertexForOsmNode; private final VertexFactory vertexFactory; private final VehicleParkingHelper vehicleParkingHelper; public ParkingProcessor( Graph graph, DataImportIssueStore issueStore, - BiFunction getVertexForOsmNode + BiFunction getVertexForOsmNode ) { this.issueStore = issueStore; this.getVertexForOsmNode = getVertexForOsmNode; @@ -475,4 +475,4 @@ private List createParkingEntrance } } -record VertexAndName(I18NString name, IntersectionVertex vertex) {} +record VertexAndName(I18NString name, Vertex vertex) {} diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/VertexGenerator.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/VertexGenerator.java index e6fec74b798..432214da5a7 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/VertexGenerator.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/VertexGenerator.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Set; import org.locationtech.jts.geom.Coordinate; +import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.osm.model.OsmLevel; import org.opentripplanner.osm.model.OsmNode; @@ -15,10 +16,13 @@ import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.model.edge.ElevatorEdge; import org.opentripplanner.street.model.vertex.BarrierVertex; -import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.OsmBoardingLocationVertex; import org.opentripplanner.street.model.vertex.OsmVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexFactory; +import org.opentripplanner.transit.model.basic.Accessibility; +import org.opentripplanner.transit.model.framework.FeedScopedId; +import org.opentripplanner.transit.model.site.Entrance; /** * Tracks the generation of vertices and returns an existing instance if a vertex is encountered @@ -28,17 +32,24 @@ class VertexGenerator { private static final String nodeLabelFormat = "osm:node:%d"; - private final Map intersectionNodes = new HashMap<>(); + private final Map intersectionNodes = new HashMap<>(); private final HashMap> multiLevelNodes = new HashMap<>(); private final OsmDatabase osmdb; private final Set boardingAreaRefTags; + private final Boolean includeOsmSubwayEntrances; private final VertexFactory vertexFactory; - public VertexGenerator(OsmDatabase osmdb, Graph graph, Set boardingAreaRefTags) { + public VertexGenerator( + OsmDatabase osmdb, + Graph graph, + Set boardingAreaRefTags, + boolean includeOsmSubwayEntrances + ) { this.osmdb = osmdb; this.vertexFactory = new VertexFactory(graph); this.boardingAreaRefTags = boardingAreaRefTags; + this.includeOsmSubwayEntrances = includeOsmSubwayEntrances; } /** @@ -51,11 +62,11 @@ public VertexGenerator(OsmDatabase osmdb, Graph graph, Set boardingAreaR * @return vertex The graph vertex. This is not always an OSM vertex; it can also be a * {@link OsmBoardingLocationVertex} */ - IntersectionVertex getVertexForOsmNode(OsmNode node, OsmWithTags way) { + Vertex getVertexForOsmNode(OsmNode node, OsmWithTags way) { // If the node should be decomposed to multiple levels, // use the numeric level because it is unique, the human level may not be (although // it will likely lead to some head-scratching if it is not). - IntersectionVertex iv = null; + Vertex iv = null; if (node.isMultiLevel()) { // make a separate node for every level return recordLevel(node, way); @@ -95,6 +106,24 @@ IntersectionVertex getVertexForOsmNode(OsmNode node, OsmWithTags way) { iv = bv; } + if (includeOsmSubwayEntrances && node.isSubwayEntrance()) { + String ref = node.getTag("ref"); + + boolean accessible = node.isTag("wheelchair", "yes"); + + FeedScopedId id = new FeedScopedId("osm", Long.toString(nid)); + Entrance entrance = Entrance + .of(id) + .withCoordinate(new WgsCoordinate(coordinate)) + .withCode(ref) + .withWheelchairAccessibility( + accessible ? Accessibility.POSSIBLE : Accessibility.NOT_POSSIBLE + ) + .build(); + + iv = vertexFactory.transitEntrance(entrance); + } + if (iv == null) { iv = vertexFactory.osm( @@ -147,7 +176,7 @@ void initIntersectionNodes() { /** * Track OSM nodes that will become graph vertices because they appear in multiple OSM ways */ - Map intersectionNodes() { + Map intersectionNodes() { return intersectionNodes; } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java index f27d80d5617..c32e6083ce2 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilder.java @@ -212,7 +212,7 @@ public void buildWithVisibility(AreaGroup group) { // or those linked to ways HashSet visibilityNodes = new HashSet<>(); HashSet alreadyAddedEdges = new HashSet<>(); - HashSet platformLinkingVertices = new HashSet<>(); + HashSet platformLinkingVertices = new HashSet<>(); // we need to accumulate visibility points from all contained areas // inside this ring, but only for shared nodes; we don't care about // convexity, which we'll handle for the grouped area only. @@ -340,7 +340,7 @@ public void buildWithVisibility(AreaGroup group) { continue; } i = (int) Math.floor(sum_i); - IntersectionVertex startEndpoint = vertexBuilder.getVertexForOsmNode(nodeI, areaEntity); + Vertex startEndpoint = vertexBuilder.getVertexForOsmNode(nodeI, areaEntity); if (startingNodes.contains(nodeI)) { startingVertices.add(startEndpoint); } @@ -355,7 +355,7 @@ public void buildWithVisibility(AreaGroup group) { NodeEdge edge = new NodeEdge(nodeI, nodeJ); if (alreadyAddedEdges.contains(edge)) continue; - IntersectionVertex endEndpoint = vertexBuilder.getVertexForOsmNode(nodeJ, areaEntity); + Vertex endEndpoint = vertexBuilder.getVertexForOsmNode(nodeJ, areaEntity); Coordinate[] coordinates = new Coordinate[] { startEndpoint.getCoordinate(), @@ -463,15 +463,15 @@ private Set createEdgesForRingSegment( return Set.of(); } alreadyAddedEdges.add(nodeEdge); - IntersectionVertex startEndpoint = vertexBuilder.getVertexForOsmNode(node, area.parent); - IntersectionVertex endEndpoint = vertexBuilder.getVertexForOsmNode(nextNode, area.parent); + Vertex startEndpoint = vertexBuilder.getVertexForOsmNode(node, area.parent); + Vertex endEndpoint = vertexBuilder.getVertexForOsmNode(nextNode, area.parent); return createSegments(startEndpoint, endEndpoint, List.of(area), edgeList); } private Set createSegments( - IntersectionVertex startEndpoint, - IntersectionVertex endEndpoint, + Vertex startEndpoint, + Vertex endEndpoint, Collection areas, AreaEdgeList edgeList ) { diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParameters.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParameters.java index 175b9c04c5b..37edaf687ab 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParameters.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParameters.java @@ -11,16 +11,28 @@ * Example: {@code "osm" : [ {source: "file:///path/to/otp/norway.pbf"} ] } * */ -public record OsmExtractParameters(URI source, OsmTagMapperSource osmTagMapper, ZoneId timeZone) +public record OsmExtractParameters( + URI source, + OsmTagMapperSource osmTagMapper, + ZoneId timeZone, + boolean includeOsmSubwayEntrances +) implements DataSourceConfig { public static final OsmTagMapperSource DEFAULT_OSM_TAG_MAPPER = OsmTagMapperSource.DEFAULT; public static final ZoneId DEFAULT_TIME_ZONE = null; + public static final boolean DEFAULT_INCLUDE_OSM_SUBWAY_ENTRANCES = false; + public static final OsmExtractParameters DEFAULT = new OsmExtractParametersBuilder().build(); OsmExtractParameters(OsmExtractParametersBuilder builder) { - this(builder.getSource(), builder.getOsmTagMapper(), builder.getTimeZone()); + this( + builder.getSource(), + builder.getOsmTagMapper(), + builder.getTimeZone(), + builder.includeOsmSubwayEntrances() + ); } @Override @@ -37,6 +49,11 @@ public ZoneId timeZone() { return timeZone; } + @Nullable + public boolean includeOsmSubwayEntrances() { + return includeOsmSubwayEntrances; + } + public OsmExtractParametersBuilder copyOf() { return new OsmExtractParametersBuilder(this); } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParametersBuilder.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParametersBuilder.java index 2d9bb71d9f5..66c65e05d81 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParametersBuilder.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmExtractParametersBuilder.java @@ -24,14 +24,18 @@ public class OsmExtractParametersBuilder { */ private ZoneId timeZone; + private boolean includeOsmSubwayEntrances; + public OsmExtractParametersBuilder() { this.osmTagMapper = OsmExtractParameters.DEFAULT_OSM_TAG_MAPPER; this.timeZone = OsmExtractParameters.DEFAULT_TIME_ZONE; + this.includeOsmSubwayEntrances = OsmExtractParameters.DEFAULT_INCLUDE_OSM_SUBWAY_ENTRANCES; } public OsmExtractParametersBuilder(OsmExtractParameters original) { this.osmTagMapper = original.osmTagMapper(); this.timeZone = original.timeZone(); + this.includeOsmSubwayEntrances = original.includeOsmSubwayEntrances(); } public OsmExtractParametersBuilder withSource(URI source) { @@ -49,6 +53,13 @@ public OsmExtractParametersBuilder withTimeZone(ZoneId timeZone) { return this; } + public OsmExtractParametersBuilder withIncludeOsmSubwayEntrances( + boolean includeOsmSubwayEntrances + ) { + this.includeOsmSubwayEntrances = includeOsmSubwayEntrances; + return this; + } + public URI getSource() { return source; } @@ -61,6 +72,10 @@ public ZoneId getTimeZone() { return timeZone; } + public boolean includeOsmSubwayEntrances() { + return includeOsmSubwayEntrances; + } + public OsmExtractParameters build() { return new OsmExtractParameters(this); } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmProcessingParameters.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmProcessingParameters.java index 52bf8d65314..a3fd14020e8 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmProcessingParameters.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/parameters/OsmProcessingParameters.java @@ -13,6 +13,7 @@ * @param platformEntriesLinking Whether platform entries should be linked * @param staticParkAndRide Whether we should create car P+R stations from OSM data. * @param staticBikeParkAndRide Whether we should create bike P+R stations from OSM data. + * @param includeOsmSubwayEntrances Whether we should create subway entrances from OSM data. */ public record OsmProcessingParameters( Set boardingAreaRefTags, @@ -21,7 +22,8 @@ public record OsmProcessingParameters( boolean areaVisibility, boolean platformEntriesLinking, boolean staticParkAndRide, - boolean staticBikeParkAndRide + boolean staticBikeParkAndRide, + boolean includeOsmSubwayEntrances ) { public OsmProcessingParameters { boardingAreaRefTags = Set.copyOf(Objects.requireNonNull(boardingAreaRefTags)); diff --git a/application/src/main/java/org/opentripplanner/model/plan/RelativeDirection.java b/application/src/main/java/org/opentripplanner/model/plan/RelativeDirection.java index ffc8993d0db..fbdb836ab6a 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/RelativeDirection.java +++ b/application/src/main/java/org/opentripplanner/model/plan/RelativeDirection.java @@ -21,6 +21,7 @@ public enum RelativeDirection { UTURN_RIGHT, ENTER_STATION, EXIT_STATION, + ENTER_OR_EXIT_STATION, FOLLOW_SIGNS; public static RelativeDirection calculate( diff --git a/application/src/main/java/org/opentripplanner/model/plan/WalkStep.java b/application/src/main/java/org/opentripplanner/model/plan/WalkStep.java index 45f2b5da701..2efe6e36aff 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/WalkStep.java +++ b/application/src/main/java/org/opentripplanner/model/plan/WalkStep.java @@ -8,6 +8,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.note.StreetNote; +import org.opentripplanner.transit.model.site.Entrance; import org.opentripplanner.utils.lang.DoubleUtils; import org.opentripplanner.utils.tostring.ToStringBuilder; @@ -44,6 +45,7 @@ public final class WalkStep { private final boolean walkingBike; private final String exit; + private final Entrance entrance; private final ElevationProfile elevationProfile; private final boolean stayOn; @@ -56,6 +58,7 @@ public final class WalkStep { I18NString directionText, Set streetNotes, String exit, + Entrance entrance, ElevationProfile elevationProfile, boolean bogusName, boolean walkingBike, @@ -76,6 +79,7 @@ public final class WalkStep { this.walkingBike = walkingBike; this.area = area; this.exit = exit; + this.entrance = entrance; this.elevationProfile = elevationProfile; this.stayOn = stayOn; this.edges = List.copyOf(Objects.requireNonNull(edges)); @@ -126,10 +130,17 @@ public Optional getAbsoluteDirection() { /** * When exiting a highway or traffic circle, the exit name/number. */ - public String getExit() { + public String getHighwayExit() { return exit; } + /** + * Get information about a subway station entrance or exit. + */ + public Entrance getEntrance() { + return entrance; + } + /** * Indicates whether a street changes direction at an intersection. */ diff --git a/application/src/main/java/org/opentripplanner/model/plan/WalkStepBuilder.java b/application/src/main/java/org/opentripplanner/model/plan/WalkStepBuilder.java index 8d4df6634fd..7ef5012e145 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/WalkStepBuilder.java +++ b/application/src/main/java/org/opentripplanner/model/plan/WalkStepBuilder.java @@ -9,6 +9,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.note.StreetNote; +import org.opentripplanner.transit.model.site.Entrance; import org.opentripplanner.utils.lang.DoubleUtils; import org.opentripplanner.utils.lang.IntUtils; @@ -25,6 +26,7 @@ public class WalkStepBuilder { private RelativeDirection relativeDirection; private ElevationProfile elevationProfile; private String exit; + private Entrance entrance; private boolean stayOn = false; /** * Distance used for appending elevation profiles @@ -74,6 +76,11 @@ public WalkStepBuilder withExit(String exit) { return this; } + public WalkStepBuilder withEntrance(Entrance entrance) { + this.entrance = entrance; + return this; + } + public WalkStepBuilder withStayOn(boolean stayOn) { this.stayOn = stayOn; return this; @@ -156,6 +163,7 @@ public WalkStep build() { directionText, streetNotes, exit, + entrance, elevationProfile, bogusName, walkingBike, diff --git a/application/src/main/java/org/opentripplanner/osm/OsmProvider.java b/application/src/main/java/org/opentripplanner/osm/OsmProvider.java index 597fd516b0e..b04a84e51c5 100644 --- a/application/src/main/java/org/opentripplanner/osm/OsmProvider.java +++ b/application/src/main/java/org/opentripplanner/osm/OsmProvider.java @@ -37,6 +37,8 @@ public class OsmProvider { private final OsmTagMapper osmTagMapper; + private boolean includeOsmSubwayEntrances = false; + private final WayPropertySet wayPropertySet; private byte[] cachedBytes = null; @@ -46,6 +48,7 @@ public OsmProvider(File file, boolean cacheDataInMem) { new FileDataSource(file, FileType.OSM), OsmTagMapperSource.DEFAULT, null, + false, cacheDataInMem, DataImportIssueStore.NOOP ); @@ -55,11 +58,13 @@ public OsmProvider( DataSource dataSource, OsmTagMapperSource tagMapperSource, ZoneId zoneId, + boolean includeOsmSubwayEntrances, boolean cacheDataInMem, DataImportIssueStore issueStore ) { this.source = dataSource; this.zoneId = zoneId; + this.includeOsmSubwayEntrances = includeOsmSubwayEntrances; this.osmTagMapper = tagMapperSource.getInstance(); this.wayPropertySet = new WayPropertySet(issueStore); osmTagMapper.populateProperties(wayPropertySet); @@ -152,6 +157,10 @@ public OsmTagMapper getOsmTagMapper() { return osmTagMapper; } + public boolean getIncludeOsmSubwayEntrances() { + return includeOsmSubwayEntrances; + } + public WayPropertySet getWayPropertySet() { return wayPropertySet; } diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmNode.java b/application/src/main/java/org/opentripplanner/osm/model/OsmNode.java index c5539d1296e..cb9fcd679f0 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmNode.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmNode.java @@ -63,6 +63,15 @@ public boolean isBarrier() { ); } + /** + * Checks if this node is a subway station entrance. + * + * @return true if it is + */ + public boolean isSubwayEntrance() { + return hasTag("railway") && "subway_entrance".equals(getTag("railway")); + } + /** * Consider barrier tag in permissions. Leave the rest for the super class. */ diff --git a/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapper.java b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapper.java index 32f5ccf533b..4c13f172255 100644 --- a/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapper.java +++ b/application/src/main/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapper.java @@ -25,6 +25,7 @@ import org.opentripplanner.street.model.edge.StreetEdge; import org.opentripplanner.street.model.edge.StreetTransitEntranceLink; import org.opentripplanner.street.model.vertex.ExitVertex; +import org.opentripplanner.street.model.vertex.TransitEntranceVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.state.State; @@ -175,6 +176,9 @@ private void processState(State backState, State forwardState) { if (edge instanceof ElevatorAlightEdge) { addStep(createElevatorWalkStep(backState, forwardState, edge)); return; + } else if (backState.getVertex() instanceof TransitEntranceVertex) { + addStep(createStationEntranceWalkStep(backState, forwardState, edge)); + return; } else if (edge instanceof PathwayEdge pwe && pwe.signpostedAs().isPresent()) { createAndSaveStep(backState, forwardState, pwe.signpostedAs().get(), FOLLOW_SIGNS, edge); return; @@ -515,6 +519,23 @@ private WalkStepBuilder createElevatorWalkStep(State backState, State forwardSta return step; } + private WalkStepBuilder createStationEntranceWalkStep( + State backState, + State forwardState, + Edge edge + ) { + // don't care what came before or comes after + var step = createWalkStep(forwardState, backState); + // There is not a way to definitively determine if a user is entering or exiting the station, + // since the doors might be between or inside stations. + step.withRelativeDirection(RelativeDirection.ENTER_OR_EXIT_STATION); + + TransitEntranceVertex vertex = (TransitEntranceVertex) backState.getVertex(); + + step.withEntrance(vertex.getEntrance()); + return step; + } + private void createAndSaveStep( State backState, State forwardState, diff --git a/application/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java b/application/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java index e9d29f596c7..a762382ccaf 100644 --- a/application/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java +++ b/application/src/main/java/org/opentripplanner/routing/linking/FlexLocationAdder.java @@ -6,17 +6,13 @@ import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.StreetEdge; -import org.opentripplanner.street.model.vertex.IntersectionVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.transit.model.site.AreaStop; import org.opentripplanner.transit.service.SiteRepository; class FlexLocationAdder { - static void addFlexLocations( - StreetEdge edge, - IntersectionVertex v0, - SiteRepository siteRepository - ) { + static void addFlexLocations(StreetEdge edge, Vertex v0, SiteRepository siteRepository) { if (edge.getPermission().allows(StreetTraversalPermission.PEDESTRIAN_AND_CAR)) { Point p = GeometryUtils.getGeometryFactory().createPoint(v0.getCoordinate()); Envelope env = p.getEnvelopeInternal(); diff --git a/application/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java b/application/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java index 48f5ff997c8..0be89121a7c 100644 --- a/application/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java +++ b/application/src/main/java/org/opentripplanner/routing/linking/VertexLinker.java @@ -26,9 +26,7 @@ import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.NamedArea; import org.opentripplanner.street.model.edge.StreetEdge; -import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.SplitterVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TemporarySplitterVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.model.vertex.VertexFactory; @@ -96,7 +94,7 @@ public void linkVertexPermanently( Vertex vertex, TraverseModeSet traverseModes, LinkingDirection direction, - BiFunction> edgeFunction + BiFunction> edgeFunction ) { link(vertex, traverseModes, direction, Scope.PERMANENT, edgeFunction); } @@ -105,7 +103,7 @@ public DisposableEdgeCollection linkVertexForRealTime( Vertex vertex, TraverseModeSet traverseModes, LinkingDirection direction, - BiFunction> edgeFunction + BiFunction> edgeFunction ) { return link(vertex, traverseModes, direction, Scope.REALTIME, edgeFunction); } @@ -114,7 +112,7 @@ public DisposableEdgeCollection linkVertexForRequest( Vertex vertex, TraverseModeSet traverseModes, LinkingDirection direction, - BiFunction> edgeFunction + BiFunction> edgeFunction ) { return link(vertex, traverseModes, direction, Scope.REQUEST, edgeFunction); } @@ -181,14 +179,14 @@ private DisposableEdgeCollection link( TraverseModeSet traverseModes, LinkingDirection direction, Scope scope, - BiFunction> edgeFunction + BiFunction> edgeFunction ) { DisposableEdgeCollection tempEdges = (scope != Scope.PERMANENT) ? new DisposableEdgeCollection(graph, scope) : null; try { - Set streetVertices = linkToStreetEdges( + Set streetVertices = linkToStreetEdges( vertex, traverseModes, direction, @@ -208,7 +206,7 @@ private DisposableEdgeCollection link( ); } - for (StreetVertex streetVertex : streetVertices) { + for (Vertex streetVertex : streetVertices) { List edges = edgeFunction.apply(vertex, streetVertex); if (tempEdges != null) { for (Edge edge : edges) { @@ -226,7 +224,7 @@ private DisposableEdgeCollection link( return tempEdges; } - private Set linkToStreetEdges( + private Set linkToStreetEdges( Vertex vertex, TraverseModeSet traverseModes, LinkingDirection direction, @@ -329,7 +327,7 @@ private Set> getClosestEdgesPerMode( } /** Split the edge if necessary return the closest vertex */ - private StreetVertex link( + private Vertex link( Vertex vertex, StreetEdge edge, double xScale, @@ -345,7 +343,7 @@ private StreetVertex link( LinearLocation ll = il.project(new Coordinate(vertex.getLon() * xScale, vertex.getLat())); double length = SphericalDistanceLibrary.length(orig); - IntersectionVertex start = null; + Vertex start = null; boolean snapped = true; // if we're very close to one end of the line or the other, or endwise, don't bother to split, @@ -356,19 +354,19 @@ private StreetVertex link( ll.getSegmentIndex() == 0 && (ll.getSegmentFraction() < 1e-8 || ll.getSegmentFraction() * length < 0.1) ) { - start = (IntersectionVertex) edge.getFromVertex(); + start = (Vertex) edge.getFromVertex(); } // -1 converts from count to index. Because of the fencepost problem, npoints - 1 is the "segment" // past the last point else if (ll.getSegmentIndex() == orig.getNumPoints() - 1) { - start = (IntersectionVertex) edge.getToVertex(); + start = (Vertex) edge.getToVertex(); } // nPoints - 2: -1 to correct for index vs count, -1 to account for fencepost problem else if ( ll.getSegmentIndex() == orig.getNumPoints() - 2 && (ll.getSegmentFraction() > 1 - 1e-8 || (1 - ll.getSegmentFraction()) * length < 0.1) ) { - start = (IntersectionVertex) edge.getToVertex(); + start = (Vertex) edge.getToVertex(); } else { snapped = false; boolean split = true; @@ -380,7 +378,7 @@ else if ( if (!linkedAreas.add(ael)) { return null; } - if (vertex instanceof IntersectionVertex iv) { + if (vertex instanceof Vertex iv) { start = iv; } else { start = splitVertex(aEdge, scope, direction, vertex.getLon(), vertex.getLat()); @@ -522,7 +520,7 @@ public boolean equals(Object o) { /** * Link a new vertex permanently with area geometry */ - public void addPermanentAreaVertex(IntersectionVertex newVertex, AreaEdgeList edgeList) { + public void addPermanentAreaVertex(Vertex newVertex, AreaEdgeList edgeList) { addAreaVertex(newVertex, edgeList, Scope.PERMANENT, null); } @@ -532,7 +530,7 @@ public void addPermanentAreaVertex(IntersectionVertex newVertex, AreaEdgeList ed */ public void addAreaVertex( - IntersectionVertex newVertex, + Vertex newVertex, AreaEdgeList edgeList, Scope scope, DisposableEdgeCollection tempEdges @@ -556,7 +554,7 @@ public void addAreaVertex( int i = 0; float sum_i = 0; - for (IntersectionVertex v : edgeList.visibilityVertices()) { + for (Vertex v : edgeList.visibilityVertices()) { sum_i += skip_ratio; if (Math.floor(sum_i) < i + 1) { continue; @@ -581,7 +579,7 @@ public void addAreaVertex( // TODO: Temporary fix for unconnected area edges. This should go away when moving walkable // area calculation to be done after stop linking if (added == 0) { - for (IntersectionVertex v : edgeList.visibilityVertices()) { + for (Vertex v : edgeList.visibilityVertices()) { createSegments(newVertex, v, edgeList, areas, scope, tempEdges); } } @@ -611,8 +609,8 @@ private Set getNoThruModes(Collection edges) { } private void createSegments( - IntersectionVertex from, - IntersectionVertex to, + Vertex from, + Vertex to, AreaEdgeList ael, List areas, Scope scope, diff --git a/application/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingEntrance.java b/application/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingEntrance.java index f6bc584fb18..73cd50e6606 100644 --- a/application/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingEntrance.java +++ b/application/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingEntrance.java @@ -5,7 +5,7 @@ import javax.annotation.Nullable; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.utils.tostring.ToStringBuilder; @@ -23,14 +23,14 @@ public class VehicleParkingEntrance implements Serializable { // If this entrance should be linked to walk/bike accessible streets private final boolean walkAccessible; // Used to explicitly specify the intersection to link to instead of using (x, y) - private transient StreetVertex vertex; + private transient Vertex vertex; VehicleParkingEntrance( VehicleParking vehicleParking, FeedScopedId entranceId, WgsCoordinate coordinate, I18NString name, - StreetVertex vertex, + Vertex vertex, boolean carAccessible, boolean walkAccessible ) { @@ -64,7 +64,7 @@ public I18NString getName() { return name; } - public StreetVertex getVertex() { + public Vertex getVertex() { return vertex; } @@ -120,7 +120,7 @@ public static class VehicleParkingEntranceBuilder { private FeedScopedId entranceId; private WgsCoordinate coordinate; private I18NString name; - private StreetVertex vertex; + private Vertex vertex; private boolean carAccessible; private boolean walkAccessible; @@ -146,7 +146,7 @@ public VehicleParkingEntranceBuilder name(I18NString name) { return this; } - public VehicleParkingEntranceBuilder vertex(StreetVertex vertex) { + public VehicleParkingEntranceBuilder vertex(Vertex vertex) { this.vertex = vertex; return this; } diff --git a/application/src/main/java/org/opentripplanner/service/vehiclerental/street/StreetVehicleRentalLink.java b/application/src/main/java/org/opentripplanner/service/vehiclerental/street/StreetVehicleRentalLink.java index 99775b6112d..869b99fd4ce 100644 --- a/application/src/main/java/org/opentripplanner/service/vehiclerental/street/StreetVehicleRentalLink.java +++ b/application/src/main/java/org/opentripplanner/service/vehiclerental/street/StreetVehicleRentalLink.java @@ -2,7 +2,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.street.model.edge.Edge; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.StateEditor; @@ -13,18 +13,18 @@ public class StreetVehicleRentalLink extends Edge { private final VehicleRentalPlaceVertex vehicleRentalPlaceVertex; - private StreetVehicleRentalLink(StreetVertex fromv, VehicleRentalPlaceVertex tov) { + private StreetVehicleRentalLink(Vertex fromv, VehicleRentalPlaceVertex tov) { super(fromv, tov); vehicleRentalPlaceVertex = tov; } - private StreetVehicleRentalLink(VehicleRentalPlaceVertex fromv, StreetVertex tov) { + private StreetVehicleRentalLink(VehicleRentalPlaceVertex fromv, Vertex tov) { super(fromv, tov); vehicleRentalPlaceVertex = fromv; } public static StreetVehicleRentalLink createStreetVehicleRentalLink( - StreetVertex fromv, + Vertex fromv, VehicleRentalPlaceVertex tov ) { return connectToGraph(new StreetVehicleRentalLink(fromv, tov)); @@ -32,7 +32,7 @@ public static StreetVehicleRentalLink createStreetVehicleRentalLink( public static StreetVehicleRentalLink createStreetVehicleRentalLink( VehicleRentalPlaceVertex fromv, - StreetVertex tov + Vertex tov ) { return connectToGraph(new StreetVehicleRentalLink(fromv, tov)); } diff --git a/application/src/main/java/org/opentripplanner/standalone/config/buildconfig/OsmConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/buildconfig/OsmConfig.java index 1b2ec0ed74d..5cc67844b50 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/buildconfig/OsmConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/buildconfig/OsmConfig.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config.buildconfig; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; import org.opentripplanner.graph_builder.module.osm.parameters.OsmExtractParameters; import org.opentripplanner.graph_builder.module.osm.parameters.OsmExtractParametersBuilder; @@ -84,6 +85,14 @@ public static OsmExtractParametersBuilder mapOsmGenericParameters( ) .docDefaultValue(docDefaults.timeZone()) .asZoneId(defaults.timeZone()) + ) + .withIncludeOsmSubwayEntrances( + node + .of("includeOsmSubwayEntrances") + .since(V2_7) + .summary("Whether to include subway entrances from the OSM data." + documentationAddition) + .docDefaultValue(docDefaults.includeOsmSubwayEntrances()) + .asBoolean(defaults.includeOsmSubwayEntrances()) ); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java b/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java index efabefa7cea..0677a7a11bf 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeBuilder.java @@ -1,6 +1,6 @@ package org.opentripplanner.street.model.edge; -import org.opentripplanner.street.model.vertex.IntersectionVertex; +import org.opentripplanner.street.model.vertex.Vertex; public class AreaEdgeBuilder extends StreetEdgeBuilder { @@ -12,13 +12,13 @@ public AreaEdge buildAndConnect() { } @Override - public IntersectionVertex fromVertex() { - return (IntersectionVertex) super.fromVertex(); + public Vertex fromVertex() { + return super.fromVertex(); } @Override - public IntersectionVertex toVertex() { - return (IntersectionVertex) super.toVertex(); + public Vertex toVertex() { + return super.toVertex(); } public AreaEdgeList area() { diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeList.java b/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeList.java index 1f8d286995b..ec2b04877e1 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeList.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/AreaEdgeList.java @@ -9,7 +9,7 @@ import java.util.stream.Stream; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Polygon; -import org.opentripplanner.street.model.vertex.IntersectionVertex; +import org.opentripplanner.street.model.vertex.Vertex; /** * This is a representation of a set of contiguous OSM areas, used for various tasks related to edge @@ -19,8 +19,8 @@ */ public class AreaEdgeList implements Serializable { - private static final Set EMPTY_SET = Set.of(); - private Set visibilityVertices = EMPTY_SET; + private static final Set EMPTY_SET = Set.of(); + private Set visibilityVertices = EMPTY_SET; // these are all of the original edges of the area, whether // or not there are corresponding OSM edges. It is used as part of a hack @@ -59,14 +59,14 @@ public Geometry getGeometry() { /** * Returns the list of visibility vertices. */ - public Set visibilityVertices() { + public Set visibilityVertices() { return visibilityVertices; } /** * Add a visibility vertex to this edge. */ - public void addVisibilityVertex(IntersectionVertex toBeAdded) { + public void addVisibilityVertex(Vertex toBeAdded) { Objects.requireNonNull(toBeAdded); synchronized (this) { if (visibilityVertices == EMPTY_SET) { diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java index b606bcd9962..786faf60098 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java @@ -28,7 +28,7 @@ import org.opentripplanner.street.model.vertex.BarrierVertex; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.SplitterVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.TraverseModeSet; import org.opentripplanner.street.search.state.State; @@ -626,7 +626,7 @@ public SplitStreetEdge splitDestructively(SplitterVertex v) { SplitLineString geoms = GeometryUtils.splitGeometryAtPoint(getGeometry(), v.getCoordinate()); StreetEdgeBuilder seb1 = new StreetEdgeBuilder<>() - .withFromVertex((StreetVertex) fromv) + .withFromVertex(fromv) .withToVertex(v) .withGeometry(geoms.beginning()) .withName(name) @@ -635,7 +635,7 @@ public SplitStreetEdge splitDestructively(SplitterVertex v) { StreetEdgeBuilder seb2 = new StreetEdgeBuilder<>() .withFromVertex(v) - .withToVertex((StreetVertex) tov) + .withToVertex(tov) .withGeometry(geoms.ending()) .withName(name) .withPermission(permission) @@ -712,7 +712,7 @@ public SplitStreetEdge splitNonDestructively( if (direction == LinkingDirection.OUTGOING || direction == LinkingDirection.BOTH_WAYS) { var seb1 = new TemporaryPartialStreetEdgeBuilder() .withParentEdge(this) - .withFromVertex((StreetVertex) fromv) + .withFromVertex(fromv) .withToVertex(v) .withGeometry(geoms.beginning()) .withName(name) @@ -726,7 +726,7 @@ public SplitStreetEdge splitNonDestructively( var seb2 = new TemporaryPartialStreetEdgeBuilder() .withParentEdge(this) .withFromVertex(v) - .withToVertex((StreetVertex) tov) + .withToVertex(tov) .withGeometry(geoms.ending()) .withName(name) .withBack(isBack()); @@ -745,7 +745,7 @@ public SplitStreetEdge splitNonDestructively( return splitEdges; } - public Optional createPartialEdge(StreetVertex from, StreetVertex to) { + public Optional createPartialEdge(Vertex from, Vertex to) { LineString parent = getGeometry(); LineString head = GeometryUtils.getInteriorSegment( parent, diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java index 99a02205eb6..7fa1bb72d4c 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdgeBuilder.java @@ -15,7 +15,7 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.street.model.StreetTraversalPermission; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.utils.lang.BitSetUtils; @@ -26,8 +26,8 @@ public class StreetEdgeBuilder> { public static final float DEFAULT_WALK_SAFETY_FACTOR = 1.0f; private static final float DEFAULT_BICYCLE_SAFETY_FACTOR = 1.0f; - private StreetVertex from; - private StreetVertex to; + private Vertex from; + private Vertex to; private LineString geometry; private I18NString name; private int millimeterLength; @@ -48,8 +48,8 @@ public StreetEdgeBuilder() { } public StreetEdgeBuilder(StreetEdge original) { - this.from = (StreetVertex) original.getFromVertex(); - this.to = (StreetVertex) original.getToVertex(); + this.from = original.getFromVertex(); + this.to = original.getToVertex(); this.geometry = original.getGeometry(); this.name = original.getName(); this.millimeterLength = original.getMillimeterLength(); @@ -65,20 +65,20 @@ public StreetEdge buildAndConnect() { return Edge.connectToGraph(new StreetEdge(this)); } - public StreetVertex fromVertex() { + public Vertex fromVertex() { return from; } - public B withFromVertex(StreetVertex from) { + public B withFromVertex(Vertex from) { this.from = from; return instance(); } - public StreetVertex toVertex() { + public Vertex toVertex() { return to; } - public B withToVertex(StreetVertex to) { + public B withToVertex(Vertex to) { this.to = to; return instance(); } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetStationCentroidLink.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetStationCentroidLink.java index 6b336907db5..d0e7ef13363 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetStationCentroidLink.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetStationCentroidLink.java @@ -1,23 +1,23 @@ package org.opentripplanner.street.model.edge; import org.opentripplanner.street.model.vertex.StationCentroidVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.Vertex; /** * This represents the connection between a street vertex and a transit station centroid vertex */ public class StreetStationCentroidLink extends FreeEdge { - private StreetStationCentroidLink(StreetVertex fromv, StationCentroidVertex tov) { + private StreetStationCentroidLink(Vertex fromv, StationCentroidVertex tov) { super(fromv, tov); } - private StreetStationCentroidLink(StationCentroidVertex fromv, StreetVertex tov) { + private StreetStationCentroidLink(StationCentroidVertex fromv, Vertex tov) { super(fromv, tov); } public static StreetStationCentroidLink createStreetStationLink( - StreetVertex fromv, + Vertex fromv, StationCentroidVertex tov ) { return connectToGraph(new StreetStationCentroidLink(fromv, tov)); @@ -25,7 +25,7 @@ public static StreetStationCentroidLink createStreetStationLink( public static StreetStationCentroidLink createStreetStationLink( StationCentroidVertex fromv, - StreetVertex tov + Vertex tov ) { return connectToGraph(new StreetStationCentroidLink(fromv, tov)); } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntityLink.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntityLink.java index 5a62eda0f90..9a05590c7d0 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntityLink.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntityLink.java @@ -5,7 +5,10 @@ import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; -import org.opentripplanner.street.model.vertex.StreetVertex; +import org.opentripplanner.street.model.vertex.StationCentroidVertex; +import org.opentripplanner.street.model.vertex.TransitEntranceVertex; +import org.opentripplanner.street.model.vertex.TransitStopVertex; +import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.StateEditor; @@ -20,13 +23,13 @@ public abstract class StreetTransitEntityLink static final int STEL_TRAVERSE_COST = 1; - private final T transitEntityVertex; + private final Vertex transitEntityVertex; private final Accessibility wheelchairAccessibility; protected StreetTransitEntityLink( - StreetVertex fromv, - T tov, + Vertex fromv, + TransitEntranceVertex tov, Accessibility wheelchairAccessibility ) { super(fromv, tov); @@ -35,8 +38,68 @@ protected StreetTransitEntityLink( } protected StreetTransitEntityLink( - T fromv, - StreetVertex tov, + TransitEntranceVertex fromv, + Vertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = fromv; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + Vertex fromv, + VehicleParkingEntranceVertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = tov; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + VehicleParkingEntranceVertex fromv, + Vertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = fromv; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + Vertex fromv, + TransitStopVertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = tov; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + TransitStopVertex fromv, + Vertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = fromv; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + Vertex fromv, + StationCentroidVertex tov, + Accessibility wheelchairAccessibility + ) { + super(fromv, tov); + this.transitEntityVertex = tov; + this.wheelchairAccessibility = wheelchairAccessibility; + } + + protected StreetTransitEntityLink( + StationCentroidVertex fromv, + Vertex tov, Accessibility wheelchairAccessibility ) { super(fromv, tov); @@ -159,7 +222,7 @@ public LineString getGeometry() { protected abstract int getStreetToStopTime(); - protected T getTransitEntityVertex() { + protected Vertex getTransitEntityVertex() { return transitEntityVertex; } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntranceLink.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntranceLink.java index 7145f6183e4..d79e54c9b76 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntranceLink.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetTransitEntranceLink.java @@ -1,7 +1,7 @@ package org.opentripplanner.street.model.edge; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TransitEntranceVertex; +import org.opentripplanner.street.model.vertex.Vertex; /** * This represents the connection between a street vertex and a transit vertex belonging the street @@ -11,18 +11,18 @@ public class StreetTransitEntranceLink extends StreetTransitEntityLink { - private StreetTransitStopLink(StreetVertex fromv, TransitStopVertex tov) { + private StreetTransitStopLink(Vertex fromv, TransitStopVertex tov) { super(fromv, tov, tov.getWheelchairAccessibility()); } - private StreetTransitStopLink(TransitStopVertex fromv, StreetVertex tov) { + private StreetTransitStopLink(TransitStopVertex fromv, Vertex tov) { super(fromv, tov, fromv.getWheelchairAccessibility()); } public static StreetTransitStopLink createStreetTransitStopLink( - StreetVertex fromv, + Vertex fromv, TransitStopVertex tov ) { return connectToGraph(new StreetTransitStopLink(fromv, tov)); @@ -26,14 +26,14 @@ public static StreetTransitStopLink createStreetTransitStopLink( public static StreetTransitStopLink createStreetTransitStopLink( TransitStopVertex fromv, - StreetVertex tov + Vertex tov ) { return connectToGraph(new StreetTransitStopLink(fromv, tov)); } protected int getStreetToStopTime() { - return getTransitEntityVertex().hasPathways() + return ((TransitStopVertex) getTransitEntityVertex()).hasPathways() ? 0 - : getTransitEntityVertex().getStreetToStopTime(); + : ((TransitStopVertex) getTransitEntityVertex()).getStreetToStopTime(); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java index 682aeca0b3e..907feea2639 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java @@ -5,8 +5,8 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.vehicle_parking.VehicleParking; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; +import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.state.State; import org.opentripplanner.street.search.state.StateEditor; @@ -18,18 +18,18 @@ public class StreetVehicleParkingLink extends Edge { private final VehicleParkingEntranceVertex vehicleParkingEntranceVertex; - private StreetVehicleParkingLink(StreetVertex fromv, VehicleParkingEntranceVertex tov) { + private StreetVehicleParkingLink(Vertex fromv, VehicleParkingEntranceVertex tov) { super(fromv, tov); vehicleParkingEntranceVertex = tov; } - private StreetVehicleParkingLink(VehicleParkingEntranceVertex fromv, StreetVertex tov) { + private StreetVehicleParkingLink(VehicleParkingEntranceVertex fromv, Vertex tov) { super(fromv, tov); vehicleParkingEntranceVertex = fromv; } public static StreetVehicleParkingLink createStreetVehicleParkingLink( - StreetVertex fromv, + Vertex fromv, VehicleParkingEntranceVertex tov ) { return connectToGraph(new StreetVehicleParkingLink(fromv, tov)); @@ -37,7 +37,7 @@ public static StreetVehicleParkingLink createStreetVehicleParkingLink( public static StreetVehicleParkingLink createStreetVehicleParkingLink( VehicleParkingEntranceVertex fromv, - StreetVertex tov + Vertex tov ) { return connectToGraph(new StreetVehicleParkingLink(fromv, tov)); } diff --git a/application/src/main/java/org/opentripplanner/street/model/vertex/StationEntranceVertex.java b/application/src/main/java/org/opentripplanner/street/model/vertex/StationEntranceVertex.java new file mode 100644 index 00000000000..e55ac7078db --- /dev/null +++ b/application/src/main/java/org/opentripplanner/street/model/vertex/StationEntranceVertex.java @@ -0,0 +1,29 @@ +package org.opentripplanner.street.model.vertex; + +public class StationEntranceVertex extends OsmVertex { + + private final String code; + private final boolean accessible; + + public StationEntranceVertex(double x, double y, long nodeId, String code, boolean accessible) { + super(x, y, nodeId); + this.code = code; + this.accessible = accessible; + } + + public String getCode() { + return code; + } + + public boolean isAccessible() { + return accessible; + } + + public String getId() { + return Long.toString(nodeId); + } + + public String toString() { + return "StationEntranceVertex(" + super.toString() + ", code=" + code + ")"; + } +} diff --git a/application/src/main/java/org/opentripplanner/street/model/vertex/TransitEntranceVertex.java b/application/src/main/java/org/opentripplanner/street/model/vertex/TransitEntranceVertex.java index 81b89ad3dfb..4e7e99d4424 100644 --- a/application/src/main/java/org/opentripplanner/street/model/vertex/TransitEntranceVertex.java +++ b/application/src/main/java/org/opentripplanner/street/model/vertex/TransitEntranceVertex.java @@ -36,4 +36,8 @@ public Entrance getEntrance() { public StationElement getStationElement() { return this.entrance; } + + public boolean isConnectedToGraph() { + return getDegreeOut() + getDegreeIn() > 0; + } } diff --git a/application/src/main/java/org/opentripplanner/street/model/vertex/Vertex.java b/application/src/main/java/org/opentripplanner/street/model/vertex/Vertex.java index 75fd5b7218e..80cd985e286 100644 --- a/application/src/main/java/org/opentripplanner/street/model/vertex/Vertex.java +++ b/application/src/main/java/org/opentripplanner/street/model/vertex/Vertex.java @@ -8,6 +8,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.locationtech.jts.geom.Coordinate; import org.opentripplanner.astar.spi.AStarVertex; import org.opentripplanner.framework.geometry.WgsCoordinate; @@ -15,7 +19,10 @@ import org.opentripplanner.street.model.RentalRestrictionExtension; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.model.edge.StreetEdge; +import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.street.search.state.State; +import org.opentripplanner.transit.model.basic.Accessibility; +import org.opentripplanner.transit.model.site.AreaStop; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +42,8 @@ public abstract class Vertex implements AStarVertex, Serial private transient Edge[] outgoing = new Edge[0]; private RentalRestrictionExtension rentalRestrictions = RentalRestrictionExtension.NO_RESTRICTION; + private static final Set EMPTY_SET = Set.of(); + private Set areaStops = EMPTY_SET; /* CONSTRUCTORS */ @@ -113,6 +122,25 @@ public int getDegreeIn() { return incoming.length; } + /** + * Does the vertex have an outgoing edge that allows driving. + */ + public boolean isConnectedToDriveableEdge() { + return this.getOutgoing() + .stream() + .anyMatch(edge -> + edge instanceof StreetEdge && ((StreetEdge) edge).getPermission().allows(TraverseMode.CAR) + ); + } + + public boolean isConnectedToWalkingEdge() { + return this.getOutgoing() + .stream() + .anyMatch(edge -> + edge instanceof StreetEdge && ((StreetEdge) edge).getPermission().allows(TraverseMode.WALK) + ); + } + /** Get the longitude of the vertex */ public final double getX() { return getLon(); @@ -225,6 +253,10 @@ public boolean rentalTraversalBanned(State currentState) { return rentalRestrictions.traversalBanned(currentState); } + public Accessibility getWheelchairAccessibility() { + return Accessibility.NO_INFORMATION; + } + public void addRentalRestriction(RentalRestrictionExtension ext) { rentalRestrictions = rentalRestrictions.add(ext); } @@ -302,4 +334,28 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE this.incoming = new Edge[0]; this.outgoing = new Edge[0]; } + + /** + * Returns the list of area stops that this vertex is inside of. + */ + public Set areaStops() { + return areaStops; + } + + /** + * Add a collection of area stops to this vertex. + */ + public void addAreaStops(Collection toBeAdded) { + Objects.requireNonNull(toBeAdded); + synchronized (this) { + if (areaStops == EMPTY_SET) { + areaStops = Set.copyOf(toBeAdded); + } else { + areaStops = + Stream + .concat(areaStops.stream(), toBeAdded.stream()) + .collect(Collectors.toUnmodifiableSet()); + } + } + } } diff --git a/application/src/main/java/org/opentripplanner/street/model/vertex/VertexFactory.java b/application/src/main/java/org/opentripplanner/street/model/vertex/VertexFactory.java index 80bd8021309..1c37d39adb6 100644 --- a/application/src/main/java/org/opentripplanner/street/model/vertex/VertexFactory.java +++ b/application/src/main/java/org/opentripplanner/street/model/vertex/VertexFactory.java @@ -94,6 +94,15 @@ public ExitVertex exit(long nid, Coordinate coordinate, String exitName) { return addToGraph(new ExitVertex(coordinate.x, coordinate.y, nid, exitName)); } + public StationEntranceVertex stationEntrance( + long nid, + Coordinate coordinate, + String code, + boolean accessible + ) { + return addToGraph(new StationEntranceVertex(coordinate.x, coordinate.y, nid, code, accessible)); + } + public OsmVertex osm( Coordinate coordinate, OsmNode node, diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index de1230b9eca..83fe952ce7e 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -73,6 +73,9 @@ interface PlaceInterface { "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown +"A feature for a step" +union StepFeature = Entrance + union StopPosition = PositionAtStop | PositionBetweenStops "A public transport agency" @@ -444,6 +447,18 @@ type Emissions { co2: Grams } +"Station entrance or exit, originating from OSM or GTFS data." +type Entrance { + "Short text or a number that identifies the entrance or exit for passengers. For example, `A` or `B`." + code: String + "ID of the entrance in the format of `FeedId:EntranceId`. If the `FeedId` is `osm`, the entrance originates from OSM data." + entranceId: String! + "Name of the entrance or exit." + name: String + "Whether the entrance or exit is accessible by wheelchair" + wheelchairAccessible: WheelchairBoarding +} + "A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'." type FareMedium { "ID of the medium" @@ -2647,6 +2662,8 @@ type step { elevationProfile: [elevationProfileComponent] "When exiting a highway or traffic circle, the exit name/number." exit: String + "Information about an feature associated with a step e.g. an station entrance or exit" + feature: StepFeature "The latitude of the start of the step." lat: Float "The longitude of the start of the step." @@ -3328,6 +3345,7 @@ enum RelativeDirection { CONTINUE DEPART ELEVATOR + ENTER_OR_EXIT_STATION ENTER_STATION EXIT_STATION FOLLOW_SIGNS diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 3aad9075f73..9d0fc235c30 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -79,6 +79,7 @@ import org.opentripplanner.standalone.config.framework.json.JsonSupport; import org.opentripplanner.test.support.FilePatternSource; import org.opentripplanner.transit.model._data.TimetableRepositoryForTest; +import org.opentripplanner.transit.model.basic.Accessibility; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.AbstractBuilder; @@ -88,6 +89,7 @@ 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.Entrance; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; @@ -231,9 +233,20 @@ public Set getRoutesForStop(StopLocation stop) { .withAbsoluteDirection(20) .build(); var step2 = walkStep("elevator").withRelativeDirection(RelativeDirection.ELEVATOR).build(); + FeedScopedId entranceId = new FeedScopedId("osm", "123"); + Entrance entrance = Entrance + .of(entranceId) + .withCoordinate(new WgsCoordinate(60, 80)) + .withCode("A") + .withWheelchairAccessibility(Accessibility.POSSIBLE) + .build(); + var step3 = walkStep("entrance") + .withRelativeDirection(RelativeDirection.ENTER_OR_EXIT_STATION) + .withEntrance(entrance) + .build(); Itinerary i1 = newItinerary(A, T11_00) - .walk(20, B, List.of(step1, step2)) + .walk(20, B, List.of(step1, step2, step3)) .bus(busRoute, 122, T11_01, T11_15, C) .rail(439, T11_30, T11_50, D) .carHail(D10m, E) diff --git a/application/src/test/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilderTest.java b/application/src/test/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilderTest.java index b712ee48c5a..1516c9df91a 100644 --- a/application/src/test/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilderTest.java +++ b/application/src/test/java/org/opentripplanner/graph_builder/module/osm/WalkableAreaBuilderTest.java @@ -48,7 +48,7 @@ public Graph buildGraph(final TestInfo testInfo) { final WalkableAreaBuilder walkableAreaBuilder = new WalkableAreaBuilder( graph, osmdb, - new VertexGenerator(osmdb, graph, Set.of()), + new VertexGenerator(osmdb, graph, Set.of(), false), new DefaultNamer(), new SafetyValueNormalizer(graph, DataImportIssueStore.NOOP), DataImportIssueStore.NOOP, diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java index b9f9d7acb56..2cd97beac0b 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/GraphRoutingTest.java @@ -39,7 +39,6 @@ import org.opentripplanner.street.model.vertex.ElevatorOnboardVertex; import org.opentripplanner.street.model.vertex.IntersectionVertex; import org.opentripplanner.street.model.vertex.StationCentroidVertex; -import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.TemporaryStreetLocation; import org.opentripplanner.street.model.vertex.TemporaryVertex; import org.opentripplanner.street.model.vertex.TransitEntranceVertex; @@ -118,8 +117,8 @@ public IntersectionVertex intersection(String label, WgsCoordinate coordinate) { } public StreetEdgeBuilder streetBuilder( - StreetVertex from, - StreetVertex to, + Vertex from, + Vertex to, int length, StreetTraversalPermission permissions ) { @@ -138,13 +137,13 @@ public StreetEdgeBuilder streetBuilder( /** * Create a street with all permissions in both directions */ - public List biStreet(StreetVertex from, StreetVertex to, int length) { + public List biStreet(Vertex from, Vertex to, int length) { return street(from, to, length, StreetTraversalPermission.ALL, StreetTraversalPermission.ALL); } public StreetEdge street( - StreetVertex from, - StreetVertex to, + Vertex from, + Vertex to, int length, StreetTraversalPermission permissions ) { @@ -152,8 +151,8 @@ public StreetEdge street( } public List street( - StreetVertex from, - StreetVertex to, + Vertex from, + Vertex to, int length, StreetTraversalPermission forwardPermissions, StreetTraversalPermission reversePermissions @@ -300,39 +299,39 @@ public StationCentroidVertex stationCentroid(Station station) { return vertexFactory.stationCentroid(station); } - public StreetTransitEntranceLink link(StreetVertex from, TransitEntranceVertex to) { + public StreetTransitEntranceLink link(Vertex from, TransitEntranceVertex to) { return StreetTransitEntranceLink.createStreetTransitEntranceLink(from, to); } - public StreetTransitEntranceLink link(TransitEntranceVertex from, StreetVertex to) { + public StreetTransitEntranceLink link(TransitEntranceVertex from, Vertex to) { return StreetTransitEntranceLink.createStreetTransitEntranceLink(from, to); } - public List biLink(StreetVertex from, TransitEntranceVertex to) { + public List biLink(Vertex from, TransitEntranceVertex to) { return List.of(link(from, to), link(to, from)); } - public StreetTransitStopLink link(StreetVertex from, TransitStopVertex to) { + public StreetTransitStopLink link(Vertex from, TransitStopVertex to) { return StreetTransitStopLink.createStreetTransitStopLink(from, to); } - public StreetTransitStopLink link(TransitStopVertex from, StreetVertex to) { + public StreetTransitStopLink link(TransitStopVertex from, Vertex to) { return StreetTransitStopLink.createStreetTransitStopLink(from, to); } - public List biLink(StreetVertex from, TransitStopVertex to) { + public List biLink(Vertex from, TransitStopVertex to) { return List.of(link(from, to), link(to, from)); } - public StreetStationCentroidLink link(StreetVertex from, StationCentroidVertex to) { + public StreetStationCentroidLink link(Vertex from, StationCentroidVertex to) { return StreetStationCentroidLink.createStreetStationLink(from, to); } - public StreetStationCentroidLink link(StationCentroidVertex from, StreetVertex to) { + public StreetStationCentroidLink link(StationCentroidVertex from, Vertex to) { return StreetStationCentroidLink.createStreetStationLink(from, to); } - public List biLink(StreetVertex from, StationCentroidVertex to) { + public List biLink(Vertex from, StationCentroidVertex to) { return List.of(link(from, to), link(to, from)); } @@ -367,11 +366,11 @@ public TemporaryStreetLocation streetLocation( ); } - public TemporaryFreeEdge link(TemporaryVertex from, StreetVertex to) { + public TemporaryFreeEdge link(TemporaryVertex from, Vertex to) { return TemporaryFreeEdge.createTemporaryFreeEdge(from, to); } - public TemporaryFreeEdge link(StreetVertex from, TemporaryVertex to) { + public TemporaryFreeEdge link(Vertex from, TemporaryVertex to) { return TemporaryFreeEdge.createTemporaryFreeEdge(from, to); } @@ -420,15 +419,15 @@ public VehicleRentalPlaceVertex vehicleRentalStation( return vehicleRentalStation(id, latitude, longitude, TEST_VEHICLE_RENTAL_NETWORK); } - public StreetVehicleRentalLink link(StreetVertex from, VehicleRentalPlaceVertex to) { + public StreetVehicleRentalLink link(Vertex from, VehicleRentalPlaceVertex to) { return StreetVehicleRentalLink.createStreetVehicleRentalLink(from, to); } - public StreetVehicleRentalLink link(VehicleRentalPlaceVertex from, StreetVertex to) { + public StreetVehicleRentalLink link(VehicleRentalPlaceVertex from, Vertex to) { return StreetVehicleRentalLink.createStreetVehicleRentalLink(from, to); } - public List biLink(StreetVertex from, VehicleRentalPlaceVertex to) { + public List biLink(Vertex from, VehicleRentalPlaceVertex to) { return List.of(link(from, to), link(to, from)); } @@ -472,7 +471,7 @@ public VehicleParking vehicleParking( } public VehicleParking.VehicleParkingEntranceCreator vehicleParkingEntrance( - StreetVertex streetVertex, + Vertex streetVertex, String id, boolean carAccessible, boolean walkAccessible @@ -487,18 +486,15 @@ public VehicleParking.VehicleParkingEntranceCreator vehicleParkingEntrance( .walkAccessible(walkAccessible); } - public StreetVehicleParkingLink link(StreetVertex from, VehicleParkingEntranceVertex to) { + public StreetVehicleParkingLink link(Vertex from, VehicleParkingEntranceVertex to) { return StreetVehicleParkingLink.createStreetVehicleParkingLink(from, to); } - public StreetVehicleParkingLink link(VehicleParkingEntranceVertex from, StreetVertex to) { + public StreetVehicleParkingLink link(VehicleParkingEntranceVertex from, Vertex to) { return StreetVehicleParkingLink.createStreetVehicleParkingLink(from, to); } - public List biLink( - StreetVertex from, - VehicleParkingEntranceVertex to - ) { + public List biLink(Vertex from, VehicleParkingEntranceVertex to) { return List.of(link(from, to), link(to, from)); } diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/walk-steps.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/walk-steps.json index be584a875be..8d79102fc59 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/walk-steps.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/walk-steps.json @@ -11,13 +11,28 @@ "streetName" : "street", "area" : false, "relativeDirection" : "DEPART", - "absoluteDirection" : "NORTHEAST" + "absoluteDirection" : "NORTHEAST", + "feature" : null }, { "streetName" : "elevator", "area" : false, "relativeDirection" : "ELEVATOR", - "absoluteDirection" : null + "absoluteDirection" : null, + "feature" : null + + }, + { + "streetName" : "entrance", + "area" : false, + "relativeDirection" : "ENTER_OR_EXIT_STATION", + "absoluteDirection" : null, + "feature": { + "__typename": "Entrance", + "code": "A", + "entranceId": "osm:123", + "wheelchairAccessible": "POSSIBLE" + } } ] }, diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/walk-steps.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/walk-steps.graphql index dd2b96395ad..565e620fed3 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/walk-steps.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/walk-steps.graphql @@ -20,6 +20,14 @@ area relativeDirection absoluteDirection + feature { + __typename + ... on Entrance { + code + entranceId + wheelchairAccessible + } + } } } } diff --git a/doc/user/BuildConfiguration.md b/doc/user/BuildConfiguration.md index 99e98066e73..c5fdfa8095b 100644 --- a/doc/user/BuildConfiguration.md +++ b/doc/user/BuildConfiguration.md @@ -84,10 +84,12 @@ Sections follow that describe particular settings in more depth. |    [sharedGroupFilePattern](#nd_sharedGroupFilePattern) | `regexp` | Pattern for matching shared group NeTEx files in a NeTEx bundle. | *Optional* | `"(\w{3})-.*-shared\.xml"` | 2.0 | |    [ferryIdsNotAllowedForBicycle](#nd_ferryIdsNotAllowedForBicycle) | `string[]` | List ferries which do not allow bikes. | *Optional* | | 2.0 | | [osm](#osm) | `object[]` | Configure properties for a given OpenStreetMap feed. | *Optional* | | 2.2 | +|       includeOsmSubwayEntrances | `boolean` | Whether to include subway entrances from the OSM data. Overrides the value specified in `osmDefaults`. | *Optional* | `false` | 2.7 | |       [osmTagMapping](#osm_0_osmTagMapping) | `enum` | The named set of mapping rules applied when parsing OSM tags. Overrides the value specified in `osmDefaults`. | *Optional* | `"default"` | 2.2 | |       source | `uri` | The unique URI pointing to the data file. | *Required* | | 2.2 | |       timeZone | `time-zone` | The timezone used to resolve opening hours in OSM data. Overrides the value specified in `osmDefaults`. | *Optional* | | 2.2 | | osmDefaults | `object` | Default properties for OpenStreetMap feeds. | *Optional* | | 2.2 | +|    includeOsmSubwayEntrances | `boolean` | Whether to include subway entrances from the OSM data. | *Optional* | `false` | 2.7 | |    [osmTagMapping](#od_osmTagMapping) | `enum` | The named set of mapping rules applied when parsing OSM tags. | *Optional* | `"default"` | 2.2 | |    timeZone | `time-zone` | The timezone used to resolve opening hours in OSM data. | *Optional* | | 2.2 | | [transferRequests](RouteRequest.md) | `object[]` | Routing requests to use for pre-calculating stop-to-stop transfers. | *Optional* | | 2.1 |