/** * This file is part of OSM2ShareNav * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * Copyright (C) 2010 Kai Krueger */ package net.sharenav.osmToShareNav; import java.io.IOException; import java.io.InputStream; import java.util.List; import crosby.binary.BinaryParser; import crosby.binary.Osmformat; import crosby.binary.Osmformat.DenseInfo; import crosby.binary.Osmformat.DenseNodes; import crosby.binary.Osmformat.HeaderBlock; import crosby.binary.file.BlockInputStream; import net.sharenav.osmToShareNav.model.Entity; import net.sharenav.osmToShareNav.model.Member; import net.sharenav.osmToShareNav.model.Node; import net.sharenav.osmToShareNav.model.Relation; import net.sharenav.osmToShareNav.model.TurnRestriction; import net.sharenav.osmToShareNav.model.Way; public class OpbfParser extends OsmParser { /** * @param i */ private class OsmPbfHandler extends BinaryParser { @Override public void parse(HeaderBlock block) { for (String s : block.getRequiredFeaturesList()) { if (s.equals("OsmSchema-V0.6")) { continue; // We can parse this. } if (s.equals("DenseNodes")) { continue; // We can parse this. } throw new Error("File requires unknown feature: " + s); } try { Thread.sleep(1000); } catch (InterruptedException ie) { } } /* * (non-Javadoc) * * @see * crosby.binary.BinaryParser#parseDense(crosby.binary.Osmformat.DenseNodes * ) */ @Override protected void parseDense(DenseNodes dn) { long last_id = 0, last_lat = 0, last_lon = 0; int j = 0; // Index into the keysvals array. for (int i = 0; i < dn.getIdCount(); i++) { // List<Tag> tags = new ArrayList<Tag>(0); long lat = dn.getLat(i) + last_lat; last_lat = lat; long lon = dn.getLon(i) + last_lon; last_lon = lon; long id = dn.getId(i) + last_id; last_id = id; float latf = (float) parseLat(lat), lonf = (float) parseLon(lon); if (nodeInArea(latf, lonf)) { Node nd = new Node(latf, lonf, id); if (dn.getKeysValsCount() > 0) { while (dn.getKeysVals(j) != 0) { int keyid = dn.getKeysVals(j++); int valid = dn.getKeysVals(j++); String key = getStringById(keyid); if (LegendParser.getRelevantKeys().contains(key)) { nd.setAttribute(key, getStringById(valid)); } } j++; // Skip over the '0' delimiter. } previousNodeWithThisId = nodes.put(nd.id, nd); nodeIns++; if (nd.getAttribute("highway") != null && nd.getAttribute("highway").equalsIgnoreCase( "traffic_signals")) { // decrement trafficSignalCount if a previous node with this // id got replaced but was a traffic signal node if (previousNodeWithThisId != null && previousNodeWithThisId.isTrafficSignals()) { trafficSignalCount--; System.out.println("DUPLICATE TRAFFIC SIGNAL NODE ID: " + previousNodeWithThisId.id + " more than once in osm file"); } nd.markAsTrafficSignals(); trafficSignalCount++; } } else { //If the nodes are not in the area, we still need to skip over the dens key-value representation: if (dn.getKeysValsCount() > 0) { while (dn.getKeysVals(j) != 0) { j+= 2; } j++; // Skip over the '0' delimiter. } } // If empty, assume that nothing here has keys or vals. } nodeTot += dn.getLatCount(); ele += dn.getLatCount(); printProgress(); } /* * (non-Javadoc) * * @see crosby.binary.BinaryParser#parseNodes(java.util.List) */ @Override protected void parseNodes(List<crosby.binary.Osmformat.Node> nds) { // TODO Auto-generated method stub // System.out.println("Parsing nodes: " + nds); nodeTot += nds.size(); ele += nds.size(); if (nds.size() > 0) { System.out.println("Non dense nodes!"); } printProgress(); } /* * (non-Javadoc) * * @see crosby.binary.BinaryParser#parseWays(java.util.List) */ @Override protected void parseWays(List<crosby.binary.Osmformat.Way> ways_chunk) { for (crosby.binary.Osmformat.Way i : ways_chunk) { Way way = new Way(i.getId()); for (int j = 0; j < i.getKeysCount(); j++) { String key = getStringById(i.getKeys(j)); if (LegendParser.getRelevantKeys().contains(key)) { way.setAttribute(key, getStringById(i.getVals(j))); } } long last_id = 0; for (long j : i.getRefsList()) { long ref = j + last_id; Node node = nodes.get(new Long(ref)); if (node != null) { way.addNode(node); } else { // Nodes for this way are missing, problem in OSM or simply // out of bounding box. // Three different cases are possible: // missing at the start, in the middle or at the end. // We simply add the current way and start a new one // with shared attributes. // Degenerate ways are not added, so don't care about // this here. if (way.getNodeCount() != 0) { Way tmp_way = new Way(way); addWay(way); way = tmp_way; } } last_id = ref; } addWay(way); if (way.isArea()) { way.saveOutline(); } } wayTot += ways.size(); ele += ways.size(); } /* * (non-Javadoc) * * @see crosby.binary.BinaryParser#parseRelations(java.util.List) */ @Override protected void parseRelations( List<crosby.binary.Osmformat.Relation> rels) { for (Osmformat.Relation i : rels) { Relation r = new Relation(i.getId()); for (int j = 0; j < i.getKeysCount(); j++) { String key = getStringById(i.getKeys(j)); if (LegendParser.getRelevantKeys().contains(key)) { r.setAttribute(key, getStringById(i.getVals(j))); } } long last_mid = 0; for (int j = 0; j < i.getMemidsCount(); j++) { long mid = last_mid + i.getMemids(j); last_mid = mid; String role = getStringById(i.getRolesSid(j)); Member m = null; if (i.getTypes(j) == Osmformat.Relation.MemberType.NODE) { m = new Member("node", mid, role); if (!nodes.containsKey(new Long(mid))) { r.setPartial(); continue; } } else if (i.getTypes(j) == Osmformat.Relation.MemberType.WAY) { m = new Member("way", mid, role); if (!ways.containsKey(new Long(mid))) { r.setPartial(); continue; } } else if (i.getTypes(j) == Osmformat.Relation.MemberType.RELATION) { m = new Member("relation", mid, role); ; if (m.getRef() > r.id) { // We haven't parsed this relation yet, so // we have to assume it is valid for the moment } else { if (!relations.containsKey(new Long(m.getRef()))) { r.setPartial(); continue; } } } else { assert false; // TODO; Illegal file? } r.add(m); } long viaNodeOrWayRef = 0; if (r.isValid()) { if (!r.isPartial()) { relIns++; viaNodeOrWayRef = r.getViaNodeOrWayRef(); } else { relPart++; } if (viaNodeOrWayRef != 0) { TurnRestriction turnRestriction = new TurnRestriction(r); if (r.isViaWay()) { // Store the ref to the via way turnRestriction.viaWayRef = viaNodeOrWayRef; // add a flag to the turn restriction if it's a way turnRestriction.flags |= TurnRestriction.VIA_TYPE_IS_WAY; // add restrictions with viaWays into an ArrayList // to be resolved later turnRestrictionsWithViaWays.add(turnRestriction); } else { // remember normal turn restrictions now // because we already know the via node addTurnRestriction(viaNodeOrWayRef, turnRestriction); } } else { relations.put(r.id, r); } } } relTot += rels.size(); ele += rels.size(); printProgress(); } private void printProgress() { if (ele > 1000000) { ele = 0; if (configuration.verbose >= 0) { System.out.println("Nodes " + nodeTot + "/" + nodeIns + ", Ways " + wayTot + "/" + wayIns + ", Relations " + relTot + "/" + relPart + "/" + relIns); } } } /* * (non-Javadoc) * * @see crosby.binary.file.BlockReaderAdapter#complete() */ @Override public void complete() { if (configuration.verbose >= 0) { System.out.println("End of document"); } } } /** * The current processed primitive */ protected Entity current = null; protected int nodeTot, nodeIns; protected int wayTot; protected int ele; protected int relTot, relPart, relIns; private long startTime; private Node previousNodeWithThisId; public OpbfParser(InputStream i) { super(i); } public OpbfParser(InputStream i, Configuration c) { super(i, c); } @Override protected String parserType() { return "Osm Pbf"; } @Override protected void init(InputStream i) { try { startTime = System.currentTimeMillis(); BlockInputStream bis = new BlockInputStream(i, new OsmPbfHandler()); if (configuration.verbose >= 0) { System.out.println("Start of Document"); System.out.println("Nodes read/used, Ways read/used, Relations read/partial/used"); } bis.process(); if (configuration.verbose >= 0) { System.out.println("Nodes " + nodeTot + "/" + nodeIns + ", Ways " + wayTot + "/" + wayIns + ", Relations " + relTot + "/" + relPart + "/" + relIns); } printMemoryUsage(2); if (configuration.verbose >= 0) { System.out.println("Parsing took " + (System.currentTimeMillis() - startTime) / 1000 + "s"); } } catch (IOException e) { System.out.println("IOException: " + e); e.printStackTrace(); /* * The planet file is presumably corrupt. So there is no point in * continuing, as it will most likely generate incorrect map data. */ System.exit(10); } catch (Exception e) { System.out.println("Other Exception: " + e); e.printStackTrace(); /* * The planet file is presumably corrupt. So there is no point in * continuing, as it will most likely generate incorrect map data. */ System.exit(10); } } }