ADD getNextNode(), getPrevNode() to net/systemeD/halcyon/connection/Way.as. These...
authorSteve Bennett <stevagewp@gmail.com>
Wed, 26 Jan 2011 11:56:53 +0000 (11:56 +0000)
committerSteve Bennett <stevagewp@gmail.com>
Wed, 26 Jan 2011 11:56:53 +0000 (11:56 +0000)
ADD followWay() to net/systemeD/potlatch2/controller/DrawWay.as. A new way to draw a way, by following an existing way. This is useful for making two areas touch each other exactly, or for a road to partially run along a border, or whatever local mapping practice dictates. Press "F" to use it.

TODO better user feedback on Follow, documenting it in user instructions, verifying correctness of getNextNode/getPrevNode.

net/systemeD/halcyon/connection/Way.as
net/systemeD/potlatch2/controller/DrawWay.as

index 6a8aa59..72fcc47 100644 (file)
@@ -1,7 +1,7 @@
 package net.systemeD.halcyon.connection {
     import flash.geom.Point;
 package net.systemeD.halcyon.connection {
     import flash.geom.Point;
-       import net.systemeD.halcyon.Globals;
-       import net.systemeD.halcyon.connection.actions.*;
+    
+    import net.systemeD.halcyon.connection.actions.*;
 
     public class Way extends Entity {
         private var nodes:Array;
 
     public class Way extends Entity {
         private var nodes:Array;
@@ -59,6 +59,29 @@ package net.systemeD.halcyon.connection {
                public function getLastNode():Node {
                        return nodes[nodes.length-1];
                }
                public function getLastNode():Node {
                        return nodes[nodes.length-1];
                }
+               
+               /** Given one node, return the next in sequence, cycling around a loop if necessary. */
+               // TODO make behave correctly for P-shaped topologies?
+               public function getNextNode(node:Node):Node {
+                       // If the last node in a loop is selected, this behaves correctly.
+                   var i:uint = indexOfNode(node);
+                   if(i < length-1)
+                   return nodes[i+1];
+               return null;
+               // What should happen for very short lengths?      
+               }
+        
+        // TODO make behave correctly for P-shaped topologies?
+        /** Given one node, return the previous, cycling around a loop if necessary. */
+        public function getPrevNode(node:Node):Node {
+            var i:uint = indexOfNode(node);
+            if(i > 0)
+                return nodes[i-1];
+            if(i == 0 && isArea() )
+                return nodes[nodes.length - 2]
+            return null;
+            // What should happen for very short lengths?      
+        }
 
         public function insertNode(index:uint, node:Node, performAction:Function):void {
                        performAction(new AddNodeToWayAction(this, node, nodes, index));
 
         public function insertNode(index:uint, node:Node, performAction:Function):void {
                        performAction(new AddNodeToWayAction(this, node, nodes, index));
index 5156736..e9f78ca 100644 (file)
@@ -171,6 +171,7 @@ package net.systemeD.potlatch2.controller {
                                case Keyboard.BACKSPACE:        
                                case 189: /* minus */       return backspaceNode(MainUndoStack.getGlobalStack().addAction);
                                case 82: /* R */            repeatTags(firstSelected); return this;
                                case Keyboard.BACKSPACE:        
                                case 189: /* minus */       return backspaceNode(MainUndoStack.getGlobalStack().addAction);
                                case 82: /* R */            repeatTags(firstSelected); return this;
+                               case 70: /* F */            followWay(); return this;
                        }
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
                        }
                        var cs:ControllerState = sharedKeyboardEvents(event);
                        return cs ? cs : this;
@@ -261,6 +262,75 @@ package net.systemeD.potlatch2.controller {
             return state;
                }
                
             return state;
                }
                
+               /** Extends the current way by "following" an existing way, after the user has already selected two nodes in a row. */
+               protected function followWay() {
+                       // TODO add a bit of feedback when following can't be carried out for some reason. 
+                       // Perhaps use the new FloatingAlert that I couldn't figure out how to use 
+                       
+                 /*
+                 If drawing way has at least two nodes
+                 and both belong to another way
+                 and those ways are the same
+                 then find the next node
+                 then add that node
+                 then update screen and scroll the new node into shot if necessary */
+                 var curnode:Node;
+                 var prevnode:Node;
+                 if (Way(firstSelected).length < 2) {
+                     return;
+                 }
+                 if (editEnd) {
+                       curnode = Way(firstSelected).getLastNode();
+                       prevnode = Way(firstSelected).getNode(Way(firstSelected).length-2);
+                 } else {
+            curnode = Way(firstSelected).getNode(0);
+            prevnode = Way(firstSelected).getNode(1);
+               
+                 }
+                 if (curnode.numParentWays <2 || prevnode.numParentWays <2) 
+                     return;
+                 var followedWay:Way = null;
+                 for (var i in curnode.parentWays) {
+                       if (curnode.parentWays[i]!=firstSelected && prevnode.hasParent(curnode.parentWays[i])) {
+                               // Could be slightly smarter when there are more than one candidate. Perhaps could see which
+                               // of the 2+ ways is the most colinear with the currently drawn way.
+                               followedWay = curnode.parentWays[i];
+                       }
+                 }
+                 if (!followedWay)
+                     return;
+                 var nextNode:Node;
+          if (followedWay.getNextNode(prevnode) == curnode) {
+              nextNode = followedWay.getNextNode(curnode);
+          } else if (followedWay.getNextNode(curnode) == prevnode){
+              nextNode = followedWay.getPrevNode(curnode);
+          } else // The two nodes selected aren't actually consecutive. Make a half-hearted
+                 // guess at which way to follow. Will be "incorrect" if the join in the loop
+                 // is between the two points. 
+            if (followedWay.indexOfNode(curnode) > followedWay.indexOfNode(prevnode)) {
+              nextNode = followedWay.getNextNode(curnode);
+            } else {
+              nextNode = followedWay.getPrevNode(curnode);
+            }
+          if (!nextNode) return;
+          if (nextNode.hasParent(firstSelected))
+            return;
+          
+          appendNode(nextNode as Node, MainUndoStack.getGlobalStack().addAction);
+          resetElastic(nextNode as Node);
+          lastClick=nextNode;
+          controller.map.setHighlight(nextNode, { selectedway: true });
+          
+          // recentre the map if the new lat/lon is offscreen
+          if (nextNode.lat > controller.map.edge_t ||
+              nextNode.lat < controller.map.edge_b ||  
+              nextNode.lon < controller.map.edge_l ||
+              nextNode.lon > controller.map.edge_r) {
+               
+            controller.map.moveMapFromLatLon(nextNode.lat, nextNode.lon);
+          }
+               }
+               
                override public function enterState():void {
                        super.enterState();
                        
                override public function enterState():void {
                        super.enterState();