Subversion Repositories mkgmap

Rev

Rev 3863 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2010 - 2012.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 or
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */


package uk.me.parabola.mkgmap.reader.osm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.Exit;
import uk.me.parabola.log.Logger;
import uk.me.parabola.util.EnhancedProperties;

/**
 * Operations mostly on highways that have to be performed during reading
 * the OSM input file.
 *
 * Some of this would be much better done in a style file or by extending the style system.
 */

public class HighwayHooks extends OsmReadingHooksAdaptor {
        private static final Logger log = Logger.getLogger(HighwayHooks.class);

        private final List<Way> motorways = new ArrayList<>();
        private final List<Node> exits = new ArrayList<>();

        private boolean makeOppositeCycleways;
        private ElementSaver saver;
        private boolean linkPOIsToWays;

        private Node currentNodeInWay;

        public boolean init(ElementSaver saver, EnhancedProperties props) {
                this.saver = saver;
                if(props.getProperty("make-all-cycleways", false)) {
                        log.error("option make-all-cycleways is deprecated, please use make-opposite-cycleways");
                        makeOppositeCycleways = true;
                }
                else {
                        makeOppositeCycleways = props.getProperty("make-opposite-cycleways", false);
                }
               
                linkPOIsToWays = props.getProperty("link-pois-to-ways", false);
                currentNodeInWay = null;

                return true;
        }

        @Override
        public Set<String> getUsedTags() {
                Set<String> usedTags = new HashSet<>(Arrays.asList("highway", "access", "barrier", "FIXME", "fixme",
                                "route", "oneway", "junction", "name", Exit.TAG_ROAD_REF, "ref"));
                if (makeOppositeCycleways) {
                        // need the additional tags
                        usedTags.add("cycleway");
                        usedTags.add("bicycle");
                        usedTags.add("oneway:bicycle");
                        usedTags.add("bicycle:oneway");
                        usedTags.add("cycleway:left");
                        usedTags.add("cycleway:right");
                }
                return usedTags;
        }
       
        public void onAddNode(Node node) {
                String val = node.getTag("highway");
                if (val != null && (val.equals("motorway_junction") || val.equals("services"))) {
                        exits.add(node);
                        node.addTag("mkgmap:osmid", String.valueOf(node.getId()));
                }
        }

        public void onCoordAddedToWay(Way way, long id, Coord co) {
                if (!linkPOIsToWays)
                        return;
                       
                currentNodeInWay = saver.getNode(id);
                // if this Coord is also a POI, replace it with an
                // equivalent CoordPOI that contains a reference to
                // the POI's Node so we can access the POI's tags
                if (!(co instanceof CoordPOI) && currentNodeInWay != null) {
                        // for now, only do this for nodes that have
                        // certain tags otherwise we will end up creating
                        // a CoordPOI for every node in the way
                        final String[] coordPOITags = { "barrier", "highway" };
                        for (String cpt : coordPOITags) {
                                if (currentNodeInWay.getTag(cpt) != null) {
                                        // the POI has one of the approved tags so
                                        // replace the Coord with a CoordPOI
                                        CoordPOI cp = new CoordPOI(co);
                                        saver.addPoint(id, cp);

                                        // we also have to jump through hoops to
                                        // make a new version of Node because we
                                        // can't replace the Coord that defines
                                        // its location
                                        Node newNode = new Node(id, cp);
                                        newNode.copyTags(currentNodeInWay);
                                        saver.addNode(newNode);
                                        // tell the CoordPOI what node it's
                                        // associated with
                                        cp.setNode(newNode);
                                        co = cp;
                                        // if original node is in exits, replace it
                                        if (exits.remove(currentNodeInWay))
                                                exits.add(newNode);
                                        currentNodeInWay = newNode;
                                        break;
                                }
                        }
                }

                if (co instanceof CoordPOI) {
                        // flag this Way as having a CoordPOI so it
                        // will be processed later
                        way.addTag("mkgmap:way-has-pois", "true");
                        if (log.isInfoEnabled())
                                log.info("Linking POI", currentNodeInWay.toBrowseURL(), "to way at", co.toOSMURL());
                }
        }

        public void onAddWay(Way way) {
                String highway = way.getTag("highway");
                if (highway != null || "ferry".equals(way.getTag("route"))) {
                        // if the way is a roundabout but isn't already
                        // flagged as "oneway", flag it here
                        if ("roundabout".equals(way.getTag("junction"))) {
                                if (way.getTag("oneway") == null) {
                                        way.addTag("oneway", "yes");
                                }
                        }

                        if (makeOppositeCycleways && !"cycleway".equals(highway)){
                                String onewayTag = way.getTag("oneway");
                                boolean oneway = way.tagIsLikeYes("oneway");
                                if (!oneway & onewayTag != null && ("-1".equals(onewayTag) || "reverse".equals(onewayTag)))
                                        oneway = true;
                                if (oneway){
                                        String cycleway = way.getTag("cycleway");
                                        boolean addCycleWay = false;
                                        // we have a oneway street, check if it allows bicycles to travel in opposite direction
                                        if ("no".equals(way.getTag("oneway:bicycle")) || "no".equals(way.getTag("bicycle:oneway"))){
                                                addCycleWay = true;
                                        }
                                        else if (cycleway != null && ("opposite".equals(cycleway) || "opposite_lane".equals(cycleway) || "opposite_track".equals(cycleway))){
                                                addCycleWay = true;    
                                        }
                                        else if ("opposite_lane".equals(way.getTag("cycleway:left")) || "opposite_lane".equals(way.getTag("cycleway:right"))){
                                                addCycleWay = true;
                                        }
                                        else if ("opposite_track".equals(way.getTag("cycleway:left")) || "opposite_track".equals(way.getTag("cycleway:right"))){
                                                addCycleWay = true;
                                        }
                                        if (addCycleWay)
                                                way.addTag("mkgmap:make-cycle-way", "yes");
                                }
                        }
                }

                if("motorway".equals(highway) || "trunk".equals(highway))
                        motorways.add(way);
        }

        public void end() {
                finishExits();
                exits.clear();
                motorways.clear();
        }

        private void finishExits() {
                for (Node e : exits) {
                        String refTag = Exit.TAG_ROAD_REF;
                        if (e.getTag(refTag) == null) {
                                String exitName = e.getTag("name");
                                if (exitName == null)
                                        exitName = e.getTag("ref");

                                String ref = null;
                                Way motorway = null;
                                for (Way w : motorways) {
                                        // uses an implicit call of Coord.equals()
                                        if (w.getPoints().contains(e.getLocation())) {
                                                motorway = w;
                                                ref = w.getTag("ref");
                                                if(ref != null)
                                                    break;
                                        }
                                }
                               
                                if (ref != null) {
                                        log.info("Adding", refTag + "=" + ref, "to exit", exitName);
                                        e.addTag(refTag, ref);
                                } else if(motorway != null) {
                                        log.warn("Motorway exit", exitName, "is positioned on a motorway that doesn't have a 'ref' tag (" + e.getLocation().toOSMURL() + ")");
                                }
                        }
                }
        }
}