From: Richard Fairhurst Date: Sun, 6 Jun 2010 22:01:06 +0000 (+0000) Subject: give Halcyon the ability to load .osm files X-Git-Tag: 0.5~420 X-Git-Url: https://git.openstreetmap.org/potlatch2.git/commitdiff_plain/792a323a047efff1d49f3c4d1023f167fa064926?hp=6c45bf4e2785c4c31dda31502e51205bf9595861 give Halcyon the ability to load .osm files --- diff --git a/TODO.txt b/TODO.txt index 90b99a30..4c0c8601 100644 --- a/TODO.txt +++ b/TODO.txt @@ -57,6 +57,7 @@ Potlatch 2: main outstanding issues * Background imagery layers should match those of p1 * Dialog for adding custom imagery url * Draggin a node under the toolbox and then mouseuping doesn't get passed to the map, so you end up with a node "stuck" to the pointer +* onDataComplete fires the first time a map call has returned - but multiple calls might have been made, so really we should count them and only reset dataWorking when it's back to 0 again == Miscellaneous data model == diff --git a/net/systemeD/halcyon/connection/Connection.as b/net/systemeD/halcyon/connection/Connection.as index f9906226..c4b5818d 100755 --- a/net/systemeD/halcyon/connection/Connection.as +++ b/net/systemeD/halcyon/connection/Connection.as @@ -25,6 +25,8 @@ package net.systemeD.halcyon.connection { if ( connectType == "XML" ) connectionInstance = new XMLConnection(); + else if ( connectType == "OSM" ) + connectionInstance = new OSMConnection(); else connectionInstance = new AMFConnection(); } diff --git a/net/systemeD/halcyon/connection/OSMConnection.as b/net/systemeD/halcyon/connection/OSMConnection.as new file mode 100644 index 00000000..252c4bd3 --- /dev/null +++ b/net/systemeD/halcyon/connection/OSMConnection.as @@ -0,0 +1,129 @@ +package net.systemeD.halcyon.connection { + + import flash.events.*; + import flash.net.*; + import flash.utils.Dictionary; + import flash.system.Security; + + import net.systemeD.halcyon.ExtendedURLLoader; + import net.systemeD.halcyon.Globals; + + // Read-only connection from local files (for Halcyon) + + // For a limited set of arbitrary files, invoke it like this: + // fo.addVariable("api","http://127.0.0.1/~richard/potlatch2"); // base URL + // fo.addVariable("connection","OSM"); + // fo.addVariable("files","-1.5_-1.4_52.1_52.2.osm"); + + // For evenly arranged tiles, invoke it like this: + // fo.addVariable("api","http://127.0.0.1/~richard/potlatch2"); // base URL + // fo.addVariable("connection","OSM"); + // fo.addVariable("tile_resolution","0.2"); + // and it'll then look for '-1.4_-1.2_52_52.2.osm', '-1.2_-1_52_52.2.osm', and so on + // (this needs some more testing) + + public class OSMConnection extends XMLBaseConnection { + + private var filemode:uint; + private static const NAMED:uint=0; + private static const TILED:uint=1; + // are we running from a limited set of files, or can we request tiles for any bbox? + + private var bboxes:Dictionary=new Dictionary(); + private static const AVAILABLE:uint=0; + private static const LOADED:uint=1; + private static const LOADING:uint=2; + private static const UNAVAILABLE:uint=3; + // a hash of known files [left,right,top,bottom], and their current status + + private var tileResolution:Number; + // degree resolution for tiles (e.g. 0.2) + + private static const FILENAME:RegExp=/([\-\d\.]+)_([\-\d\.]+)_([\-\d\.]+)_([\-\d\.]+)\./i; + + public function OSMConnection() { + + if (Connection.policyURL!='') + Security.loadPolicyFile(Connection.policyURL); + + tileResolution = Number(Connection.getParam("tile_resolution", "0.2")); + + var o:Object = new Object(); + var files:String = Connection.getParam("files",""); + if (files=="") { + filemode=TILED; + } else { + filemode=NAMED; + for each (var file:String in files.split(/,/)) { + if ((o=FILENAME.exec(file))) { + bboxes[[o[1],o[2],o[3],o[4]]]=AVAILABLE; + } + } + } + } + + override public function loadBbox(left:Number,right:Number, + top:Number,bottom:Number):void { + var l:Number, r:Number, t:Number, b:Number, x:Number, y:Number, k:Array; + + // look through bboxes, assemble any within the requested bbox that are AVAILABLE + for (var box:* in bboxes) { + k=box as Array; + l=k[0]; r=k[1]; t=k[2]; b=k[3]; + if ( ( (left>=l && left<=r) || (right>=l && right<=r) || (leftr) ) && + ( (top>=b && top<=t) || (bottom>=b && bottom<=t) || (bottomt) ) ) { + // yay, it intersects + if (bboxes[box]==AVAILABLE) { loadFile(box); } + } + } + if (filemode==NAMED) { return; } + + // look through tiles for any areas that are not covered + for (x=roundDown(left, tileResolution); x<=roundUp(right, tileResolution); x+=tileResolution) { + for (y=roundDown(bottom, tileResolution); y<=roundUp(top, tileResolution); y+=tileResolution) { + k=[x,x+tileResolution,y,y+tileResolution]; + if (bboxes[k]) { + if (bboxes[k]==AVAILABLE) { loadFile(k); } + } else { + loadFile(k); + } + } + } + } + + private function loadFile(box:Array):void { + Globals.vars.root.addDebug("called loadFile for "+box); + bboxes[box]=LOADING; + + var mapRequest:URLRequest = new URLRequest(Connection.apiBaseURL+"/"+box[0]+"_"+box[1]+"_"+box[2]+"_"+box[3]+".osm"); + var mapLoader:ExtendedURLLoader = new ExtendedURLLoader(); + mapLoader.info['bbox']=box; + mapLoader.addEventListener(Event.COMPLETE, markMapLoaded); + mapLoader.addEventListener(IOErrorEvent.IO_ERROR, markMapUnloadable); + mapLoader.load(mapRequest); + dispatchEvent(new Event(LOAD_STARTED)); + } + + private function markMapLoaded(e:Event):void { + bboxes[e.target.info['bbox']]=LOADED; + loadedMap(e); + } + + private function markMapUnloadable(e:Event):void { + bboxes[e.target.info['bbox']]=UNAVAILABLE; + } + + override public function purgeOutside(left:Number, right:Number, top:Number, bottom:Number):void { + // we don't purge in an OSMConnection + } + + private function roundUp(a:Number,i:Number):Number { + if (a/i==Math.floor(a/i)) { return a/i; } + return Math.floor(a/i+1)*i; + } + private function roundDown(a:Number,i:Number):Number { + return Math.floor(a/i)*i; + } + + } +} diff --git a/net/systemeD/halcyon/connection/XMLBaseConnection.as b/net/systemeD/halcyon/connection/XMLBaseConnection.as new file mode 100644 index 00000000..9c68b0e6 --- /dev/null +++ b/net/systemeD/halcyon/connection/XMLBaseConnection.as @@ -0,0 +1,126 @@ +package net.systemeD.halcyon.connection { + + import flash.events.*; + + import flash.system.Security; + import flash.net.*; + import org.iotashan.oauth.*; + + import net.systemeD.halcyon.Globals; + + public class XMLBaseConnection extends Connection { + + public function XMLBaseConnection() { + } + + protected function loadedMap(event:Event):void { + dispatchEvent(new Event(LOAD_COMPLETED)); + + var map:XML = new XML(URLLoader(event.target).data); + var id:Number; + var version:uint; + var tags:Object; + + for each(var nodeData:XML in map.node) { + id = Number(nodeData.@id); + version = uint(nodeData.@version); + + var node:Node = getNode(id); + if ( node == null || !node.loaded ) { + var lat:Number = Number(nodeData.@lat); + var lon:Number = Number(nodeData.@lon); + tags = parseTags(nodeData.tag); + if ( node == null ) + setNode(new Node(id, version, tags, true, lat, lon),false); + else { + node.update(version, tags, true, lat, lon); + sendEvent(new EntityEvent(NEW_NODE, node), false); + } + } + } + + for each(var data:XML in map.way) { + id = Number(data.@id); + version = uint(data.@version); + + var way:Way = getWay(id); + if ( way == null || !way.loaded ) { + var nodes:Array = []; + for each(var nd:XML in data.nd) + nodes.push(getNode(Number(nd.@ref))); + tags = parseTags(data.tag); + if ( way == null ) + setWay(new Way(id, version, tags, true, nodes),false); + else { + way.update(version, tags, true, nodes); + sendEvent(new EntityEvent(NEW_WAY, way), false); + } + } + } + + for each(var relData:XML in map.relation) { + id = Number(relData.@id); + version = uint(relData.@version); + + var rel:Relation = getRelation(id); + if ( rel == null || !rel.loaded ) { + tags = parseTags(relData.tag); + var members:Array = []; + for each(var memberXML:XML in relData.member) { + var type:String = memberXML.@type.toLowerCase(); + var role:String = memberXML.@role; + var memberID:Number = Number(memberXML.@ref); + var member:Entity = null; + if ( type == "node" ) { + member = getNode(memberID); + if ( member == null ) { + member = new Node(memberID,0,{},false,0,0); + setNode(Node(member),true); + } + } else if ( type == "way" ) { + member = getWay(memberID); + if (member == null) { + member = new Way(memberID,0,{},false,[]); + setWay(Way(member),true); + } + } else if ( type == "relation" ) { + member = getRelation(memberID); + if (member == null) { + member = new Relation(memberID,0,{},false,[]); + setRelation(Relation(member),true); + } + } + + if ( member != null ) + members.push(new RelationMember(member, role)); + } + + if ( rel == null ) + setRelation(new Relation(id, version, tags, true, members), false); + else { + rel.update(version,tags,true,members); + sendEvent(new EntityEvent(NEW_RELATION, rel), false); + } + } + } + + registerPOINodes(); + } + + protected function registerPOINodes():void { + for each (var nodeID:Number in getAllNodeIDs()) { + var node:Node = getNode(nodeID); + if (!node.hasParentWays) + registerPOI(node); + } + } + + private function parseTags(tagElements:XMLList):Object { + var tags:Object = {}; + for each (var tagEl:XML in tagElements) + tags[tagEl.@k] = tagEl.@v; + return tags; + } + + } +} diff --git a/net/systemeD/halcyon/connection/XMLConnection.as b/net/systemeD/halcyon/connection/XMLConnection.as index 224d3e95..d2291575 100644 --- a/net/systemeD/halcyon/connection/XMLConnection.as +++ b/net/systemeD/halcyon/connection/XMLConnection.as @@ -8,7 +8,7 @@ package net.systemeD.halcyon.connection { import net.systemeD.halcyon.Globals; - public class XMLConnection extends Connection { + public class XMLConnection extends XMLBaseConnection { //public var readConnection:NetConnection; @@ -39,121 +39,12 @@ package net.systemeD.halcyon.connection { dispatchEvent(new Event(LOAD_STARTED)); } - private function parseTags(tagElements:XMLList):Object { - var tags:Object = {}; - for each (var tagEl:XML in tagElements) - tags[tagEl.@k] = tagEl.@v; - return tags; - } - private function errorOnMapLoad(event:Event):void { trace("error loading map"); } private function mapLoadStatus(event:HTTPStatusEvent):void { trace("loading map status = "+event.status); } - - private function loadedMap(event:Event):void { - dispatchEvent(new Event(LOAD_COMPLETED)); - - var map:XML = new XML(URLLoader(event.target).data); - var id:Number; - var version:uint; - var tags:Object; - - for each(var nodeData:XML in map.node) { - id = Number(nodeData.@id); - version = uint(nodeData.@version); - - var node:Node = getNode(id); - if ( node == null || !node.loaded ) { - var lat:Number = Number(nodeData.@lat); - var lon:Number = Number(nodeData.@lon); - tags = parseTags(nodeData.tag); - if ( node == null ) - setNode(new Node(id, version, tags, true, lat, lon),false); - else { - node.update(version, tags, true, lat, lon); - sendEvent(new EntityEvent(NEW_NODE, node), false); - } - } - } - - for each(var data:XML in map.way) { - id = Number(data.@id); - version = uint(data.@version); - - var way:Way = getWay(id); - if ( way == null || !way.loaded ) { - var nodes:Array = []; - for each(var nd:XML in data.nd) - nodes.push(getNode(Number(nd.@ref))); - tags = parseTags(data.tag); - if ( way == null ) - setWay(new Way(id, version, tags, true, nodes),false); - else { - way.update(version, tags, true, nodes); - sendEvent(new EntityEvent(NEW_WAY, way), false); - } - } - } - - for each(var relData:XML in map.relation) { - id = Number(relData.@id); - version = uint(relData.@version); - - var rel:Relation = getRelation(id); - if ( rel == null || !rel.loaded ) { - tags = parseTags(relData.tag); - var members:Array = []; - for each(var memberXML:XML in relData.member) { - var type:String = memberXML.@type.toLowerCase(); - var role:String = memberXML.@role; - var memberID:Number = Number(memberXML.@ref); - var member:Entity = null; - if ( type == "node" ) { - member = getNode(memberID); - if ( member == null ) { - member = new Node(memberID,0,{},false,0,0); - setNode(Node(member),true); - } - } else if ( type == "way" ) { - member = getWay(memberID); - if (member == null) { - member = new Way(memberID,0,{},false,[]); - setWay(Way(member),true); - } - } else if ( type == "relation" ) { - member = getRelation(memberID); - if (member == null) { - member = new Relation(memberID,0,{},false,[]); - setRelation(Relation(member),true); - } - } - - if ( member != null ) - members.push(new RelationMember(member, role)); - } - - if ( rel == null ) - setRelation(new Relation(id, version, tags, true, members), false); - else { - rel.update(version,tags,true,members); - sendEvent(new EntityEvent(NEW_RELATION, rel), false); - } - } - } - - registerPOINodes(); - } - - protected function registerPOINodes():void { - for each (var nodeID:Number in getAllNodeIDs()) { - var node:Node = getNode(nodeID); - if (!node.hasParentWays) - registerPOI(node); - } - } protected var appID:OAuthConsumer; protected var authToken:OAuthToken;