1 package net.systemeD.halcyon {
3 // ** Need to support different zoom levels
4 // When zoom level changes:
5 // - double or halve xoffset/yoffset accordingly
6 // - blank the tile queue
8 import flash.display.*;
12 import net.systemeD.halcyon.ImageURLLoader;
13 import net.systemeD.halcyon.Globals;
14 import flash.system.LoaderContext;
16 public class TileSet extends Sprite {
18 public var baseurl:String;
20 public var tile_l:int;
21 public var tile_r:int;
22 public var tile_b:int;
23 public var tile_t:int;
25 public var xoffset:Number=0;
26 public var yoffset:Number=0;
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
35 public function TileSet(map:Map) {
39 public function init(url:String):void {
42 // Update bounds - called on every move
44 public function update():void {
45 tile_l=lon2tile(map.edge_l+xoffset);
46 tile_r=lon2tile(map.edge_r+xoffset);
47 tile_t=lat2tile(map.edge_t+yoffset);
48 tile_b=lat2tile(map.edge_b+yoffset);
49 for (var tx:int=tile_l; tx<=tile_r; tx++) {
50 for (var ty:int=tile_t; ty<=tile_b; ty++) {
51 if (!tiles[map.scale+','+tx+','+ty]) { addRequest(tx,ty); }
56 // Mark that a tile needs to be loaded
58 public function addRequest(tx:int,ty:int):void {
59 tiles[map.scale+','+tx+','+ty]=true;
60 requests.push([map.scale,tx,ty]);
63 // Service tile queue - called on every frame to download new tiles
65 public function serviceQueue():void {
66 if (waiting==4 || requests.length==0) { return; }
67 var r:Array, tx:int, ty:int, tz:int;
69 for (var i:uint=0; i<Math.min(requests.length, 4-waiting); i++) {
70 r=requests.shift(); tz=r[0]; tx=r[1]; ty=r[2];
71 if (tx>=tile_l && tx<=tile_r && ty>=tile_t && ty<=tile_b) {
72 // Tile is on-screen, so load
73 var loader:Loader = new Loader();
74 loader.contentLoaderInfo.addEventListener(Event.INIT, doImgInit);
75 loader.load(new URLRequest(tileURL(tx,ty)),
76 new LoaderContext(true));
77 this.addChild(loader);
78 loader.x=map.lon2coord(tile2lon(tx));
79 loader.y=map.lat2coord(tile2lat(ty));
85 protected function doImgInit(evt:Event):void {
93 private function tileURL(tx:int,ty:int):String {
94 return "http://npe.openstreetmap.org/"+map.scale+"/"+tx+"/"+ty+".png";
95 // return "http://andy.sandbox.cloudmade.com/tiles/cycle/"+map.scale+"/"+tx+"/"+ty+".png";
100 // ------------------------------------------------------------------
101 // Co-ordinate conversion functions
103 private function lon2tile(lon:Number):int {
104 return (Math.floor((lon+180)/360*Math.pow(2,map.scale)));
106 private function lat2tile(lat:Number):int {
107 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)));
109 private function tile2lon(t:int):Number {
110 return (t/Math.pow(2,map.scale)*360-180);
112 private function tile2lat(t:int):Number {
113 var n:Number=Math.PI-2*Math.PI*t/Math.pow(2,map.scale);
114 return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));