Core reverse lookup code for caching the results of reverse-lookup operations.
--- core-dave/src/org/openstreetmap/josm/data/osm/DataSet.java | 3 core-dave/src/org/openstreetmap/josm/tools/ReverseLookup.java | 236 ++++++++++ 2 files changed, 239 insertions(+) diff -puN src/org/openstreetmap/josm/data/osm/DataSet.java~reverselookup src/org/openstreetmap/josm/data/osm/DataSet.java --- core/src/org/openstreetmap/josm/data/osm/DataSet.java~reverselookup 2008-04-28 18:59:24.000000000 -0700 +++ core-dave/src/org/openstreetmap/josm/data/osm/DataSet.java 2008-04-28 18:59:24.000000000 -0700 @@ -9,6 +9,7 @@ import java.util.LinkedList; import java.util.List; import org.openstreetmap.josm.data.SelectionChangedListener; +import org.openstreetmap.josm.tools.ReverseLookup; /** * DataSet is the data behind the application. It can consists of only a few @@ -202,4 +203,6 @@ public class DataSet implements Cloneabl ds.dataSources.add(new DataSource(source.bounds, source.origin)); return ds; } + + public ReverseLookup rl = new ReverseLookup(this); } diff -puN src/org/openstreetmap/josm/tools/ReverseLookup.java~reverselookup src/org/openstreetmap/josm/tools/ReverseLookup.java --- core/src/org/openstreetmap/josm/tools/ReverseLookup.java~reverselookup 2008-04-28 18:59:24.000000000 -0700 +++ core-dave/src/org/openstreetmap/josm/tools/ReverseLookup.java 2008-04-28 18:59:24.000000000 -0700 @@ -0,0 +1,236 @@ +// License: GPL. Copyright 2007 by Immanuel Scholz and others +package org.openstreetmap.josm.tools; + +import java.util.*; + +import org.openstreetmap.josm.Main; +import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor; +import org.openstreetmap.josm.data.osm.*; + + +public class ReverseLookup { + private HashMap<Node,List<Way>> waysUsingNodeCache = null; + private int misses = 0; + private int hits = 0; + private DataSet ds; + + static boolean debug = false; + static int nr = 0; + int thisnr; + public ReverseLookup(DataSet set) + { + this.ds = set; + thisnr = nr++; + } + public List<Way> slowWaysUsingNode(Node n) + { + List<Way> ways = new ArrayList<Way>(); + CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(ds, false); + n.visit(v); + for (OsmPrimitive ref : v.data) { + if (ref instanceof Way) + ways.add((Way)ref); + } + return ways; + } + + static String pref() { + String p = Main.pref.get("reverse-lookup"); + // for debugging // p = "never"; + if (p.length() == 0) + p = "cache"; + return p; + } + boolean enabled = true; + + static boolean pref_disabled() { + return pref().equals("never"); + } + static boolean pref_always() { + return pref().equals("always"); + } + static boolean pref_can_cache() { + if (pref_always()) + return true; + return pref().equals("cache"); + } + boolean can_cache() { + if (!enabled) + return false; + return pref_can_cache(); + } + boolean always() { + if (!enabled) + return false; + return pref_always(); + } + boolean disabled() { + if (!enabled) + return true; + return pref_disabled(); + } + public void disable() { + enabled = false; + waysUsingNodeCache = null; + } + public void enable() { + enabled = true; + } + private void enable_cache() + { + if (waysUsingNodeCache == null) + waysUsingNodeCache = new HashMap<Node,List<Way>>(); + } + private List<Way> fastWaysUsingNode(Node n) + { + //Main.debug(this.thisnr + " fastWaysUsingNode("+n.hashCode()+")"); + boolean debugme = false; + if (debugme) { + int i=0; + List<Way> wl; + for (Node ntmp : waysUsingNodeCache.keySet()) { + wl = waysUsingNodeCache.get(ntmp); + Main.debug("key nr: " + i + ": " + ntmp.hashCode() + + " wl: " + wl + "ntmp == n : " + (n == ntmp)); + i++; + } + } + + if (disabled()) { + //Main.debug("disabled, skipping out of fastWaysUsingNode()"); + return null; + } + List<Way> ways = waysUsingNodeCache.get(n); + if ((hits+misses+1)%10000 == 0) + Main.debug("fastWaysUsingNode("+pref()+":"+pref_always()+") hits: " + hits + " misses: " + misses); + if (ways == null) { + //Main.debug("missed"); + misses++; + return null; + } + //Main.debug("hit"); + hits++; + return ways; + } + + public void check(Node n) + { + if (true) + return; + if (disabled()) + return; + List<Way> ways = fastWaysUsingNode(n); + int cs = ways.size(); + int ss = slowWaysUsingNode(n).size(); + if (cs == ss) + return; + + Main.debug("waysUsingNodeCreate("+n.id+") cached nr != slow nr: "+cs+"/"+ss); + for (Way w : ways) { + System.out.print("cached way: " + w.id + " ["); + for (Node nn : w.nodes) + System.out.print(nn.id + ", "); + Main.debug("]"); + } + for (Way w : slowWaysUsingNode(n)) { + System.out.print("slow way: " + w.id + " ["); + for (Node nn : w.nodes) + System.out.print(nn.id + ", "); + Main.debug("]"); + } + throw new ArithmeticException(); + } + + private List<Way> waysUsingNodeCreate(Node n) + { + if (can_cache()) + enable_cache(); + List<Way> ways = fastWaysUsingNode(n); + if (ways != null) + return ways; + //Main.debug("waysUsingNodeCreate("+n.hashCode()+") first touch, always: " + always()); + // This is the first call for this particular node + // so don't even bother with the slow path, and assume + // this is a new node touching no ways, yet. + if (always()) + ways = new ArrayList<Way>(); + else + ways = slowWaysUsingNode(n); + + if (can_cache()) { + //Main.debug("about to put this: " + ways + " in place of this: " + + // waysUsingNodeCache.get(n)); + waysUsingNodeCache.put(n, ways); + } + return ways; + } + public List<Way> waysUsingNode(Node n) + { + List<Way> ways = waysUsingNodeCreate(n); + return Collections.unmodifiableList(ways); + } + + public static HashSet<Relation> relationsUsingWays(List<Way> selectedWays) { + HashSet<Relation> relationsUsingWays = new HashSet<Relation>(); + for (Relation r : Main.ds.relations) { + if (r.deleted || r.incomplete) + continue; + for (RelationMember rm : r.members) { + if (!(rm.member instanceof Way)) + continue; + for(Way w : selectedWays) { + if (rm.member != w) + continue; + relationsUsingWays.add(r); + } + } + } + return relationsUsingWays; + } + public void addWayToNodeMap(Collection<Node> nodes, Way w) + { + for (Node n : nodes) + addWayToNodeMap(n, w); + for (Node n : nodes) + check(n); + } + public void removeWayFromNodeMap(Collection<Node> nodes, Way w) + { + for (Node n : nodes) + removeWayFromNodeMap_nocheck(n, w); + for (Node n : nodes) + check(n); + } + public void addWayToNodeMap_nocheck(Node n, Way w) + { + List<Way> ways = waysUsingNodeCreate(n); + if (can_cache() && !ways.contains(w)) { + ways.add(w); + //Main.debug("addWaysToNodeMap("+n.hashCode() + ", " +w.hashCode()+") ways size:" + ways.size()); + } + } + public void removeWayFromNodeMap_nocheck(Node n, Way w) + { + List<Way> ways = waysUsingNodeCreate(n); + if (can_cache()) { + //in.debug("removeWaysFromNodeMap("+n.hashCode() + ", " +w.hashCode()+") ways size:" + ways.size()); + ways.remove(w); + } + } + public void addWayToNodeMap(Node n, Way w) + { + addWayToNodeMap_nocheck(n, w); + check(n); + } + public void removeWayFromNodeMap(Node n, Way w) + { + removeWayFromNodeMap_nocheck(n, w); + check(n); + } + public void removeWay(Way w) + { + for (Node n : w.nodes) + removeWayFromNodeMap(n, w); + } +} + _ _______________________________________________ josm-dev mailing list josm-dev@openstreetmap.org http://lists.openstreetmap.org/cgi-bin/mailman/listinfo/josm-dev