diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmDatabase.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmDatabase.java index bb958fd9414..23999d1fec5 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmDatabase.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmDatabase.java @@ -688,7 +688,7 @@ private void processSingleWayAreas() { } } try { - newArea(new Area(way, List.of(way), Collections.emptyList(), nodesById)); + addArea(new Area(way, List.of(way), Collections.emptyList(), nodesById)); } catch (Area.AreaConstructionException | Ring.RingConstructionException e) { // this area cannot be constructed, but we already have all the // necessary nodes to construct it. So, something must be wrong with @@ -751,7 +751,7 @@ private void processMultipolygonRelations() { } processedAreas.add(relation); try { - newArea(new Area(relation, outerWays, innerWays, nodesById)); + addArea(new Area(relation, outerWays, innerWays, nodesById)); } catch (Area.AreaConstructionException | Ring.RingConstructionException e) { issueStore.add(new InvalidOsmGeometry(relation)); continue; @@ -786,10 +786,12 @@ private void processMultipolygonRelations() { /** * Handler for a new Area (single way area or multipolygon relations) */ - private void newArea(Area area) { - StreetTraversalPermission permissions = area.parent.overridePermissions( - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE - ); + private void addArea(Area area) { + StreetTraversalPermission permissions = area.parent + .getOsmProvider() + .getWayPropertySet() + .getDataForWay(area.parent) + .getPermission(); if (area.parent.isRoutable() && permissions != StreetTraversalPermission.NONE) { walkableAreas.add(area); } 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..2802ee70a89 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 @@ -499,9 +499,14 @@ private Set createSegments( Area area = intersects.getFirst(); OsmWithTags areaEntity = area.parent; - StreetTraversalPermission areaPermissions = areaEntity.overridePermissions( - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE - ); + WayProperties wayData; + if (!wayPropertiesCache.containsKey(areaEntity)) { + wayData = areaEntity.getOsmProvider().getWayPropertySet().getDataForWay(areaEntity); + wayPropertiesCache.put(areaEntity, wayData); + } else { + wayData = wayPropertiesCache.get(areaEntity); + } + StreetTraversalPermission areaPermissions = wayData.getPermission(); float carSpeed = areaEntity .getOsmProvider() @@ -520,8 +525,8 @@ private Set createSegments( startEndpoint.getLabel() + " to " + endEndpoint.getLabel(); - I18NString name = namer.getNameForWay(areaEntity, label); + I18NString name = namer.getNameForWay(areaEntity, label); AreaEdgeBuilder streetEdgeBuilder = new AreaEdgeBuilder() .withFromVertex(startEndpoint) .withToVertex(endEndpoint) @@ -543,8 +548,8 @@ private Set createSegments( endEndpoint.getLabel() + " to " + startEndpoint.getLabel(); - name = namer.getNameForWay(areaEntity, label); + name = namer.getNameForWay(areaEntity, label); AreaEdgeBuilder backStreetEdgeBuilder = new AreaEdgeBuilder() .withFromVertex(endEndpoint) .withToVertex(startEndpoint) @@ -559,22 +564,10 @@ private Set createSegments( .withWheelchairAccessible(areaEntity.isWheelchairAccessible()) .withLink(areaEntity.isLink()); - if (!wayPropertiesCache.containsKey(areaEntity)) { - WayProperties wayData = areaEntity - .getOsmProvider() - .getWayPropertySet() - .getDataForWay(areaEntity); - wayPropertiesCache.put(areaEntity, wayData); - } - AreaEdge street = streetEdgeBuilder.buildAndConnect(); + AreaEdge backStreet = backStreetEdgeBuilder.buildAndConnect(); - normalizer.applyWayProperties( - street, - backStreet, - wayPropertiesCache.get(areaEntity), - areaEntity - ); + normalizer.applyWayProperties(street, backStreet, wayData, areaEntity); return Set.of(street, backStreet); } else { // take the part that intersects with the start vertex @@ -640,12 +633,12 @@ private void createNamedAreas(AreaEdgeList edgeList, Ring ring, Collection I18NString name = namer.getNameForWay(areaEntity, id); namedArea.setName(name); + WayProperties wayData; if (!wayPropertiesCache.containsKey(areaEntity)) { - WayProperties wayData = areaEntity - .getOsmProvider() - .getWayPropertySet() - .getDataForWay(areaEntity); + wayData = areaEntity.getOsmProvider().getWayPropertySet().getDataForWay(areaEntity); wayPropertiesCache.put(areaEntity, wayData); + } else { + wayData = wayPropertiesCache.get(areaEntity); } double bicycleSafety = wayPropertiesCache.get(areaEntity).bicycleSafety().forward(); @@ -653,14 +646,8 @@ private void createNamedAreas(AreaEdgeList edgeList, Ring ring, Collection double walkSafety = wayPropertiesCache.get(areaEntity).walkSafety().forward(); namedArea.setWalkSafetyMultiplier(walkSafety); - namedArea.setOriginalEdges(intersection); - - StreetTraversalPermission permission = areaEntity.overridePermissions( - StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE - ); - namedArea.setPermission(permission); - + namedArea.setPermission(wayData.getPermission()); edgeList.addArea(namedArea); } } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/AtlantaMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/AtlantaMapper.java index 4d190c0b667..34ba62a1daa 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/AtlantaMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/AtlantaMapper.java @@ -13,10 +13,9 @@ * * @author demory * @see OsmTagMapper - * @see DefaultMapper */ -class AtlantaMapper implements OsmTagMapper { +class AtlantaMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -27,7 +26,6 @@ public void populateProperties(WayPropertySet props) { // Max speed limit in Georgia is 70 mph ~= 113kmh ~= 31.3m/s props.maxPossibleCarSpeed = 31.4f; - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/ConstantSpeedMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/ConstantSpeedMapper.java index 9f1b1ac0ade..e2ecb998159 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/ConstantSpeedMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/ConstantSpeedMapper.java @@ -6,7 +6,7 @@ /** * OSM way properties for optimizing distance (not traveling time) in routing. */ -class ConstantSpeedFinlandMapper implements OsmTagMapper { +class ConstantSpeedFinlandMapper extends FinlandMapper { private float speed; @@ -23,8 +23,7 @@ public ConstantSpeedFinlandMapper(float speed) { @Override public void populateProperties(WayPropertySet props) { props.setCarSpeed("highway=*", speed); - // Read the rest from the default set - new FinlandMapper().populateProperties(props); + super.populateProperties(props); props.maxPossibleCarSpeed = speed; } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/DefaultMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/DefaultMapper.java deleted file mode 100644 index faa666c750a..00000000000 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/DefaultMapper.java +++ /dev/null @@ -1,721 +0,0 @@ -package org.opentripplanner.osm.tagmapping; - -import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofBicycleSafety; -import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofWalkSafety; -import static org.opentripplanner.osm.wayproperty.WayPropertiesBuilder.withModes; -import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; -import static org.opentripplanner.street.model.StreetTraversalPermission.BICYCLE_AND_CAR; -import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; -import static org.opentripplanner.street.model.StreetTraversalPermission.NONE; -import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; -import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; - -import org.opentripplanner.osm.wayproperty.WayProperties; -import org.opentripplanner.osm.wayproperty.WayPropertySet; -import org.opentripplanner.osm.wayproperty.specifier.BestMatchSpecifier; -import org.opentripplanner.osm.wayproperty.specifier.LogicalOrSpecifier; -import org.opentripplanner.routing.services.notes.StreetNotesService; - -/** - * This factory class provides a default collection of {@link WayProperties} that determine how OSM - * streets can be traversed in various modes. - *

- * Circa January 2011, Grant and Mele at TriMet undertook proper testing of bike (and transit) - * routing, and worked with David Turner on assigning proper weights to different facility types. - * The weights in this file grew organically from trial and error, and are the result of months of - * testing and tweaking the routes that OTP returned, as well as actually walking/biking these - * routes and making changes based on those experiences. This set of weights should be a great - * starting point for others to use, but they are to some extent tailored to the situation in - * Portland and people shouldn't hesitate to adjust them to for their own instance. - *

- * The rules for assigning WayProperties to OSM ways are explained in. The final tie breaker if two - * Pickers both match is the sequence that the properties are added in this file: if all else is - * equal the 'props.setProperties' statement that is closer to the top of the page will prevail over - * those lower down the page. - *

- * Foot and bicycle permissions are also addressed in OpenStreetMapGraphBuilderImpl.Handler#getPermissionsForEntity(). - * For instance, if a way that normally does not permit walking based on its tag matches (the - * prevailing 'props.setProperties' statement) has a 'foot=yes' tag the permissions are overridden - * and walking is allowed on that way. - *

- * TODO clarify why this needs a separate factory interface. - * - * @author bdferris, novalis - * @see OsmTagMapper - */ -class DefaultMapper implements OsmTagMapper { - - /* Populate properties on existing WayPropertySet */ - public void populateProperties(WayPropertySet props) { - WayProperties allWayProperties = withModes(ALL).build(); - WayProperties noneWayProperties = withModes(NONE).build(); - WayProperties pedestrianWayProperties = withModes(PEDESTRIAN).build(); - WayProperties pedestrianAndBicycleWayProperties = withModes(PEDESTRIAN_AND_BICYCLE).build(); - /* no bicycle tags */ - - /* NONE */ - props.setProperties("mtb:scale=3", noneWayProperties); - props.setProperties("mtb:scale=4", noneWayProperties); - props.setProperties("mtb:scale=5", noneWayProperties); - props.setProperties("mtb:scale=6", noneWayProperties); - - /* PEDESTRIAN */ - props.setProperties("highway=corridor", pedestrianWayProperties); - props.setProperties("highway=steps", pedestrianWayProperties); - props.setProperties("highway=crossing", pedestrianWayProperties); - props.setProperties("highway=platform", pedestrianWayProperties); - props.setProperties("public_transport=platform", pedestrianWayProperties); - props.setProperties("railway=platform", pedestrianWayProperties); - props.setProperties("footway=sidewalk;highway=footway", pedestrianWayProperties); - props.setProperties("mtb:scale=1", pedestrianWayProperties); - props.setProperties("mtb:scale=2", pedestrianWayProperties); - - /* PEDESTRIAN_AND_BICYCLE */ - props.setProperties("mtb:scale=0", pedestrianAndBicycleWayProperties); - props.setProperties("highway=cycleway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.6)); - props.setProperties("highway=path", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75)); - props.setProperties("highway=pedestrian", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.9)); - props.setProperties("highway=footway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1)); - props.setProperties("highway=bridleway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.3)); - - /* ALL */ - props.setProperties("highway=living_street", withModes(ALL).bicycleSafety(0.9)); - props.setProperties("highway=unclassified", allWayProperties); - props.setProperties("highway=road", allWayProperties); - props.setProperties("highway=byway", withModes(ALL).bicycleSafety(1.3)); - props.setProperties("highway=track", withModes(ALL).bicycleSafety(1.3)); - props.setProperties("highway=service", withModes(ALL).bicycleSafety(1.1)); - props.setProperties("highway=residential", withModes(ALL).bicycleSafety(0.98)); - props.setProperties("highway=residential_link", withModes(ALL).bicycleSafety(0.98)); - props.setProperties("highway=tertiary", allWayProperties); - props.setProperties("highway=tertiary_link", allWayProperties); - props.setProperties("highway=secondary", withModes(ALL).bicycleSafety(1.5)); - props.setProperties("highway=secondary_link", withModes(ALL).bicycleSafety(1.5)); - props.setProperties("highway=primary", withModes(ALL).bicycleSafety(2.06)); - props.setProperties("highway=primary_link", withModes(ALL).bicycleSafety(2.06)); - - /* DRIVING ONLY */ - // trunk and motorway links are often short distances and necessary connections - props.setProperties("highway=trunk_link", withModes(CAR).bicycleSafety(2.06)); - props.setProperties("highway=motorway_link", withModes(CAR).bicycleSafety(2.06)); - - props.setProperties("highway=trunk", withModes(CAR).bicycleSafety(7.47)); - props.setProperties("highway=motorway", withModes(CAR).bicycleSafety(8)); - - /* cycleway=lane */ - props.setProperties( - "highway=*;cycleway=lane", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.87) - ); - props.setProperties("highway=service;cycleway=lane", withModes(ALL).bicycleSafety(0.77)); - props.setProperties("highway=residential;cycleway=lane", withModes(ALL).bicycleSafety(0.77)); - props.setProperties( - "highway=residential_link;cycleway=lane", - withModes(ALL).bicycleSafety(0.77) - ); - props.setProperties("highway=tertiary;cycleway=lane", withModes(ALL).bicycleSafety(0.87)); - props.setProperties("highway=tertiary_link;cycleway=lane", withModes(ALL).bicycleSafety(0.87)); - props.setProperties("highway=secondary;cycleway=lane", withModes(ALL).bicycleSafety(0.96)); - props.setProperties("highway=secondary_link;cycleway=lane", withModes(ALL).bicycleSafety(0.96)); - props.setProperties("highway=primary;cycleway=lane", withModes(ALL).bicycleSafety(1.15)); - props.setProperties("highway=primary_link;cycleway=lane", withModes(ALL).bicycleSafety(1.15)); - - /* BICYCLE_AND_CAR */ - props.setProperties( - "highway=trunk;cycleway=lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.5) - ); - props.setProperties( - "highway=trunk_link;cycleway=lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.15) - ); - props.setProperties( - "highway=motorway;cycleway=lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(2) - ); - props.setProperties( - "highway=motorway_link;cycleway=lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.15) - ); - - /* cycleway=share_busway */ - props.setProperties( - "highway=*;cycleway=share_busway", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.92) - ); - props.setProperties( - "highway=service;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.85) - ); - props.setProperties( - "highway=residential;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.85) - ); - props.setProperties( - "highway=residential_link;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.85) - ); - props.setProperties( - "highway=tertiary;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.92) - ); - props.setProperties( - "highway=tertiary_link;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.92) - ); - props.setProperties( - "highway=secondary;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.99) - ); - props.setProperties( - "highway=secondary_link;cycleway=share_busway", - withModes(ALL).bicycleSafety(0.99) - ); - props.setProperties( - "highway=primary;cycleway=share_busway", - withModes(ALL).bicycleSafety(1.25) - ); - props.setProperties( - "highway=primary_link;cycleway=share_busway", - withModes(ALL).bicycleSafety(1.25) - ); - props.setProperties( - "highway=trunk;cycleway=share_busway", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.75) - ); - props.setProperties( - "highway=trunk_link;cycleway=share_busway", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.25) - ); - props.setProperties( - "highway=motorway;cycleway=share_busway", - withModes(BICYCLE_AND_CAR).bicycleSafety(2.5) - ); - props.setProperties( - "highway=motorway_link;cycleway=share_busway", - withModes(BICYCLE_AND_CAR).bicycleSafety(1.25) - ); - - /* cycleway=opposite_lane */ - props.setProperties( - "highway=*;cycleway=opposite_lane", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1, 0.87) - ); - props.setProperties( - "highway=service;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(1.1, 0.77) - ); - props.setProperties( - "highway=residential;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(0.98, 0.77) - ); - props.setProperties( - "highway=residential_link;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(0.98, 0.77) - ); - props.setProperties( - "highway=tertiary;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(1, 0.87) - ); - props.setProperties( - "highway=tertiary_link;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(1, 0.87) - ); - props.setProperties( - "highway=secondary;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(1.5, 0.96) - ); - props.setProperties( - "highway=secondary_link;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(1.5, 0.96) - ); - props.setProperties( - "highway=primary;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(2.06, 1.15) - ); - props.setProperties( - "highway=primary_link;cycleway=opposite_lane", - withModes(ALL).bicycleSafety(2.06, 1.15) - ); - props.setProperties( - "highway=trunk;cycleway=opposite_lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(7.47, 1.5) - ); - props.setProperties( - "highway=trunk_link;cycleway=opposite_lane", - withModes(BICYCLE_AND_CAR).bicycleSafety(2.06, 1.15) - ); - - /* cycleway=track */ - props.setProperties( - "highway=*;cycleway=track", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) - ); - props.setProperties("highway=service;cycleway=track", withModes(ALL).bicycleSafety(0.65)); - props.setProperties("highway=residential;cycleway=track", withModes(ALL).bicycleSafety(0.65)); - props.setProperties( - "highway=residential_link;cycleway=track", - withModes(ALL).bicycleSafety(0.65) - ); - props.setProperties("highway=tertiary;cycleway=track", withModes(ALL).bicycleSafety(0.75)); - props.setProperties("highway=tertiary_link;cycleway=track", withModes(ALL).bicycleSafety(0.75)); - props.setProperties("highway=secondary;cycleway=track", withModes(ALL).bicycleSafety(0.8)); - props.setProperties("highway=secondary_link;cycleway=track", withModes(ALL).bicycleSafety(0.8)); - props.setProperties("highway=primary;cycleway=track", withModes(ALL).bicycleSafety(0.85)); - props.setProperties("highway=primary_link;cycleway=track", withModes(ALL).bicycleSafety(0.85)); - props.setProperties( - "highway=trunk;cycleway=track", - withModes(BICYCLE_AND_CAR).bicycleSafety(0.95) - ); - props.setProperties( - "highway=trunk_link;cycleway=track", - withModes(BICYCLE_AND_CAR).bicycleSafety(0.85) - ); - - /* cycleway=opposite_track */ - props.setProperties( - "highway=*;cycleway=opposite_track", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.0, 0.75) - ); - props.setProperties( - "highway=service;cycleway=opposite_track", - withModes(ALL).bicycleSafety(1.1, 0.65) - ); - props.setProperties( - "highway=residential;cycleway=opposite_track", - withModes(ALL).bicycleSafety(0.98, 0.65) - ); - props.setProperties( - "highway=residential_link;cycleway=opposite_track", - withModes(ALL).bicycleSafety(0.98, 0.65) - ); - props.setProperties( - "highway=tertiary;cycleway=opposite_track", - withModes(ALL).bicycleSafety(1, 0.75) - ); - props.setProperties( - "highway=tertiary_link;cycleway=opposite_track", - withModes(ALL).bicycleSafety(1, 0.75) - ); - props.setProperties( - "highway=secondary;cycleway=opposite_track", - withModes(ALL).bicycleSafety(1.5, 0.8) - ); - props.setProperties( - "highway=secondary_link;cycleway=opposite_track", - withModes(ALL).bicycleSafety(1.5, 0.8) - ); - props.setProperties( - "highway=primary;cycleway=opposite_track", - withModes(ALL).bicycleSafety(2.06, 0.85) - ); - props.setProperties( - "highway=primary_link;cycleway=opposite_track", - withModes(ALL).bicycleSafety(2.06, 0.85) - ); - props.setProperties( - "highway=trunk;cycleway=opposite_track", - withModes(BICYCLE_AND_CAR).bicycleSafety(7.47, 0.95) - ); - props.setProperties( - "highway=trunk_link;cycleway=opposite_track", - withModes(BICYCLE_AND_CAR).bicycleSafety(2.06, 0.85) - ); - - /* cycleway=shared_lane a.k.a. bike boulevards or neighborhood greenways */ - props.setProperties( - "highway=*;cycleway=shared_lane", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.77) - ); - props.setProperties("highway=service;cycleway=shared_lane", withModes(ALL).bicycleSafety(0.73)); - props.setProperties( - "highway=residential;cycleway=shared_lane", - withModes(ALL).bicycleSafety(0.77) - ); - props.setProperties( - "highway=residential_link;cycleway=shared_lane", - withModes(ALL).bicycleSafety(0.77) - ); - props.setProperties( - "highway=tertiary;cycleway=shared_lane", - withModes(ALL).bicycleSafety(0.83) - ); - props.setProperties( - "highway=tertiary_link;cycleway=shared_lane", - withModes(ALL).bicycleSafety(0.83) - ); - props.setProperties( - "highway=secondary;cycleway=shared_lane", - withModes(ALL).bicycleSafety(1.25) - ); - props.setProperties( - "highway=secondary_link;cycleway=shared_lane", - withModes(ALL).bicycleSafety(1.25) - ); - props.setProperties("highway=primary;cycleway=shared_lane", withModes(ALL).bicycleSafety(1.75)); - props.setProperties( - "highway=primary_link;cycleway=shared_lane", - withModes(ALL).bicycleSafety(1.75) - ); - - /* cycleway=opposite */ - props.setProperties( - "highway=*;cycleway=opposite", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1, 1.4) - ); - props.setProperties("highway=service;cycleway=opposite", withModes(ALL).bicycleSafety(1.1)); - props.setProperties( - "highway=residential;cycleway=opposite", - withModes(ALL).bicycleSafety(0.98) - ); - props.setProperties( - "highway=residential_link;cycleway=opposite", - withModes(ALL).bicycleSafety(0.98) - ); - props.setProperties("highway=tertiary;cycleway=opposite", allWayProperties); - props.setProperties("highway=tertiary_link;cycleway=opposite", allWayProperties); - props.setProperties( - "highway=secondary;cycleway=opposite", - withModes(ALL).bicycleSafety(1.5, 1.71) - ); - props.setProperties( - "highway=secondary_link;cycleway=opposite", - withModes(ALL).bicycleSafety(1.5, 1.71) - ); - props.setProperties( - "highway=primary;cycleway=opposite", - withModes(ALL).bicycleSafety(2.06, 2.99) - ); - props.setProperties( - "highway=primary_link;cycleway=opposite", - withModes(ALL).bicycleSafety(2.06, 2.99) - ); - - /* - * path designed for bicycles (should be treated exactly as a cycleway is), this is a multi-use path (MUP) - */ - props.setProperties( - "highway=path;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.60) - ); - - /* special cases for footway, pedestrian and bicycles */ - props.setProperties( - "highway=footway;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) - ); - props.setProperties( - "highway=footway;bicycle=yes;area=yes", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.9) - ); - props.setProperties( - "highway=pedestrian;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) - ); - - /* sidewalk and crosswalk */ - props.setProperties( - "footway=sidewalk;highway=footway;bicycle=yes", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(2.5) - ); - props.setProperties( - "footway=sidewalk;highway=footway;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1) - ); - props.setProperties( - "highway=footway;footway=crossing", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(2.5) - ); - props.setProperties( - "highway=footway;footway=crossing;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1) - ); - - /* - * bicycles on tracks (tracks are defined in OSM as: Roads for agricultural use, gravel roads in the forest etc.; usually unpaved/unsealed but - * may occasionally apply to paved tracks as well.) - */ - props.setProperties( - "highway=track;bicycle=yes", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.18) - ); - props.setProperties( - "highway=track;bicycle=designated", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.99) - ); - props.setProperties( - "highway=track;bicycle=yes;surface=*", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.18) - ); - props.setProperties( - "highway=track;bicycle=designated;surface=*", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.99) - ); - /* this is to avoid double counting since tracks are almost of surface type that is penalized */ - props.setProperties( - "highway=track;surface=*", - withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.3) - ); - - /* bicycle=designated, but no bike infrastructure is present */ - props.setProperties("highway=*;bicycle=designated", withModes(ALL).bicycleSafety(0.97)); - props.setProperties("highway=service;bicycle=designated", withModes(ALL).bicycleSafety(0.84)); - props.setProperties( - "highway=residential;bicycle=designated", - withModes(ALL).bicycleSafety(0.95) - ); - props.setProperties( - "highway=unclassified;bicycle=designated", - withModes(ALL).bicycleSafety(0.95) - ); - props.setProperties( - "highway=residential_link;bicycle=designated", - withModes(ALL).bicycleSafety(0.95) - ); - props.setProperties("highway=tertiary;bicycle=designated", withModes(ALL).bicycleSafety(0.97)); - props.setProperties( - "highway=tertiary_link;bicycle=designated", - withModes(ALL).bicycleSafety(0.97) - ); - props.setProperties("highway=secondary;bicycle=designated", withModes(ALL).bicycleSafety(1.46)); - props.setProperties( - "highway=secondary_link;bicycle=designated", - withModes(ALL).bicycleSafety(1.46) - ); - props.setProperties("highway=primary;bicycle=designated", withModes(ALL).bicycleSafety(2)); - props.setProperties("highway=primary_link;bicycle=designated", withModes(ALL).bicycleSafety(2)); - props.setProperties( - "highway=trunk;bicycle=designated", - withModes(BICYCLE_AND_CAR).bicycleSafety(7.25) - ); - props.setProperties( - "highway=trunk_link;bicycle=designated", - withModes(BICYCLE_AND_CAR).bicycleSafety(2) - ); - props.setProperties( - "highway=motorway;bicycle=designated", - withModes(BICYCLE_AND_CAR).bicycleSafety(7.76) - ); - props.setProperties( - "highway=motorway_link;bicycle=designated", - withModes(BICYCLE_AND_CAR).bicycleSafety(2) - ); - - // We assume highway/cycleway of a cycle network to be safer (for bicycle network relations, their network is copied to way in postLoad) - // this uses a OR since you don't want to apply the safety multiplier more than once. - // Signed bicycle_roads and cyclestreets exist in traffic codes of some european countries. - // Tagging in OSM and on-the-ground use is varied, so just assume they are "somehow safer", too. - // In my test area ways often, but not always, have both tags. - // For simplicity these two concepts are handled together. - props.setMixinProperties( - new LogicalOrSpecifier( - "lcn=yes", - "rcn=yes", - "ncn=yes", - "bicycle_road=yes", - "cyclestreet=yes" - ), - ofBicycleSafety(0.7) - ); - - /* - * Automobile speeds in the United States: Based on my (mattwigway) personal experience, primarily in California - */ - props.setCarSpeed("highway=motorway", 29); // 29 m/s ~= 65 mph - props.setCarSpeed("highway=motorway_link", 15); // ~= 35 mph - props.setCarSpeed("highway=trunk", 24.6f); // ~= 55 mph - props.setCarSpeed("highway=trunk_link", 15); // ~= 35 mph - props.setCarSpeed("highway=primary", 20); // ~= 45 mph - props.setCarSpeed("highway=primary_link", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=secondary", 15); // ~= 35 mph - props.setCarSpeed("highway=secondary_link", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=tertiary", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=tertiary_link", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=living_street", 2.2f); // ~= 5 mph - - // generally, these will not allow cars at all, but the docs say - // "For roads used mainly/exclusively for pedestrians . . . which may allow access by - // motorised vehicles only for very limited periods of the day." - // http://wiki.openstreetmap.org/wiki/Key:highway - // This of course makes the street network time-dependent - props.setCarSpeed("highway=pedestrian", 2.2f); // ~= 5 mph - - props.setCarSpeed("highway=residential", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=unclassified", 11.2f); // ~= 25 mph - props.setCarSpeed("highway=service", 6.7f); // ~= 15 mph - props.setCarSpeed("highway=track", 4.5f); // ~= 10 mph - props.setCarSpeed("highway=road", 11.2f); // ~= 25 mph - - // default ~= 25 mph - props.defaultCarSpeed = 11.2f; - // 38 m/s ~= 85 mph ~= 137 kph - props.maxPossibleCarSpeed = 38f; - - /* special situations */ - - /* - * cycleway:left/right=lane/track/shared_lane permutations - no longer needed because left/right matching algorithm does this - */ - - /* cycleway:left=lane */ - /* cycleway:right=track */ - /* cycleway:left=track */ - /* cycleway:right=shared_lane */ - /* cycleway:left=shared_lane */ - /* cycleway:right=lane, cycleway:left=track */ - /* cycleway:right=lane, cycleway:left=shared_lane */ - /* cycleway:right=track, cycleway:left=lane */ - /* cycleway:right=track, cycleway:left=shared_lane */ - /* cycleway:right=shared_lane, cycleway:left=lane */ - /* cycleway:right=shared_lane, cycleway:left=track */ - - /* surface=* mixins */ - - /* - * The following tags have been removed from surface weights because they are no more of an impedence to bicycling than a paved surface - * surface=paving_stones surface=fine_gravel (sounds counter-intuitive but see the definition on the OSM Wiki) surface=tartan (this what - * running tracks are usually made of) - */ - - props.setMixinProperties("surface=unpaved", ofBicycleSafety(1.18)); - props.setMixinProperties("surface=compacted", ofBicycleSafety(1.18)); - props.setMixinProperties("surface=wood", ofBicycleSafety(1.18)); - - props.setMixinProperties("surface=cobblestone", ofBicycleSafety(1.3)); - props.setMixinProperties("surface=sett", ofBicycleSafety(1.3)); - props.setMixinProperties("surface=unhewn_cobblestone", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=grass_paver", ofBicycleSafety(1.3)); - props.setMixinProperties("surface=pebblestone", ofBicycleSafety(1.3)); - // Can be slick if wet, but otherwise not unfavorable to bikes - props.setMixinProperties("surface=metal", ofBicycleSafety(1.3)); - props.setMixinProperties("surface=ground", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=dirt", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=earth", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=grass", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=mud", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=woodchip", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=gravel", ofBicycleSafety(1.5)); - props.setMixinProperties("surface=artifical_turf", ofBicycleSafety(1.5)); - - /* sand is deadly for bikes */ - props.setMixinProperties("surface=sand", ofBicycleSafety(100)); - - /* Portland-local mixins */ - - props.setMixinProperties("foot=discouraged", ofWalkSafety(3)); - props.setMixinProperties("bicycle=discouraged", ofBicycleSafety(3)); - - props.setMixinProperties("foot=use_sidepath", ofWalkSafety(5)); - props.setMixinProperties("bicycle=use_sidepath", ofBicycleSafety(5)); - - populateNotesAndNames(props); - - // slope overrides - props.setSlopeOverride(new BestMatchSpecifier("bridge=*"), true); - props.setSlopeOverride(new BestMatchSpecifier("embankment=*"), true); - props.setSlopeOverride(new BestMatchSpecifier("cutting=*"), true); - props.setSlopeOverride(new BestMatchSpecifier("tunnel=*"), true); - props.setSlopeOverride(new BestMatchSpecifier("location=underground"), true); - props.setSlopeOverride(new BestMatchSpecifier("indoor=yes"), true); - } - - public void populateNotesAndNames(WayPropertySet props) { - /* and the notes */ - // TODO: The curly brackets in the string below mean that the CreativeNamer should substitute in OSM tag values. - // However they are not taken into account when passed to the translation function. - // props.createNotes("wheelchair:description=*", "{wheelchair:description}", StreetNotesService.WHEELCHAIR_MATCHER); - // TODO: The two entries below produce lots of spurious notes (because of OSM mapper comments) - // props.createNotes("note=*", "{note}", StreetNotesService.ALWAYS_MATCHER); - // props.createNotes("notes=*", "{notes}", StreetNotesService.ALWAYS_MATCHER); - props.createNotes( - "RLIS:bicycle=caution_area", - "note.caution", - StreetNotesService.BICYCLE_MATCHER - ); - props.createNotes( - "CCGIS:bicycle=caution_area", - "note.caution", - StreetNotesService.BICYCLE_MATCHER - ); - // TODO: Maybe we should apply the following notes only for car/bike - props.createNotes("surface=unpaved", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes( - "surface=compacted", - "note.unpaved_surface", - StreetNotesService.ALWAYS_MATCHER - ); - props.createNotes("surface=ground", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes("surface=dirt", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes("surface=earth", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes("surface=grass", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes("surface=mud", "note.muddy_surface", StreetNotesService.ALWAYS_MATCHER); - props.createNotes("toll=yes", "note.toll", StreetNotesService.DRIVING_MATCHER); - props.createNotes("toll:motorcar=yes", "note.toll", StreetNotesService.DRIVING_MATCHER); - - /* and some names */ - // Basics - props.createNames("highway=cycleway", "name.bike_path"); - props.createNames("cycleway=track", "name.bike_path"); - props.createNames("highway=pedestrian", "name.pedestrian_path"); - props.createNames("highway=pedestrian;area=yes", "name.pedestrian_area"); - props.createNames("highway=path", "name.path"); - props.createNames("highway=footway", "name.pedestrian_path"); - props.createNames("highway=bridleway", "name.bridleway"); - props.createNames("highway=footway;bicycle=no", "name.pedestrian_path"); - - // Platforms - props.createNames("otp:route_ref=*", "name.otp_route_ref"); - props.createNames("highway=platform;ref=*", "name.platform_ref"); - props.createNames("railway=platform;ref=*", "name.platform_ref"); - props.createNames("railway=platform;highway=footway;footway=sidewalk", "name.platform"); - props.createNames("railway=platform;highway=path;path=sidewalk", "name.platform"); - props.createNames("railway=platform;highway=pedestrian", "name.platform"); - props.createNames("railway=platform;highway=path", "name.platform"); - props.createNames("railway=platform;highway=footway", "name.platform"); - props.createNames("highway=platform", "name.platform"); - props.createNames("railway=platform", "name.platform"); - props.createNames("railway=platform;highway=footway;bicycle=no", "name.platform"); - - // Bridges/Tunnels - props.createNames("highway=pedestrian;bridge=*", "name.footbridge"); - props.createNames("highway=path;bridge=*", "name.footbridge"); - props.createNames("highway=footway;bridge=*", "name.footbridge"); - - props.createNames("highway=pedestrian;tunnel=*", "name.underpass"); - props.createNames("highway=path;tunnel=*", "name.underpass"); - props.createNames("highway=footway;tunnel=*", "name.underpass"); - - // Basic Mappings - props.createNames("highway=motorway", "name.road"); - props.createNames("highway=motorway_link", "name.ramp"); - props.createNames("highway=trunk", "name.road"); - props.createNames("highway=trunk_link", "name.ramp"); - - props.createNames("highway=primary", "name.road"); - props.createNames("highway=primary_link", "name.link"); - props.createNames("highway=secondary", "name.road"); - props.createNames("highway=secondary_link", "name.link"); - props.createNames("highway=tertiary", "name.road"); - props.createNames("highway=tertiary_link", "name.link"); - props.createNames("highway=unclassified", "name.road"); - props.createNames("highway=residential", "name.road"); - props.createNames("highway=living_street", "name.road"); - props.createNames("highway=road", "name.road"); - props.createNames("highway=service", "name.service_road"); - props.createNames("highway=service;service=alley", "name.alley"); - props.createNames("highway=service;service=parking_aisle", "name.parking_aisle"); - props.createNames("highway=byway", "name.byway"); - props.createNames("highway=track", "name.track"); - - props.createNames("highway=footway;footway=sidewalk", "name.sidewalk"); - props.createNames("highway=path;path=sidewalk", "name.sidewalk"); - - props.createNames("highway=steps", "name.steps"); - - props.createNames("amenity=bicycle_parking;name=*", "name.bicycle_parking_name"); - props.createNames("amenity=bicycle_parking", "name.bicycle_parking"); - - props.createNames("amenity=parking;name=*", "name.park_and_ride_name"); - props.createNames("amenity=parking", "name.park_and_ride_station"); - } -} diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java index e796ebff17f..5e413af510a 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java @@ -23,9 +23,8 @@ * * @author juusokor * @see OsmTagMapper - * @see DefaultMapper */ -class FinlandMapper implements OsmTagMapper { +class FinlandMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -203,8 +202,7 @@ else if (speedLimit <= 16.65f) { // ~= 16 kph props.setCarSpeed("highway=track", 4.5f); - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } @Override diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/GermanyMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/GermanyMapper.java index 70a5bd593aa..af56b572bd8 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/GermanyMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/GermanyMapper.java @@ -15,9 +15,8 @@ * networks. * * @see OsmTagMapper - * @see DefaultMapper */ -class GermanyMapper implements OsmTagMapper { +class GermanyMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -88,7 +87,6 @@ public void populateProperties(WayPropertySet props) { props.setProperties("highway=unclassified;cycleway=lane", withModes(ALL).bicycleSafety(0.87)); - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/HamburgMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/HamburgMapper.java index 47bd5164d1f..755f5864ba2 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/HamburgMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/HamburgMapper.java @@ -7,7 +7,6 @@ * * @see GermanyMapper * @see OsmTagMapper - * @see DefaultMapper * * @author Maintained by HBT (geofox-team@hbt.de) */ diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/HoustonMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/HoustonMapper.java index 7e4aba9da4e..1d24dbafffb 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/HoustonMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/HoustonMapper.java @@ -14,7 +14,7 @@ * 1. In Houston we want to disallow usage of downtown pedestrian tunnel system. */ -class HoustonMapper implements OsmTagMapper { +class HoustonMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -26,11 +26,9 @@ public void populateProperties(WayPropertySet props) { new ExactMatchSpecifier("highway=footway;layer=-1;tunnel=yes;indoor=yes"), withModes(NONE) ); - // Max speed limit in Texas is 38 m/s ~= 85 mph ~= 137 kph props.maxPossibleCarSpeed = 38f; - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/NorwayMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/NorwayMapper.java index 9e06c0aa591..c37de8533c6 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/NorwayMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/NorwayMapper.java @@ -24,9 +24,9 @@ * * @author seime * @see OsmTagMapper - * @see DefaultMapper + * @see OsmTagMapper */ -class NorwayMapper implements OsmTagMapper { +class NorwayMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -621,7 +621,7 @@ else if (speedLimit >= 11.1f) { props.defaultCarSpeed = 22.22f; // 80 km/h props.maxPossibleCarSpeed = 30.56f; // 110 km/h - new DefaultMapper().populateNotesAndNames(props); + super.populateNotesAndNames(props); props.setSlopeOverride(new BestMatchSpecifier("bridge=*"), true); props.setSlopeOverride(new BestMatchSpecifier("cutting=*"), true); diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java index 9bf0ed2d20d..e4c258ccdc4 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java @@ -1,18 +1,727 @@ package org.opentripplanner.osm.tagmapping; +import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofBicycleSafety; +import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofWalkSafety; +import static org.opentripplanner.osm.wayproperty.WayPropertiesBuilder.withModes; +import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; +import static org.opentripplanner.street.model.StreetTraversalPermission.BICYCLE_AND_CAR; +import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; +import static org.opentripplanner.street.model.StreetTraversalPermission.NONE; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; + import org.opentripplanner.osm.model.OsmWithTags; +import org.opentripplanner.osm.wayproperty.WayProperties; import org.opentripplanner.osm.wayproperty.WayPropertySet; +import org.opentripplanner.osm.wayproperty.specifier.BestMatchSpecifier; +import org.opentripplanner.osm.wayproperty.specifier.Condition; +import org.opentripplanner.osm.wayproperty.specifier.ExactMatchSpecifier; +import org.opentripplanner.osm.wayproperty.specifier.LogicalOrSpecifier; +import org.opentripplanner.routing.services.notes.StreetNotesService; /** - * Interface for populating a {@link WayPropertySet} that determine how OSM streets can be traversed - * in various modes and named. + * This factory class provides a default collection of {@link WayProperties} that determine how OSM + * streets can be traversed in various modes. + *

+ * Circa January 2011, Grant and Mele at TriMet undertook proper testing of bike (and transit) + * routing, and worked with David Turner on assigning proper weights to different facility types. + * The weights in this file grew organically from trial and error, and are the result of months of + * testing and tweaking the routes that OTP returned, as well as actually walking/biking these + * routes and making changes based on those experiences. This set of weights should be a great + * starting point for others to use, but they are to some extent tailored to the situation in + * Portland and people shouldn't hesitate to adjust them to for their own instance. + *

+ * The rules for assigning WayProperties to OSM ways are explained in. The final tie breaker if two + * Pickers both match is the sequence that the properties are added in this file: if all else is + * equal the 'props.setProperties' statement that is closer to the top of the page will prevail over + * those lower down the page. + *

+ * Foot and bicycle permissions are also addressed in OpenStreetMapGraphBuilderImpl.Handler#getPermissionsForEntity(). + * For instance, if a way that normally does not permit walking based on its tag matches (the + * prevailing 'props.setProperties' statement) has a 'foot=yes' tag the permissions are overridden + * and walking is allowed on that way. + *

* - * @author bdferris, novalis, seime + * @author bdferris, novalis */ -public interface OsmTagMapper { - void populateProperties(WayPropertySet wayPropertySet); - default boolean doesTagValueDisallowThroughTraffic(String tagValue) { +public class OsmTagMapper { + + /* Populate properties on existing WayPropertySet */ + public void populateProperties(WayPropertySet props) { + WayProperties allWayProperties = withModes(ALL).build(); + WayProperties noneWayProperties = withModes(NONE).build(); + WayProperties pedestrianWayProperties = withModes(PEDESTRIAN).build(); + WayProperties pedestrianAndBicycleWayProperties = withModes(PEDESTRIAN_AND_BICYCLE).build(); + /* no bicycle tags */ + + /* NONE */ + props.setProperties("mtb:scale=3", noneWayProperties); + props.setProperties("mtb:scale=4", noneWayProperties); + props.setProperties("mtb:scale=5", noneWayProperties); + props.setProperties("mtb:scale=6", noneWayProperties); + + /* PEDESTRIAN */ + props.setProperties("highway=corridor", pedestrianWayProperties); + props.setProperties("highway=steps", pedestrianWayProperties); + props.setProperties("highway=crossing", pedestrianWayProperties); + props.setProperties("highway=platform", pedestrianWayProperties); + props.setProperties("public_transport=platform", pedestrianWayProperties); + props.setProperties("railway=platform", pedestrianWayProperties); + props.setProperties("footway=sidewalk;highway=footway", pedestrianWayProperties); + props.setProperties("mtb:scale=1", pedestrianWayProperties); + props.setProperties("mtb:scale=2", pedestrianWayProperties); + + /* PEDESTRIAN_AND_BICYCLE */ + props.setProperties("mtb:scale=0", pedestrianAndBicycleWayProperties); + props.setProperties("highway=cycleway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.6)); + props.setProperties("highway=path", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75)); + props.setProperties("highway=pedestrian", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.9)); + props.setProperties("highway=footway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1)); + props.setProperties("highway=bridleway", withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.3)); + + /* ALL */ + props.setProperties("highway=living_street", withModes(ALL).bicycleSafety(0.9)); + props.setProperties("highway=unclassified", allWayProperties); + props.setProperties("highway=road", allWayProperties); + props.setProperties("highway=byway", withModes(ALL).bicycleSafety(1.3)); + props.setProperties("highway=track", withModes(ALL).bicycleSafety(1.3)); + props.setProperties("highway=service", withModes(ALL).bicycleSafety(1.1)); + props.setProperties("highway=residential", withModes(ALL).bicycleSafety(0.98)); + props.setProperties("highway=residential_link", withModes(ALL).bicycleSafety(0.98)); + props.setProperties("highway=tertiary", allWayProperties); + props.setProperties("highway=tertiary_link", allWayProperties); + props.setProperties("highway=secondary", withModes(ALL).bicycleSafety(1.5)); + props.setProperties("highway=secondary_link", withModes(ALL).bicycleSafety(1.5)); + props.setProperties("highway=primary", withModes(ALL).bicycleSafety(2.06)); + props.setProperties("highway=primary_link", withModes(ALL).bicycleSafety(2.06)); + + /* DRIVING ONLY */ + // trunk and motorway links are often short distances and necessary connections + props.setProperties("highway=trunk_link", withModes(CAR).bicycleSafety(2.06)); + props.setProperties("highway=motorway_link", withModes(CAR).bicycleSafety(2.06)); + + props.setProperties("highway=trunk", withModes(CAR).bicycleSafety(7.47)); + props.setProperties("highway=motorway", withModes(CAR).bicycleSafety(8)); + + /* cycleway=lane */ + props.setProperties( + "highway=*;cycleway=lane", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.87) + ); + props.setProperties("highway=service;cycleway=lane", withModes(ALL).bicycleSafety(0.77)); + props.setProperties("highway=residential;cycleway=lane", withModes(ALL).bicycleSafety(0.77)); + props.setProperties( + "highway=residential_link;cycleway=lane", + withModes(ALL).bicycleSafety(0.77) + ); + props.setProperties("highway=tertiary;cycleway=lane", withModes(ALL).bicycleSafety(0.87)); + props.setProperties("highway=tertiary_link;cycleway=lane", withModes(ALL).bicycleSafety(0.87)); + props.setProperties("highway=secondary;cycleway=lane", withModes(ALL).bicycleSafety(0.96)); + props.setProperties("highway=secondary_link;cycleway=lane", withModes(ALL).bicycleSafety(0.96)); + props.setProperties("highway=primary;cycleway=lane", withModes(ALL).bicycleSafety(1.15)); + props.setProperties("highway=primary_link;cycleway=lane", withModes(ALL).bicycleSafety(1.15)); + + /* BICYCLE_AND_CAR */ + props.setProperties( + "highway=trunk;cycleway=lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.5) + ); + props.setProperties( + "highway=trunk_link;cycleway=lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.15) + ); + props.setProperties( + "highway=motorway;cycleway=lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(2) + ); + props.setProperties( + "highway=motorway_link;cycleway=lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.15) + ); + + /* cycleway=share_busway */ + props.setProperties( + "highway=*;cycleway=share_busway", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.92) + ); + props.setProperties( + "highway=service;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.85) + ); + props.setProperties( + "highway=residential;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.85) + ); + props.setProperties( + "highway=residential_link;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.85) + ); + props.setProperties( + "highway=tertiary;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.92) + ); + props.setProperties( + "highway=tertiary_link;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.92) + ); + props.setProperties( + "highway=secondary;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.99) + ); + props.setProperties( + "highway=secondary_link;cycleway=share_busway", + withModes(ALL).bicycleSafety(0.99) + ); + props.setProperties( + "highway=primary;cycleway=share_busway", + withModes(ALL).bicycleSafety(1.25) + ); + props.setProperties( + "highway=primary_link;cycleway=share_busway", + withModes(ALL).bicycleSafety(1.25) + ); + props.setProperties( + "highway=trunk;cycleway=share_busway", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.75) + ); + props.setProperties( + "highway=trunk_link;cycleway=share_busway", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.25) + ); + props.setProperties( + "highway=motorway;cycleway=share_busway", + withModes(BICYCLE_AND_CAR).bicycleSafety(2.5) + ); + props.setProperties( + "highway=motorway_link;cycleway=share_busway", + withModes(BICYCLE_AND_CAR).bicycleSafety(1.25) + ); + + /* cycleway=opposite_lane */ + props.setProperties( + "highway=*;cycleway=opposite_lane", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1, 0.87) + ); + props.setProperties( + "highway=service;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(1.1, 0.77) + ); + props.setProperties( + "highway=residential;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(0.98, 0.77) + ); + props.setProperties( + "highway=residential_link;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(0.98, 0.77) + ); + props.setProperties( + "highway=tertiary;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(1, 0.87) + ); + props.setProperties( + "highway=tertiary_link;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(1, 0.87) + ); + props.setProperties( + "highway=secondary;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(1.5, 0.96) + ); + props.setProperties( + "highway=secondary_link;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(1.5, 0.96) + ); + props.setProperties( + "highway=primary;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(2.06, 1.15) + ); + props.setProperties( + "highway=primary_link;cycleway=opposite_lane", + withModes(ALL).bicycleSafety(2.06, 1.15) + ); + props.setProperties( + "highway=trunk;cycleway=opposite_lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(7.47, 1.5) + ); + props.setProperties( + "highway=trunk_link;cycleway=opposite_lane", + withModes(BICYCLE_AND_CAR).bicycleSafety(2.06, 1.15) + ); + + /* cycleway=track */ + props.setProperties( + "highway=*;cycleway=track", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) + ); + props.setProperties("highway=service;cycleway=track", withModes(ALL).bicycleSafety(0.65)); + props.setProperties("highway=residential;cycleway=track", withModes(ALL).bicycleSafety(0.65)); + props.setProperties( + "highway=residential_link;cycleway=track", + withModes(ALL).bicycleSafety(0.65) + ); + props.setProperties("highway=tertiary;cycleway=track", withModes(ALL).bicycleSafety(0.75)); + props.setProperties("highway=tertiary_link;cycleway=track", withModes(ALL).bicycleSafety(0.75)); + props.setProperties("highway=secondary;cycleway=track", withModes(ALL).bicycleSafety(0.8)); + props.setProperties("highway=secondary_link;cycleway=track", withModes(ALL).bicycleSafety(0.8)); + props.setProperties("highway=primary;cycleway=track", withModes(ALL).bicycleSafety(0.85)); + props.setProperties("highway=primary_link;cycleway=track", withModes(ALL).bicycleSafety(0.85)); + props.setProperties( + "highway=trunk;cycleway=track", + withModes(BICYCLE_AND_CAR).bicycleSafety(0.95) + ); + props.setProperties( + "highway=trunk_link;cycleway=track", + withModes(BICYCLE_AND_CAR).bicycleSafety(0.85) + ); + + /* cycleway=opposite_track */ + props.setProperties( + "highway=*;cycleway=opposite_track", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.0, 0.75) + ); + props.setProperties( + "highway=service;cycleway=opposite_track", + withModes(ALL).bicycleSafety(1.1, 0.65) + ); + props.setProperties( + "highway=residential;cycleway=opposite_track", + withModes(ALL).bicycleSafety(0.98, 0.65) + ); + props.setProperties( + "highway=residential_link;cycleway=opposite_track", + withModes(ALL).bicycleSafety(0.98, 0.65) + ); + props.setProperties( + "highway=tertiary;cycleway=opposite_track", + withModes(ALL).bicycleSafety(1, 0.75) + ); + props.setProperties( + "highway=tertiary_link;cycleway=opposite_track", + withModes(ALL).bicycleSafety(1, 0.75) + ); + props.setProperties( + "highway=secondary;cycleway=opposite_track", + withModes(ALL).bicycleSafety(1.5, 0.8) + ); + props.setProperties( + "highway=secondary_link;cycleway=opposite_track", + withModes(ALL).bicycleSafety(1.5, 0.8) + ); + props.setProperties( + "highway=primary;cycleway=opposite_track", + withModes(ALL).bicycleSafety(2.06, 0.85) + ); + props.setProperties( + "highway=primary_link;cycleway=opposite_track", + withModes(ALL).bicycleSafety(2.06, 0.85) + ); + props.setProperties( + "highway=trunk;cycleway=opposite_track", + withModes(BICYCLE_AND_CAR).bicycleSafety(7.47, 0.95) + ); + props.setProperties( + "highway=trunk_link;cycleway=opposite_track", + withModes(BICYCLE_AND_CAR).bicycleSafety(2.06, 0.85) + ); + + /* cycleway=shared_lane a.k.a. bike boulevards or neighborhood greenways */ + props.setProperties( + "highway=*;cycleway=shared_lane", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.77) + ); + props.setProperties("highway=service;cycleway=shared_lane", withModes(ALL).bicycleSafety(0.73)); + props.setProperties( + "highway=residential;cycleway=shared_lane", + withModes(ALL).bicycleSafety(0.77) + ); + props.setProperties( + "highway=residential_link;cycleway=shared_lane", + withModes(ALL).bicycleSafety(0.77) + ); + props.setProperties( + "highway=tertiary;cycleway=shared_lane", + withModes(ALL).bicycleSafety(0.83) + ); + props.setProperties( + "highway=tertiary_link;cycleway=shared_lane", + withModes(ALL).bicycleSafety(0.83) + ); + props.setProperties( + "highway=secondary;cycleway=shared_lane", + withModes(ALL).bicycleSafety(1.25) + ); + props.setProperties( + "highway=secondary_link;cycleway=shared_lane", + withModes(ALL).bicycleSafety(1.25) + ); + props.setProperties("highway=primary;cycleway=shared_lane", withModes(ALL).bicycleSafety(1.75)); + props.setProperties( + "highway=primary_link;cycleway=shared_lane", + withModes(ALL).bicycleSafety(1.75) + ); + + /* cycleway=opposite */ + props.setProperties( + "highway=*;cycleway=opposite", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1, 1.4) + ); + props.setProperties("highway=service;cycleway=opposite", withModes(ALL).bicycleSafety(1.1)); + props.setProperties( + "highway=residential;cycleway=opposite", + withModes(ALL).bicycleSafety(0.98) + ); + props.setProperties( + "highway=residential_link;cycleway=opposite", + withModes(ALL).bicycleSafety(0.98) + ); + props.setProperties("highway=tertiary;cycleway=opposite", allWayProperties); + props.setProperties("highway=tertiary_link;cycleway=opposite", allWayProperties); + props.setProperties( + "highway=secondary;cycleway=opposite", + withModes(ALL).bicycleSafety(1.5, 1.71) + ); + props.setProperties( + "highway=secondary_link;cycleway=opposite", + withModes(ALL).bicycleSafety(1.5, 1.71) + ); + props.setProperties( + "highway=primary;cycleway=opposite", + withModes(ALL).bicycleSafety(2.06, 2.99) + ); + props.setProperties( + "highway=primary_link;cycleway=opposite", + withModes(ALL).bicycleSafety(2.06, 2.99) + ); + + /* + * path designed for bicycles (should be treated exactly as a cycleway is), this is a multi-use path (MUP) + */ + props.setProperties( + "highway=path;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.60) + ); + + /* special cases for footway, pedestrian and bicycles */ + props.setProperties( + "highway=footway;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) + ); + props.setProperties( + new ExactMatchSpecifier("highway=footway;bicycle=yes;area=yes"), + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.9) + ); + props.setProperties( + "highway=pedestrian;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.75) + ); + + /* sidewalk and crosswalk */ + props.setProperties( + "footway=sidewalk;highway=footway;bicycle=yes", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(2.5) + ); + props.setProperties( + "footway=sidewalk;highway=footway;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1) + ); + props.setProperties( + "highway=footway;footway=crossing", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(2.5) + ); + props.setProperties( + "highway=footway;footway=crossing;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.1) + ); + + /* + * bicycles on tracks (tracks are defined in OSM as: Roads for agricultural use, gravel roads in the forest etc.; usually unpaved/unsealed but + * may occasionally apply to paved tracks as well.) + */ + props.setProperties( + "highway=track;bicycle=yes", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.18) + ); + props.setProperties( + "highway=track;bicycle=designated", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.99) + ); + props.setProperties( + "highway=track;bicycle=yes;surface=*", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.18) + ); + props.setProperties( + "highway=track;bicycle=designated;surface=*", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(0.99) + ); + /* this is to avoid double counting since tracks are almost of surface type that is penalized */ + props.setProperties( + "highway=track;surface=*", + withModes(PEDESTRIAN_AND_BICYCLE).bicycleSafety(1.3) + ); + + /* bicycle=designated, but no bike infrastructure is present */ + props.setProperties("highway=*;bicycle=designated", withModes(ALL).bicycleSafety(0.97)); + props.setProperties("highway=service;bicycle=designated", withModes(ALL).bicycleSafety(0.84)); + props.setProperties( + "highway=residential;bicycle=designated", + withModes(ALL).bicycleSafety(0.95) + ); + props.setProperties( + "highway=unclassified;bicycle=designated", + withModes(ALL).bicycleSafety(0.95) + ); + props.setProperties( + "highway=residential_link;bicycle=designated", + withModes(ALL).bicycleSafety(0.95) + ); + props.setProperties("highway=tertiary;bicycle=designated", withModes(ALL).bicycleSafety(0.97)); + props.setProperties( + "highway=tertiary_link;bicycle=designated", + withModes(ALL).bicycleSafety(0.97) + ); + props.setProperties("highway=secondary;bicycle=designated", withModes(ALL).bicycleSafety(1.46)); + props.setProperties( + "highway=secondary_link;bicycle=designated", + withModes(ALL).bicycleSafety(1.46) + ); + props.setProperties("highway=primary;bicycle=designated", withModes(ALL).bicycleSafety(2)); + props.setProperties("highway=primary_link;bicycle=designated", withModes(ALL).bicycleSafety(2)); + props.setProperties( + "highway=trunk;bicycle=designated", + withModes(BICYCLE_AND_CAR).bicycleSafety(7.25) + ); + props.setProperties( + "highway=trunk_link;bicycle=designated", + withModes(BICYCLE_AND_CAR).bicycleSafety(2) + ); + props.setProperties( + "highway=motorway;bicycle=designated", + withModes(BICYCLE_AND_CAR).bicycleSafety(7.76) + ); + props.setProperties( + "highway=motorway_link;bicycle=designated", + withModes(BICYCLE_AND_CAR).bicycleSafety(2) + ); + + // We assume highway/cycleway of a cycle network to be safer (for bicycle network relations, their network is copied to way in postLoad) + // this uses a OR since you don't want to apply the safety multiplier more than once. + // Signed bicycle_roads and cyclestreets exist in traffic codes of some european countries. + // Tagging in OSM and on-the-ground use is varied, so just assume they are "somehow safer", too. + // In my test area ways often, but not always, have both tags. + // For simplicity these two concepts are handled together. + props.setMixinProperties( + new LogicalOrSpecifier( + "lcn=yes", + "rcn=yes", + "ncn=yes", + "bicycle_road=yes", + "cyclestreet=yes" + ), + ofBicycleSafety(0.7) + ); + + /* + * Automobile speeds in the United States: Based on my (mattwigway) personal experience, primarily in California + */ + props.setCarSpeed("highway=motorway", 29); // 29 m/s ~= 65 mph + props.setCarSpeed("highway=motorway_link", 15); // ~= 35 mph + props.setCarSpeed("highway=trunk", 24.6f); // ~= 55 mph + props.setCarSpeed("highway=trunk_link", 15); // ~= 35 mph + props.setCarSpeed("highway=primary", 20); // ~= 45 mph + props.setCarSpeed("highway=primary_link", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=secondary", 15); // ~= 35 mph + props.setCarSpeed("highway=secondary_link", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=tertiary", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=tertiary_link", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=living_street", 2.2f); // ~= 5 mph + + // generally, these will not allow cars at all, but the docs say + // "For roads used mainly/exclusively for pedestrians . . . which may allow access by + // motorised vehicles only for very limited periods of the day." + // http://wiki.openstreetmap.org/wiki/Key:highway + // This of course makes the street network time-dependent + props.setCarSpeed("highway=pedestrian", 2.2f); // ~= 5 mph + + props.setCarSpeed("highway=residential", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=unclassified", 11.2f); // ~= 25 mph + props.setCarSpeed("highway=service", 6.7f); // ~= 15 mph + props.setCarSpeed("highway=track", 4.5f); // ~= 10 mph + props.setCarSpeed("highway=road", 11.2f); // ~= 25 mph + + // default ~= 25 mph + props.defaultCarSpeed = 11.2f; + // 38 m/s ~= 85 mph ~= 137 kph + props.maxPossibleCarSpeed = 38f; + + /* special situations */ + + /* + * cycleway:left/right=lane/track/shared_lane permutations - no longer needed because left/right matching algorithm does this + */ + + /* cycleway:left=lane */ + /* cycleway:right=track */ + /* cycleway:left=track */ + /* cycleway:right=shared_lane */ + /* cycleway:left=shared_lane */ + /* cycleway:right=lane, cycleway:left=track */ + /* cycleway:right=lane, cycleway:left=shared_lane */ + /* cycleway:right=track, cycleway:left=lane */ + /* cycleway:right=track, cycleway:left=shared_lane */ + /* cycleway:right=shared_lane, cycleway:left=lane */ + /* cycleway:right=shared_lane, cycleway:left=track */ + + /* surface=* mixins */ + + /* + * The following tags have been removed from surface weights because they are no more of an impedence to bicycling than a paved surface + * surface=paving_stones surface=fine_gravel (sounds counter-intuitive but see the definition on the OSM Wiki) surface=tartan (this what + * running tracks are usually made of) + */ + + props.setMixinProperties("surface=unpaved", ofBicycleSafety(1.18)); + props.setMixinProperties("surface=compacted", ofBicycleSafety(1.18)); + props.setMixinProperties("surface=wood", ofBicycleSafety(1.18)); + + props.setMixinProperties("surface=cobblestone", ofBicycleSafety(1.3)); + props.setMixinProperties("surface=sett", ofBicycleSafety(1.3)); + props.setMixinProperties("surface=unhewn_cobblestone", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=grass_paver", ofBicycleSafety(1.3)); + props.setMixinProperties("surface=pebblestone", ofBicycleSafety(1.3)); + // Can be slick if wet, but otherwise not unfavorable to bikes + props.setMixinProperties("surface=metal", ofBicycleSafety(1.3)); + props.setMixinProperties("surface=ground", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=dirt", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=earth", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=grass", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=mud", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=woodchip", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=gravel", ofBicycleSafety(1.5)); + props.setMixinProperties("surface=artifical_turf", ofBicycleSafety(1.5)); + + /* sand is deadly for bikes */ + props.setMixinProperties("surface=sand", ofBicycleSafety(100)); + + /* Portland-local mixins */ + + props.setMixinProperties("foot=discouraged", ofWalkSafety(3)); + props.setMixinProperties("bicycle=discouraged", ofBicycleSafety(3)); + + props.setMixinProperties("foot=use_sidepath", ofWalkSafety(5)); + props.setMixinProperties("bicycle=use_sidepath", ofBicycleSafety(5)); + + populateNotesAndNames(props); + + // slope overrides + props.setSlopeOverride(new BestMatchSpecifier("bridge=*"), true); + props.setSlopeOverride(new BestMatchSpecifier("embankment=*"), true); + props.setSlopeOverride(new BestMatchSpecifier("cutting=*"), true); + props.setSlopeOverride(new BestMatchSpecifier("tunnel=*"), true); + props.setSlopeOverride(new BestMatchSpecifier("location=underground"), true); + props.setSlopeOverride(new BestMatchSpecifier("indoor=yes"), true); + } + + public void populateNotesAndNames(WayPropertySet props) { + /* and the notes */ + // TODO: The curly brackets in the string below mean that the CreativeNamer should substitute in OSM tag values. + // However they are not taken into account when passed to the translation function. + // props.createNotes("wheelchair:description=*", "{wheelchair:description}", StreetNotesService.WHEELCHAIR_MATCHER); + // TODO: The two entries below produce lots of spurious notes (because of OSM mapper comments) + // props.createNotes("note=*", "{note}", StreetNotesService.ALWAYS_MATCHER); + // props.createNotes("notes=*", "{notes}", StreetNotesService.ALWAYS_MATCHER); + props.createNotes( + "RLIS:bicycle=caution_area", + "note.caution", + StreetNotesService.BICYCLE_MATCHER + ); + props.createNotes( + "CCGIS:bicycle=caution_area", + "note.caution", + StreetNotesService.BICYCLE_MATCHER + ); + // TODO: Maybe we should apply the following notes only for car/bike + props.createNotes("surface=unpaved", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes( + "surface=compacted", + "note.unpaved_surface", + StreetNotesService.ALWAYS_MATCHER + ); + props.createNotes("surface=ground", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes("surface=dirt", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes("surface=earth", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes("surface=grass", "note.unpaved_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes("surface=mud", "note.muddy_surface", StreetNotesService.ALWAYS_MATCHER); + props.createNotes("toll=yes", "note.toll", StreetNotesService.DRIVING_MATCHER); + props.createNotes("toll:motorcar=yes", "note.toll", StreetNotesService.DRIVING_MATCHER); + + /* and some names */ + // Basics + props.createNames("highway=cycleway", "name.bike_path"); + props.createNames("cycleway=track", "name.bike_path"); + props.createNames("highway=pedestrian", "name.pedestrian_path"); + props.createNames("highway=pedestrian;area=yes", "name.pedestrian_area"); + props.createNames("highway=path", "name.path"); + props.createNames("highway=footway", "name.pedestrian_path"); + props.createNames("highway=bridleway", "name.bridleway"); + props.createNames("highway=footway;bicycle=no", "name.pedestrian_path"); + + // Platforms + props.createNames("otp:route_ref=*", "name.otp_route_ref"); + props.createNames("highway=platform;ref=*", "name.platform_ref"); + props.createNames("railway=platform;ref=*", "name.platform_ref"); + props.createNames("railway=platform;highway=footway;footway=sidewalk", "name.platform"); + props.createNames("railway=platform;highway=path;path=sidewalk", "name.platform"); + props.createNames("railway=platform;highway=pedestrian", "name.platform"); + props.createNames("railway=platform;highway=path", "name.platform"); + props.createNames("railway=platform;highway=footway", "name.platform"); + props.createNames("highway=platform", "name.platform"); + props.createNames("railway=platform", "name.platform"); + props.createNames("railway=platform;highway=footway;bicycle=no", "name.platform"); + + // Bridges/Tunnels + props.createNames("highway=pedestrian;bridge=*", "name.footbridge"); + props.createNames("highway=path;bridge=*", "name.footbridge"); + props.createNames("highway=footway;bridge=*", "name.footbridge"); + + props.createNames("highway=pedestrian;tunnel=*", "name.underpass"); + props.createNames("highway=path;tunnel=*", "name.underpass"); + props.createNames("highway=footway;tunnel=*", "name.underpass"); + + // Basic Mappings + props.createNames("highway=motorway", "name.road"); + props.createNames("highway=motorway_link", "name.ramp"); + props.createNames("highway=trunk", "name.road"); + props.createNames("highway=trunk_link", "name.ramp"); + + props.createNames("highway=primary", "name.road"); + props.createNames("highway=primary_link", "name.link"); + props.createNames("highway=secondary", "name.road"); + props.createNames("highway=secondary_link", "name.link"); + props.createNames("highway=tertiary", "name.road"); + props.createNames("highway=tertiary_link", "name.link"); + props.createNames("highway=unclassified", "name.road"); + props.createNames("highway=residential", "name.road"); + props.createNames("highway=living_street", "name.road"); + props.createNames("highway=road", "name.road"); + props.createNames("highway=service", "name.service_road"); + props.createNames("highway=service;service=alley", "name.alley"); + props.createNames("highway=service;service=parking_aisle", "name.parking_aisle"); + props.createNames("highway=byway", "name.byway"); + props.createNames("highway=track", "name.track"); + + props.createNames("highway=footway;footway=sidewalk", "name.sidewalk"); + props.createNames("highway=path;path=sidewalk", "name.sidewalk"); + + props.createNames("highway=steps", "name.steps"); + + props.createNames("amenity=bicycle_parking;name=*", "name.bicycle_parking_name"); + props.createNames("amenity=bicycle_parking", "name.bicycle_parking"); + + props.createNames("amenity=parking;name=*", "name.park_and_ride_name"); + props.createNames("amenity=parking", "name.park_and_ride_station"); + } + + public boolean doesTagValueDisallowThroughTraffic(String tagValue) { return ( "no".equals(tagValue) || "destination".equals(tagValue) || @@ -22,20 +731,20 @@ default boolean doesTagValueDisallowThroughTraffic(String tagValue) { ); } - default float getCarSpeedForWay(OsmWithTags way, boolean backward) { + public float getCarSpeedForWay(OsmWithTags way, boolean backward) { return way.getOsmProvider().getWayPropertySet().getCarSpeedForWay(way, backward); } - default Float getMaxUsedCarSpeed(WayPropertySet wayPropertySet) { + public Float getMaxUsedCarSpeed(WayPropertySet wayPropertySet) { return wayPropertySet.maxUsedCarSpeed; } - default boolean isGeneralNoThroughTraffic(OsmWithTags way) { + public boolean isGeneralNoThroughTraffic(OsmWithTags way) { String access = way.getTag("access"); return doesTagValueDisallowThroughTraffic(access); } - default boolean isVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way) { + public boolean isVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way) { String vehicle = way.getTag("vehicle"); if (vehicle != null) { return doesTagValueDisallowThroughTraffic(vehicle); @@ -47,7 +756,7 @@ default boolean isVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way) { /** * Returns true if through traffic for motor vehicles is not allowed. */ - default boolean isMotorVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way) { + public boolean isMotorVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way) { String motorVehicle = way.getTag("motor_vehicle"); if (motorVehicle != null) { return doesTagValueDisallowThroughTraffic(motorVehicle); @@ -59,7 +768,7 @@ default boolean isMotorVehicleThroughTrafficExplicitlyDisallowed(OsmWithTags way /** * Returns true if through traffic for bicycle is not allowed. */ - default boolean isBicycleNoThroughTrafficExplicitlyDisallowed(OsmWithTags way) { + public boolean isBicycleNoThroughTrafficExplicitlyDisallowed(OsmWithTags way) { String bicycle = way.getTag("bicycle"); if (bicycle != null) { return doesTagValueDisallowThroughTraffic(bicycle); @@ -71,7 +780,7 @@ default boolean isBicycleNoThroughTrafficExplicitlyDisallowed(OsmWithTags way) { /** * Returns true if through traffic for walk is not allowed. */ - default boolean isWalkNoThroughTrafficExplicitlyDisallowed(OsmWithTags way) { + public boolean isWalkNoThroughTrafficExplicitlyDisallowed(OsmWithTags way) { String foot = way.getTag("foot"); if (foot != null) { return doesTagValueDisallowThroughTraffic(foot); diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapperSource.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapperSource.java index b40c2e7f75a..98593ef70d0 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapperSource.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapperSource.java @@ -18,7 +18,7 @@ public enum OsmTagMapperSource { public OsmTagMapper getInstance() { return switch (this) { - case DEFAULT -> new DefaultMapper(); + case DEFAULT -> new OsmTagMapper(); case NORWAY -> new NorwayMapper(); case UK -> new UKMapper(); case FINLAND -> new FinlandMapper(); diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/PortlandMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/PortlandMapper.java index 98379852689..7da8f8ca886 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/PortlandMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/PortlandMapper.java @@ -9,7 +9,7 @@ import org.opentripplanner.osm.wayproperty.specifier.Condition.GreaterThan; import org.opentripplanner.osm.wayproperty.specifier.ExactMatchSpecifier; -class PortlandMapper implements OsmTagMapper { +class PortlandMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -57,7 +57,6 @@ public void populateProperties(WayPropertySet props) { // Max speed limit in Oregon is 70 mph ~= 113kmh ~= 31.3m/s props.maxPossibleCarSpeed = 31.4f; - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } } diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/UKMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/UKMapper.java index 08531ce051d..35a575b00c8 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/UKMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/UKMapper.java @@ -21,9 +21,9 @@ * * @author marcusyoung * @see OsmTagMapper - * @see DefaultMapper + * @see OsmTagMapper */ -class UKMapper implements OsmTagMapper { +class UKMapper extends OsmTagMapper { @Override public void populateProperties(WayPropertySet props) { @@ -79,7 +79,6 @@ public void populateProperties(WayPropertySet props) { props.setProperties("indoor=area", pedestrianWayProperties); props.setProperties("indoor=corridor", pedestrianWayProperties); - // Read the rest from the default set - new DefaultMapper().populateProperties(props); + super.populateProperties(props); } } diff --git a/application/src/main/java/org/opentripplanner/osm/wayproperty/specifier/BestMatchSpecifier.java b/application/src/main/java/org/opentripplanner/osm/wayproperty/specifier/BestMatchSpecifier.java index 94dbab99b26..7dacc61e6b8 100644 --- a/application/src/main/java/org/opentripplanner/osm/wayproperty/specifier/BestMatchSpecifier.java +++ b/application/src/main/java/org/opentripplanner/osm/wayproperty/specifier/BestMatchSpecifier.java @@ -26,6 +26,10 @@ public class BestMatchSpecifier implements OsmSpecifier { public static final int NO_MATCH_SCORE = 0; private final Condition[] conditions; + /** + * @deprecated Logic is fuzzy and unpredictable, use ExactMatchSpecifier instead + */ + @Deprecated public BestMatchSpecifier(String spec) { conditions = OsmSpecifier.parseConditions(spec, ";"); } diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java index e3f24f64c6c..8e931e1096a 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java @@ -2,6 +2,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.street.model.StreetTraversalPermission.NONE; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.model.OsmWay; @@ -194,4 +196,28 @@ public void testTagMapping() { wayData = wps.getDataForWay(way); assertEquals(wayData.getPermission(), NONE); } + + /** + * Test that biking is not allowed in footway areas and transit platforms + */ + @Test + public void testArea() { + OsmWithTags way; + WayProperties wayData; + + way = new OsmWay(); + way.addTag("highway", "footway"); + way.addTag("area", "yes"); + wayData = wps.getDataForWay(way); + assertEquals(wayData.getPermission(), PEDESTRIAN); + + way = new OsmWay(); + way.addTag("public_transport", "platform"); + way.addTag("area", "yes"); + wayData = wps.getDataForWay(way); + assertEquals(wayData.getPermission(), PEDESTRIAN); + way.addTag("bicycle", "yes"); + wayData = wps.getDataForWay(way); + assertEquals(wayData.getPermission(), PEDESTRIAN_AND_BICYCLE); + } } diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/GermanyMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/GermanyMapperTest.java index 28f482a3388..c0901f4fcf5 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/GermanyMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/GermanyMapperTest.java @@ -1,6 +1,8 @@ package org.opentripplanner.osm.tagmapping; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; +import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -279,4 +281,19 @@ void testGermanAutobahnSpeed() { autobahn.addTag("maxspeed", "none"); assertEquals(33.33000183105469, wps.getCarSpeedForWay(autobahn, false), epsilon); } + + /** + * Test that biking is not allowed in transit platforms + */ + @Test + public void testArea() { + OsmWithTags way; + + way = new OsmWithTags(); + way.addTag("public_transport", "platform"); + way.addTag("area", "yes"); + assertEquals(wps.getDataForWay(way).getPermission(), PEDESTRIAN); + way.addTag("bicycle", "yes"); + assertEquals(wps.getDataForWay(way).getPermission(), PEDESTRIAN_AND_BICYCLE); + } } diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java index e0c70690e91..aaaf5178d5b 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java @@ -3,20 +3,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofBicycleSafety; -import static org.opentripplanner.osm.wayproperty.WayPropertiesBuilder.withModes; import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.model.OsmWithTags; -import org.opentripplanner.osm.wayproperty.WayPropertySet; public class OsmTagMapperTest { @Test public void isMotorThroughTrafficExplicitlyDisallowed() { OsmWithTags o = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); assertFalse(osmTagMapper.isMotorVehicleThroughTrafficExplicitlyDisallowed(o)); @@ -52,7 +49,7 @@ public void constantSpeedCarRouting() { @Test public void isBicycleNoThroughTrafficExplicitlyDisallowed() { - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); assertTrue( osmTagMapper.isBicycleNoThroughTrafficExplicitlyDisallowed(way("bicycle", "destination")) ); @@ -63,38 +60,17 @@ public void isBicycleNoThroughTrafficExplicitlyDisallowed() { @Test public void isWalkNoThroughTrafficExplicitlyDisallowed() { - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); assertTrue(osmTagMapper.isWalkNoThroughTrafficExplicitlyDisallowed(way("foot", "destination"))); assertTrue( osmTagMapper.isWalkNoThroughTrafficExplicitlyDisallowed(way("access", "destination")) ); } - @Test - public void mixin() { - var source = new DefaultMapper(); - var wps = new WayPropertySet(); - - wps.setProperties("tag=imaginary", withModes(CAR).bicycleSafety(2)); - - wps.setMixinProperties("foo=bar", ofBicycleSafety(0.5)); - source.populateProperties(wps); - - var withoutFoo = new OsmWithTags(); - withoutFoo.addTag("tag", "imaginary"); - assertEquals(2, wps.getDataForWay(withoutFoo).bicycleSafety().back()); - - // the mixin for foo=bar reduces the bike safety factor - var withFoo = new OsmWithTags(); - withFoo.addTag("tag", "imaginary"); - withFoo.addTag("foo", "bar"); - assertEquals(1, wps.getDataForWay(withFoo).bicycleSafety().back()); - } - @Test public void testAccessNo() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "no"); @@ -106,7 +82,7 @@ public void testAccessNo() { @Test public void testAccessPrivate() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "private"); @@ -118,7 +94,7 @@ public void testAccessPrivate() { @Test public void testFootModifier() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "private"); tags.addTag("foot", "yes"); @@ -131,7 +107,7 @@ public void testFootModifier() { @Test public void testVehicleDenied() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("vehicle", "destination"); @@ -143,7 +119,7 @@ public void testVehicleDenied() { @Test public void testVehicleDeniedMotorVehiclePermissive() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("vehicle", "destination"); tags.addTag("motor_vehicle", "designated"); @@ -156,7 +132,7 @@ public void testVehicleDeniedMotorVehiclePermissive() { @Test public void testVehicleDeniedBicyclePermissive() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("vehicle", "destination"); tags.addTag("bicycle", "designated"); @@ -169,7 +145,7 @@ public void testVehicleDeniedBicyclePermissive() { @Test public void testMotorcycleModifier() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "private"); tags.addTag("motor_vehicle", "yes"); @@ -182,7 +158,7 @@ public void testMotorcycleModifier() { @Test public void testBicycleModifier() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "private"); tags.addTag("bicycle", "yes"); @@ -195,7 +171,7 @@ public void testBicycleModifier() { @Test public void testBicyclePermissive() { OsmWithTags tags = new OsmWithTags(); - OsmTagMapper osmTagMapper = new DefaultMapper(); + OsmTagMapper osmTagMapper = new OsmTagMapper(); tags.addTag("access", "private"); tags.addTag("bicycle", "permissive"); diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/DefaultMapperTest.java b/application/src/test/java/org/opentripplanner/osm/wayproperty/MapperTest.java similarity index 89% rename from application/src/test/java/org/opentripplanner/osm/tagmapping/DefaultMapperTest.java rename to application/src/test/java/org/opentripplanner/osm/wayproperty/MapperTest.java index 87e23acbf12..2cd9a74f06b 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/DefaultMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/wayproperty/MapperTest.java @@ -1,21 +1,23 @@ -package org.opentripplanner.osm.tagmapping; +package org.opentripplanner.osm.wayproperty; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.osm.wayproperty.MixinPropertiesBuilder.ofBicycleSafety; +import static org.opentripplanner.osm.wayproperty.WayPropertiesBuilder.withModes; import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; +import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.model.OsmWithTags; -import org.opentripplanner.osm.wayproperty.SpeedPicker; -import org.opentripplanner.osm.wayproperty.WayPropertySet; +import org.opentripplanner.osm.tagmapping.OsmTagMapper; import org.opentripplanner.osm.wayproperty.specifier.BestMatchSpecifier; import org.opentripplanner.osm.wayproperty.specifier.WayTestData; -public class DefaultMapperTest { +public class MapperTest { private WayPropertySet wps; private OsmTagMapper mapper; @@ -24,7 +26,7 @@ public class DefaultMapperTest { @BeforeEach public void setup() { var wps = new WayPropertySet(); - DefaultMapper source = new DefaultMapper(); + var source = new OsmTagMapper(); source.populateProperties(wps); this.wps = wps; this.mapper = source; @@ -199,6 +201,22 @@ void slopeOverrides() { assertTrue(wps.getSlopeOverride(indoor)); } + @Test + public void mixin() { + wps.setProperties("tag=imaginary", withModes(CAR).bicycleSafety(2)); + wps.setMixinProperties("foo=bar", ofBicycleSafety(0.5)); + + var withoutFoo = new OsmWithTags(); + withoutFoo.addTag("tag", "imaginary"); + assertEquals(2, wps.getDataForWay(withoutFoo).bicycleSafety().back()); + + // the mixin for foo=bar reduces the bike safety factor + var withFoo = new OsmWithTags(); + withFoo.addTag("tag", "imaginary"); + withFoo.addTag("foo", "bar"); + assertEquals(1, wps.getDataForWay(withFoo).bicycleSafety().back()); + } + /** * Test that two values are within epsilon of each other. */ diff --git a/doc/user/osm/Default.md b/doc/user/osm/OsmTag.md similarity index 100% rename from doc/user/osm/Default.md rename to doc/user/osm/OsmTag.md diff --git a/mkdocs.yml b/mkdocs.yml index 15e73773d78..b40f77ff3c0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -74,7 +74,7 @@ nav: - Introduction: 'Configuration.md' - Build: 'BuildConfiguration.md' - OSM Tag Mapping: - - Default: 'osm/Default.md' + - Default: 'osm/OsmTag.md' - Finland: 'osm/Finland.md' - Germany: 'osm/Germany.md' - Norway: 'osm/Norway.md'