some more footling around with POI nodes in ways
[potlatch2.git] / net / systemeD / halcyon / TileSet.as
1 package net.systemeD.halcyon {
2
3         // ** Need to support different zoom levels
4         //    When zoom level changes: 
5         //              - double or halve xoffset/yoffset accordingly
6         //              - blank the tile queue
7
8         import flash.display.*;
9         import flash.events.*;
10         import flash.net.*;
11         
12         import net.systemeD.halcyon.ImageURLLoader;
13         import flash.system.LoaderContext;
14         
15     public class TileSet extends Sprite {
16
17                 public var baseurl:String;
18
19                 public var tile_l:int;
20                 public var tile_r:int;
21                 public var tile_b:int;
22                 public var tile_t:int;
23
24                 public var xoffset:Number=0;
25                 public var yoffset:Number=0;
26
27                 private var requests:Array=[];
28                 private var tiles:Object={};            // key is "z,x,y"; value "true" (needed) or reference to sprite
29                 private var waiting:int=0;                      // number of tiles currently being downloaded
30
31                 private var map:Map;
32
33
34         public function TileSet(map:Map) {
35                         this.map=map;
36                 }
37         
38                 public function init(url:String):void {
39                 }
40
41                 // Update bounds - called on every move
42                 
43                 public function update():void {
44                         tile_l=lon2tile(map.edge_l+xoffset);
45                         tile_r=lon2tile(map.edge_r+xoffset);
46                         tile_t=lat2tile(map.edge_t+yoffset);
47                         tile_b=lat2tile(map.edge_b+yoffset);
48                         for (var tx:int=tile_l; tx<=tile_r; tx++) {
49                                 for (var ty:int=tile_t; ty<=tile_b; ty++) {
50                                         if (!tiles[map.scale+','+tx+','+ty]) { addRequest(tx,ty); }
51                                 }
52                         }
53                 }
54
55                 // Mark that a tile needs to be loaded
56                 
57                 public function addRequest(tx:int,ty:int):void {
58                         tiles[map.scale+','+tx+','+ty]=true;
59                         requests.push([map.scale,tx,ty]);
60                 }
61
62                 // Service tile queue - called on every frame to download new tiles
63                 
64                 public function serviceQueue():void {
65                         if (waiting==4 || requests.length==0) { return; }
66                         var r:Array, tx:int, ty:int, tz:int;
67
68                         for (var i:uint=0; i<Math.min(requests.length, 4-waiting); i++) {
69                                 r=requests.shift(); tz=r[0]; tx=r[1]; ty=r[2];
70                                 if (tx>=tile_l && tx<=tile_r && ty>=tile_t && ty<=tile_b) {
71                                         // Tile is on-screen, so load
72                                         waiting++;
73                                         var loader:Loader = new Loader();
74                                         loader.contentLoaderInfo.addEventListener(Event.INIT, doImgInit);
75                         loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, missingTileError);
76                                         loader.load(new URLRequest(tileURL(tx,ty)), 
77                                                     new LoaderContext(true));
78                                         this.addChild(loader);
79                                         loader.x=map.lon2coord(tile2lon(tx));
80                                         loader.y=map.lat2coord(tile2lat(ty));
81                                         loader.alpha=0.5;
82                                 }
83                         }
84                 }
85
86         private function missingTileError(event:Event):void {
87                         waiting--;
88                         return;
89                 }
90
91                 protected function doImgInit(event:Event):void {
92                         waiting--;
93                         return;
94                 }
95
96                 
97                 // Assemble tile URL
98                 
99                 private function tileURL(tx:int,ty:int):String {
100                         return "http://npe.openstreetmap.org/"+map.scale+"/"+tx+"/"+ty+".png";
101 //                      return "http://andy.sandbox.cloudmade.com/tiles/cycle/"+map.scale+"/"+tx+"/"+ty+".png";
102                 }
103
104
105                 
106                 // ------------------------------------------------------------------
107                 // Co-ordinate conversion functions
108
109                 private function lon2tile(lon:Number):int {
110                         return (Math.floor((lon+180)/360*Math.pow(2,map.scale)));
111                 }
112                 private function lat2tile(lat:Number):int { 
113                         return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,map.scale)));
114                 }
115                 private function tile2lon(t:int):Number {
116                         return (t/Math.pow(2,map.scale)*360-180);
117                 }
118                 private function tile2lat(t:int):Number { 
119                         var n:Number=Math.PI-2*Math.PI*t/Math.pow(2,map.scale);
120                         return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
121                 }
122
123         }
124 }