Files
openlayers/src/ol/ellipsoid.js
2013-02-18 12:32:43 +01:00

171 lines
5.3 KiB
JavaScript

goog.provide('ol.Ellipsoid');
goog.require('goog.math');
goog.require('ol.Coordinate');
/**
* @constructor
* @param {number} a Major radius.
* @param {number} flattening Flattening.
*/
ol.Ellipsoid = function(a, flattening) {
/**
* @type {number}
*/
this.a = a;
/**
* @type {number}
*/
this.flattening = flattening;
/**
* @type {number}
*/
this.b = this.a * (1 - this.flattening);
};
/**
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {{distance: number, initialBearing: number, finalBearing: number}}
* Vincenty.
*/
ol.Ellipsoid.prototype.vincenty =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var minDeltaLambda = goog.isDef(opt_minDeltaLambda) ?
opt_minDeltaLambda : 1e-12;
var maxIterations = goog.isDef(opt_maxIterations) ?
opt_maxIterations : 100;
var f = this.flattening;
var lat1 = goog.math.toRadians(c1.y);
var lat2 = goog.math.toRadians(c2.y);
var deltaLon = goog.math.toRadians(c2.x - c1.x);
var U1 = Math.atan((1 - f) * Math.tan(lat1));
var cosU1 = Math.cos(U1);
var sinU1 = Math.sin(U1);
var U2 = Math.atan((1 - f) * Math.tan(lat2));
var cosU2 = Math.cos(U2);
var sinU2 = Math.sin(U2);
var lambda = deltaLon;
var cosSquaredAlpha, sinAlpha;
var cosLambda, deltaLambda = Infinity, sinLambda;
var cos2SigmaM, cosSigma, sigma, sinSigma;
var i;
for (i = maxIterations; i > 0; --i) {
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
var x = cosU2 * sinLambda;
var y = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
sinSigma = Math.sqrt(x * x + y * y);
if (sinSigma === 0) {
return {
distance: 0,
initialBearing: 0,
finalBearing: 0
};
}
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = Math.atan2(sinSigma, cosSigma);
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
cosSquaredAlpha = 1 - sinAlpha * sinAlpha;
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSquaredAlpha;
if (isNaN(cos2SigmaM)) {
cos2SigmaM = 0;
}
var C = f / 16 * cosSquaredAlpha * (4 + f * (4 - 3 * cosSquaredAlpha));
var lambdaPrime = deltaLon + (1 - C) * f * sinAlpha * (sigma +
C * sinSigma * (cos2SigmaM +
C * cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1)));
deltaLambda = Math.abs(lambdaPrime - lambda);
lambda = lambdaPrime;
if (deltaLambda < minDeltaLambda) {
break;
}
}
if (i === 0) {
return {
distance: NaN,
finalBearing: NaN,
initialBearing: NaN
};
}
var aSquared = this.a * this.a;
var bSquared = this.b * this.b;
var uSquared = cosSquaredAlpha * (aSquared - bSquared) / bSquared;
var A = 1 + uSquared / 16384 *
(4096 + uSquared * (uSquared * (320 - 175 * uSquared) - 768));
var B = uSquared / 1024 *
(256 + uSquared * (uSquared * (74 - 47 * uSquared) - 128));
var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 *
(cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1) -
B / 6 * cos2SigmaM * (4 * sinSigma * sinSigma - 3) *
(4 * cos2SigmaM * cos2SigmaM - 3)));
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
var alpha1 = Math.atan2(cosU2 * sinLambda,
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
var alpha2 = Math.atan2(cosU1 * sinLambda,
cosU1 * sinU2 * cosLambda - sinU1 * cosU2);
return {
distance: this.b * A * (sigma - deltaSigma),
initialBearing: goog.math.toDegrees(alpha1),
finalBearing: goog.math.toDegrees(alpha2)
};
};
/**
* Returns the distance from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Vincenty distance.
*/
ol.Ellipsoid.prototype.vincentyDistance =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.distance;
};
/**
* Returns the final bearing from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Initial bearing.
*/
ol.Ellipsoid.prototype.vincentyFinalBearing =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.finalBearing;
};
/**
* Returns the initial bearing from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Initial bearing.
*/
ol.Ellipsoid.prototype.vincentyInitialBearing =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.initialBearing;
};