246 lines
8.4 KiB
JavaScript
246 lines
8.4 KiB
JavaScript
'use strict';
|
|
import {PJD_3PARAM, PJD_7PARAM, HALF_PI} from './constants/values';
|
|
export function compareDatums(source, dest) {
|
|
if (source.datum_type !== dest.datum_type) {
|
|
return false; // false, datums are not equal
|
|
} else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) {
|
|
// the tolerance for es is to ensure that GRS80 and WGS84
|
|
// are considered identical
|
|
return false;
|
|
} else if (source.datum_type === PJD_3PARAM) {
|
|
return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]);
|
|
} else if (source.datum_type === PJD_7PARAM) {
|
|
return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]);
|
|
} else {
|
|
return true; // datums are equal
|
|
}
|
|
} // cs_compare_datums()
|
|
|
|
/*
|
|
* The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
|
|
* (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
|
|
* according to the current ellipsoid parameters.
|
|
*
|
|
* Latitude : Geodetic latitude in radians (input)
|
|
* Longitude : Geodetic longitude in radians (input)
|
|
* Height : Geodetic height, in meters (input)
|
|
* X : Calculated Geocentric X coordinate, in meters (output)
|
|
* Y : Calculated Geocentric Y coordinate, in meters (output)
|
|
* Z : Calculated Geocentric Z coordinate, in meters (output)
|
|
*
|
|
*/
|
|
export function geodeticToGeocentric(p, es, a) {
|
|
var Longitude = p.x;
|
|
var Latitude = p.y;
|
|
var Height = p.z ? p.z : 0; //Z value not always supplied
|
|
|
|
var Rn; /* Earth radius at location */
|
|
var Sin_Lat; /* Math.sin(Latitude) */
|
|
var Sin2_Lat; /* Square of Math.sin(Latitude) */
|
|
var Cos_Lat; /* Math.cos(Latitude) */
|
|
|
|
/*
|
|
** Don't blow up if Latitude is just a little out of the value
|
|
** range as it may just be a rounding issue. Also removed longitude
|
|
** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
|
|
*/
|
|
if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
|
|
Latitude = -HALF_PI;
|
|
} else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
|
|
Latitude = HALF_PI;
|
|
} else if (Latitude < -HALF_PI) {
|
|
/* Latitude out of range */
|
|
//..reportError('geocent:lat out of range:' + Latitude);
|
|
return { x: -Infinity, y: -Infinity, z: p.z };
|
|
} else if (Latitude > HALF_PI) {
|
|
/* Latitude out of range */
|
|
return { x: Infinity, y: Infinity, z: p.z };
|
|
}
|
|
|
|
if (Longitude > Math.PI) {
|
|
Longitude -= (2 * Math.PI);
|
|
}
|
|
Sin_Lat = Math.sin(Latitude);
|
|
Cos_Lat = Math.cos(Latitude);
|
|
Sin2_Lat = Sin_Lat * Sin_Lat;
|
|
Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat));
|
|
return {
|
|
x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
|
|
y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
|
|
z: ((Rn * (1 - es)) + Height) * Sin_Lat
|
|
};
|
|
} // cs_geodetic_to_geocentric()
|
|
|
|
export function geocentricToGeodetic(p, es, a, b) {
|
|
/* local defintions and variables */
|
|
/* end-criterium of loop, accuracy of sin(Latitude) */
|
|
var genau = 1e-12;
|
|
var genau2 = (genau * genau);
|
|
var maxiter = 30;
|
|
|
|
var P; /* distance between semi-minor axis and location */
|
|
var RR; /* distance between center and location */
|
|
var CT; /* sin of geocentric latitude */
|
|
var ST; /* cos of geocentric latitude */
|
|
var RX;
|
|
var RK;
|
|
var RN; /* Earth radius at location */
|
|
var CPHI0; /* cos of start or old geodetic latitude in iterations */
|
|
var SPHI0; /* sin of start or old geodetic latitude in iterations */
|
|
var CPHI; /* cos of searched geodetic latitude */
|
|
var SPHI; /* sin of searched geodetic latitude */
|
|
var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
|
|
var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */
|
|
|
|
var X = p.x;
|
|
var Y = p.y;
|
|
var Z = p.z ? p.z : 0.0; //Z value not always supplied
|
|
var Longitude;
|
|
var Latitude;
|
|
var Height;
|
|
|
|
P = Math.sqrt(X * X + Y * Y);
|
|
RR = Math.sqrt(X * X + Y * Y + Z * Z);
|
|
|
|
/* special cases for latitude and longitude */
|
|
if (P / a < genau) {
|
|
|
|
/* special case, if P=0. (X=0., Y=0.) */
|
|
Longitude = 0.0;
|
|
|
|
/* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
|
|
* of ellipsoid (=center of mass), Latitude becomes PI/2 */
|
|
if (RR / a < genau) {
|
|
Latitude = HALF_PI;
|
|
Height = -b;
|
|
return {
|
|
x: p.x,
|
|
y: p.y,
|
|
z: p.z
|
|
};
|
|
}
|
|
} else {
|
|
/* ellipsoidal (geodetic) longitude
|
|
* interval: -PI < Longitude <= +PI */
|
|
Longitude = Math.atan2(Y, X);
|
|
}
|
|
|
|
/* --------------------------------------------------------------
|
|
* Following iterative algorithm was developped by
|
|
* "Institut for Erdmessung", University of Hannover, July 1988.
|
|
* Internet: www.ife.uni-hannover.de
|
|
* Iterative computation of CPHI,SPHI and Height.
|
|
* Iteration of CPHI and SPHI to 10**-12 radian resp.
|
|
* 2*10**-7 arcsec.
|
|
* --------------------------------------------------------------
|
|
*/
|
|
CT = Z / RR;
|
|
ST = P / RR;
|
|
RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST);
|
|
CPHI0 = ST * (1.0 - es) * RX;
|
|
SPHI0 = CT * RX;
|
|
iter = 0;
|
|
|
|
/* loop to find sin(Latitude) resp. Latitude
|
|
* until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
|
|
do {
|
|
iter++;
|
|
RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0);
|
|
|
|
/* ellipsoidal (geodetic) height */
|
|
Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0);
|
|
|
|
RK = es * RN / (RN + Height);
|
|
RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST);
|
|
CPHI = ST * (1.0 - RK) * RX;
|
|
SPHI = CT * RX;
|
|
SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
|
|
CPHI0 = CPHI;
|
|
SPHI0 = SPHI;
|
|
}
|
|
while (SDPHI * SDPHI > genau2 && iter < maxiter);
|
|
|
|
/* ellipsoidal (geodetic) latitude */
|
|
Latitude = Math.atan(SPHI / Math.abs(CPHI));
|
|
return {
|
|
x: Longitude,
|
|
y: Latitude,
|
|
z: Height
|
|
};
|
|
} // cs_geocentric_to_geodetic()
|
|
|
|
/****************************************************************/
|
|
// pj_geocentic_to_wgs84( p )
|
|
// p = point to transform in geocentric coordinates (x,y,z)
|
|
|
|
|
|
/** point object, nothing fancy, just allows values to be
|
|
passed back and forth by reference rather than by value.
|
|
Other point classes may be used as long as they have
|
|
x and y properties, which will get modified in the transform method.
|
|
*/
|
|
export function geocentricToWgs84(p, datum_type, datum_params) {
|
|
|
|
if (datum_type === PJD_3PARAM) {
|
|
// if( x[io] === HUGE_VAL )
|
|
// continue;
|
|
return {
|
|
x: p.x + datum_params[0],
|
|
y: p.y + datum_params[1],
|
|
z: p.z + datum_params[2],
|
|
};
|
|
} else if (datum_type === PJD_7PARAM) {
|
|
var Dx_BF = datum_params[0];
|
|
var Dy_BF = datum_params[1];
|
|
var Dz_BF = datum_params[2];
|
|
var Rx_BF = datum_params[3];
|
|
var Ry_BF = datum_params[4];
|
|
var Rz_BF = datum_params[5];
|
|
var M_BF = datum_params[6];
|
|
// if( x[io] === HUGE_VAL )
|
|
// continue;
|
|
return {
|
|
x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
|
|
y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
|
|
z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
|
|
};
|
|
}
|
|
} // cs_geocentric_to_wgs84
|
|
|
|
/****************************************************************/
|
|
// pj_geocentic_from_wgs84()
|
|
// coordinate system definition,
|
|
// point to transform in geocentric coordinates (x,y,z)
|
|
export function geocentricFromWgs84(p, datum_type, datum_params) {
|
|
|
|
if (datum_type === PJD_3PARAM) {
|
|
//if( x[io] === HUGE_VAL )
|
|
// continue;
|
|
return {
|
|
x: p.x - datum_params[0],
|
|
y: p.y - datum_params[1],
|
|
z: p.z - datum_params[2],
|
|
};
|
|
|
|
} else if (datum_type === PJD_7PARAM) {
|
|
var Dx_BF = datum_params[0];
|
|
var Dy_BF = datum_params[1];
|
|
var Dz_BF = datum_params[2];
|
|
var Rx_BF = datum_params[3];
|
|
var Ry_BF = datum_params[4];
|
|
var Rz_BF = datum_params[5];
|
|
var M_BF = datum_params[6];
|
|
var x_tmp = (p.x - Dx_BF) / M_BF;
|
|
var y_tmp = (p.y - Dy_BF) / M_BF;
|
|
var z_tmp = (p.z - Dz_BF) / M_BF;
|
|
//if( x[io] === HUGE_VAL )
|
|
// continue;
|
|
|
|
return {
|
|
x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
|
|
y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
|
|
z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
|
|
};
|
|
} //cs_geocentric_from_wgs84()
|
|
}
|