geodesic line drawing: alternative intermediate point calculation code - based on simpler lon->lat formula rather than N intermediate points
more than good enough for line drawing, and hopefully will avoid odd rounding issues seen on mobile
This commit is contained in:
parent
0dff718f1f
commit
e536fb6d12
80
external/L.Geodesic.js
vendored
80
external/L.Geodesic.js
vendored
@ -34,52 +34,54 @@ Modified by qnstie 2013-07-17 to maintain compatibility with Leaflet.draw
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function geodesicConvertLine(startLatlng, endLatlng, convertedPoints) {
|
|
||||||
var i,
|
|
||||||
R = 6378137, // earth radius in meters (doesn't have to be exact)
|
|
||||||
maxlength = 5000, // meters before splitting
|
|
||||||
d2r = L.LatLng.DEG_TO_RAD,
|
|
||||||
r2d = L.LatLng.RAD_TO_DEG,
|
|
||||||
lat1, lat2, lng1, lng2, dLng, d, segments,
|
|
||||||
f, A, B, x, y, z, fLat, fLng;
|
|
||||||
|
|
||||||
dLng = (endLatlng.lng - startLatlng.lng) * d2r;
|
|
||||||
lat1 = startLatlng.lat * d2r;
|
|
||||||
lat2 = endLatlng.lat * d2r;
|
|
||||||
lng1 = startLatlng.lng * d2r;
|
|
||||||
lng2 = endLatlng.lng * d2r;
|
|
||||||
|
|
||||||
// http://en.wikipedia.org/wiki/Great-circle_distance
|
// alternative geodesic line intermediate points function
|
||||||
d = Math.atan2(Math.sqrt( Math.pow(Math.cos(lat2) * Math.sin(dLng), 2) + Math.pow(Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLng), 2) ), Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(dLng));
|
// as north/south lines have very little curvature in the projection, we cam use longitude (east/west) seperation
|
||||||
|
// to calculate intermediate points. hopeefully this will avoid the rounding issues seen in the full intermediate
|
||||||
|
// points code that have been seen
|
||||||
|
function geodesicConvertLine(startLatLng, endLatLng, convertedPoints) {
|
||||||
|
var R = 6378137; // earth radius in meters (doesn't have to be exact)
|
||||||
|
var d2r = L.LatLng.DEG_TO_RAD;
|
||||||
|
var r2d = L.LatLng.RAD_TO_DEG;
|
||||||
|
|
||||||
segments = Math.ceil(d * R / maxlength);
|
// maths based on http://williams.best.vwh.net/avform.htm#Int
|
||||||
// loop starts at 1 - we don't add the very first point
|
|
||||||
// loop ends before 'segments' is reached - we don't add the very last point here but outside the loop
|
|
||||||
// (this was to fix a bug - https://github.com/jonatkins/ingress-intel-total-conversion/issues/471
|
|
||||||
// rounding errors? maths bug? not sure - but it solves the issue! and is a slight optimisation)
|
|
||||||
// UPDATE: there still seem to be rounding errors on relatively short links - but only on mobile.
|
|
||||||
// let's only add intermediate points if there's two or more
|
|
||||||
if (segments >= 3) {
|
|
||||||
for (i = 1; i < segments; i++) {
|
|
||||||
// http://williams.best.vwh.net/avform.htm#Intermediate
|
|
||||||
// modified to handle longitude above +-180 degrees
|
|
||||||
f = i / segments;
|
|
||||||
A = Math.sin((1-f)*d) / Math.sin(d);
|
|
||||||
B = Math.sin(f*d) / Math.sin(d);
|
|
||||||
x = A * Math.cos(lat1) * Math.cos(0) + B * Math.cos(lat2) * Math.cos(dLng);
|
|
||||||
y = A * Math.cos(lat1) * Math.sin(0) + B * Math.cos(lat2) * Math.sin(dLng);
|
|
||||||
z = A * Math.sin(lat1) + B * Math.sin(lat2);
|
|
||||||
fLat = r2d * Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
|
|
||||||
fLng = r2d * (Math.atan2(y, x)+lng1);
|
|
||||||
|
|
||||||
convertedPoints.push(L.latLng([fLat, fLng]));
|
var lat1 = startLatLng.lat * d2r;
|
||||||
|
var lat2 = endLatLng.lat * d2r;
|
||||||
|
var lng1 = startLatLng.lng * d2r;
|
||||||
|
var lng2 = endLatLng.lng * d2r;
|
||||||
|
|
||||||
|
var dLng = lng2-lng1;
|
||||||
|
|
||||||
|
var segments = Math.floor(Math.abs(dLng * R / 5000));
|
||||||
|
|
||||||
|
if (segments > 1) {
|
||||||
|
// pre-calculate some constant values for the loop
|
||||||
|
var sinLat1 = Math.sin(lat1);
|
||||||
|
var sinLat2 = Math.sin(lat2);
|
||||||
|
var cosLat1 = Math.cos(lat1);
|
||||||
|
var cosLat2 = Math.cos(lat2);
|
||||||
|
|
||||||
|
var sinLat1CosLat2 = sinLat1*cosLat2;
|
||||||
|
var sinLat2CosLat1 = sinLat2*cosLat1;
|
||||||
|
|
||||||
|
var cosLat1CosLat2SinDLng = cosLat1*cosLat2*Math.sin(dLng);
|
||||||
|
|
||||||
|
for (var i=1; i < segments; i++) {
|
||||||
|
var iLng = lng1+dLng*(i/segments);
|
||||||
|
var iLat = Math.atan( (sinLat1CosLat2*Math.sin(lng2-iLng) + sinLat2CosLat1*Math.sin(iLng-lng1))
|
||||||
|
/ cosLat1CosLat2SinDLng)
|
||||||
|
|
||||||
|
var point = L.latLng ( [iLat*r2d, iLng*r2d] );
|
||||||
|
convertedPoints.push(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// push the final point unmodified
|
|
||||||
convertedPoints.push(L.latLng(endLatlng));
|
convertedPoints.push(L.latLng(endLatLng));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
L.geodesicConvertLines = function (latlngs, fill) {
|
L.geodesicConvertLines = function (latlngs, fill) {
|
||||||
if (latlngs.length == 0) {
|
if (latlngs.length == 0) {
|
||||||
return [];
|
return [];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user