2c9a75dbbe618eaf6dc1d8f3cbf62b507417d160
[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.DisplayObjectContainer;
9         import flash.display.Bitmap;
10         import flash.events.*;
11         import flash.net.*;
12         
13         import net.systemeD.halcyon.ImageLoader;
14         import net.systemeD.halcyon.Globals;
15
16     public class TileSet extends DisplayObjectContainer {
17
18                 public var baseurl:String;
19
20                 public var tile_l:int;
21                 public var tile_r:int;
22                 public var tile_b:int;
23                 public var tile_t:int;
24
25                 public var xoffset:Number;
26                 public var yoffset:Number;
27
28                 private var requests:Array=[];
29                 private var tiles:Object={};            // key is "z,x,y"; value "true" (needed) or reference to sprite
30                 private var waiting:int=0;                      // number of tiles currently being downloaded
31
32                 private var map:Map;
33
34
35         public function TileSet(map:Map) {
36                         this.map=map;
37                 }
38         
39                 public function init(url:String):void {
40                 }
41
42                 // Update bounds - called on every move
43                 
44                 public function update():void {
45                         tile_l=lon2tile(map.coord2lon(-xoffset-map.x));
46                         tile_r=lon2tile(map.coord2lon(-xoffset-map.x+map.mapwidth));
47                         tile_t=lat2tile(map.coord2lat(-yoffset-map.y));
48                         tile_b=lat2tile(map.coord2lat(-yoffset-map.y+map.mapheight));
49
50                         for (var tx:int=tile_l; tx<=tile_r; tx++) {
51                                 for (var ty:int=tile_t; ty<=tile_b; ty++) {
52                                         if (!tiles[map.scale+','+tx+','+ty]) { addRequest(tx,ty); }
53                                 }
54                         }
55                 }
56
57                 // Mark that a tile needs to be loaded
58                 
59                 public function addRequest(tx:int,ty:int):void {
60                         tiles[map.scale+','+tx+','+ty]=true;
61                         requests.push([map.scale,tx,ty]);
62                 }
63
64                 // Service tile queue - called on every frame to download new tiles
65                 
66                 public function serviceQueue():void {
67                         if (waiting==4 || requests.length==0) { return; }
68                         var r:Array, tx:int, ty:int, tz:int;
69                         var loader:ImageLoader, urlreq:URLRequest;
70
71                         for (var i:uint=0; i<Math.min(requests.length, 4-waiting); i++) {
72                                 r=requests.shift(); tz=r[0]; tx=r[1]; ty=r[2];
73                                 if (tx>=tile_l && tx<=tile_r && ty>=tile_t && ty<=tile_b) {
74                                         // Tile is on-screen, so load
75                                         urlreq=new URLRequest(tileURL(tx,ty));
76                                         loader=new ImageLoader();
77                                         loader.dataFormat=URLLoaderDataFormat.BINARY;
78                                         loader.filename=[tz,tx,ty];
79                                         loader.addEventListener(Event.COMPLETE,                                         loadedTile,                             false, 0, true);
80                                         loader.addEventListener(HTTPStatusEvent.HTTP_STATUS,            httpStatusHandler,              false, 0, true);
81                                         loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,      securityErrorHandler,   false, 0, true);
82                                         loader.addEventListener(IOErrorEvent.IO_ERROR,                          ioErrorHandler,                 false, 0, true);
83                                         loader.load(urlreq);
84                                 }
85                         }
86                 }
87
88                 // Tile has loaded, so place on display list
89
90                 private function loadedTile(event:Event):void {
91                         var r:Array=event.target.filename as Array;
92                         var tz:int=r[0]; var tx:int=r[1]; var ty:int=r[2];
93                         
94                         var image:Bitmap = event.target.content as Bitmap;
95                         addChild(image);
96                         image.x=map.lon2coord(tile2lon(tx));
97                         image.y=map.lat2coord(tile2lat(ty));
98
99                         waiting--;
100                 }
101
102                 
103                 // Assemble tile URL
104                 
105                 private function tileURL(tx:int,ty:int):String {
106                         // ***** to do
107                         return '';
108                 }
109
110                 private function httpStatusHandler( event:HTTPStatusEvent ):void { }
111                 private function securityErrorHandler( event:SecurityErrorEvent ):void { Globals.vars.root.addDebug("securityerrorevent"); }
112                 private function ioErrorHandler( event:IOErrorEvent ):void { Globals.vars.root.addDebug("ioerrorevent"); }
113
114                 
115                 // ------------------------------------------------------------------
116                 // Co-ordinate conversion functions
117
118                 private function lon2tile(lon:Number):int {
119                         return (Math.floor((lon+180)/360*Math.pow(2,map.scale)));
120                 }
121                 private function lat2tile(lat:Number):int { 
122                         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))); 
123                 }
124                 private function tile2lon(t:int):Number {
125                         return (t/Math.pow(2,map.scale)*360-180);
126                 }
127                 private function tile2lat(t:int):Number { 
128                         var n:Number=Math.PI-2*Math.PI*t/Math.pow(2,map.scale);
129                         return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
130                 }
131
132         }
133 }