diff --git a/Phi/3rdparty/leaflet-0.7.3/Leaflet.Geodesic.min.js b/Phi/3rdparty/leaflet-0.7.3/Leaflet.Geodesic.min.js new file mode 100644 index 000000000..a73870359 --- /dev/null +++ b/Phi/3rdparty/leaflet-0.7.3/Leaflet.Geodesic.min.js @@ -0,0 +1,49 @@ +/*! Leaflet.Geodesic https://github.com/henrythasler/Leaflet.Geodesic*/ +void 0===Number.prototype.toRadians&&(Number.prototype.toRadians=function(){return this*Math.PI/180}),void 0===Number.prototype.toDegrees&&(Number.prototype.toDegrees=function(){return 180*this/Math.PI}) +var INTERSECT_LNG=179.999 +L.Geodesic=L.MultiPolyline.extend({options:{color:"blue",steps:10,dash:1,wrap:!0},initialize:function(t,a){this.options=this._merge_options(this.options,a),this.datum={},this.datum.ellipsoid={a:6378137,b:6356752.3142,f:1/298.257223563},L.MultiPolyline.prototype.initialize.call(this,t,this.options)},setLatLngs:function(t){this._latlngs=this.options.dash<1?this._generate_GeodesicDashed(t):this._generate_Geodesic(t),L.MultiPolyline.prototype.setLatLngs.call(this,this._latlngs)},getStats:function(){var t,a,n={distance:0,points:0,polygons:this._latlngs.length} +for(t=0;t180){var o=this._vincenty_inverse(e,l),r=this._intersection(e,o.initialBearing,{lat:-89,lng:l.lng-e.lng>0?-INTERSECT_LNG:INTERSECT_LNG},0) +r?(i[s].push(L.latLng(r.lat,r.lng)),s++,i[s]=[],e=L.latLng(r.lat,-r.lng),i[s].push(e)):(s++,i[s]=[],i[s].push(l),e=l,n++)}else i[s].push(l),e=l,n++}this._latlngs=i,L.MultiPolyline.prototype.setLatLngs.call(this,this._latlngs)},_generate_Geodesic:function(t){var a,n,i,s=[],e=0 +for(n=0;n180){var g=this._intersection(L.latLng(t[n][i]),h.initialBearing,{lat:-89,lng:r.lng-l.lng>0?-INTERSECT_LNG:INTERSECT_LNG},0) +g?(s[e].push(L.latLng(g.lat,g.lng)),e++,s[e]=[],l=L.latLng(g.lat,-g.lng),s[e].push(l)):(e++,s[e]=[],s[e].push(r),l=r,a++)}else s[e].push(r),l=r,a++}}e++}return s},_generate_GeodesicDashed:function(t){var a,n,i,s=[],e=0 +for(n=0;n180){var g=this._intersection(L.latLng(t[n][i]),h.initialBearing,{lat:-89,lng:r.lng-l.lng>0?-INTERSECT_LNG:INTERSECT_LNG},0) +g?(s[e].push(L.latLng(g.lat,g.lng)),e++,s[e]=[],l=L.latLng(g.lat,-g.lng),s[e].push(l)):(e++,s[e]=[],s[e].push(r),l=r,a++)}else{s[e].push(r),e++ +var M=this._vincenty_direct(L.latLng(t[n][i]),h.initialBearing,h.distance/this.options.steps*a,this.options.wrap) +s[e]=[],s[e].push(L.latLng(M.lat,M.lng)),a++}}}e++}return s},_vincenty_direct:function(t,a,n,i){var s,e=t.lat.toRadians(),h=t.lng.toRadians(),l=a.toRadians(),o=n,r=this.datum.ellipsoid.a,g=this.datum.ellipsoid.b,M=this.datum.ellipsoid.f,c=Math.sin(l),p=Math.cos(l),u=(1-M)*Math.tan(e),L=1/Math.sqrt(1+u*u),d=u*L,v=Math.atan2(u,p),_=L*c,f=1-_*_,y=f*(r*r-g*g)/(g*g),I=1+y/16384*(4096+y*(-768+y*(320-175*y))),N=y/1024*(256+y*(-128+y*(74-47*y))),R=o/(g*I),P=0 +do{var m=Math.cos(2*v+R),b=Math.sin(R),E=Math.cos(R),T=N*b*(m+N/4*(E*(-1+2*m*m)-N/6*m*(-3+4*b*b)*(-3+4*m*m))) +s=R,R=o/(g*I)+T}while(Math.abs(R-s)>1e-12&&++P) +var G=d*b-L*E*p,D=Math.atan2(d*E+L*b*p,(1-M)*Math.sqrt(_*_+G*G)),B=Math.atan2(b*c,L*E-d*b*p),C=M/16*f*(4+M*(4-3*f)),S=B-(1-C)*M*_*(R+C*b*(m+C*E*(-1+2*m*m))) +if(i)var w=(h+S+3*Math.PI)%(2*Math.PI)-Math.PI +else var w=h+S +var q=Math.atan2(_,-G) +return{lat:D.toDegrees(),lng:w.toDegrees(),finalBearing:q.toDegrees()}},_vincenty_inverse:function(t,a){var n,i=t.lat.toRadians(),s=t.lng.toRadians(),e=a.lat.toRadians(),h=a.lng.toRadians(),l=this.datum.ellipsoid.a,o=this.datum.ellipsoid.b,r=this.datum.ellipsoid.f,g=h-s,M=(1-r)*Math.tan(i),c=1/Math.sqrt(1+M*M),p=M*c,u=(1-r)*Math.tan(e),L=1/Math.sqrt(1+u*u),d=u*L,v=g,_=0 +do{var f=Math.sin(v),y=Math.cos(v),I=L*f*L*f+(c*d-p*L*y)*(c*d-p*L*y),N=Math.sqrt(I) +if(0==N)return 0 +var R=p*d+c*L*y,P=Math.atan2(N,R),m=c*L*f/N,b=1-m*m,E=R-2*p*d/b +isNaN(E)&&(E=0) +var T=r/16*b*(4+r*(4-3*b)) +n=v,v=g+(1-T)*r*m*(P+T*N*(E+T*R*(-1+2*E*E)))}while(Math.abs(v-n)>1e-12&&++_<100) +if(_>=100)return console.log("Formula failed to converge. Altering target position."),this._vincenty_inverse(t,{lat:a.lat,lng:a.lng-.01}) +var G=b*(l*l-o*o)/(o*o),D=1+G/16384*(4096+G*(-768+G*(320-175*G))),B=G/1024*(256+G*(-128+G*(74-47*G))),C=B*N*(E+B/4*(R*(-1+2*E*E)-B/6*E*(-3+4*N*N)*(-3+4*E*E))),S=o*D*(P-C),w=Math.atan2(L*f,c*d-p*L*y),q=Math.atan2(c*f,-p*L+c*d*y) +return S=+S.toFixed(3),{distance:S,initialBearing:w.toDegrees(),finalBearing:q.toDegrees()}},_intersection:function(t,a,n,i){var s=t.lat.toRadians(),e=t.lng.toRadians(),h=n.lat.toRadians(),l=n.lng.toRadians(),o=(+a).toRadians(),r=(+i).toRadians(),g=h-s,M=l-e,c=2*Math.asin(Math.sqrt(Math.sin(g/2)*Math.sin(g/2)+Math.cos(s)*Math.cos(h)*Math.sin(M/2)*Math.sin(M/2))) +if(0==c)return null +var p=Math.acos((Math.sin(h)-Math.sin(s)*Math.cos(c))/(Math.sin(c)*Math.cos(s))) +isNaN(p)&&(p=0) +var u=Math.acos((Math.sin(s)-Math.sin(h)*Math.cos(c))/(Math.sin(c)*Math.cos(h))) +if(Math.sin(l-e)>0)var L=p,d=2*Math.PI-u +else var L=2*Math.PI-p,d=u +var v=(o-L+Math.PI)%(2*Math.PI)-Math.PI,_=(d-r+Math.PI)%(2*Math.PI)-Math.PI +if(0==Math.sin(v)&&0==Math.sin(_))return null +if(Math.sin(v)*Math.sin(_)<0)return null +var f=Math.acos(-Math.cos(v)*Math.cos(_)+Math.sin(v)*Math.sin(_)*Math.cos(c)),y=Math.atan2(Math.sin(c)*Math.sin(v)*Math.sin(_),Math.cos(_)+Math.cos(v)*Math.cos(f)),I=Math.asin(Math.sin(s)*Math.cos(y)+Math.cos(s)*Math.sin(y)*Math.cos(o)),N=Math.atan2(Math.sin(o)*Math.sin(y)*Math.cos(s),Math.cos(y)-Math.sin(s)*Math.sin(I)),R=e+N +return R=(R+3*Math.PI)%(2*Math.PI)-Math.PI,{lat:I.toDegrees(),lng:R.toDegrees()}},_merge_options:function(t,a){var n={} +for(var i in t)n[i]=t[i] +for(var i in a)n[i]=a[i] +return n}}),L.geodesic=function(t,a){return new L.Geodesic(t,a)} \ No newline at end of file diff --git a/Phi/main.js b/Phi/main.js index 6dcf49979..96a4940b3 100644 --- a/Phi/main.js +++ b/Phi/main.js @@ -7,6 +7,7 @@ require.config({ kojqui : '3rdparty/knockout-jqueryui', sprintf : '3rdparty/sprintf/sprintf.min', leaflet : '3rdparty/leaflet-0.7.3/leaflet', + geodesic : '3rdparty/leaflet-0.7.3/Leaflet.Geodesic.min', text : '3rdparty/require/text', flot : '3rdparty/flot/jquery.flot', flotresize : '3rdparty/flot/jquery.flot.resize', diff --git a/Phi/topics/Map/RouteLayer.js b/Phi/topics/Map/RouteLayer.js index 8e2a2e893..041900945 100644 --- a/Phi/topics/Map/RouteLayer.js +++ b/Phi/topics/Map/RouteLayer.js @@ -2,7 +2,7 @@ if (typeof define === "function" && define.amd) { // AMD. Register as an anonymous module. define([ - 'leaflet', 'props', './MapIcons', 'knockout' + 'leaflet', 'props', './MapIcons', 'knockout', 'geodesic' ], factory); } else { // Browser globals @@ -31,13 +31,21 @@ }); self.waypointCountSubscription = self.waypointCount.subscribe(function() { self.update(); + }); - }) + self.geodesic = L.geodesic([], { + weight: 5, + opacity: 0.5, + color: 'blue', + steps: 20, + }).addTo(map); }, onRemove : function(map) { - this.waypointCountSubscription.dispose(); - this.waypointCount.dispose(); + var self = this; + self.waypointCountSubscription.dispose(); + self.waypointCount.dispose(); + map.removeLayer(self.geodesic); leaflet.GeoJSON.prototype.onRemove.call(this, map); }, @@ -55,8 +63,15 @@ var jqxhr = $.get(url).done(function(data) { self.clearLayers(); var geoJSON = self.routePropsToGeoJson(data); - if (geoJSON) + if (geoJSON) { self.addData(geoJSON); + var latlngs = []; + geoJSON.features.forEach( function(f) { + if( f.geometry && f.geometry.coordinates ) + latlngs.push( new L.LatLng(f.geometry.coordinates[1], f.geometry.coordinates[0] ) ); + }); + self.geodesic.setLatLngs([latlngs]); + } }).fail(function(a, b) { // self.stop(); // TODO: Should we? alert('failed to load RouteManager data'); @@ -69,7 +84,6 @@ type : "FeatureCollection", features : [], }; - var lineString = []; var root = new SGPropertyNode(props); root.getChildren("wp").forEach(function(wp) { @@ -80,7 +94,6 @@ var position = [ lon, lat ]; - lineString.push(position); geoJSON.features.push({ "type" : "Feature", @@ -93,12 +106,7 @@ }); }); - geoJSON.features.push({ - "type" : "LineString", - "coordinates" : lineString, - }); - - if (lineString.length >= 2) + if (geoJSON.features.length >= 2) return geoJSON; },