📄 geocent.cpp
字号:
#include "stdafx.h"
#include "geocent.h"#include <math.h>
/* * math.h - is needed for calls to sin, cos, tan and sqrt. * geocent.h - is needed for Error codes and prototype error checking. *//***************************************************************************//* * DEFINES */#define PI 3.14159265358979323e0#define PI_OVER_2 (PI / 2.0e0)#define FALSE 0#define TRUE 1#define COS_67P5 0.38268343236508977 /* cosine of 67.5 degrees */#define AD_C 1.0026000 /* Toms region 1 constant *//***************************************************************************//* * GLOBAL DECLARATIONS *//* Ellipsoid parameters, default to WGS 84 */double Geocent_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */double Geocent_b = 6356752.3142; /* Semi-minor axis of ellipsoid */double Geocent_a2 = 40680631590769.0; /* Square of semi-major axis */double Geocent_b2 = 40408299984087.05; /* Square of semi-minor axis */double Geocent_e2 = 0.0066943799901413800; /* Eccentricity squared */double Geocent_ep2 = 0.00673949675658690300; /* 2nd eccentricity squared *//* * These state variables are for optimization purposes. The only function * that should modify them is Set_Geocentric_Parameters. *//***************************************************************************//* * FUNCTIONS */long Set_Geocentric_Parameters (double a, double b) { /* BEGIN Set_Geocentric_Parameters *//* * The function Set_Geocentric_Parameters receives the ellipsoid parameters * as inputs and sets the corresponding state variables. * * a : Semi-major axis, in meters. (input) * b : Semi-minor axis, in meters. (input) */ long Error_Code = GEOCENT_NO_ERROR; if (a <= 0.0) Error_Code |= GEOCENT_A_ERROR; if (b <= 0.0) Error_Code |= GEOCENT_B_ERROR; if (a < b) Error_Code |= GEOCENT_A_LESS_B_ERROR; if (!Error_Code) { Geocent_a = a; Geocent_b = b; Geocent_a2 = a * a; Geocent_b2 = b * b; Geocent_e2 = (Geocent_a2 - Geocent_b2) / Geocent_a2; Geocent_ep2 = (Geocent_a2 - Geocent_b2) / Geocent_b2; } return (Error_Code);} /* END OF Set_Geocentric_Parameters */void Get_Geocentric_Parameters (double *a, double *b){ /* BEGIN Get_Geocentric_Parameters *//* * The function Get_Geocentric_Parameters returns the ellipsoid parameters * to be used in geocentric coordinate conversions. * * a : Semi-major axis, in meters. (output) * b : Semi-minor axis, in meters. (output) */ *a = Geocent_a; *b = Geocent_b;} /* END OF Get_Geocentric_Parameters */long Convert_Geodetic_To_Geocentric (double Latitude, double Longitude, double Height, double *X, double *Y, double *Z) { /* BEGIN Convert_Geodetic_To_Geocentric *//* * 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) * */ long Error_Code = GEOCENT_NO_ERROR; double Rn; /* Earth radius at location */ double Sin_Lat; /* sin(Latitude) */ double Sin2_Lat; /* Square of sin(Latitude) */ double Cos_Lat; /* 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 cos() and sin(). NFW for PROJ.4, Sep/2001. */ if( Latitude < -PI_OVER_2 && Latitude > -1.001 * PI_OVER_2 ) Latitude = -PI_OVER_2; else if( Latitude > PI_OVER_2 && Latitude < 1.001 * PI_OVER_2 ) Latitude = PI_OVER_2; else if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2)) { /* Latitude out of range */ Error_Code |= GEOCENT_LAT_ERROR; } if (!Error_Code) { /* no errors */ if (Longitude > PI) Longitude -= (2*PI); Sin_Lat = sin(Latitude); Cos_Lat = cos(Latitude); Sin2_Lat = Sin_Lat * Sin_Lat; Rn = Geocent_a / (sqrt(1.0e0 - Geocent_e2 * Sin2_Lat)); *X = (Rn + Height) * Cos_Lat * cos(Longitude); *Y = (Rn + Height) * Cos_Lat * sin(Longitude); *Z = ((Rn * (1 - Geocent_e2)) + Height) * Sin_Lat; } return (Error_Code);} /* END OF Convert_Geodetic_To_Geocentric *//* * The function Convert_Geocentric_To_Geodetic converts geocentric * coordinates (X, Y, Z) to geodetic coordinates (latitude, longitude, * and height), according to the current ellipsoid parameters. * * X : Geocentric X coordinate, in meters. (input) * Y : Geocentric Y coordinate, in meters. (input) * Z : Geocentric Z coordinate, in meters. (input) * Latitude : Calculated latitude value in radians. (output) * Longitude : Calculated longitude value in radians. (output) * Height : Calculated height value, in meters. (output) */#define USE_ITERATIVE_METHODvoid Convert_Geocentric_To_Geodetic (double X, double Y, double Z, double *Latitude, double *Longitude, double *Height){ /* BEGIN Convert_Geocentric_To_Geodetic */#if !defined(USE_ITERATIVE_METHOD)/* * The method used here is derived from 'An Improved Algorithm for * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996 *//* Note: Variable names follow the notation used in Toms, Feb 1996 */ double W; /* distance from Z axis */ double W2; /* square of distance from Z axis */ double T0; /* initial estimate of vertical component */ double T1; /* corrected estimate of vertical component */ double S0; /* initial estimate of horizontal component */ double S1; /* corrected estimate of horizontal component */ double Sin_B0; /* sin(B0), B0 is estimate of Bowring aux variable */ double Sin3_B0; /* cube of sin(B0) */ double Cos_B0; /* cos(B0) */ double Sin_p1; /* sin(phi1), phi1 is estimated latitude */ double Cos_p1; /* cos(phi1) */ double Rn; /* Earth radius at location */ double Sum; /* numerator of cos(phi1) */ int At_Pole; /* indicates location is in polar region */ At_Pole = FALSE; if (X != 0.0) { *Longitude = atan2(Y,X); } else { if (Y > 0) { *Longitude = PI_OVER_2; } else if (Y < 0) { *Longitude = -PI_OVER_2; } else { At_Pole = TRUE; *Longitude = 0.0; if (Z > 0.0) { /* north pole */ *Latitude = PI_OVER_2; } else if (Z < 0.0) { /* south pole */ *Latitude = -PI_OVER_2; } else { /* center of earth */ *Latitude = PI_OVER_2; *Height = -Geocent_b; return; } } } W2 = X*X + Y*Y; W = sqrt(W2); T0 = Z * AD_C; S0 = sqrt(T0 * T0 + W2); Sin_B0 = T0 / S0; Cos_B0 = W / S0; Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0; T1 = Z + Geocent_b * Geocent_ep2 * Sin3_B0; Sum = W - Geocent_a * Geocent_e2 * Cos_B0 * Cos_B0 * Cos_B0; S1 = sqrt(T1*T1 + Sum * Sum); Sin_p1 = T1 / S1; Cos_p1 = Sum / S1; Rn = Geocent_a / sqrt(1.0 - Geocent_e2 * Sin_p1 * Sin_p1); if (Cos_p1 >= COS_67P5) { *Height = W / Cos_p1 - Rn; } else if (Cos_p1 <= -COS_67P5) { *Height = W / -Cos_p1 - Rn; } else { *Height = Z / Sin_p1 + Rn * (Geocent_e2 - 1.0); } if (At_Pole == FALSE) { *Latitude = atan(Sin_p1 / Cos_p1); }#else /* defined(USE_ITERATIVE_METHOD) *//** Reference...* ============* Wenzel, H.-G.(1985): Hochauflösende Kugelfunktionsmodelle für* das Gravitationspotential der Erde. Wiss. Arb. Univ. Hannover* Nr. 137, p. 130-131.* Programmed by GGA- Leibniz-Institue of Applied Geophysics* Stilleweg 2* D-30655 Hannover* Federal Republic of Germany* Internet: www.gga-hannover.de** Hannover, March 1999, April 2004.* see also: comments in statements* remarks:* Mathematically exact and because of symmetry of rotation-ellipsoid,* each point (X,Y,Z) has at least two solutions (Latitude1,Longitude1,Height1) and* (Latitude2,Longitude2,Height2). Is point=(0.,0.,Z) (P=0.), so you get even* four solutions, every two symmetrical to the semi-minor axis.* Here Height1 and Height2 have at least a difference in order of* radius of curvature (e.g. (0,0,b)=> (90.,0.,0.) or (-90.,0.,-2b);* (a+100.)*(sqrt(2.)/2.,sqrt(2.)/2.,0.) => (0.,45.,100.) or* (0.,225.,-(2a+100.))).* The algorithm always computes (Latitude,Longitude) with smallest |Height|.* For normal computations, that means |Height|<10000.m, algorithm normally* converges after to 2-3 steps!!!* But if |Height| has the amount of length of ellipsoid's axis* (e.g. -6300000.m), algorithm needs about 15 steps.*//* local defintions and variables *//* end-criterium of loop, accuracy of sin(Latitude) */#define genau 1.E-12#define genau2 (genau*genau)#define maxiter 30 double P; /* distance between semi-minor axis and location */ double RR; /* distance between center and location */ double CT; /* sin of geocentric latitude */ double ST; /* cos of geocentric latitude */ double RX; double RK; double RN; /* Earth radius at location */ double CPHI0; /* cos of start or old geodetic latitude in iterations */ double SPHI0; /* sin of start or old geodetic latitude in iterations */ double CPHI; /* cos of searched geodetic latitude */ double SPHI; /* sin of searched geodetic latitude */ double SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */ int At_Pole; /* indicates location is in polar region */ int iter; /* # of continous iteration, max. 30 is always enough (s.a.) */ At_Pole = FALSE; P = sqrt(X*X+Y*Y); RR = sqrt(X*X+Y*Y+Z*Z);/* special cases for latitude and longitude */ if (P/Geocent_a < genau) {/* special case, if P=0. (X=0., Y=0.) */ At_Pole = TRUE; *Longitude = 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/Geocent_a < genau) { *Latitude = PI_OVER_2; *Height = -Geocent_b; return ; } } else {/* ellipsoidal (geodetic) longitude * interval: -PI < Longitude <= +PI */ *Longitude=atan2(Y,X); }/* -------------------------------------------------------------- * Following iterative algorithm was developped by * "Institut für 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/sqrt(1.0-Geocent_e2*(2.0-Geocent_e2)*ST*ST); CPHI0 = ST*(1.0-Geocent_e2)*RX; SPHI0 = CT*RX; iter = 0;/* loop to find sin(Latitude) resp. Latitude * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */ do { iter++; RN = Geocent_a/sqrt(1.0-Geocent_e2*SPHI0*SPHI0);/* ellipsoidal (geodetic) height */ *Height = P*CPHI0+Z*SPHI0-RN*(1.0-Geocent_e2*SPHI0*SPHI0); RK = Geocent_e2*RN/(RN+*Height); RX = 1.0/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=atan(SPHI/fabs(CPHI)); return;#endif /* defined(USE_ITERATIVE_METHOD) */} /* END OF Convert_Geocentric_To_Geodetic */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -