support GPX 1.1 too
[potlatch2.git] / net / systemeD / potlatch2 / utils / TrackLoader.as
1 package net.systemeD.potlatch2.utils {
2
3         import net.systemeD.halcyon.connection.*;
4         import net.systemeD.halcyon.Map;
5         import net.systemeD.halcyon.VectorLayer;
6         import flash.net.*;
7         import flash.events.*;
8
9         /* still to do:
10         - empty layer on reload
11         - cope with tracks with timestamps */
12
13         public class TrackLoader {
14
15                 private var left:Number=0;
16                 private var right:Number=0;
17                 private var top:Number=0;
18                 private var bottom:Number=0;
19                 private var page:uint=0;
20                 private var _layer:VectorLayer;
21
22                 private var map:Map;
23                 private var apiBaseURL:String;
24
25                 private static const STYLESHEET:String="gpx.css";
26                 
27                 public function TrackLoader(map:Map, url:String) {
28                         this.map=map;
29                         apiBaseURL=url;
30                 }
31                 
32                 public function load(keep:Boolean=false):void {
33                         if (map.edge_l==left && map.edge_r==right && map.edge_t==top && map.edge_b==bottom) {
34                                 page++;
35                         } else {
36                                 left  =map.edge_l;
37                                 right =map.edge_r;
38                                 top   =map.edge_t;
39                                 bottom=map.edge_b;
40                                 page=0;
41                                 if (!keep) { } // ** TODO: blank the vector layer
42                         }
43
44                         var loader:URLLoader = new URLLoader();
45                         loader.load(new URLRequest(apiBaseURL+"trackpoints?bbox="+left+","+bottom+","+right+","+top+"&page="+page));
46                         loader.addEventListener(Event.COMPLETE, parseGPX);
47                 }
48
49                 public function parseGPX(event:Event):void {
50                         var file:XML = new XML(event.target.data);
51                         for each (var ns:Namespace in file.namespaceDeclarations()) {
52                                 if (ns.uri.match(/^http:\/\/www\.topografix\.com\/GPX\/1\/[01]$/)) {
53                                         default xml namespace = ns;
54                                 }
55                         }
56
57                         for each (var trkseg:XML in file..trkseg) {
58                                 var nodestring:Array = [];
59                                 var lat:Number = NaN, lastlat:Number = NaN;
60                                 var lon:Number = NaN, lastlon:Number = NaN;
61                 for each (var trkpt:XML in trkseg.trkpt) {
62                                         lat = trkpt.@lat;
63                     lon = trkpt.@lon;
64                     if (lastlat && nodestring.length > 0 && greatCircle(lat, lon, lastlat, lastlon) > 30) {
65                         layer.createWay({}, nodestring);
66                         nodestring = [];
67                     }
68                     nodestring.push(layer.createNode({}, lat, lon));
69                     lastlat = lat; lastlon = lon;
70                                 }
71                 if (nodestring.length > 0) { layer.createWay({}, nodestring); }
72                         }
73             
74                         layer.paint.updateEntityUIs(layer.getObjectsByBbox(left,right,top,bottom), false, false);
75                 }
76
77                 
78                 private function get layer():VectorLayer {
79                         if (!_layer) {
80                                 var n:String='GPS tracks';
81                                 _layer=new VectorLayer(n,map,STYLESHEET);
82                                 map.addVectorLayer(_layer);
83                         }
84                         return _layer;
85                 }
86                 
87                 private function greatCircle(lat1:Number,lon1:Number,lat2:Number,lon2:Number):Number {
88                         var dlat:Number=(lat2-lat1)*Math.PI/180;
89                         var dlon:Number=(lon2-lon1)*Math.PI/180;
90                         var a:Number=Math.pow(Math.sin(dlat / 2),2) + 
91                                      Math.cos(lat1*Math.PI/180) * 
92                                      Math.cos(lat2*Math.PI/180) * 
93                                      Math.pow(Math.sin(dlon / 2),2);
94                         a=Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
95                         return a*3958.75*1609;
96                 }
97                 
98         }
99 }