Implement J for Join on selectedWayNode - joins a node to overlapping ways, and remov...
authorAndy Allan <gravitystorm@gmail.com>
Tue, 7 Dec 2010 16:46:34 +0000 (16:46 +0000)
committerAndy Allan <gravitystorm@gmail.com>
Tue, 7 Dec 2010 16:46:34 +0000 (16:46 +0000)
net/systemeD/halcyon/connection/Connection.as
net/systemeD/halcyon/connection/Node.as
net/systemeD/halcyon/connection/actions/JoinNodeAction.as [new file with mode: 0644]
net/systemeD/halcyon/connection/actions/ReplaceNodeAction.as [new file with mode: 0644]
net/systemeD/potlatch2/controller/SelectedWayNode.as

index fe5589d..45c3a0a 100644 (file)
@@ -417,6 +417,13 @@ package net.systemeD.halcyon.connection {
             return 0;
         }
 
+        public function getNodesAtPosition(lat:Number, lon:Number):Array {
+            if (nodePositions[lat+","+lon]) {
+              return nodePositions[lat+","+lon];
+            }
+            return [];
+        }
+
         // these are functions that the Connection implementation is expected to
         // provide. This class has some generic helpers for the implementation.
                public function loadBbox(left:Number, right:Number,
index 19a69b9..4044331 100644 (file)
@@ -83,6 +83,33 @@ package net.systemeD.halcyon.connection {
             }
         }
 
+        /**
+        * Insert this node into the list of ways, and remove dupes at the same time.
+        * Please, don't call this on a node from a vector background, chaos will ensue.
+        */
+        public function join(ways:Array, performAction:Function):void {
+            if (this.isDupe() || ways.length > 0) {
+              var connection:Connection = Connection.getConnection();
+              var nodes:Array = connection.getNodesAtPosition(lat,lon);
+              // filter the nodes array to remove any occurances of this.
+              // Pass "this" as thisObject to get "this" into the callback function
+              var dupes:Array = nodes.filter(
+                  function(element:*, index:int, arr:Array):Boolean {
+                    return (element != this);
+                  },
+                  this
+                );
+              performAction(new JoinNodeAction(this, dupes, ways));
+            }
+        }
+
+        /**
+        * Replace all occurances of this node with the given target node
+        */
+        public function replaceWith(target:Node, performAction:Function):void {
+            performAction(new ReplaceNodeAction(this, target));
+        }
+
         public function isDupe():Boolean {
             var connection:Connection = Connection.getConnection();
             if (connection.getNode(this.id) == this // node could be part of a vector layer
diff --git a/net/systemeD/halcyon/connection/actions/JoinNodeAction.as b/net/systemeD/halcyon/connection/actions/JoinNodeAction.as
new file mode 100644 (file)
index 0000000..85fac0f
--- /dev/null
@@ -0,0 +1,49 @@
+package net.systemeD.halcyon.connection.actions {
+
+    import net.systemeD.halcyon.connection.*;
+
+    public class JoinNodeAction extends CompositeUndoableAction {
+
+      private var node:Node;
+      private var nodes:Array;
+      private var ways:Array;
+
+      /**
+      * For the given node, replace all the given nodes with this node, and insert
+      * the given node into the list of ways.
+      */
+      public function JoinNodeAction(node:Node, nodes:Array, ways:Array) {
+          super("Join node "+node.id);
+          this.node = node;
+          this.nodes = nodes;
+          this.ways = ways;
+      }
+
+      public override function doAction():uint {
+
+          // don't insert the node into either a way that contains it already,
+          // nor a way that contains a dupe we're replacing.
+          var avoidWays:Array = node.parentWays;
+
+          for each (var dupe:Node in nodes) {
+            for each (var parentWay:Way in dupe.parentWays) {
+              avoidWays.push(parentWay);
+            }
+
+            dupe.replaceWith(node, push);
+          }
+
+          for each (var way:Way in ways) {
+            if (avoidWays.indexOf(way) == -1) {
+              way.insertNodeAtClosestPosition(node, false, push);
+            }
+          }
+          return super.doAction();
+      }
+
+      public override function undoAction():uint {
+          return super.undoAction();
+      }
+
+    }
+}
\ No newline at end of file
diff --git a/net/systemeD/halcyon/connection/actions/ReplaceNodeAction.as b/net/systemeD/halcyon/connection/actions/ReplaceNodeAction.as
new file mode 100644 (file)
index 0000000..ea1df2f
--- /dev/null
@@ -0,0 +1,51 @@
+package net.systemeD.halcyon.connection.actions {
+
+    import net.systemeD.halcyon.connection.*;
+
+    public class ReplaceNodeAction extends CompositeUndoableAction {
+
+        private var node:Node;
+        private var replacement:Node;
+
+        /**
+        * @param node The node we're getting rid of
+        * @param replacement The node we want to end up with
+        */
+        public function ReplaceNodeAction(node:Node, replacement:Node) {
+            super("Replace node "+node+" with "+replacement);
+            this.node = node;
+            this.replacement = replacement;
+        }
+
+        public override function doAction():uint {
+
+            for each (var way:Way in node.parentWays) {
+              for (var x:uint=0; x<way.length; x++) {
+                if (way.getNode(x) == node) {
+                  way.removeNodeByIndex(x, push);
+                  way.insertNode(x, replacement, push);
+                }
+              }
+            }
+
+            for each (var relation:Relation in node.parentRelations) {
+              for (var y:uint=0; y<relation.length; y++) {
+                var member:RelationMember = relation.getMember(y);
+                if (member.entity == node) {
+                  relation.removeMemberByIndex(y, push);
+                  relation.insertMember(y, new RelationMember(replacement, member.role), push);
+                }
+              }
+            }
+
+            node.remove(push);
+
+            return super.doAction();
+        }
+
+        public override function undoAction():uint {
+            return super.undoAction();
+        }
+    }
+}
+
index fff7629..f013129 100644 (file)
@@ -3,6 +3,7 @@ package net.systemeD.potlatch2.controller {
        import flash.ui.Keyboard;
        import flash.geom.Point;
     import net.systemeD.potlatch2.EditController;
+    import net.systemeD.halcyon.WayUI;
     import net.systemeD.halcyon.connection.*;
     import net.systemeD.halcyon.connection.actions.*;
        import net.systemeD.halcyon.Globals;
@@ -70,7 +71,7 @@ package net.systemeD.potlatch2.controller {
                                case 82:                                        repeatTags(firstSelected); return this; // 'R'
                                case 87:                                        return new SelectedWay(parentWay);              // 'W'
                                case 191:                                       return cycleWays();                                             // '/'
-                case 74:                    if (event.shiftKey) { return unjoin() }; return this;// 'J'
+                case 74:                    if (event.shiftKey) { return unjoin() }; return join();// 'J'
                                case Keyboard.BACKSPACE:        return deleteNode();
                                case Keyboard.DELETE:           return deleteNode();
                        }
@@ -153,5 +154,19 @@ package net.systemeD.potlatch2.controller {
             return this;
         }
 
+        public function join():ControllerState {
+            // detect the ways that overlap this node
+            var p:Point = new Point(controller.map.lon2coord(Node(firstSelected).lon),
+                                             controller.map.latp2coord(Node(firstSelected).latp));
+            var q:Point = map.localToGlobal(p);
+            var ways:Array=[]; var w:Way;
+            for each (var wayui:WayUI in controller.map.paint.wayuis) {
+                w=wayui.hitTest(q.x, q.y);
+                if (w && w!=selectedWay) { ways.push(w); }
+            }
+
+            Node(firstSelected).join(ways,MainUndoStack.getGlobalStack().addAction);
+            return this;
+        }
     }
 }