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
|
||||
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));
|
||||
// alternative geodesic line intermediate points function
|
||||
// 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);
|
||||
// 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);
|
||||
// maths based on http://williams.best.vwh.net/avform.htm#Int
|
||||
|
||||
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) {
|
||||
if (latlngs.length == 0) {
|
||||
return [];
|
||||
|
Loading…
x
Reference in New Issue
Block a user