geodesy.c

Go to the documentation of this file.
00001 /**
00002 \file    geodesy.c
00003 \brief   GNSS core 'c' function library: geodesy related functions.
00004 \author  Glenn D. MacGougan (GDM)
00005 \date    2007-11-28
00006 \since   2005-08-14
00007 
00008 \b "LICENSE INFORMATION" \n
00009 Copyright (c) 2007, refer to 'author' doxygen tags \n
00010 All rights reserved. \n
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided the following conditions are met: \n
00014 
00015 - Redistributions of source code must retain the above copyright
00016  notice, this list of conditions and the following disclaimer. \n
00017 - Redistributions in binary form must reproduce the above copyright
00018  notice, this list of conditions and the following disclaimer in the
00019  documentation and/or other materials provided with the distribution. \n
00020 - The name(s) of the contributor(s) may not be used to endorse or promote 
00021  products derived from this software without specific prior written 
00022  permission. \n
00023 
00024 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00025 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00026 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00028 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00030 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00031 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00032 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00033 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00034 SUCH DAMAGE.
00035 */
00036 
00037 #include <math.h>
00038 #include "geodesy.h"
00039 #include "constants.h"
00040 
00041 
00042 /*************************************************************************************************/
00043 // static function definitions (for functions used in this file only)
00044 // static functions are functions that are only visable to other functions in the same file.
00045 
00046 // Many functions contained herein only need a, and e2.
00047 static BOOL GEODESY_GetReferenceEllipseParameters_A_E2( 
00048   const GEODESY_enumReferenceEllipse ellipse,
00049   double* a,      // semi-major axis of the reference ellipse                     [m]
00050   double* e2      // eccentricity of the reference ellipse (e2 = (a*a-b*b)/(a*a)) [] 
00051   );
00052 
00053 // Many functions contained herein only need a, b and e2.
00054 static BOOL GEODESY_GetReferenceEllipseParameters_A_B_E2( 
00055   const GEODESY_enumReferenceEllipse ellipse,
00056   double* a,      // semi-major axis of the reference ellipse                     [m]
00057   double* b,      // semi-minor axis of the reference ellipse                     [m]
00058   double* e2      // eccentricity of the reference ellipse (e2 = (a*a-b*b)/(a*a)) [] 
00059   );
00060 
00061 // return TRUE(1) if valid, FALSE(0) otherwise.
00062 static BOOL GEODESY_IsLatitudeValid( 
00063   const double latitude //!< expecting a value -pi/2 to pi/2 [rad]
00064   );
00065 /*************************************************************************************************/
00066 
00067 
00068 
00069 
00070 BOOL GEODESY_GetReferenceEllipseParameters( 
00071   const GEODESY_enumReferenceEllipse ellipse, //!< reference ellipse enumerated []
00072   double* a,      //!< semi-major axis of the reference ellipse                     [m]
00073   double* b,      //!< semi-minor axis of the reference ellipse (b = a - a*f_inv)   [m] 
00074   double* f_inv,  //!< inverse of the flattening of the reference ellipse           []
00075   double* e2      //!< eccentricity of the reference ellipse (e2 = (a*a-b*b)/(a*a)) [] 
00076   )
00077 {
00078   switch( ellipse )
00079   {
00080   case GEODESY_REFERENCE_ELLIPSE_AIRY_1830: 
00081     *a     = GEODESY_REFERENCE_ELLIPSE_AIRY_1830_A;
00082     *f_inv = GEODESY_REFERENCE_ELLIPSE_AIRY_1830_F_INV;
00083     *b     = GEODESY_REFERENCE_ELLIPSE_AIRY_1830_B;
00084     *e2    = GEODESY_REFERENCE_ELLIPSE_AIRY_1830_E2;
00085     break;
00086     
00087   case GEODESY_REFERENCE_ELLIPSE_MODIFED_AIRY:
00088     *a     = GEODESY_REFERENCE_ELLIPSE_MODIFED_AIRY_A;
00089     *f_inv = GEODESY_REFERENCE_ELLIPSE_MODIFED_AIRY_F_INV;
00090     *b     = GEODESY_REFERENCE_ELLIPSE_MODIFED_AIRY_B;
00091     *e2    = GEODESY_REFERENCE_ELLIPSE_MODIFED_AIRY_E2;
00092     break;
00093     
00094   case GEODESY_REFERENCE_ELLIPSE_AUSTRALIAN_NATIONAL:
00095     *a     = GEODESY_REFERENCE_ELLIPSE_AUSTRALIAN_NATIONAL_A;
00096     *f_inv = GEODESY_REFERENCE_ELLIPSE_AUSTRALIAN_NATIONAL_F_INV;
00097     *b     = GEODESY_REFERENCE_ELLIPSE_AUSTRALIAN_NATIONAL_B;
00098     *e2    = GEODESY_REFERENCE_ELLIPSE_AUSTRALIAN_NATIONAL_E2;
00099     break;
00100     
00101   case GEODESY_REFERENCE_ELLIPSE_BESSEL_1841:
00102     *a     = GEODESY_REFERENCE_ELLIPSE_BESSEL_1841_A;
00103     *f_inv = GEODESY_REFERENCE_ELLIPSE_BESSEL_1841_F_INV;
00104     *b     = GEODESY_REFERENCE_ELLIPSE_BESSEL_1841_B;
00105     *e2    = GEODESY_REFERENCE_ELLIPSE_BESSEL_1841_E2;
00106     break;
00107     
00108   case GEODESY_REFERENCE_ELLIPSE_CLARKE_1866:
00109     *a     = GEODESY_REFERENCE_ELLIPSE_CLARKE_1866_A;
00110     *f_inv = GEODESY_REFERENCE_ELLIPSE_CLARKE_1866_F_INV;
00111     *b     = GEODESY_REFERENCE_ELLIPSE_CLARKE_1866_B;
00112     *e2    = GEODESY_REFERENCE_ELLIPSE_CLARKE_1866_E2;
00113     break;
00114     
00115   case GEODESY_REFERENCE_ELLIPSE_CLARKE_1880:
00116     *a     = GEODESY_REFERENCE_ELLIPSE_CLARKE_1880_A;
00117     *f_inv = GEODESY_REFERENCE_ELLIPSE_CLARKE_1880_F_INV;
00118     *b     = GEODESY_REFERENCE_ELLIPSE_CLARKE_1880_B;
00119     *e2    = GEODESY_REFERENCE_ELLIPSE_CLARKE_1880_E2;
00120     break;
00121     
00122   case GEODESY_REFERENCE_ELLIPSE_EVEREST_INDIA_1830:
00123     *a     = GEODESY_REFERENCE_ELLIPSE_EVEREST_INDIA_1830_A;
00124     *f_inv = GEODESY_REFERENCE_ELLIPSE_EVEREST_INDIA_1830_F_INV;
00125     *b     = GEODESY_REFERENCE_ELLIPSE_EVEREST_INDIA_1830_B;
00126     *e2    = GEODESY_REFERENCE_ELLIPSE_EVEREST_INDIA_1830_E2;
00127     break;
00128     
00129   case GEODESY_REFERENCE_ELLIPSE_EVEREST_BRUNEI_E_MALAYSIA:
00130     *a     = GEODESY_REFERENCE_ELLIPSE_EVEREST_BRUNEI_E_MALAYSIA_A;
00131     *f_inv = GEODESY_REFERENCE_ELLIPSE_EVEREST_BRUNEI_E_MALAYSIA_F_INV;
00132     *b     = GEODESY_REFERENCE_ELLIPSE_EVEREST_BRUNEI_E_MALAYSIA_B;
00133     *e2    = GEODESY_REFERENCE_ELLIPSE_EVEREST_BRUNEI_E_MALAYSIA_E2;
00134     break;
00135     
00136   case GEODESY_REFERENCE_ELLIPSE_EVEREST_W_MALAYSIA_SINGAPORE:
00137     *a     = GEODESY_REFERENCE_ELLIPSE_EVEREST_W_MALAYSIA_SINGAPORE_A;
00138     *f_inv = GEODESY_REFERENCE_ELLIPSE_EVEREST_W_MALAYSIA_SINGAPORE_F_INV;
00139     *b     = GEODESY_REFERENCE_ELLIPSE_EVEREST_W_MALAYSIA_SINGAPORE_B;
00140     *e2    = GEODESY_REFERENCE_ELLIPSE_EVEREST_W_MALAYSIA_SINGAPORE_E2;
00141     break;
00142     
00143   case GEODESY_REFERENCE_ELLIPSE_GRS_1980:
00144     *a     = GEODESY_REFERENCE_ELLIPSE_GRS_1980_A;
00145     *f_inv = GEODESY_REFERENCE_ELLIPSE_GRS_1980_F_INV;
00146     *b     = GEODESY_REFERENCE_ELLIPSE_GRS_1980_B;
00147     *e2    = GEODESY_REFERENCE_ELLIPSE_GRS_1980_E2;
00148     break;
00149     
00150   case GEODESY_REFERENCE_ELLIPSE_HELMERT_1906:
00151     *a     = GEODESY_REFERENCE_ELLIPSE_HELMERT_1906_A;
00152     *f_inv = GEODESY_REFERENCE_ELLIPSE_HELMERT_1906_F_INV;
00153     *b     = GEODESY_REFERENCE_ELLIPSE_HELMERT_1906_B;
00154     *e2    = GEODESY_REFERENCE_ELLIPSE_HELMERT_1906_E2;
00155     break;
00156     
00157   case GEODESY_REFERENCE_ELLIPSE_HOUGH_1960:
00158     *a     = GEODESY_REFERENCE_ELLIPSE_HOUGH_1960_A;
00159     *f_inv = GEODESY_REFERENCE_ELLIPSE_HOUGH_1960_F_INV;
00160     *b     = GEODESY_REFERENCE_ELLIPSE_HOUGH_1960_B;
00161     *e2    = GEODESY_REFERENCE_ELLIPSE_HOUGH_1960_E2;
00162     break;
00163     
00164   case GEODESY_REFERENCE_ELLIPSE_INTERNATIONAL_1924:
00165     *a     = GEODESY_REFERENCE_ELLIPSE_INTERNATIONAL_1924_A;
00166     *f_inv = GEODESY_REFERENCE_ELLIPSE_INTERNATIONAL_1924_F_INV;
00167     *b     = GEODESY_REFERENCE_ELLIPSE_INTERNATIONAL_1924_B;
00168     *e2    = GEODESY_REFERENCE_ELLIPSE_INTERNATIONAL_1924_E2;
00169     break;
00170     
00171   case GEODESY_REFERENCE_ELLIPSE_SOUTH_AMERICAN_1969:
00172     *a     = GEODESY_REFERENCE_ELLIPSE_SOUTH_AMERICAN_1969_A;
00173     *f_inv = GEODESY_REFERENCE_ELLIPSE_SOUTH_AMERICAN_1969_F_INV;
00174     *b     = GEODESY_REFERENCE_ELLIPSE_SOUTH_AMERICAN_1969_B;
00175     *e2    = GEODESY_REFERENCE_ELLIPSE_SOUTH_AMERICAN_1969_E2;
00176     break;
00177     
00178   case GEODESY_REFERENCE_ELLIPSE_WGS72:
00179     *a     = GEODESY_REFERENCE_ELLIPSE_WGS72_A;
00180     *f_inv = GEODESY_REFERENCE_ELLIPSE_WGS72_F_INV;
00181     *b     = GEODESY_REFERENCE_ELLIPSE_WGS72_B;
00182     *e2    = GEODESY_REFERENCE_ELLIPSE_WGS72_E2;
00183     break;
00184     
00185   case GEODESY_REFERENCE_ELLIPSE_WGS84:
00186     *a     = GEODESY_REFERENCE_ELLIPSE_WGS84_A;
00187     *f_inv = GEODESY_REFERENCE_ELLIPSE_WGS84_F_INV;
00188     *b     = GEODESY_REFERENCE_ELLIPSE_WGS84_B;
00189     *e2    = GEODESY_REFERENCE_ELLIPSE_WGS84_E2;
00190     break;
00191 
00192   default:
00193     return FALSE;
00194     break;  
00195   }
00196   return TRUE;
00197 }
00198 
00199 
00200 // static
00201 BOOL GEODESY_GetReferenceEllipseParameters_A_E2( 
00202   const GEODESY_enumReferenceEllipse ellipse,
00203   double* a,      // semi-major axis of the reference ellipse                     [m]
00204   double* e2      // eccentricity of the reference ellipse (e2 = (a*a-b*b)/(a*a)) [] 
00205   )
00206 {  
00207   double b;
00208   double f_inv;  
00209   BOOL result;
00210 
00211   result = GEODESY_GetReferenceEllipseParameters( 
00212     ellipse,
00213     a,
00214     &b,
00215     &f_inv,
00216     e2 );
00217 
00218   return result;
00219 }
00220 
00221 
00222 // static
00223 BOOL GEODESY_GetReferenceEllipseParameters_A_B_E2( 
00224   const GEODESY_enumReferenceEllipse ellipse,
00225   double* a,      // semi-major axis of the reference ellipse                     [m]
00226   double* b,      // semi-minor axis of the reference ellipse                     [m]
00227   double* e2      // eccentricity of the reference ellipse (e2 = (a*a-b*b)/(a*a)) [] 
00228   )
00229 {  
00230   double f_inv;  
00231   BOOL result;
00232 
00233   result = GEODESY_GetReferenceEllipseParameters( 
00234     ellipse,
00235     a,
00236     b,
00237     &f_inv,
00238     e2 );
00239 
00240   return result;
00241 }
00242 
00243 // static
00244 BOOL GEODESY_IsLatitudeValid( 
00245   const double latitude //!< expecting a value -pi/2 to pi/2 [rad]
00246   )
00247 {
00248   // check for valid latitude out of range
00249   if( latitude > HALFPI || latitude < -HALFPI )  
00250     return FALSE;
00251   else
00252     return TRUE;
00253 }
00254 
00255 
00256 
00257 
00258 
00259 
00260 
00261 BOOL GEODESY_ConvertGeodeticCurvilinearToEarthFixedCartesianCoordinates(
00262   const GEODESY_enumReferenceEllipse  referenceEllipse,  //!< reference ellipse enumerated []
00263   const double latitude,   //!< geodetic latitude                [rad]
00264   const double longitude,  //!< geodetic longitude               [rad]
00265   const double height,     //!< geodetic height                  [m]
00266   double *x,               //!< earth fixed cartesian coordinate [m]
00267   double *y,               //!< earth fixed cartesian coordinate [m]
00268   double *z                //!< earth fixed cartesian coordinate [m]
00269   )
00270 {  
00271   double a;      // semi-major axis of reference ellipse [m]
00272   double e2;     // first eccentricity of reference ellipse []
00273   double N;      // prime vertical radius of curvature [m]
00274   double sinlat; // sin of the latitude
00275   double dtmp;   // temp
00276   BOOL result;
00277 
00278   // get necessary reference ellipse parameters
00279   result = GEODESY_GetReferenceEllipseParameters_A_E2( referenceEllipse, &a, &e2 );
00280   if( result == FALSE )
00281   {
00282     *x = 0.0;
00283     *y = 0.0;
00284     *z = 0.0;
00285     return FALSE;
00286   }
00287   
00288   // check for valid latitude out of range
00289   result = GEODESY_IsLatitudeValid( latitude );
00290   if( result == FALSE )
00291   {
00292     *x = 0.0;
00293     *y = 0.0;
00294     *z = 0.0;
00295     return FALSE;
00296   }
00297 
00298   sinlat = sin( latitude );             
00299   N = a / sqrt( 1.0 - e2 * sinlat*sinlat );      
00300   dtmp = (N + height) * cos(latitude);
00301 
00302   *x = dtmp * cos(longitude);
00303   *y = dtmp * sin(longitude);
00304   *z = ( (1.0 - e2)*N + height ) * sinlat;
00305 
00306   return TRUE;
00307 }
00308 
00309 
00310 
00311 
00312 BOOL GEODESY_ConvertEarthFixedCartesianToGeodeticCurvilinearCoordinates(
00313   const GEODESY_enumReferenceEllipse  referenceEllipse,  //!< reference ellipse enumerated []
00314   const double x,              // earth fixed cartesian coordinate [m]
00315   const double y,              // earth fixed cartesian coordinate [m]
00316   const double z,              // earth fixed cartesian coordinate [m]  
00317   double *latitude,            // geodetic latitude              [rad]
00318   double *longitude,           // geodetic longitude             [rad]
00319   double *height               // geodetic height                [m]
00320   )
00321 {
00322   double a;      // semi-major axis of reference ellipse [m]
00323   double b;      // semi-minor axis of reference ellipse [m]
00324   double e2;     // first eccentricity of reference ellipse []
00325   double N;      // prime vertical radius of curvature [m]
00326   double p;      // sqrt( x^2 + y^2 ) [m]
00327   double dtmp;   // temp
00328   double sinlat; // sin(lat)
00329   double lat;    // temp geodetic latitude  [rad]
00330   double lon;    // temp geodetic longitude [rad]
00331   double hgt;    // temp geodetic height    [m]
00332   BOOL result;
00333   
00334   // get necessary reference ellipse parameters
00335   result = GEODESY_GetReferenceEllipseParameters_A_B_E2( referenceEllipse, &a, &b, &e2 );
00336   if( result == FALSE )
00337   {
00338     *latitude  = 0;
00339     *longitude = 0;  
00340     *height    = 0;  
00341     return FALSE;
00342   }
00343   
00344   if( x == 0.0 && y == 0.0 ) 
00345   {
00346     // at a pole    
00347     // most likely to happen while using a simulator
00348     
00349     // longitude is really unknown
00350     lon = 0.0; 
00351     
00352     if( z < 0 )
00353     {
00354       hgt = -z - b;
00355       lat = -HALFPI;
00356     }
00357     else
00358     {
00359       hgt = z - b;
00360       lat = HALFPI;
00361     }
00362   }
00363   else
00364   {
00365     p = sqrt( x*x + y*y );
00366 
00367     // unique solution for longitude
00368     // best formula for any longitude and applies well near the poles
00369     // pp. 178 reference [2]
00370     lon = 2.0 * atan2( y , ( x + p ) );
00371     
00372     // set approximate initial latitude assuming a height of 0.0
00373     lat = atan( z / (p * (1.0 - e2)) );
00374     hgt = 0.0;
00375     do
00376     { 
00377       dtmp = hgt;
00378       sinlat = sin(lat);
00379       N   = a / sqrt( 1.0 - e2*sinlat*sinlat );
00380       hgt = p / cos(lat) - N;
00381       lat = atan( z / (p * ( 1.0 - e2*N/(N + hgt) )) );      
00382 
00383     } while( fabs( hgt - dtmp ) > 0.0001 );  // 0.1 mm convergence for height
00384   }
00385 
00386   *latitude  = lat;
00387   *longitude = lon;  
00388   *height    = hgt;
00389   return TRUE;
00390 }
00391 
00392 
00393 BOOL GEODESY_ComputeNorthingEastingVertical(
00394   const GEODESY_enumReferenceEllipse  referenceEllipse,  //!< reference ellipse enumerated []
00395   const double referenceLatitude,  //!< datum geodetic latitude  [rad]
00396   const double referenceLongitude, //!< datum geodetic longitude [rad]
00397   const double referenceHeight,    //!< datum geodetic height    [m]
00398   const double latitude,           //!< geodetic latitude        [rad]
00399   const double longitude,          //!< geodetic longitude       [rad]
00400   const double height,             //!< geodetic height          [m]
00401   double *northing,                //!< local geodetic northing  [m]
00402   double *easting,                 //!< local geodetic easting   [m]
00403   double *vertical                 //!< local geodetic vertical  [m]
00404   )
00405 {
00406   double x_ref;
00407   double y_ref;
00408   double z_ref;
00409   double x;
00410   double y;
00411   double z;
00412   double dx;
00413   double dy;
00414   double dz;
00415   double A;   // rotation angle [rad]
00416   double B;   // rotation angle [rad]
00417   double cosA;
00418   double sinA;
00419   double cosB;
00420   double sinB;
00421   BOOL result;
00422 
00423   *northing = 0;
00424   *easting  = 0;
00425   *vertical = 0;
00426 
00427   result = GEODESY_IsLatitudeValid( referenceLatitude );
00428   if( result == FALSE )
00429     return FALSE;  
00430   result = GEODESY_IsLatitudeValid( latitude );
00431   if( result == FALSE )
00432     return FALSE;  
00433   
00434   result = GEODESY_ConvertGeodeticCurvilinearToEarthFixedCartesianCoordinates(
00435     referenceEllipse,
00436     referenceLatitude,
00437     referenceLongitude,
00438     referenceHeight,
00439     &x_ref,
00440     &y_ref,
00441     &z_ref );
00442   if( result == FALSE )
00443     return FALSE;
00444   
00445   result = GEODESY_ConvertGeodeticCurvilinearToEarthFixedCartesianCoordinates(
00446     referenceEllipse,
00447     latitude,
00448     longitude,
00449     height,
00450     &x,
00451     &y,
00452     &z );
00453   if( result == FALSE )
00454     return FALSE;
00455 
00456   // A and B are rotation angles
00457   A = referenceLatitude - HALFPI;
00458   B = referenceLongitude - PI;
00459 
00460   cosA = cos(A);
00461   sinA = sin(A);
00462   cosB = cos(B);
00463   sinB = sin(B);
00464 
00465   // the cartesian vector between the two points in the geodetic 
00466   // frame is rotated to the local geodetic frame
00467   dx = x - x_ref;
00468   dy = y - y_ref;
00469   dz = z - z_ref;   
00470 
00471   *northing = cosA*cosB * dx  +  cosA*sinB * dy  -  sinA*dz;
00472   *easting  = sinB      * dx  -  cosB      * dy;
00473   *vertical = sinA*cosB * dx  +  sinA*sinB * dy  +  cosA*dz;   
00474   return TRUE;
00475 }
00476 
00477 
00478 BOOL GEODESY_ComputePositionDifference(
00479   const GEODESY_enumReferenceEllipse  referenceEllipse,  //!< reference ellipse enumerated []
00480   const double referenceLatitude,  //!< reference point geodetic latitude  [rad]
00481   const double referenceLongitude, //!< reference point geodetic longitude [rad]
00482   const double referenceHeight,    //!< reference point geodetic height    [m]
00483   const double latitude,           //!< geodetic latitude        [rad]
00484   const double longitude,          //!< geodetic longitude       [rad]
00485   const double height,             //!< geodetic height          [m]
00486   double *difference_northing,     //!< difference in northing   [m]  (+2 m, means 2 m North of the reference)
00487   double *difference_easting,      //!< difference in easting    [m]  (+2 m, means 2 m East  of the reference)
00488   double *difference_vertical      //!< difference in vertical   [m]  (+2 m, means 2 m above of the reference)
00489   )
00490 {
00491   BOOL result;
00492   result = GEODESY_ComputeNorthingEastingVertical(
00493     referenceEllipse,
00494     referenceLatitude, 
00495     referenceLongitude,
00496     referenceHeight,   
00497     latitude,          
00498     longitude,         
00499     height,            
00500     difference_northing,
00501     difference_easting,
00502     difference_vertical );  
00503   return result;
00504 }
00505 
00506 
00507 
00508 
00509 BOOL GEODESY_ComputeMeridianRadiusOfCurvature(
00510   const GEODESY_enumReferenceEllipse  referenceEllipse, //!< reference ellipse enumerated []
00511   const double latitude,  //!< geodetic latitude                     [rad]
00512   double*  M              //!< computed meridian radius of curvature [m]
00513   )
00514 {
00515   double a;  // semi-major axis of reference ellipse    [m]
00516   double e2; // first eccentricity of reference ellipse []
00517   double dtmp;
00518   BOOL result;
00519   
00520   // get necessary reference ellipse parameters
00521   result = GEODESY_GetReferenceEllipseParameters_A_E2( referenceEllipse, &a, &e2 );
00522   if( result == FALSE )
00523   {
00524     *M = 0;
00525     return result;
00526   }
00527     
00528   dtmp = sin(latitude);
00529   dtmp = sqrt( 1.0 - e2 * dtmp * dtmp );  // W
00530   dtmp = dtmp*dtmp*dtmp;                  // W^3    
00531   
00532   *M = a * ( 1.0 - e2 ) / dtmp;
00533   return TRUE;
00534 }
00535 
00536 
00537 
00538 
00539 
00540 BOOL GEODESY_ComputePrimeVerticalRadiusOfCurvature(
00541   const GEODESY_enumReferenceEllipse  referenceEllipse, //!< reference ellipse enumerated []
00542   const double latitude,  //!< geodetic latitude                           [rad]
00543   double*  N              //!< computed prime vertical radius of curvature [m]
00544   )
00545 {
00546   double a;  // semi-major axis of reference ellipse [m]
00547   double e2; // first eccentricity of reference ellipse []
00548   double W;
00549   BOOL result;
00550   
00551   // get necessary reference ellipse parameters
00552   result = GEODESY_GetReferenceEllipseParameters_A_E2( referenceEllipse, &a, &e2 );
00553   if( result == FALSE )
00554   {
00555     *N = 0;
00556     return result;  
00557   }
00558   
00559   W = sin(latitude);
00560   W = sqrt( 1.0 - e2 * W * W );      
00561   
00562   *N = a / W;
00563   return TRUE;
00564 }
00565 
00566 
00567 BOOL GEODESY_ComputeMeridianArcBetweenTwoLatitudes(
00568   const GEODESY_enumReferenceEllipse  referenceEllipse, //!< reference ellipse enumerated []
00569   const double referenceLatitude,  //!< datum geodetic latitude  [rad]
00570   const double latitude,           //!< geodetic latitude        [rad]
00571   double*      arc                 //!< computed meridian arc, North +ve, South -ve [m]
00572   )
00573 {
00574   double a;  // semi-major axis of reference ellipse [m]
00575   double e2; // first eccentricity of reference ellipse []
00576   double e4; 
00577   double e6;
00578   double e8;
00579   double dtmp;
00580   double A;
00581   double B;
00582   double C;
00583   double D; 
00584   double E;
00585   double arc_ref; // arc from equator for the reference lat [m]
00586   double arc_p;   // arc from eqautor for point 'P' [m]
00587   BOOL result;
00588 
00589   *arc = 0;
00590 
00591   result = GEODESY_IsLatitudeValid( referenceLatitude );
00592   if( result == FALSE )
00593     return result;
00594   
00595   // get necessary reference ellipse parameters
00596   result = GEODESY_GetReferenceEllipseParameters_A_E2( referenceEllipse, &a, &e2 );
00597   if( result == FALSE )
00598     return result;  
00599     
00600   e4 = e2*e2;
00601   e6 = e4*e2;
00602   e8 = e6*e2;
00603   dtmp = a*(1.0-e2);
00604 
00605   A =  dtmp * ( 1.0 + 0.75  * e2 + 0.703125   * e4 + 0.68359375     * e6 + 0.67291259765625 * e8 ); //  dtmp * (1.0 + 3.0/4.0*e2 + 45.0/64.0*e4  + 175.0/256.0*e6  + 11025.0/16384.0*e8 );
00606   B = -dtmp * (       0.375 * e2 + 0.46875    * e4 + 0.5126953125   * e6 + 0.538330078125   * e8 ); // -dtmp * (      3.0/8.0*e2 + 15.0/32.0*e4  + 525.0/1024.0*e6 + 2205.0/4096.0*e8 );
00607   C =  dtmp * (                    0.05859375 * e4 + 0.1025390625   * e6 + 0.13458251953125 * e8 ); // -dtmp * (                   15.0/256.0*e4 + 105.0/1024.0*e6 + 2205.0/16384.0*e8 );  
00608   D = -dtmp * (                                      0.011393229167 * e6 + 0.025634765625   * e8 ); // -dtmp * (                                   35.0/3072.0*e6  + 105.0/4096.0*e8 );  
00609   E =  dtmp * ( 2.4032593e-03 * e8 );                                                             
00610 
00611   arc_ref = A*referenceLatitude + B*sin(2.0*referenceLatitude) + C*sin(4.0*referenceLatitude) + D*sin(6.0*referenceLatitude) + E*sin(8.0*referenceLatitude);
00612   arc_p = A*latitude + B*sin(2.0*latitude) + C*sin(4.0*latitude) + D*sin(6.0*latitude) + E*sin(8.0*latitude);
00613 
00614   *arc = arc_p - arc_ref;
00615   return TRUE;
00616 }
00617 
00618 
00619 
00620 
00621 BOOL GEODESY_ComputeParallelArcBetweenTwoLongitudes(
00622   const GEODESY_enumReferenceEllipse  referenceEllipse, //!< reference ellipse enumerated []
00623   const double referenceLatitude,  //!< reference geodetic latitude  [rad]
00624   const double referenceLongitude, //!< reference geodetic longitude [rad]
00625   const double longitude,          //!< geodetic longitude           [rad]
00626   double*      arc                 //!< computed parallel arc, East +ve, West -ve [m]
00627   )
00628 {
00629   double a;  // semi-major axis of reference ellipse [m]
00630   double e2; // first eccentricity of reference ellipse []
00631   double N;  // computed prime vertical radius of curvature [m]
00632   BOOL result;
00633 
00634   *arc = 0;
00635   
00636   // get necessary reference ellipse parameters
00637   result = GEODESY_GetReferenceEllipseParameters_A_E2( referenceEllipse, &a, &e2 );
00638   if( result == FALSE )
00639     return result;    
00640 
00641   result = GEODESY_IsLatitudeValid( referenceLatitude );
00642   if( result == FALSE )
00643     return result;    
00644   
00645   N = sin(referenceLatitude);
00646   N = a / sqrt( 1.0 - e2 * N * N );
00647 
00648   *arc = N * cos(referenceLatitude) * (longitude - referenceLongitude);  
00649   return TRUE;
00650 }
00651 
00652 
00653 
00654 
00655 BOOL GEODESY_RotateVectorFromLocalGeodeticFrameToEarthFixedFrame(
00656   const double referenceLatitude,  //!< reference geodetic latitude                 [rad]
00657   const double referenceLongitude, //!< reference geodetic longitude                [rad]
00658   const double dN,                 //!< local geodetic northing vector component    [m]
00659   const double dE,                 //!< local geodetic easting  vector component    [m]
00660   const double dUp,                //!< local geodetic vertical vector component    [m]
00661   double* dX,                      //!< earth centered earth fixed vector component [m]
00662   double* dY,                      //!< earth centered earth fixed vector component [m]
00663   double* dZ                       //!< earth centered earth fixed vector component [m]
00664   )
00665 {
00666   double sinlat;
00667   double coslat;
00668   double sinlon;
00669   double coslon;
00670   BOOL result;
00671 
00672   result = GEODESY_IsLatitudeValid( referenceLatitude );
00673   if( result == FALSE )
00674   {
00675     *dX = 0;
00676     *dY = 0;
00677     *dZ = 0;
00678     return result;
00679   }
00680 
00681   sinlat = sin(referenceLatitude);
00682   coslat = cos(referenceLatitude);
00683   sinlon = sin(referenceLongitude);
00684   coslon = cos(referenceLongitude);
00685   
00686   *dX = -sinlat*coslon * dN  -  sinlon * dE  +  coslat*coslon * dUp;
00687   *dY = -sinlat*sinlon * dN  +  coslon * dE  +  coslat*sinlon * dUp;
00688   *dZ =  coslat        * dN                  +  sinlat        * dUp;
00689   return TRUE;
00690 }
00691 
00692 
00693 
00694 
00695 BOOL GEODESY_RotateVectorFromEarthFixedFrameToLocalGeodeticFrame(
00696   const double referenceLatitude,  //!< reference geodetic latitude                 [rad]
00697   const double referenceLongitude, //!< reference geodetic longitude                [rad]
00698   const double dX,                 //!< earth centered earth fixed vector component [m]
00699   const double dY,                 //!< earth centered earth fixed vector component [m]
00700   const double dZ,                 //!< earth centered earth fixed vector component [m]
00701   double* dN,                      //!< local geodetic northing vector component    [m]
00702   double* dE,                      //!< local geodetic easting  vector component    [m]
00703   double* dUp                      //!< local geodetic vertical vector component    [m]
00704   )
00705 {
00706   double sinlat;
00707   double coslat;
00708   double sinlon;
00709   double coslon;
00710   BOOL result;
00711 
00712   result = GEODESY_IsLatitudeValid( referenceLatitude );
00713   if( result == FALSE )
00714   {
00715     *dN = 0;
00716     *dE = 0;
00717     *dUp = 0;
00718     return result;    
00719   }
00720 
00721   sinlat = sin(referenceLatitude);
00722   coslat = cos(referenceLatitude);
00723   sinlon = sin(referenceLongitude);
00724   coslon = cos(referenceLongitude);
00725   
00726   *dN  = -sinlat*coslon * dX  -  sinlat*sinlon * dY  +  coslat * dZ;
00727   *dE  = -sinlon        * dX  +  coslon        * dY;
00728   *dUp =  coslat*coslon * dX  +  coslat*sinlon * dY  +  sinlat * dZ;  
00729 
00730   return TRUE;
00731 }
00732 
00733 
00734 
00735 BOOL GEODESY_ComputeAzimuthAndElevationAnglesBetweenToPointsInTheEarthFixedFrame(
00736   const GEODESY_enumReferenceEllipse  referenceEllipse, //!< reference ellipse enumerated []
00737   const double fromX, //!< earth centered earth fixed vector from point X component [m]
00738   const double fromY, //!< earth centered earth fixed vector from point Y component [m]
00739   const double fromZ, //!< earth centered earth fixed vector from point Z component [m]
00740   const double toX,   //!< earth centered earth fixed vector to point X component   [m]
00741   const double toY,   //!< earth centered earth fixed vector to point Y component   [m]
00742   const double toZ,   //!< earth centered earth fixed vector to point Z component   [m]
00743   double* elevation,  //!< elevation angle [rad]
00744   double* azimuth     //!< azimuth angle   [rad]
00745   )
00746 {
00747   double lat; // reference geodetic latitude  ('from' point) [rad]
00748   double lon; // reference geodetic longitude ('from' point) [rad]
00749   double dX;  // ECEF X vector component between 'from' and 'to' point (m)
00750   double dY;  // ECEF Y vector component between 'from' and 'to' point (m)
00751   double dZ;  // ECEF Z vector component between 'from' and 'to' point (m)
00752   double dN;  // LG northing vector component between 'from' and 'to' point (m)
00753   double dE;  // LG easting  vector component between 'from' and 'to' point (m)
00754   double dUp; // LG vertical vector component between 'from' and 'to' point (m)
00755   double tmp; // temp value
00756   BOOL result;
00757 
00758   *elevation = 0;
00759   *azimuth = 0; 
00760 
00761   // get the reference geodetic curvilinear coordinates from the 'from' point
00762   result = GEODESY_ConvertEarthFixedCartesianToGeodeticCurvilinearCoordinates(
00763     referenceEllipse,
00764     fromX,
00765     fromY,
00766     fromZ,
00767     &lat,
00768     &lon,
00769     &tmp );
00770   if( result == FALSE )
00771     return result;      
00772 
00773   // vector between the two points in the earth fixed frame
00774   dX = toX - fromX;
00775   dY = toY - fromY;
00776   dZ = toZ - fromZ;
00777 
00778   // rotate the vector to the local geodetic frame
00779   result = GEODESY_RotateVectorFromEarthFixedFrameToLocalGeodeticFrame(
00780     lat,
00781     lon,
00782     dX,
00783     dY,
00784     dZ,
00785     &dN,
00786     &dE,
00787     &dUp );
00788   if( result == FALSE )
00789     return result;    
00790   
00791   // compute the elevation
00792   tmp = sqrt( dN*dN + dE*dE );
00793   *elevation = atan( dUp / tmp );
00794   
00795   // compute the azimuth
00796   *azimuth = atan2(dE, dN);
00797 
00798   // by convention, azimuth will be between 0 to 2 PI
00799   if( *azimuth < 0.0 )
00800     *azimuth += TWOPI;
00801   
00802   return TRUE;
00803 }
00804