All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rinde.sim.util.OSM Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/**
 * 
 */
package rinde.sim.util;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import rinde.sim.core.graph.Connection;
import rinde.sim.core.graph.Graph;
import rinde.sim.core.graph.MultiAttributeData;
import rinde.sim.core.graph.Point;
import rinde.sim.core.graph.TableGraph;

/**
 * @author Rinde van Lon ([email protected])
 * 
 */
public class OSM {

    static HashSet highwayNames = new HashSet();

    public static Graph parse(String filename) {
        try {
            InputSource inputSource = new InputSource(new FileInputStream(
                    filename));
            XMLReader xmlReader = XMLReaderFactory.createXMLReader();
            // Multimap graph = HashMultimap.create();

            TableGraph graph = new TableGraph(
                    MultiAttributeData.EMPTY);

            OSMParser parser = new OSMParser(graph);
            xmlReader.setContentHandler(parser);
            xmlReader.setErrorHandler(parser);
            xmlReader.parse(inputSource);

            // remove circular connections
            List> removeList = new ArrayList>();
            for (Connection connection : graph
                    .getConnections()) {
                if (connection.from.equals(connection.to)) {
                    removeList.add(connection);
                }
            }
            for (Connection connection : removeList) {
                graph.removeConnection(connection.from, connection.to);
            }
            // System.out.println(highwayNames.toString());
            return graph;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to load xml file properly: "
                    + filename);
        }

    }

    static class OSMParser extends DefaultHandler {

        protected Graph rs;
        protected HashMap nodes;
        protected WayParser current;

        public OSMParser(Graph rs) {
            super();
            this.rs = rs;
            nodes = new HashMap();
        }

        // the earth radius in meters
        private static final long EARTH_RADIUS = 6378137L;

        // private double gradeToRadian(double grade) {
        // return grade * Math.PI / 180;
        // }

        @Override
        public void startElement(String namespaceURI, String localName,
                String qualifiedName, Attributes attributes) {
            if (current != null) {
                current.startElement(namespaceURI, localName, qualifiedName, attributes);
            } else if (localName.equals("node")) {
                double lat = Double.parseDouble(attributes.getValue("lat"));
                double lon = Double.parseDouble(attributes.getValue("lon"));
                // LatLng latlong = new LatLng(lat, lon);
                // latlong.toWGS84();
                // UTMRef ref = latlong.toUTMRef();

                // lat = gradeToRadian(lat);
                // lon = gradeToRadian(lon);
                // long y = Math.round(earthRadius * Math.cos(lat) *
                // Math.cos(lon));

                // cos(latitude * pi/180) * earth circumference

                // ground resolution = cos(latitude * pi/180) * earth
                // circumference / map width
                // = (cos(latitude * pi/180) * 2 * pi * 6378137 meters) / (256 *
                // 2^level pixels)

                // MAGIC constant! Don't touch this without consulting either
                // Rinde van Lon or Bartosz Michalik, preferably both :-)
                double scale = 1000000 / 1.425139046;// Math.toDegrees(Math.cos(Math.toRadians(lat)
                                                     // * Math.PI /
                                                     // Math.toRadians(180)))
                                                     // * 2 * Math.PI *
                                                     // earthRadius / 1000;

                //

                // sinLatitude = sin(latitude * pi/180)
                //
                // pixelX = ((longitude + 180) / 360) * 256 * 2 level
                // pixelY = (0.5 - log((1 + sinLatitude) / (1 - sinLatitude)) /
                // (4 * pi)) * 256 * 2 level

                // double sinLattitude = Math.sin(Math.toRadians(lat * Math.PI /
                // 180));
                // double x = ((lon + 180) / 360.0);
                // double y = (0.5 - Math.log((1 + sinLattitude) / (1 -
                // sinLattitude)) / (4 * Math.PI));

                // MERCATOR:
                double x = scale * lon; // Math.round(earthRadius *
                                        // Math.cos(lat) * Math.sin(lon));
                double y = scale
                        * Math.toDegrees(1.0 / Math.sinh(Math.tan(Math
                                .toRadians(lat))));// Math.log(Math.tan(.25
                                                   // *
                                                   // Math.PI
                                                   // +
                                                   // .5
                                                   // *
                                                   // gradeToRadian(lat)));

                // check: http://www.movable-type.co.uk/scripts/latlong.html for
                // a great explanation

                // converting to the Mercator projection:
                // http://mathworld.wolfram.com/MercatorProjection.html
                // Fun fact: Did you know that the Mercator projection was named
                // after Gerardus Mercator (1512-1594), a Flemish cartographer?

                // double dLat = (l)

                // var R = 6371; // km
                // var dLat = (lat2-lat1).toRad();
                // var dLon = (lon2-lon1).toRad();
                // var lat1 = lat1.toRad();
                // var lat2 = lat2.toRad();
                //
                // var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                // Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) *
                // Math.cos(lat2);
                // var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
                // var d = R * c;

                // ref.

                // String[] converted = CoordinateConversion.latLon2MGRUTM(x,
                // y).split(" ");
                // nodes.put(attributes.getValue("id"), new
                // Point(Double.parseDouble(converted[2]),
                // -Double.parseDouble(converted[3])));

                nodes.put(attributes.getValue("id"), new Point(x, y));

            } else if (localName.equals("way")) {
                current = new WayParser(nodes);
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            if (localName.equals("way")) {
                current.addWaysTo(rs);
                current = null;
            }
        }

        @Override
        public void endDocument() {}

    }

    static class WayParser extends DefaultHandler {

        protected final HashSet highwayTypes = new HashSet(
                Arrays.asList("motorway", "motorway_link", "trunk", "trunk_link", "primary", "primary_link", "motorway_junction", "secondary", "secondary_link", "tertiary", "road", "living_street", "residental", "residential", "residential;unclassified", "crossing", "ditch", "unclassified", "raceway", "path", "turning_circle", "track", "trunk_link", "trunk", "platform", "minor"));
        // what about 'unclassified'?

        protected final HashSet junctionTypes = new HashSet(
                Arrays.asList("roundabout"));

        protected List nodes;
        protected double maxSpeed;
        protected boolean oneWay;
        protected boolean isValidRoad;
        protected HashMap nodeMapping;

        public WayParser(HashMap nodeMapping) {
            nodes = new ArrayList();
            oneWay = false;
            maxSpeed = Double.NaN;
            isValidRoad = false;
            this.nodeMapping = nodeMapping;
        }

        @Override
        public void startElement(String namespaceURI, String localName,
                String qualifiedName, Attributes attributes) {
            if (localName.equals("tag")) {

                if (attributes.getValue("k").equals("highway")) {
                    highwayNames.add(attributes.getValue("v"));
                }

                if (attributes.getValue("k").equals("oneway")
                        && attributes.getValue("v").equals("yes")) {
                    oneWay = true;
                } else if (attributes.getValue("k").equals("highway")
                        && highwayTypes.contains(attributes.getValue("v"))) {
                    isValidRoad = true;
                } else if (attributes.getValue("k").equals("junction")
                        && junctionTypes.contains(attributes.getValue("v"))) {
                    isValidRoad = true;
                } else if (attributes.getValue("k").equals("maxspeed")) {
                    try {
                        maxSpeed = 1000.0 * Integer.parseInt(attributes
                                .getValue("v").replaceAll("\\D", ""));
                    } catch (NumberFormatException nfe) {
                        // ignore if this happens, it means that no max speed
                        // was defined
                    }
                }
            } else if (localName.equals("nd")) {
                nodes.add(attributes.getValue("ref"));
            }
        }

        public void addWaysTo(Graph graph) {
            if (isValidRoad) {
                for (int i = 1; i < nodes.size(); i++) {
                    Point from = nodeMapping.get(nodes.get(i - 1));
                    Point to = nodeMapping.get(nodes.get(i));
                    if (from != null && to != null && !from.equals(to)) {

                        double length = Point.distance(from, to);
                        if (!graph.hasConnection(from, to)) {
                            graph.addConnection(from, to, new MultiAttributeData(
                                    length, maxSpeed));
                        }
                        if (!oneWay && !graph.hasConnection(to, from)) {
                            graph.addConnection(to, from, new MultiAttributeData(
                                    length, maxSpeed));
                        }
                    }
                }
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy