create new ways w00t! and extend old ones
authorDave Stubbs <osm@randomjunk.co.uk>
Sun, 6 Sep 2009 15:30:44 +0000 (15:30 +0000)
committerDave Stubbs <osm@randomjunk.co.uk>
Sun, 6 Sep 2009 15:30:44 +0000 (15:30 +0000)
net/systemeD/halcyon/Elastic.as [new file with mode: 0755]
net/systemeD/halcyon/connection/Node.as
net/systemeD/halcyon/connection/Way.as
net/systemeD/halcyon/connection/XMLConnection.as
net/systemeD/potlatch2/EditController.as
net/systemeD/potlatch2/controller/ControllerState.as
net/systemeD/potlatch2/controller/CreateWay.as [new file with mode: 0644]
net/systemeD/potlatch2/controller/DrawWay.as [new file with mode: 0644]
net/systemeD/potlatch2/controller/NoSelection.as
net/systemeD/potlatch2/controller/SelectedWay.as

diff --git a/net/systemeD/halcyon/Elastic.as b/net/systemeD/halcyon/Elastic.as
new file mode 100755 (executable)
index 0000000..c7cdfa0
--- /dev/null
@@ -0,0 +1,153 @@
+package net.systemeD.halcyon {
+
+       import flash.display.*;
+       import flash.geom.Matrix;
+       import flash.geom.Point;
+       import flash.geom.Rectangle;
+       import flash.text.AntiAliasType;
+       import flash.text.GridFitType;
+       import flash.text.TextField;
+       import flash.text.TextFormat;
+       import flash.events.*;
+       import net.systemeD.halcyon.styleparser.*;
+    import net.systemeD.halcyon.connection.*;
+
+       public class Elastic {
+
+               public var map:Map;                                                     // reference to parent map
+               public var sprites:Array=new Array();           // instances in display list
+        private var _start:Point;
+        private var _end:Point;
+
+               public function Elastic(map:Map, start:Point, end:Point) {
+                       this.map = map;
+                       this._start = start;
+                       this._end = end;
+                       redraw();
+               }
+               
+               public function set start(start:Point):void {
+                   this._start = start;
+                   redraw();
+               }
+
+               public function set end(end:Point):void {
+                   this._end = end;
+                   redraw();
+               }
+               
+               public function get start():Point {
+                   return _start;
+               }
+               
+               public function get end():Point {
+                   return _end;
+               }
+               
+               public function removeSprites():void {
+                       // Remove all currently existing sprites
+                       while (sprites.length>0) {
+                               var d:DisplayObject=sprites.pop(); d.parent.removeChild(d);
+                       }
+        }
+        
+               public function redraw():void {
+                   removeSprites();
+
+                       // Iterate through each sublayer, drawing any styles on that layer
+                       var p0:Point = start;
+                       var p1:Point = end;
+
+                       // Create stroke object
+                       var stroke:Shape = new Shape();
+            stroke.graphics.lineStyle(1, 0xff0000, 1, false, "normal", CapsStyle.ROUND, JointStyle.ROUND);
+                       addToLayer(stroke,2);
+                       dashedLine(stroke.graphics, [2,2]);
+                       
+                       var nodes:Sprite = new Sprite();
+            drawNodes(nodes.graphics);
+            addToLayer(nodes, 2);
+
+               }
+               
+               // ------------------------------------------------------------------------------------------
+               // Drawing support functions
+
+               private function drawNodes(g:Graphics):void {
+            g.lineStyle(1, 0xff0000, 1, false, "normal", CapsStyle.ROUND, JointStyle.ROUND);
+                       for (var i:uint = 0; i < 1; i++) {
+                var p:Point = i == 0 ? start : end;
+                var x:Number = map.lon2coord(p.x);
+                var y:Number = map.latp2coord(p.y);
+                g.moveTo(x-2, y-2);
+                g.lineTo(x+2, y-2);
+                g.lineTo(x+2, y+2);
+                g.lineTo(x-2, y+2);
+                g.lineTo(x-2, y-2);
+                       }
+               }
+
+               // Draw dashed polyline
+               
+               private function dashedLine(g:Graphics,dashes:Array):void {
+                       var draw:Boolean=false, dashleft:Number=0, dc:Array=new Array();
+                       var a:Number, xc:Number, yc:Number;
+                       var curx:Number, cury:Number;
+                       var dx:Number, dy:Number, segleft:Number=0;
+                       var i:int=0;
+
+            var p0:Point = start;
+            var p1:Point = end;
+                       g.moveTo(map.lon2coord(p0.x), map.latp2coord(p0.y));
+                       while (i < 1 || segleft>0) {
+                               if (dashleft<=0) {      // should be ==0
+                                       if (dc.length==0) { dc=dashes.slice(0); }
+                                       dashleft=dc.shift();
+                                       draw=!draw;
+                               }
+                               if (segleft<=0) {       // should be ==0
+                                       curx=map.lon2coord(p0.x);
+                    dx=map.lon2coord(p1.x)-curx;
+                                       cury=map.latp2coord(p0.y);
+                    dy=map.latp2coord(p1.y)-cury;
+                                       a=Math.atan2(dy,dx); xc=Math.cos(a); yc=Math.sin(a);
+                                       segleft=Math.sqrt(dx*dx+dy*dy);
+                                       i++;
+                               }
+
+                               if (segleft<=dashleft) {
+                                       // the path segment is shorter than the dash
+                                       curx+=dx; cury+=dy;
+                                       moveLine(g,curx,cury,draw);
+                                       dashleft-=segleft; segleft=0;
+                               } else {
+                                       // the path segment is longer than the dash
+                                       curx+=dashleft*xc; dx-=dashleft*xc;
+                                       cury+=dashleft*yc; dy-=dashleft*yc;
+                                       moveLine(g,curx,cury,draw);
+                                       segleft-=dashleft; dashleft=0;
+                               }
+                       }
+               }
+
+               private function moveLine(g:Graphics,x:Number,y:Number,draw:Boolean):void {
+                       if (draw) { g.lineTo(x,y); }
+                                else { g.moveTo(x,y); }
+               }
+
+               
+               // Add object (stroke/fill/roadname) to layer sprite
+               
+               private function addToLayer(s:DisplayObject,t:uint,sublayer:int=-1):void {
+                       var l:DisplayObject=Map(map).getChildAt(5);
+                       var o:DisplayObject=Sprite(l).getChildAt(t);
+                       if (sublayer!=-1) { o=Sprite(o).getChildAt(sublayer); }
+                       Sprite(o).addChild(s);
+                       sprites.push(s);
+            if ( s is Sprite ) {
+                Sprite(s).mouseEnabled = false;
+                Sprite(s).mouseChildren = false;
+            }
+               }
+       }
+}
index 7510462..ef75101 100644 (file)
@@ -59,7 +59,7 @@ package net.systemeD.halcyon.connection {
             return 180/Math.PI * Math.log(Math.tan(Math.PI/4+lat*(Math.PI/180)/2));
         }
 
-               public function latp2lat(a:Number):Number {
+               public static function latp2lat(a:Number):Number {
                    return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2);
                }
                
index 0dec6af..9604dae 100644 (file)
@@ -40,6 +40,10 @@ package net.systemeD.halcyon.connection {
             dispatchEvent(new WayNodeEvent(Connection.WAY_NODE_ADDED, node, this, nodes.length - 1));
             return nodes.length;
         }
+        
+        public function indexOfNode(node:Node):uint {
+            return nodes.indexOf(node);
+        }
 
         public function removeNode(index:uint):void {
             var removed:Array=nodes.splice(index, 1);
index 4c1155b..3d60345 100644 (file)
@@ -77,6 +77,16 @@ package net.systemeD.halcyon.connection {
                     setWay(new Way(id, version, tags,true,  nodes));
                 }
             }
+            
+            registerPOINodes();
+        }
+        
+        protected function registerPOINodes():void {
+            for each (var nodeID:Number in getAllNodeIDs()) {
+                var node:Node = getNode(nodeID);
+                if ( node.parentWays.length == 0 )
+                    registerPOI(node);
+            }
         }
 
         protected var appID:OAuthConsumer;
index fcab341..fa903c6 100644 (file)
@@ -28,6 +28,7 @@ package net.systemeD.potlatch2 {
             map.parent.addEventListener(MouseEvent.MOUSE_UP, mapMouseEvent);
             map.parent.addEventListener(MouseEvent.MOUSE_DOWN, mapMouseEvent);
             map.parent.addEventListener(MouseEvent.CLICK, mapMouseEvent);
+            map.parent.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
         }
 
         public function setActive():void {
@@ -47,45 +48,30 @@ package net.systemeD.potlatch2 {
             tagViewer.setEntity(entity);
         }
         
+        private function keyUpHandler(event:KeyboardEvent):void {
+            trace("key code "+event.keyCode);
+            var newState:ControllerState = state.processKeyboardEvent(event);
+            setState(newState);            
+               }
+
         private function mapMouseEvent(event:MouseEvent):void {
+            map.stage.focus = map.parent;
+            
             var mapLoc:Point = map.globalToLocal(new Point(event.stageX, event.stageY));
             event.localX = mapLoc.x;
             event.localY = mapLoc.y;
 
             var newState:ControllerState = state.processMouseEvent(event, null);
             setState(newState);
-            if ( draggingNode != null ) {
-            }
         }
         
         public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
+            map.stage.focus = map.parent;
             //if ( event.type == MouseEvent.MOUSE_DOWN )
-                event.stopPropagation();
+            event.stopPropagation();
                 
             var newState:ControllerState = state.processMouseEvent(event, entity);
             setState(newState);
-
-            /*
-            if ( entity is Node || draggingNode != null ) {
-                processNodeEvent(event, entity);
-            } else if ( enity is Way ) {
-                processWayEvent(event, entity);
-            }
-            
-            if ( event.type == MouseEvent.CLICK ) {
-                if ( selectedWay != null ) {
-                    map.setHighlight(selectedWay, "selected", false);
-                    map.setHighlight(selectedWay, "showNodes", false);
-                }
-                tagViewer.setEntity(entity);
-                map.setHighlight(entity, "selected", true);
-                map.setHighlight(entity, "showNodes", true);
-                selectedWay = entity;
-            } else if ( event.type == MouseEvent.MOUSE_OVER )
-                map.setHighlight(entity, "hover", true);
-            else if ( event.type == MouseEvent.MOUSE_OUT )
-                map.setHighlight(entity, "hover", false);
-            */
         }
         
         private function setState(newState:ControllerState):void {
index 286cd54..fa1b0d5 100644 (file)
@@ -23,6 +23,10 @@ package net.systemeD.potlatch2.controller {
             return this;
         }
         
+        public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
+            return this;
+        }
+        
         public function enterState():void {}
         public function exitState():void {}
 
diff --git a/net/systemeD/potlatch2/controller/CreateWay.as b/net/systemeD/potlatch2/controller/CreateWay.as
new file mode 100644 (file)
index 0000000..ccc43bc
--- /dev/null
@@ -0,0 +1,64 @@
+package net.systemeD.potlatch2.controller {
+       import flash.events.*;
+       import flash.geom.*;
+    import net.systemeD.potlatch2.EditController;
+    import net.systemeD.halcyon.connection.*;
+    import net.systemeD.halcyon.Elastic;
+
+    public class CreateWay extends ControllerState {
+        private var start:Point;
+        private var mouse:Point;
+        private var elastic:Elastic;
+        
+        public function CreateWay(event:MouseEvent) {
+            start = new Point(event.localX, event.localY);
+            mouse = new Point(event.localX, event.localY);
+        }
+        
+        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
+            var focus:Entity = NoSelection.getTopLevelFocusEntity(entity);
+            if ( event.type == MouseEvent.CLICK ) {
+                if ( focus == null ) {
+                    var lat:Number = controller.map.coord2lat(event.localY);
+                    var lon:Number = controller.map.coord2lon(event.localX);
+                    var endNode:Node = controller.connection.createNode({}, lat, lon);
+                    
+                    lat = Node.latp2lat(start.y);
+                    lon = start.x;
+                    var startNode:Node = controller.connection.createNode({}, lat, lon);
+                    
+                    var way:Way = controller.connection.createWay({}, [startNode, endNode]);
+                    return new DrawWay(way, true);
+                }
+            } else if ( event.type == MouseEvent.MOUSE_MOVE ) {
+                mouse = new Point(
+                          controller.map.coord2lon(event.localX),
+                          controller.map.coord2latp(event.localY));
+                elastic.end = mouse;
+            }
+
+            return this;
+        }
+
+        override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
+            if ( event.keyCode == 27 )
+                return new NoSelection();
+            return this;
+        }
+
+        override public function enterState():void {
+            // transform points
+            start.x = controller.map.coord2lon(start.x);
+            start.y = controller.map.coord2latp(start.y);
+            mouse.x = controller.map.coord2lon(mouse.x);
+            mouse.y = controller.map.coord2latp(mouse.y);
+            
+            elastic = new Elastic(controller.map, start, mouse);
+        }
+        
+        override public function exitState():void {
+            elastic.removeSprites();
+            elastic = null;
+        }
+    }
+}
diff --git a/net/systemeD/potlatch2/controller/DrawWay.as b/net/systemeD/potlatch2/controller/DrawWay.as
new file mode 100644 (file)
index 0000000..4c1a412
--- /dev/null
@@ -0,0 +1,83 @@
+package net.systemeD.potlatch2.controller {
+       import flash.events.*;
+       import flash.geom.*;
+    import net.systemeD.potlatch2.EditController;
+    import net.systemeD.halcyon.connection.*;
+    import net.systemeD.halcyon.Elastic;
+
+    public class DrawWay extends SelectedWay {
+        private var elastic:Elastic;
+        private var editEnd:Boolean;
+        
+        public function DrawWay(way:Way, editEnd:Boolean) {
+            super(way);
+            
+            this.editEnd = editEnd;
+        }
+        
+        override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
+            var mouse:Point;
+            var node:Node;
+            var focus:Entity = NoSelection.getTopLevelFocusEntity(entity);
+            if ( event.type == MouseEvent.CLICK ) {
+                if ( focus == null ) {
+                    node = createAndAddNode(event);
+                    resetElastic(node);
+                } else if ( focus is Node ) {
+                    appendNode(focus as Node);
+                } else if ( focus is Way ) {
+                    node = createAndAddNode(event);
+                    Way(focus).insertNodeAtClosestPosition(node, true);
+                    resetElastic(node);
+                }
+            } else if ( event.type == MouseEvent.MOUSE_MOVE ) {
+                mouse = new Point(
+                          controller.map.coord2lon(event.localX),
+                          controller.map.coord2latp(event.localY));
+                elastic.end = mouse;
+            }
+
+            return this;
+        }
+        
+        protected function resetElastic(node:Node):void {
+            var mouse:Point = new Point(node.lon, node.latp);
+            elastic.start = mouse;
+            elastic.end = mouse;
+        }
+
+        override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
+            if ( event.keyCode == 13 || event.keyCode == 27 )
+                return new SelectedWay(selectedWay);
+            return this;
+        }
+
+        public function createAndAddNode(event:MouseEvent):Node {
+            var lat:Number = controller.map.coord2lat(event.localY);
+            var lon:Number = controller.map.coord2lon(event.localX);
+            var node:Node = controller.connection.createNode({}, lat, lon);
+            appendNode(node);
+            return node;
+        }
+        
+        protected function appendNode(node:Node):void {
+            if ( editEnd )
+                selectedWay.appendNode(node);
+            else
+                selectedWay.insertNode(0, node);
+        }
+        
+        override public function enterState():void {
+            super.enterState();
+            
+            var node:Node = selectedWay.getNode(editEnd ? selectedWay.length - 1 : 0);
+            var start:Point = new Point(node.lon, node.latp);
+            elastic = new Elastic(controller.map, start, start);
+        }
+        override public function exitState():void {
+            super.exitState();
+            elastic.removeSprites();
+            elastic = null;
+        }
+    }
+}
index 2de2e21..32e26a8 100644 (file)
@@ -14,6 +14,8 @@ package net.systemeD.potlatch2.controller {
                     return new SelectedWay(focus as Way);
                 else if ( focus is Node )
                     trace("select poi");
+                else if ( focus == null )
+                    return new CreateWay(event);
             else if ( event.type == MouseEvent.MOUSE_OVER )
                 controller.map.setHighlight(focus, "hover", true);
             else if ( event.type == MouseEvent.MOUSE_OUT )
index 1af1a55..0dfe13b 100644 (file)
@@ -4,8 +4,9 @@ package net.systemeD.potlatch2.controller {
     import net.systemeD.halcyon.connection.*;
 
     public class SelectedWay extends ControllerState {
-        private var selectedWay:Way;
-        private var initWay:Way;
+        protected var selectedWay:Way;
+        protected var selectedNode:Node;
+        protected var initWay:Way;
         
         public function SelectedWay(way:Way) {
             initWay = way;
@@ -22,7 +23,24 @@ package net.systemeD.potlatch2.controller {
             selectedWay = way;
             initWay = way;
         }
-        
+
+        protected function selectNode(node:Node):void {
+            if ( node == selectedNode )
+                return;
+            
+            clearSelectedNode();
+            controller.setTagViewer(node);
+            controller.map.setHighlight(node, "selected", true);
+            selectedNode = node;
+        }
+                
+        protected function clearSelectedNode():void {
+            if ( selectedNode != null ) {
+                controller.map.setHighlight(selectedNode, "selected", false);
+                controller.setTagViewer(selectedWay);
+                selectedNode = null;
+            }
+        }
         protected function clearSelection():void {
             if ( selectedWay != null ) {
                 controller.map.setHighlight(selectedWay, "selected", false);
@@ -42,7 +60,7 @@ package net.systemeD.potlatch2.controller {
                 else if ( focus is Node )
                     trace("select poi");
                 else if ( focus == null )
-                    return previousState;
+                    return new NoSelection();
             } else if ( event.type == MouseEvent.MOUSE_DOWN ) {
                 if ( entity is Node && entity.hasParent(selectedWay) )
                     return new DragWayNode(selectedWay, Node(entity), event);
@@ -58,14 +76,23 @@ package net.systemeD.potlatch2.controller {
                 else
                     trace("start new way");
             } else {
-                if ( entity is Node )
-                    trace("select way node");
+                if ( entity is Node ) {
+                    if ( selectedNode == entity ) {
+                        var i:uint = selectedWay.indexOfNode(selectedNode);
+                        if ( i == 0 )
+                            return new DrawWay(selectedWay, false);
+                        else if ( i == selectedWay.length - 1 )
+                            return new DrawWay(selectedWay, true);
+                    } else {
+                        selectNode(entity as Node);
+                    }
+                }
             }
             
             return this;
         }
         
-        public function addNode(event:MouseEvent):void {
+        private function addNode(event:MouseEvent):void {
             trace("add node");
             var lat:Number = controller.map.coord2lat(event.localY);
             var lon:Number = controller.map.coord2lon(event.localX);