/** * 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) 2007 Harald Mueller * Copyright (C) 2007, 2008 Kai Krueger */ package net.sharenav.osmToShareNav; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import net.sharenav.osmToShareNav.model.Hash; import net.sharenav.osmToShareNav.model.Node; import net.sharenav.osmToShareNav.model.Storage; import net.sharenav.osmToShareNav.model.Way; /** * @author hmueller * */ public class CleanUpData { private final OsmParser parser; private final Configuration conf; private HashMap<Node,Node> replaceNodes = new HashMap<Node,Node>(); public CleanUpData(OsmParser parser, Configuration conf) { this.parser = parser; this.conf = conf; removeEmptyWays(); removeDupNodes(); removeUnusedNodes(); parser.dropHashMap(); parser.resize(); if (conf.verbose >= 0) { System.out.println("Remaining after cleanup:"); System.out.println(" Nodes: " + parser.getNodes().size()); System.out.println(" Ways: " + parser.getWays().size()); System.out.println(" Relations: " + parser.getRelations().size()); } } private static class NodeHash implements Hash<Node, Node> { /* (non-Javadoc) * @see net.sharenav.osmToShareNav.model.Hash#equals(java.lang.Object, java.lang.Object) */ @Override public boolean equals(Node k, Node t) { return k.lat == t.lat && k.lon == t.lon; } /* (non-Javadoc) * @see net.sharenav.osmToShareNav.model.Hash#getHashCode(java.lang.Object) */ @Override public int getHashCode(Node k) { return Float.floatToIntBits(k.lat) + Float.floatToIntBits(k.lon); } } private static class NodeHash2 implements Hash<Node, Node> { /* (non-Javadoc) * @see net.sharenav.osmToShareNav.model.Hash#equals(java.lang.Object, java.lang.Object) */ @Override public boolean equals(Node k, Node t) { return k.lat == t.lat && k.lon == t.lon && k.getType(Configuration.getConfiguration()) == t.getType(Configuration.getConfiguration()); } /* (non-Javadoc) * @see net.sharenav.osmToShareNav.model.Hash#getHashCode(java.lang.Object) */ @Override public int getHashCode(Node k) { return Float.floatToIntBits(k.lat) + Float.floatToIntBits(k.lon) + k.getType(Configuration.getConfiguration()); } } /** * */ private void removeDupNodes() { int progressCounter = 0; int duplicates = 0; int noNodes = parser.getNodes().size() / 20; Storage<Node> nodes = new Storage<Node>(new NodeHash()); Storage<Node> nodesReEnabled = new Storage<Node>(new NodeHash2()); if (conf.verbose >= 0) { System.out.println("PLEASE HELP and fix reported duplicates in OpenStreetMap"); } long startTime = System.currentTimeMillis(); int iReSetToUsed = 0; for (Node n : parser.getNodes()) { progressCounter++; if (noNodes > 0 && progressCounter % noNodes == 0) { if (conf.verbose >= 0) { System.out.println("Processed " + progressCounter + " of " + noNodes * 20 + " nodes, " + duplicates + " duplicates found"); } } n.used = true; //latlonKey = MyMath.latlon2XYZ(n); if (!nodes.add(n)) { duplicates++; n.used = false; Node rn = nodes.get(n); Node nReEnabled = nodesReEnabled.get(n); if (n.getType(conf) != rn.getType(conf) && nReEnabled == null) { System.out.println("Differing duplicate nodes: " + n + " / " + rn); System.out.println(" Detail URL: " + n.toUrl()); // Shouldn't substitute in this case; n.used = true; nodesReEnabled.put(n); iReSetToUsed++; } else { if (nReEnabled != null) { // A node of same position and type is in the list // of re enabled nodes. Substitude with this node later. //System.out.println("In re enabled: " + n); replaceNodes.put(n, nReEnabled); } else { replaceNodes.put(n, rn); } } } } Iterator<Node> it = parser.getNodes().iterator(); int rm = 0; while (it.hasNext()) { Node n = it.next(); if (n.used == false) { it.remove(); rm++; } } substitute(); long time = (System.currentTimeMillis() - startTime); if (conf.verbose >= 0) { System.out.println("Removed " + rm + " duplicate nodes, took " + time + " ms, reset to used " + iReSetToUsed); } } /** * Replaces all duplicate nodes in the ways which use them. * Uses the replaceNodes HashMap for this. */ private boolean substitute() { for (Way w:parser.getWays()) { w.replace(replaceNodes); } return true; } private void removeEmptyWays() { /** * At this point, the area triangulation should have happened * that might reference empty ways. Also the tag information for * area POIs (whos ways has no type) should have been copied over too. * So it should be safe to remove all ways (and in the second step free the nodes) * of ways that have no type. This can save quite a lot of memory depending on style-file */ ArrayList<Way> rmWays = new ArrayList<Way>(); for (Way w : parser.getWays()) { if (w.getType(conf) < 0) { rmWays.add(w); } } for (Way w : rmWays) { parser.removeWay(w); } } /** * */ private void removeUnusedNodes() { long startTime = System.currentTimeMillis(); for (Node n:parser.getNodes()) { if (n.getType(conf) < 0 ) { n.used = false; } else { n.used = true; } } for (Way w:parser.getWays()){ for (Node n:w.getNodes()) { n.used = true; } } ArrayList<Node> rmNodes = new ArrayList<Node>(); for (Node n:parser.getNodes()) { if (n.used == false) { rmNodes.add(n); } } parser.removeNodes(rmNodes); long time = (System.currentTimeMillis() - startTime); if (conf.verbose >= 0) { System.out.println("Removed " + rmNodes.size() + " unused nodes, took " + time + " ms"); } } }