1 package net.systemeD.halcyon.connection {
5 import flash.utils.Dictionary;
6 import flash.system.Security;
8 import net.systemeD.halcyon.ExtendedURLLoader;
11 * Read-only connection from local OSM-XML format (.osm) files.
12 * This is used by Halcyon; Potlatch 2 needs a full server connection
13 * of the type provided by XMLConnection
16 // For a limited set of arbitrary files, invoke it like this:
17 // fo.addVariable("api","http://127.0.0.1/~richard/potlatch2"); // base URL
18 // fo.addVariable("connection","OSM");
19 // fo.addVariable("files","-1.5_-1.4_52.1_52.2.osm");
21 // For evenly arranged tiles, invoke it like this:
22 // fo.addVariable("api","http://127.0.0.1/~richard/potlatch2"); // base URL
23 // fo.addVariable("connection","OSM");
24 // fo.addVariable("tile_resolution","0.2");
25 // and it'll then look for '-1.4_-1.2_52_52.2.osm', '-1.2_-1_52_52.2.osm', and so on
26 // (this needs some more testing)
28 public class OSMConnection extends XMLBaseConnection {
30 private var filemode:uint;
31 private static const NAMED:uint=0;
32 private static const TILED:uint=1;
33 // are we running from a limited set of files, or can we request tiles for any bbox?
35 private var bboxes:Dictionary=new Dictionary();
36 private static const AVAILABLE:uint=0;
37 private static const LOADED:uint=1;
38 private static const LOADING:uint=2;
39 private static const UNAVAILABLE:uint=3;
40 // a hash of known files [left,right,top,bottom], and their current status
42 private var tileResolution:Number;
43 // degree resolution for tiles (e.g. 0.2)
45 private static const FILENAME:RegExp=/([\-\d\.]+)_([\-\d\.]+)_([\-\d\.]+)_([\-\d\.]+)\./i;
47 public function OSMConnection(name:String,api:String,policy:String,initparams:Object) {
49 super(name,api,policy,initparams);
50 if (policyURL!='') Security.loadPolicyFile(policyURL);
52 tileResolution = Number(getParam("tile_resolution", "0.2"));
54 var o:Object = new Object();
55 var files:String = getParam("files","");
60 for each (var file:String in files.split(/,/)) {
61 if ((o=FILENAME.exec(file))) {
62 bboxes[[o[1],o[2],o[3],o[4]]]=AVAILABLE;
68 override public function loadBbox(left:Number,right:Number,
69 top:Number,bottom:Number):void {
70 var l:Number, r:Number, t:Number, b:Number, x:Number, y:Number, k:Array;
72 // look through bboxes, assemble any within the requested bbox that are AVAILABLE
73 for (var box:* in bboxes) {
75 l=k[0]; r=k[1]; t=k[2]; b=k[3];
76 if ( ( (left>=l && left<=r) || (right>=l && right<=r) || (left<l && right>r) ) &&
77 ( (top>=b && top<=t) || (bottom>=b && bottom<=t) || (bottom<b && top>t) ) ) {
79 if (bboxes[box]==AVAILABLE) { loadFile(box); }
82 if (filemode==NAMED) { return; }
84 // look through tiles for any areas that are not covered
85 for (x=roundDown(left, tileResolution); x<=roundUp(right, tileResolution); x+=tileResolution) {
86 for (y=roundDown(bottom, tileResolution); y<=roundUp(top, tileResolution); y+=tileResolution) {
87 k=[x,x+tileResolution,y,y+tileResolution];
89 if (bboxes[k]==AVAILABLE) { loadFile(k); }
97 private function loadFile(box:Array):void {
100 var mapRequest:URLRequest = new URLRequest(apiBaseURL+"/"+box[0]+"_"+box[1]+"_"+box[2]+"_"+box[3]+".osm");
101 var mapLoader:ExtendedURLLoader = new ExtendedURLLoader();
102 mapLoader.info['bbox']=box;
103 mapLoader.addEventListener(Event.COMPLETE, markMapLoaded);
104 mapLoader.addEventListener(IOErrorEvent.IO_ERROR, markMapUnloadable);
105 mapLoader.load(mapRequest);
106 dispatchEvent(new Event(LOAD_STARTED));
109 private function markMapLoaded(e:Event):void {
110 bboxes[e.target.info['bbox']]=LOADED;
114 private function markMapUnloadable(e:Event):void {
115 bboxes[e.target.info['bbox']]=UNAVAILABLE;
118 override public function purgeOutside(left:Number, right:Number, top:Number, bottom:Number):void {
119 // we don't purge in an OSMConnection
122 private function roundUp(a:Number,i:Number):Number {
123 if (a/i==Math.floor(a/i)) { return a/i; }
124 return Math.floor(a/i+1)*i;
126 private function roundDown(a:Number,i:Number):Number {
127 return Math.floor(a/i)*i;