@progress/kendo-charts
Version:
Kendo UI platform-independent Charts library
191 lines (159 loc) • 5.38 kB
JavaScript
import {
deepExtend,
deg,
rad,
round,
defined
} from '../common';
import {
datums
} from './datums';
function toSquare(value) {
return value * value;
}
let math = Math,
abs = math.abs,
atan = math.atan,
atan2 = math.atan2,
cos = math.cos,
sin = math.sin,
tan = math.tan;
export class Location {
constructor(lat, lng) {
this.initProperties();
if (arguments.length === 1) {
this.lat = lat[0];
this.lng = lat[1];
} else {
this.lat = lat;
this.lng = lng;
}
}
initProperties() {
deepExtend(this, {
DISTANCE_ITERATIONS: 100,
DISTANCE_CONVERGENCE: 1e-12,
DISTANCE_PRECISION: 2,
FORMAT: '{0:N6}{1:N6}'
});
}
toArray() {
return [
this.lat,
this.lng
];
}
equals(loc) {
return loc && loc.lat === this.lat && loc.lng === this.lng;
}
clone() {
return new Location(this.lat, this.lng);
}
round(precision) {
this.lng = round(this.lng, precision);
this.lat = round(this.lat, precision);
return this;
}
wrap() {
this.lng = this.lng % 180;
this.lat = this.lat % 90;
return this;
}
distanceTo(dest, datum) {
return this.greatCircleTo(dest, datum).distance;
}
destination(distance, initialBearing, initialDatum) {
let bearing = rad(initialBearing);
let datum = initialDatum || datums.WGS84;
let fromLat = rad(this.lat);
let fromLng = rad(this.lng);
let dToR = distance / datum.a;
let lat = math.asin(sin(fromLat) * cos(dToR) + cos(fromLat) * sin(dToR) * cos(bearing));
let lng = fromLng + atan2(sin(bearing) * sin(dToR) * cos(fromLat), cos(dToR) - sin(fromLat) * sin(lat));
return new Location(deg(lat), deg(lng));
}
greatCircleTo(initialDest, initialDatum) {
let dest = Location.create(dest);
let datum = initialDatum || datums.WGS84;
if (!dest || this.clone().round(8).equals(dest.clone().round(8))) {
return {
distance: 0,
azimuthFrom: 0,
azimuthTo: 0
};
}
// See http://en.wikipedia.org/wiki/Vincenty's_formulae#Notation
// o == sigma
// A == alpha
let a = datum.a;
let b = datum.b;
let f = datum.f;
let L = rad(dest.lng - this.lng);
let U1 = atan((1 - f) * tan(rad(this.lat)));
let sinU1 = sin(U1);
let cosU1 = cos(U1);
let U2 = atan((1 - f) * tan(rad(dest.lat)));
let sinU2 = sin(U2);
let cosU2 = cos(U2);
let lambda = L;
let prevLambda;
let i = this.DISTANCE_ITERATIONS;
let converged = false;
let sinLambda;
let cosLambda;
let sino;
let cosA2;
let coso;
let cos2om;
let sigma;
while (!converged && i-- > 0) {
sinLambda = sin(lambda);
cosLambda = cos(lambda);
sino = math.sqrt(toSquare(cosU2 * sinLambda) + toSquare(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
coso = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = atan2(sino, coso);
let sinA = cosU1 * cosU2 * sinLambda / sino;
cosA2 = 1 - toSquare(sinA);
cos2om = 0;
if (cosA2 !== 0) {
cos2om = coso - 2 * sinU1 * sinU2 / cosA2;
}
prevLambda = lambda;
let C = f / 16 * cosA2 * (4 + f * (4 - 3 * cosA2));
lambda = L + (1 - C) * f * sinA * (sigma + C * sino * (cos2om + C * coso * (-1 + 2 * toSquare(cos2om))));
converged = abs(lambda - prevLambda) <= this.DISTANCE_CONVERGENCE;
}
let u2 = cosA2 * (toSquare(a) - toSquare(b)) / toSquare(b);
let A = 1 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2)));
let B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2)));
let deltao = B * sino * (cos2om + B / 4 * (coso * (-1 + 2 * toSquare(cos2om)) - B / 6 * cos2om * (-3 + 4 * toSquare(sino)) * (-3 + 4 * toSquare(cos2om))));
let azimuthFrom = atan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
let azimuthTo = atan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
return {
distance: round(b * A * (sigma - deltao), this.DISTANCE_PRECISION),
azimuthFrom: deg(azimuthFrom),
azimuthTo: deg(azimuthTo)
};
}
// IE < 9 doesn't allow to override toString on definition
toString() {
// return kendo.format(this.FORMAT, this.lat, this.lng);
return String(this.lat) + "," + String(this.lng);
}
static fromLngLat(lngAndLat) {
return new Location(lngAndLat[1], lngAndLat[0]);
}
static fromLatLng(lngAndLat) {
return new Location(lngAndLat[0], lngAndLat[1]);
}
static create(a, b) {
if (defined(a)) {
if (a instanceof Location) {
return a.clone();
} else if (arguments.length === 1 && a.length === 2) {
return Location.fromLatLng(a);
}
return new Location(a, b);
}
}
}