[josm-dev] QuadBuckets in Dataset

Dave Hansen dave at sr71.net
Sat Oct 31 16:31:26 GMT 2009


On Sat, 2009-10-31 at 17:08 +0100, Jiri Klement wrote:
> > I'd just like to note that as a JOSM user I appreciated QuadBuckets
> > since I could run the Validator on large datasets for the first time
> > without JOSM taking forever (& having to be killed).
> 
> I've noticed that validator plugin is using QuadBuckets, but in my
> opinion UnconnectedWays test will miss some cases in case they're
> caused by moved nodes, because MoveCommand doesn't reindex
> QuadBuckets. Or am I missing something?

One suggestion was to use the UndoRedoHandler code to catch
modifications and reindex the primitives.  How about something like
this?

Index: src/org/openstreetmap/josm/data/UndoRedoHandler.java
===================================================================
--- src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 2355)
+++ src/org/openstreetmap/josm/data/UndoRedoHandler.java	(working copy)
@@ -3,11 +3,13 @@
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.HashSet;
 import java.util.Stack;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
@@ -38,16 +40,32 @@
     public void addNoRedraw(final Command c) {
         c.executeCommand();
         commands.add(c);
+        recordModified(c);
         redoCommands.clear();
     }
 
-    public void afterAdd() {
+    HashSet<OsmPrimitive> modifiedPrimitives = new HashSet<OsmPrimitive>();
+    void recordModified(Command c)
+    {
+        LinkedList<OsmPrimitive> deleted = new LinkedList<OsmPrimitive>();
+        LinkedList<OsmPrimitive> added = new LinkedList<OsmPrimitive>();
+        LinkedList<OsmPrimitive> modified = new LinkedList<OsmPrimitive>();
+        c.fillModifiedData(modified, deleted, added);
+        modifiedPrimitives.addAll(modified);
+    }
+    public void sendNotifications()
+    {
         if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
             OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
             data.fireDataChange();
         }
+        Main.main.getCurrentDataSet().notifyPrimitiveChange(modifiedPrimitives);
+        modifiedPrimitives.clear();
         fireCommandsChanged();
+    }
 
+    public void afterAdd() {
+        sendNotifications();
         // the command may have changed the selection so tell the listeners about the current situation
         Main.main.getCurrentDataSet().fireSelectionChanged();
     }
@@ -69,11 +87,8 @@
         final Command c = commands.removeLast();
         c.undoCommand();
         redoCommands.push(c);
-        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-            data.fireDataChange();
-        }
-        fireCommandsChanged();
+        recordModified(c);
+        sendNotifications();
         Main.main.getCurrentDataSet().setSelected();
     }
 
@@ -86,12 +101,9 @@
             return;
         final Command c = redoCommands.pop();
         c.executeCommand();
+        recordModified(c);
         commands.add(c);
-        if (Main.map != null && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer) {
-            OsmDataLayer data = (OsmDataLayer)Main.map.mapView.getActiveLayer();
-            data.fireDataChange();
-        }
-        fireCommandsChanged();
+        sendNotifications();
     }
 
     public void fireCommandsChanged() {
Index: src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 2355)
+++ src/org/openstreetmap/josm/data/osm/DataSet.java	(working copy)
@@ -645,4 +645,62 @@
         }
         return ret;
     }
+
+    List<Way> waysUsingNode(Node n)
+    {
+        List<Way> possible_ways = ways.search(n.getCoor(), 0.0);
+        List<Way> result = new ArrayList<Way>();
+        for (Way w : possible_ways) {
+            if (!w.containsNode(n))
+                continue;
+            result.add(w);
+        }
+        return result;
+    }
+
+    void reIndex(Way w)
+    {
+        ways.remove(w);
+        ways.add(w);
+    }
+
+    void reIndex(Node n)
+    {
+        nodes.remove(n);
+        nodes.add(n);
+    }
+
+    void reIndexPrimitives(Collection<OsmPrimitive> modified)
+    {
+        for (OsmPrimitive o : modified) {
+            if (o instanceof Way)
+                reIndex((Way)o);
+            if (o instanceof Node)
+                reIndex((Node)o);
+        }
+    }
+
+    /*
+     * When nodes and ways get modified, their spatial properties may
+     * change.  This means that their locations in the spatially-indexed
+     * QuadBuckets structures may change.  When this happens, delete
+     * and reinsert them.
+     */
+    public void notifyPrimitiveChange(Collection<OsmPrimitive> modified)
+    {
+        /*
+         * Make sure to reindex all the ways first.  This will
+         * make sure that waysUsingNode() can find the ways
+         * if they got changed.
+         */
+        reIndexPrimitives(modified);
+        HashSet<OsmPrimitive> waysTouchedByNodes = new HashSet<OsmPrimitive>();
+        for (OsmPrimitive o : modified) {
+            if (!(o instanceof Node))
+                continue;
+            Node n = (Node)o;
+            modified.addAll(waysUsingNode(n));
+        }
+        reIndexPrimitives(waysTouchedByNodes);
+    }
 }


-- Dave





More information about the josm-dev mailing list