Merge branch 'master' into history
[potlatch2.git] / net / systemeD / halcyon / connection / Node.as
1 package net.systemeD.halcyon.connection {
2
3     import net.systemeD.halcyon.connection.actions.*;
4
5     public class Node extends Entity {
6         private var _lat:Number;
7         private var _latproj:Number;
8         private var _lon:Number;
9
10         public function Node(connection:Connection, id:Number, version:uint, tags:Object, loaded:Boolean, lat:Number, lon:Number, uid:Number = NaN, timestamp:String = null, user:String = null) {
11             super(connection, id, version, tags, loaded, uid, timestamp, user);
12             this._lat = lat;
13             this._latproj = lat2latp(lat);
14             this._lon = lon;
15         }
16
17                 public function update(version:uint, tags:Object, loaded:Boolean, parentsLoaded:Boolean, lat:Number, lon:Number, uid:Number = NaN, timestamp:String = null, user:String = null):void {
18                         updateEntityProperties(version,tags,loaded,parentsLoaded,uid,timestamp,user); setLatLonImmediate(lat,lon);
19                 }
20
21         public function get lat():Number {
22             return _lat;
23         }
24
25         public function get latp():Number {
26             return _latproj;
27         }
28
29         public function get lon():Number {
30             return _lon;
31         }
32
33         private function setLatLonImmediate(lat:Number, lon:Number):void {
34             connection.removeDupe(this);
35             this._lat = lat;
36             this._latproj = lat2latp(lat);
37             this._lon = lon;
38             connection.addDupe(this);
39                         for each (var way:Way in this.parentWays) {
40                                 way.expandBbox(this);
41                         }
42         }
43         
44         public function set lat(lat:Number):void {
45             MainUndoStack.getGlobalStack().addAction(new MoveNodeAction(this, lat, _lon, setLatLonImmediate));
46         }
47
48         public function set latp(latproj:Number):void {
49             MainUndoStack.getGlobalStack().addAction(new MoveNodeAction(this, latp2lat(latproj), _lon, setLatLonImmediate));
50         }
51
52         public function set lon(lon:Number):void {
53             MainUndoStack.getGlobalStack().addAction(new MoveNodeAction(this, _lat, lon, setLatLonImmediate));
54         }
55         
56         public function setLatLon(lat:Number, lon:Number, performAction:Function):void {
57             performAction(new MoveNodeAction(this, lat, lon, setLatLonImmediate));
58         } 
59
60                 public function setLonLatp(lon:Number,latproj:Number, performAction:Function):void {
61                     performAction(new MoveNodeAction(this, latp2lat(latproj), lon, setLatLonImmediate));
62                 }
63
64         public override function toString():String {
65             return "Node("+id+"@"+version+"): "+lat+","+lon+" "+getTagList();
66         }
67
68                 public override function remove(performAction:Function):void {
69                         performAction(new DeleteNodeAction(this, setDeletedState));
70                 }
71
72                 public override function within(left:Number,right:Number,top:Number,bottom:Number):Boolean {
73                         if (_lon<left || _lon>right || _lat<bottom || _lat>top || deleted) { return false; }
74                         return true;
75                 }
76
77         public function unjoin(selectedWay:Way, performAction:Function):void {
78             if (parentWays.length > 1) {
79               performAction(new UnjoinNodeAction(this, selectedWay));
80             } else {
81               trace("not enough ways");
82             }
83         }
84
85         /**
86         * Insert this node into the list of ways, and remove dupes at the same time.
87         * Please, don't call this on a node from a vector background, chaos will ensue.
88         */
89         public function join(ways:Array, performAction:Function):void {
90             if (this.isDupe() || ways.length > 0) {
91               var nodes:Array = connection.getNodesAtPosition(lat,lon);
92               // filter the nodes array to remove any occurances of this.
93               // Pass "this" as thisObject to get "this" into the callback function
94               var dupes:Array = nodes.filter(
95                   function(element:*, index:int, arr:Array):Boolean {
96                     return (element != this);
97                   },
98                   this
99                 );
100               performAction(new JoinNodeAction(this, dupes, ways));
101             }
102         }
103
104         /**
105         * Replace all occurances of this node with the given target node
106         */
107         public function replaceWith(target:Node, performAction:Function):void {
108             performAction(new ReplaceNodeAction(this, target));
109         }
110         public function replaceWithNew(connection:Connection, lat:Number, lon:Number, tags:Object, performAction:Function):Node {
111                         var action:ReplaceNodeWithNewAction = new ReplaceNodeWithNewAction(this, connection, lat, lon, tags);
112                         performAction(action);
113                         return action.replacement;
114         }
115
116         public function isDupe():Boolean {
117             if (connection.getNode(this.id) == this // node could be part of a vector layer
118                 && connection.nodesAtPosition(lat, lon) > 1) {
119               return true;
120             }
121             return false;
122         }
123
124                 internal override function isEmpty():Boolean {
125                         return deleted;
126                 }
127
128         public static function lat2latp(lat:Number):Number {
129             return 180/Math.PI * Math.log(Math.tan(Math.PI/4+lat*(Math.PI/180)/2));
130         }
131
132                 public static function latp2lat(a:Number):Number {
133                     return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2);
134                 }
135                 
136                 public override function getType():String {
137                         return 'node';
138                 }
139                 
140         /** Merge another node into this one, removing the other one. */
141         public function mergeWith(node:Node, performAction:Function):void {
142             performAction(new MergeNodesAction(this, node));
143         }
144                 
145     }
146
147 }