/** * <<<<<<< HEAD ======= Copies useful metadata from multipolygon relations to the relevant ways. * * <p>This is done at a different time than processRelations(), so that way purging doesn't * remove the used ways. */ private void processMultipolygons() { for (OSMRelation relation : _relations.values()) { if (!(relation.isTag("type", "multipolygon") && relation.hasTag("highway"))) { continue; } for (OSMRelationMember member : relation.getMembers()) { if (!("way".equals(member.getType()) && _ways.containsKey(member.getRef()))) { continue; } OSMWay way = _ways.get(member.getRef()); if (way == null) { continue; } if (relation.hasTag("highway") && !way.hasTag("highway")) { way.addTag("highway", relation.getTag("highway")); } if (relation.hasTag("name") && !way.hasTag("name")) { way.addTag("name", relation.getTag("name")); } if (relation.hasTag("ref") && !way.hasTag("ref")) { way.addTag("ref", relation.getTag("ref")); } } } }
/** >>>>>>> origin/master Copies useful metadata from relations to the relevant ways/nodes. */ private void processRelations() { _log.debug("Processing relations..."); for (OSMRelation relation : _relations.values()) { if (relation.isTag("type", "restriction")) { processRestriction(relation); } else if (relation.isTag("type", "level_map")) { processLevelMap(relation); } else if (relation.isTag("type", "route")) { processRoad(relation); } // multipolygons were already processed in secondPhase() } }
/* * Handle route=road relations. * * @param relation */ private void processRoad(OSMRelation relation) { for (OSMRelationMember member : relation.getMembers()) { if (!("way".equals(member.getType()) && _ways.containsKey(member.getRef()))) { continue; } OSMWay way = _ways.get(member.getRef()); if (way == null) { continue; } if (relation.hasTag("name")) { if (way.hasTag("otp:route_name")) { way.addTag( "otp:route_name", addUniqueName(way.getTag("otp:route_name"), relation.getTag("name"))); } else { way.addTag(new OSMTag("otp:route_name", relation.getTag("name"))); } } if (relation.hasTag("ref")) { if (way.hasTag("otp:route_ref")) { way.addTag( "otp:route_ref", addUniqueName(way.getTag("otp:route_ref"), relation.getTag("ref"))); } else { way.addTag(new OSMTag("otp:route_ref", relation.getTag("ref"))); } } } }
public void addRelation(OSMRelation relation) { if (_relations.containsKey(relation.getId())) return; if (!(relation.isTag("type", "restriction")) && !(relation.isTag("type", "route") && relation.isTag("route", "road")) && !(relation.isTag("type", "multipolygon") && relation.hasTag("highway")) && !(relation.isTag("type", "level_map"))) { return; } _relations.put(relation.getId(), relation); if (_relations.size() % 100 == 0) _log.debug("relations=" + _relations.size()); }
/** * Process an OSM level map. * * @param relation */ private void processLevelMap(OSMRelation relation) { ArrayList<String> levels = new ArrayList<String>(); // This stores the mapping from level keys to the full level values HashMap<String, String> levelFullNames = new HashMap<String, String>(); int levelDelta = 0; /* * parse all of the levels * this array is ordered * this is a little different than the OpenStreetMap levels notation, * because the lowest level of a building (basement or whatever) is * always otp:numeric_level 0. This is OK, as otp:numeric_level tags * are *always* accompanied by otp:human_level tags that give the actual * name of the level; otp:numeric_level is used only for relative * position, and should *never* be shown to the user. To make things more understandable * we try to find a delta to compensate and put the basement where it should be, but * this data should never be displayed to the user or mixed with OSM levels * from elsewhere. It's possible we wouldn't find a delta (imagine * levels=Garage;Basement;Lobby;Sky Bridge;Roof), but this is OK. */ Pattern isRange = Pattern.compile("^[0-9]+\\-[0-9]+$"); Matcher m; for (String level : relation.getTag("levels").split(";")) { // split out ranges m = isRange.matcher(level); if (m.matches()) { String[] range = level.split("-"); int endOfRange = Integer.parseInt(range[1]); for (int i = Integer.parseInt(range[0]); i <= endOfRange; i++) { levels.add(Integer.toString(i)); } } // not a range, just normal else { levels.add(level); } } // try to get a best-guess delta between level order and level numbers, and fix up // levels for (int i = 0; i < levels.size(); i++) { String level = levels.get(i); // leaving it null gives NullPointerException when there is no matched 0 level // making it 1 doesn't matter, since its only purpose is to be compared to 0 Integer numLevel = 1; // try to parse out the level number try { numLevel = Integer.parseInt(level); } catch (NumberFormatException e) { try { numLevel = Integer.parseInt(level.split("=")[0]); } catch (NumberFormatException e2) { try { // http://stackoverflow.com/questions/1181969/java-get-last-element-after-split int lastInd = level.lastIndexOf('@'); if (lastInd != -1) { numLevel = Integer.parseInt(level.substring(lastInd + 1)); } } catch (NumberFormatException e3) { // do nothing } } } if (numLevel == 0) { levelDelta = -1 * levels.indexOf(level); } String levelIndex; String levelName; // get just the human-readable level name from a name like T=Tunnel@-15 // first, discard elevation info // don't use split, in case there is an @ in the level name; split on only the last // one int lastIndAt = level.lastIndexOf('@'); if (lastIndAt >= 1) { level = level.substring(0, lastIndAt); } // if it's there, discard the long name, but put it into a hashmap for retrieval // below // Why not just use the hashmap? Because we need the ordered ArrayList. Integer levelSplit = level.indexOf('='); if (levelSplit >= 1) { levelIndex = level.substring(0, levelSplit); levelName = level.substring(levelSplit + 1); } else { // set them both the same, the @whatever has already been discarded levelIndex = levelName = level; } // overwrite for later indexing levels.set(i, levelIndex); // add to the HashMap levelFullNames.put(levelIndex, levelName); } for (OSMRelationMember member : relation.getMembers()) { if ("way".equals(member.getType()) && _ways.containsKey(member.getRef())) { OSMWay way = _ways.get(member.getRef()); if (way != null) { String role = member.getRole(); // this would indicate something more complicated than a single // level. Skip it. if (!relation.hasTag("role:" + role)) { if (levels.indexOf(role) != -1) { way.addTag( "otp:numeric_level", Integer.toString(levels.indexOf(role) + levelDelta)); way.addTag("otp:human_level", levelFullNames.get(role)); } else { _log.warn(member.getRef() + " has undefined level " + role); } } } } } }
/** * Handle turn restrictions * * @param relation */ private void processRestriction(OSMRelation relation) { long from = -1, to = -1, via = -1; for (OSMRelationMember member : relation.getMembers()) { String role = member.getRole(); if (role.equals("from")) { from = member.getRef(); } else if (role.equals("to")) { to = member.getRef(); } else if (role.equals("via")) { via = member.getRef(); } } if (from == -1 || to == -1 || via == -1) { _log.warn( GraphBuilderAnnotation.register(graph, Variety.TURN_RESTRICTION_BAD, relation.getId())); return; } Set<TraverseMode> modes = EnumSet.of(TraverseMode.BICYCLE, TraverseMode.CAR); String exceptModes = relation.getTag("except"); if (exceptModes != null) { for (String m : exceptModes.split(";")) { if (m.equals("motorcar")) { modes.remove(TraverseMode.CAR); } else if (m.equals("bicycle")) { modes.remove(TraverseMode.BICYCLE); _log.warn( GraphBuilderAnnotation.register( graph, Variety.TURN_RESTRICTION_EXCEPTION, via, from)); } } } modes = TraverseMode.internSet(modes); TurnRestrictionTag tag; if (relation.isTag("restriction", "no_right_turn")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.NO_TURN); } else if (relation.isTag("restriction", "no_left_turn")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.NO_TURN); } else if (relation.isTag("restriction", "no_straight_on")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.NO_TURN); } else if (relation.isTag("restriction", "no_u_turn")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.NO_TURN); } else if (relation.isTag("restriction", "only_straight_on")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.ONLY_TURN); } else if (relation.isTag("restriction", "only_right_turn")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.ONLY_TURN); } else if (relation.isTag("restriction", "only_left_turn")) { tag = new TurnRestrictionTag(via, TurnRestrictionType.ONLY_TURN); } else { _log.warn( GraphBuilderAnnotation.register( graph, Variety.TURN_RESTRICTION_UNKNOWN, relation.getTag("restriction"))); return; } TurnRestriction restriction = new TurnRestriction(); restriction.type = tag.type; restriction.modes = modes; turnRestrictionsByTag.put(tag, restriction); MapUtils.addToMapList(turnRestrictionsByFromWay, from, tag); MapUtils.addToMapList(turnRestrictionsByToWay, to, tag); }