1 package net.systemeD.halcyon {
3 import net.systemeD.halcyon.Map;
4 import net.systemeD.halcyon.MapPaint;
5 import net.systemeD.halcyon.connection.*;
6 import net.systemeD.halcyon.connection.actions.*;
7 import net.systemeD.halcyon.styleparser.RuleSet;
9 /** The VectorLayer class is used for the concept of Vector Background Layers.
10 * It is similar in concept to the various Connection layers used for the core
11 * OpenStreetMap data, and as such it stores its own list of nodes, ways and relations.
12 * The most interesting function is pullThrough which allows moving entities out
13 * of a VectorLayer and into the main map layer
15 public class VectorLayer extends Object {
18 public var paint:MapPaint; // sprites
19 public var name:String;
20 public var url:String;
21 public var style:String='';
23 public var ways:Object=new Object(); // geodata
24 public var nodes:Object=new Object(); // |
25 public var relations:Object=new Object(); // |
26 private var pois:Array=[]; // |
28 private var markers:Object=new Object(); // markers
29 private var negativeID:Number = -1;
31 /** Create a new VectorLayer
32 * @param n The name of the VectorLayer (eg 'GPS tracks')
33 * @param m The map. You probably have a global reference to this
34 * @param s The style you wish to use (eg 'gpx.css')
36 public function VectorLayer(n:String,m:Map,s:String) {
40 paint=new MapPaint(m,0,0);
44 public function redrawFromCSS(style:String):void {
45 paint.ruleset=new RuleSet(map.MINSCALE,map.MAXSCALE,paint.redraw,paint.redrawPOIs);
46 paint.ruleset.loadFromCSS(style);
49 /** Create a new node on the vector layer. Note that the node won't show up until on the map
50 * until the the relevant nodeUI is created, so you will need to instruct the paint to create one
52 * e.g. <code>layer.paint.updateEntityUIs(...);</code>
54 public function createNode(tags:Object,lat:Number,lon:Number):Node {
55 var node:Node = new Node(negativeID, 0, tags, true, lat, lon);
56 nodes[negativeID]=node; negativeID--;
61 * @param tags The tags for the new Way
62 * @param nodes An array of Node objects
64 public function createWay(tags:Object,nodes:Array):Way {
65 var way:Way = new Way(negativeID, 0, tags, true, nodes.concat());
66 ways[negativeID]=way; negativeID--;
71 * @param tags The tags for the new relation
72 * @param members An array of RelationMember objects
74 public function createRelation(tags:Object,members:Array):Relation {
75 var relation:Relation = new Relation(negativeID, 0, tags, true, members.concat());
76 relations[negativeID]=relation; negativeID--;
81 * Create a new Marker on the VectorLayer. If you pass in an id it'll check first whether that
82 * marker has been created already, and won't duplicate it.
84 * @param tags The tags for the new Marker
85 * @param lat The latitude
86 * @param lon The longitude
87 * @param id Use this id for the marker, useful for when layer might be reloaded during panning
89 public function createMarker(tags:Object,lat:Number,lon:Number,id:Number=NaN):Marker {
94 var marker:Marker = markers[id];
96 marker = new Marker(id, 0, tags, true, lat, lon);
102 public function registerPOI(node:Node):void {
103 if (pois.indexOf(node)<0) { pois.push(node); }
105 public function unregisterPOI(node:Node):void {
106 var index:uint = pois.indexOf(node);
107 if ( index >= 0 ) { pois.splice(index,1); }
110 public function getObjectsByBbox(left:Number, right:Number, top:Number, bottom:Number):Object {
111 // ** FIXME: this is just copied-and-pasted from Connection.as, which really isn't very
112 // good practice. Is there a more elegant way of doing it?
113 var o:Object = { poisInside: [], poisOutside: [], waysInside: [], waysOutside: [],
114 markersInside: [], markersOutside: [] };
116 for each (var way:Way in ways) {
117 if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
118 else { o.waysOutside.push(way); }
120 for each (var poi:Node in pois) {
121 if (poi.within(left,right,top,bottom)) { o.poisInside.push(poi); }
122 else { o.poisOutside.push(poi); }
124 for each (var marker:Marker in markers) {
125 if (marker.within(left,right,top,bottom)) { o.markersInside.push(marker); }
126 else { o.markersOutside.push(marker); }
132 * Transfers an entity from the VectorLayer into the main layer
133 * @param entity The entity from the VectorLayer that you want to transfer.
134 * @param connection The Connection instance to transfer to (eg Connection.getConnection() )
136 * @return either the newly created entity, or null
138 public function pullThrough(entity:Entity,connection:Connection):Entity {
140 var oldNode:Node, newNode:Node;
142 // copy way through to main layer
143 // ** shouldn't do this if the nodes are already in the main layer
144 // (or maybe we should just match on lat/long to avoid ways in background having nodes in foreground)
145 var oldWay:Way=Way(entity);
146 var newWay:Way=connection.createWay(oldWay.getTagsCopy(), [], MainUndoStack.getGlobalStack().addAction);
147 var nodemap:Object={};
148 for (i=0; i<oldWay.length; i++) {
149 oldNode = oldWay.getNode(i);
150 newNode = nodemap[oldNode.id] ? nodemap[oldNode.id] : connection.createNode(
151 oldNode.getTagsCopy(), oldNode.lat, oldNode.lon,
152 MainUndoStack.getGlobalStack().addAction);
153 newWay.appendNode(newNode, MainUndoStack.getGlobalStack().addAction);
154 nodemap[oldNode.id]=newNode;
157 while (oldWay.length) {
158 var id:Number=oldWay.getNode(0).id;
159 oldWay.removeNodeByIndex(0,MainUndoStack.getGlobalStack().addAction,false);
162 paint.wayuis[oldWay.id].redraw();
163 delete ways[oldWay.id];
164 map.paint.createWayUI(newWay);
167 } else if (entity is Node && !entity.hasParentWays) {
168 // copy node through to main layer
169 // ** should be properly undoable
170 oldNode=Node(entity);
171 unregisterPOI(oldNode);
172 var newPoiAction:CreatePOIAction = new CreatePOIAction(
173 oldNode.getTagsCopy(), oldNode.lat, oldNode.lon);
174 MainUndoStack.getGlobalStack().addAction(newPoiAction);
175 paint.deleteNodeUI(oldNode);
176 delete nodes[oldNode.id];
177 return newPoiAction.getNode();
183 * Remove all the nodes, ways, and relations from the VectorLayer.
184 * Also removes the associated NodeUIs, WayUIs and POIs
186 public function blank():void {
187 for each (var node:Node in nodes) { paint.deleteNodeUI(node); }
188 for each (var way:Way in ways) { paint.deleteWayUI(way); }
189 relations={}; nodes={}; ways={}; pois=[];
193 * Load more data, eg during panning of the map. This can be overridden by
194 * vector layers if it makes sense to support it.
196 public function loadBbox(left:Number, right:Number,
197 top:Number, bottom:Number):void {