it's the end of the world as we know it
[potlatch2.git] / net / systemeD / halcyon / Map.as
1 package net.systemeD.halcyon {
2
3         import flash.text.TextField;
4         import flash.display.DisplayObjectContainer;
5         import flash.display.Sprite;
6         import flash.display.Shape;
7         import flash.display.Stage;
8         import flash.events.*;
9         import net.systemeD.halcyon.styleparser.*;
10         import flash.net.*;
11         
12     public class Map extends Sprite {
13
14                 public const MASTERSCALE:Number=5825.4222222222;// master map scale - how many Flash pixels in 1 degree longitude
15                                                                                                                 // (for Landsat, 5120)
16                 public const MINSCALE:uint=13;                                  // don't zoom out past this
17                 public const MAXSCALE:uint=19;                                  // don't zoom in past this
18
19                 public var ruleset:RuleSet=new RuleSet();               // rules
20                 
21                 public var ways:Object=new Object();                    // geodata
22                 public var nodes:Object=new Object();                   //  |
23                 public var pois:Object=new Object();                    //  |
24                 public var relations:Object=new Object();               //  |
25
26                 public var scale:uint=14;                                               // map scale
27                 public var scalefactor:Number=MASTERSCALE;              // current scaling factor for lon/latp
28                 public var bigedge_l:Number= 999999;                    // area of largest whichways
29                 public var bigedge_r:Number=-999999;                    //  |
30                 public var bigedge_b:Number= 999999;                    //  |
31                 public var bigedge_t:Number=-999999;                    //  |
32                 public var bscale:Number=Math.pow(2,scale-13);  // scale factor (2**(zoom-13))
33
34                 public var waycount:uint=0;                                             // ways:                number currently loaded
35                 public var waysrequested:uint=0;                                //                              total number requested
36                 public var waysreceived:uint=0;                                 //                              total number received
37                 public var relcount:uint=0;                                             // relations:   number currently loaded
38                 public var relsrequested:uint=0;                                //                              total number requested
39                 public var relsreceived:uint=0;                                 //                              total number received
40                 public var poicount:uint=0;                                             // POIs:                number currently loaded
41                 public var whichrequested:uint=0;                               // whichways:   total number requested
42                 public var whichreceived:uint=0;                                //                              total number received
43
44                 public var edge_l:Number;                                               // current bounding box
45                 public var edge_r:Number;                                               //  |
46                 public var edge_t:Number;                                               //  |
47                 public var edge_b:Number;                                               //  |
48
49                 public var baselon:Number;                                              // urllon-xradius/masterscale/bscale;
50                 public var basey:Number;                                                // lat2lat2p(urllat)+yradius/masterscale/bscale;
51                 public var mapwidth:uint;                                               // width (Flash pixels)
52                 public var mapheight:uint;                                              // height (Flash pixels)
53
54                 private var dragging:Boolean=false;                             // dragging map?
55                 private var lastxmouse:Number;                                  //  |
56                 private var lastymouse:Number;                                  //  |
57                 
58                 public var backdrop:Object;                                             // reference to backdrop sprite
59                 
60                 public var connection:AMFConnection;                    // server connection
61
62                 // ------------------------------------------------------------------------------------------
63                 // Map constructor function
64
65         public function Map() {
66
67                         for (var l:int=0; l<11; l++) {                          // 11 layers (10 is +5, 0 is -5)
68                                 var s:Sprite=new Sprite();
69                                 s.addChild(new Sprite());                               // [layer][0]=fill, [1]=stroke, [2]=names
70                                 s.addChild(new Sprite());
71                                 s.addChild(new Sprite());
72                                 addChild(s);
73                         }
74
75                         connection=new AMFConnection(
76                                 "http://127.0.0.1:3000/api/0.6/amf/read",
77                                 "http://127.0.0.1:3000/api/0.6/amf/write",
78                                 "http://127.0.0.1:3000/api/crossdomain.xml");
79                         connection.getEnvironment(new Responder(gotEnvironment,connectionError));
80
81         }
82
83                 public function gotEnvironment(r:Object):void {
84                         init(52.022,-1.2745);
85                 }
86
87                 // ------------------------------------------------------------------------------------------
88                 // Initialise map at a given lat/lon
89
90         public function init(startlat:Number,startlon:Number):void {
91
92                         ruleset.load("test.yaml?d="+Math.random());
93 //                      rules.initExample();            // initialise dummy rules
94
95                         updateSize();
96                         baselon  =startlon                      -(mapwidth /2)/MASTERSCALE/bscale;
97                         basey    =lat2latp(startlat)+(mapheight/2)/MASTERSCALE/bscale;
98                         addDebug("Baselon "+baselon+", basey "+basey);
99                         updateCoords(0,0);
100                         addDebug("L "+edge_l+", R "+edge_r);
101                         download();
102                         
103         }
104
105                 // ------------------------------------------------------------------------------------------
106                 // Recalculate co-ordinates from new Flash origin
107
108                 public function updateCoords(tx:Number,ty:Number):void {
109
110                         bscale=Math.pow(2,scale-13);
111                         x=tx; y=ty;
112 //                      scaleX=bscale; scaleY=bscale;
113
114                         // ** calculate tile_l etc.
115                         edge_t=coord2lat((-y          )/bscale);
116                         edge_b=coord2lat((-y+mapheight)/bscale);
117                         edge_l=coord2lon((-x          )/bscale);
118                         edge_r=coord2lon((-x+mapwidth )/bscale);
119
120                 }
121
122                 // Co-ordinate conversion functions
123
124                 public function latp2coord(a:Number):Number     { return -(a-basey)*scalefactor; }
125                 public function coord2latp(a:Number):Number     { return a/-scalefactor+basey; }
126                 public function lon2coord(a:Number):Number      { return (a-baselon)*scalefactor; }
127                 public function coord2lon(a:Number):Number      { return a/scalefactor+baselon; }
128
129                 public function latp2lat(a:Number):Number       { return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); }
130                 public function lat2latp(a:Number):Number       { return 180/Math.PI * Math.log(Math.tan(Math.PI/4+a*(Math.PI/180)/2)); }
131
132                 public function lat2coord(a:Number):Number      { return -(lat2latp(a)-basey)*scalefactor; }
133                 public function coord2lat(a:Number):Number      { return latp2lat(a/-scalefactor+basey); }
134
135 //              public function centrelat(o) { return coord2lat((yradius-_root.map._y-o)/Math.pow(2,_root.scale-13)); }
136 //              public function centrelon(o) { return coord2lon((xradius-_root.map._x-o)/Math.pow(2,_root.scale-13)); }
137
138
139                 // ------------------------------------------------------------------------------------------
140                 // Resize map size based on current stage and height
141
142                 public function updateSize():void {
143                         mapwidth =stage.stageWidth; mask.width=mapwidth; backdrop.width=mapwidth;
144                         mapheight=stage.stageHeight; mask.height=mapheight; backdrop.height=mapheight;
145                         // addDebug("Mapwidth "+mapwidth+", mapheight "+mapheight);
146                 }
147
148                 // ------------------------------------------------------------------------------------------
149                 // Download map data
150                 // (typically from whichways, but will want to add more connections)
151
152                 public function download():void {
153                         if (edge_l>=bigedge_l && edge_r<=bigedge_r &&
154                                 edge_b>=bigedge_b && edge_t<=bigedge_t) { return; }     // we have already loaded this area, so ignore
155                         bigedge_l=edge_l; bigedge_r=edge_r;
156                         bigedge_b=edge_b; bigedge_t=edge_t;
157                         addDebug("Calling with "+edge_l+"-"+edge_r+", "+edge_t+"-"+edge_b);
158                         connection.getBbox(edge_l,edge_r,edge_t,edge_b,new Responder(gotBbox,connectionError));
159                 }
160
161                 public function gotBbox(r:Object):void {
162                         addDebug("got whichways");
163                         var code:uint         =r.shift(); if (code) { connectionError(); return; }
164                         var message:String    =r.shift();
165                         var waylist:Array     =r[0];
166                         var pointlist:Array   =r[1];
167                         var relationlist:Array=r[2];
168                         var i:uint, v:uint;
169
170                         for each (var w:Array in waylist) {
171                                 i=w[0]; v=w[1];
172                                 if (ways[i] && ways[i].version==v) { continue; }
173                                 ways[i]=new Way(i,v,this);
174                                 ways[i].load(connection);
175                         }
176
177                         for each (var p:Array in pointlist) {
178                                 i=w[0]; v=w[4];
179                                 if (pois[i] && pois[i].version==v) { continue; }
180                                 pois[i]=new POI(i,v,w[1],w[2],w[3],this);
181                         }
182
183                         addDebug("waylist is "+waylist);
184                 }
185
186
187                 // ------------------------------------------------------------------------------------------
188                 // Redraw all items, zoom in and out
189                 
190                 public function redraw():void {
191                         addDebug("redrawing");
192                         var s:String='';
193                         for each (var w:Way in ways) { w.redraw(); s+=w.id+","; }
194                         addDebug(s);
195                         // ** do POIs, etc.
196                 }
197
198                 public function zoomIn():void {
199                         if (scale==MAXSCALE) { return; }
200                         changeScale(scale+1);
201                 }
202
203                 public function zoomOut():void {
204                         if (scale==MINSCALE) { return; }
205                         changeScale(scale-1);
206                 }
207
208                 private function changeScale(newscale:uint):void {
209                         addDebug("new scale "+newscale);
210                         scale=newscale;
211                         scalefactor=MASTERSCALE/Math.pow(2,14-scale);
212                         redraw();
213                 }
214                 
215                 private function reportPosition():void {
216                         addDebug("lon "+coord2lon(mouseX)+", lat "+coord2lat(mouseY));
217                 }
218
219
220                 // ==========================================================================================
221                 // Events
222                 
223                 // ------------------------------------------------------------------------------------------
224                 // Mouse events
225                 
226                 public function mouseDownHandler(event:MouseEvent):void {
227                         dragging=true;
228                         lastxmouse=mouseX; lastymouse=mouseY;
229                 }
230         
231                 public function mouseUpHandler(event:MouseEvent):void {
232                         if (!dragging) { return; }
233                         dragging=false;
234                         updateCoords(x,y);
235                         download();
236                 }
237         
238                 public function mouseMoveHandler(event:MouseEvent):void {
239                         if (!dragging) { return; }
240                         x+=mouseX-lastxmouse;
241                         y+=mouseY-lastymouse;
242                         lastxmouse=mouseX; lastymouse=mouseY;
243                 }
244         
245                 // ------------------------------------------------------------------------------------------
246                 // Miscellaneous events
247                 
248                 public function keyUpHandler(event:KeyboardEvent):void {
249 addDebug("pressed "+event.keyCode);
250                         if (event.keyCode==82) { this.redraw(); }                       // R - redraw
251                         if (event.keyCode==73) { this.zoomIn(); }                       // I - zoom in
252                         if (event.keyCode==79) { this.zoomOut(); }                      // O - zoom out
253                         if (event.keyCode==76) { this.reportPosition(); }       // L - report lat/long
254                 }
255
256                 public function connectionError(err:Object=null): void {
257                         addDebug("got error"); 
258                 }
259
260                 // ------------------------------------------------------------------------------------------
261                 // Debugging
262                 
263                 public function addDebug(text:String):void {
264                         Globals.vars.debug.appendText(text+"\n");
265                         Globals.vars.debug.scrollV=Globals.vars.debug.maxScrollV;
266                 }
267                 
268         }
269 }