UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

191 lines (159 loc) 5.38 kB
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); } } }