/** * Handle oneway streets, cycleways, and whatnot. See http://wiki.openstreetmap.org/wiki/Bicycle * for various scenarios, along with * http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing#Oneway. * * @param end * @param start */ private P2<PlainStreetEdge> getEdgesForStreet( IntersectionVertex start, IntersectionVertex end, OSMWay way, long startNode, StreetTraversalPermission permissions, LineString geometry) { // get geometry length in meters, irritatingly. Coordinate[] coordinates = geometry.getCoordinates(); double d = 0; for (int i = 1; i < coordinates.length; ++i) { d += DistanceLibrary.distance(coordinates[i - 1], coordinates[i]); } LineString backGeometry = (LineString) geometry.reverse(); Map<String, String> tags = way.getTags(); if (permissions == StreetTraversalPermission.NONE) return new P2<PlainStreetEdge>(null, null); PlainStreetEdge street = null, backStreet = null; /* * pedestrian rules: everything is two-way (assuming pedestrians are allowed at all) * bicycle rules: default: permissions; * * cycleway=dismount means walk your bike -- the engine will automatically try walking * bikes any time it is forbidden to ride them, so the only thing to do here is to * remove bike permissions * * oneway=... sets permissions for cars and bikes oneway:bicycle overwrites these * permissions for bikes only * * now, cycleway=opposite_lane, opposite, opposite_track can allow once oneway has been * set by oneway:bicycle, but should give a warning if it conflicts with oneway:bicycle * * bicycle:backward=yes works like oneway:bicycle=no bicycle:backwards=no works like * oneway:bicycle=yes */ String foot = way.getTag("foot"); if ("yes".equals(foot) || "designated".equals(foot)) { permissions = permissions.add(StreetTraversalPermission.PEDESTRIAN); } if (OSMWithTags.isFalse(foot)) { permissions = permissions.remove(StreetTraversalPermission.PEDESTRIAN); } boolean forceBikes = false; String bicycle = way.getTag("bicycle"); if ("yes".equals(bicycle) || "designated".equals(bicycle)) { permissions = permissions.add(StreetTraversalPermission.BICYCLE); forceBikes = true; } if (way.isTag("cycleway", "dismount") || "dismount".equals(bicycle)) { permissions = permissions.remove(StreetTraversalPermission.BICYCLE); if (forceBikes) { _log.warn( GraphBuilderAnnotation.register(graph, Variety.CONFLICTING_BIKE_TAGS, way.getId())); } } StreetTraversalPermission permissionsFront = permissions; StreetTraversalPermission permissionsBack = permissions; if (way.isTagTrue("oneway") || "roundabout".equals(tags.get("junction"))) { permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE_AND_CAR); } if (way.isTag("oneway", "-1")) { permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE_AND_CAR); } String oneWayBicycle = way.getTag("oneway:bicycle"); if (OSMWithTags.isTrue(oneWayBicycle) || way.isTagFalse("bicycle:backwards")) { permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE); } if ("-1".equals(oneWayBicycle)) { permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE); } if (OSMWithTags.isFalse(oneWayBicycle) || way.isTagTrue("bicycle:backwards")) { if (permissions.allows(StreetTraversalPermission.BICYCLE)) { permissionsFront = permissionsFront.add(StreetTraversalPermission.BICYCLE); permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE); } } // any cycleway which is opposite* allows contraflow biking String cycleway = way.getTag("cycleway"); String cyclewayLeft = way.getTag("cycleway:left"); String cyclewayRight = way.getTag("cycleway:right"); if ((cycleway != null && cycleway.startsWith("opposite")) || (cyclewayLeft != null && cyclewayLeft.startsWith("opposite")) || (cyclewayRight != null && cyclewayRight.startsWith("opposite"))) { permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE); } String access = way.getTag("access"); boolean noThruTraffic = "destination".equals(access) || "private".equals(access) || "customers".equals(access) || "delivery".equals(access) || "forestry".equals(access) || "agricultural".equals(access); if (permissionsFront != StreetTraversalPermission.NONE) { street = getEdgeForStreet(start, end, way, startNode, d, permissionsFront, geometry, false); street.setNoThruTraffic(noThruTraffic); } if (permissionsBack != StreetTraversalPermission.NONE) { backStreet = getEdgeForStreet(end, start, way, startNode, d, permissionsBack, backGeometry, true); backStreet.setNoThruTraffic(noThruTraffic); } /* mark edges that are on roundabouts */ if ("roundabout".equals(tags.get("junction"))) { if (street != null) street.setRoundabout(true); if (backStreet != null) backStreet.setRoundabout(true); } return new P2<PlainStreetEdge>(street, backStreet); }
private StreetTraversalPermission getPermissionsForEntity( OSMWithTags entity, StreetTraversalPermission def) { Map<String, String> tags = entity.getTags(); StreetTraversalPermission permission = null; String highway = tags.get("highway"); String cycleway = tags.get("cycleway"); String access = tags.get("access"); String motorcar = tags.get("motorcar"); String bicycle = tags.get("bicycle"); String foot = tags.get("foot"); /* * Only a few tags are examined here, because we only care about modes supported by OTP * (wheelchairs are not of concern here) * * Only a few values are checked for, all other values are presumed to be permissive (=> * This may not be perfect, but is closer to reality, since most people don't follow the * rules perfectly ;-) */ if (access != null) { if ("no".equals(access) || "license".equals(access)) { // this can actually be overridden permission = StreetTraversalPermission.NONE; if (entity.doesTagAllowAccess("motorcar")) { permission = permission.add(StreetTraversalPermission.CAR); } if (entity.doesTagAllowAccess("bicycle")) { permission = permission.add(StreetTraversalPermission.BICYCLE); } if (entity.doesTagAllowAccess("foot")) { permission = permission.add(StreetTraversalPermission.PEDESTRIAN); } } else { permission = def; } } else if (motorcar != null || bicycle != null || foot != null) { permission = def; } if (motorcar != null) { if ("no".equals(motorcar) || "license".equals(motorcar)) { permission = permission.remove(StreetTraversalPermission.CAR); } else { permission = permission.add(StreetTraversalPermission.CAR); } } if (bicycle != null) { if ("no".equals(bicycle) || "license".equals(bicycle)) { permission = permission.remove(StreetTraversalPermission.BICYCLE); } else { permission = permission.add(StreetTraversalPermission.BICYCLE); } } if (foot != null) { if ("no".equals(foot) || "license".equals(foot)) { permission = permission.remove(StreetTraversalPermission.PEDESTRIAN); } else { permission = permission.add(StreetTraversalPermission.PEDESTRIAN); } } if (highway != null) { if ("construction".equals(highway)) { permission = StreetTraversalPermission.NONE; } } else { if ("construction".equals(cycleway)) { permission = StreetTraversalPermission.NONE; } } if (permission == null) return def; return permission; }