LCOV - code coverage report
Current view: top level - home/lbartoletti/qgis/external/nmea - gmath.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 189 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            : * Copyright Tim (xtimor@gmail.com)
       3                 :            : *
       4                 :            : * NMEA library is free software; you can redistribute it and/or modify
       5                 :            : * it under the terms of the GNU Lesser General Public License as published by
       6                 :            : * the Free Software Foundation; either version 2 of the License, or
       7                 :            : * (at your option) any later version.
       8                 :            : *
       9                 :            : * This program is distributed in the hope that it will be useful,
      10                 :            : * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 :            : * GNU Lesser General Public License for more details.
      13                 :            : *
      14                 :            : * You should have received a copy of the GNU Lesser General Public License
      15                 :            : * along with this program.  If not, see <http://www.gnu.org/licenses/>
      16                 :            : */
      17                 :            : /*
      18                 :            :  *
      19                 :            :  * NMEA library
      20                 :            :  * URL: http://nmea.sourceforge.net
      21                 :            :  * Author: Tim (xtimor@gmail.com)
      22                 :            :  * Licence: http://www.gnu.org/licenses/lgpl.html
      23                 :            :  * $Id: gmath.c 17 2008-03-11 11:56:11Z xtimor $
      24                 :            :  *
      25                 :            :  */
      26                 :            : 
      27                 :            : //! \file gmath.h
      28                 :            : 
      29                 :            : #include "gmath.h"
      30                 :            : 
      31                 :            : #include <math.h>
      32                 :            : #include <float.h>
      33                 :            : 
      34                 :            : /**
      35                 :            :  * \fn nmea_degree2radian
      36                 :            :  * \brief Convert degree to radian
      37                 :            :  */
      38                 :          0 : double nmea_degree2radian( double val )
      39                 :          0 : { return ( val * NMEA_PI180 ); }
      40                 :            : 
      41                 :            : /**
      42                 :            :  * \fn nmea_radian2degree
      43                 :            :  * \brief Convert radian to degree
      44                 :            :  */
      45                 :          0 : double nmea_radian2degree( double val )
      46                 :          0 : { return ( val / NMEA_PI180 ); }
      47                 :            : 
      48                 :            : /**
      49                 :            :  * \brief Convert NDEG (NMEA degree) to fractional degree
      50                 :            :  */
      51                 :          0 : double nmea_ndeg2degree( double val )
      52                 :            : {
      53                 :          0 :   double deg = ( ( int )( val / 100 ) );
      54                 :          0 :   val = deg + ( val - deg * 100 ) / 60;
      55                 :          0 :   return val;
      56                 :            : }
      57                 :            : 
      58                 :            : /**
      59                 :            :  * \brief Convert fractional degree to NDEG (NMEA degree)
      60                 :            :  */
      61                 :          0 : double nmea_degree2ndeg( double val )
      62                 :            : {
      63                 :            :   double int_part;
      64                 :            :   double fra_part;
      65                 :          0 :   fra_part = modf( val, &int_part );
      66                 :          0 :   val = int_part * 100 + fra_part * 60;
      67                 :          0 :   return val;
      68                 :            : }
      69                 :            : 
      70                 :            : /**
      71                 :            :  * \fn nmea_ndeg2radian
      72                 :            :  * \brief Convert NDEG (NMEA degree) to radian
      73                 :            :  */
      74                 :          0 : double nmea_ndeg2radian( double val )
      75                 :          0 : { return nmea_degree2radian( nmea_ndeg2degree( val ) ); }
      76                 :            : 
      77                 :            : /**
      78                 :            :  * \fn nmea_radian2ndeg
      79                 :            :  * \brief Convert radian to NDEG (NMEA degree)
      80                 :            :  */
      81                 :          0 : double nmea_radian2ndeg( double val )
      82                 :          0 : { return nmea_degree2ndeg( nmea_radian2degree( val ) ); }
      83                 :            : 
      84                 :            : /**
      85                 :            :  * \brief Calculate PDOP (Position Dilution Of Precision) factor
      86                 :            :  */
      87                 :          0 : double nmea_calc_pdop( double hdop, double vdop )
      88                 :            : {
      89                 :          0 :   return sqrt( pow( hdop, 2 ) + pow( vdop, 2 ) );
      90                 :            : }
      91                 :            : 
      92                 :          0 : double nmea_dop2meters( double dop )
      93                 :          0 : { return ( dop * NMEA_DOP_FACTOR ); }
      94                 :            : 
      95                 :          0 : double nmea_meters2dop( double meters )
      96                 :          0 : { return ( meters / NMEA_DOP_FACTOR ); }
      97                 :            : 
      98                 :            : /**
      99                 :            :  * \brief Calculate distance between two points
     100                 :            :  * \return Distance in meters
     101                 :            :  */
     102                 :          0 : double nmea_distance(
     103                 :            :   const nmeaPOS *from_pos,    //!< From position in radians
     104                 :            :   const nmeaPOS *to_pos       //!< To position in radians
     105                 :            : )
     106                 :            : {
     107                 :          0 :   double dist = ( ( double )NMEA_EARTHRADIUS_M ) * acos(
     108                 :          0 :                   sin( to_pos->lat ) * sin( from_pos->lat ) +
     109                 :          0 :                   cos( to_pos->lat ) * cos( from_pos->lat ) * cos( to_pos->lon - from_pos->lon )
     110                 :            :                 );
     111                 :          0 :   return dist;
     112                 :            : }
     113                 :            : 
     114                 :            : /**
     115                 :            :  * \brief Calculate distance between two points
     116                 :            :  * This function uses an algorithm for an oblate spheroid earth model.
     117                 :            :  * The algorithm is described here:
     118                 :            :  * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
     119                 :            :  * \return Distance in meters
     120                 :            :  */
     121                 :          0 : double nmea_distance_ellipsoid(
     122                 :            :   const nmeaPOS *from_pos,    //!< From position in radians
     123                 :            :   const nmeaPOS *to_pos,      //!< To position in radians
     124                 :            :   double *from_azimuth,       //!< (O) azimuth at "from" position in radians
     125                 :            :   double *to_azimuth          //!< (O) azimuth at "to" position in radians
     126                 :            : )
     127                 :            : {
     128                 :            :   /* All variables */
     129                 :            :   double f, a, b, sqr_a, sqr_b;
     130                 :            :   double L, phi1, phi2, U1, U2, sin_U1, sin_U2, cos_U1, cos_U2;
     131                 :            :   double sigma, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, sqr_cos_alpha, lambda, sin_lambda, cos_lambda, delta_lambda;
     132                 :            :   int remaining_steps;
     133                 :            :   double sqr_u, A, B, delta_sigma;
     134                 :            : 
     135                 :            :   /* Check input */
     136                 :          0 :   NMEA_ASSERT( from_pos != 0 );
     137                 :          0 :   NMEA_ASSERT( to_pos != 0 );
     138                 :            : 
     139                 :          0 :   if ( ( from_pos->lat == to_pos->lat ) && ( from_pos->lon == to_pos->lon ) )
     140                 :            :   {
     141                 :            :     /* Identical points */
     142                 :          0 :     if ( from_azimuth != 0 )
     143                 :          0 :       *from_azimuth = 0;
     144                 :          0 :     if ( to_azimuth != 0 )
     145                 :          0 :       *to_azimuth = 0;
     146                 :          0 :     return 0;
     147                 :            :   } /* Identical points */
     148                 :            : 
     149                 :            :   /* Earth geometry */
     150                 :          0 :   f = NMEA_EARTH_FLATTENING;
     151                 :          0 :   a = NMEA_EARTH_SEMIMAJORAXIS_M;
     152                 :          0 :   b = ( 1 - f ) * a;
     153                 :          0 :   sqr_a = a * a;
     154                 :          0 :   sqr_b = b * b;
     155                 :            : 
     156                 :            :   /* Calculation */
     157                 :          0 :   L = to_pos->lon - from_pos->lon;
     158                 :          0 :   phi1 = from_pos->lat;
     159                 :          0 :   phi2 = to_pos->lat;
     160                 :          0 :   U1 = atan( ( 1 - f ) * tan( phi1 ) );
     161                 :          0 :   U2 = atan( ( 1 - f ) * tan( phi2 ) );
     162                 :          0 :   sin_U1 = sin( U1 );
     163                 :          0 :   sin_U2 = sin( U2 );
     164                 :          0 :   cos_U1 = cos( U1 );
     165                 :          0 :   cos_U2 = cos( U2 );
     166                 :            : 
     167                 :            :   /* Initialize iteration */
     168                 :          0 :   sigma = 0;
     169                 :          0 :   sin_sigma = sin( sigma );
     170                 :          0 :   cos_sigma = cos( sigma );
     171                 :          0 :   cos_2_sigmam = 0;
     172                 :          0 :   sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
     173                 :          0 :   sqr_cos_alpha = 0;
     174                 :          0 :   lambda = L;
     175                 :          0 :   sin_lambda = sin( lambda );
     176                 :          0 :   cos_lambda = cos( lambda );
     177                 :          0 :   delta_lambda = lambda;
     178                 :          0 :   remaining_steps = 20;
     179                 :            : 
     180                 :          0 :   while ( ( delta_lambda > 1e-12 ) && ( remaining_steps > 0 ) )
     181                 :            :   {
     182                 :            :     /* Iterate */
     183                 :            :     /* Variables */
     184                 :            :     double tmp1, tmp2, sin_alpha, cos_alpha, C, lambda_prev;
     185                 :            : 
     186                 :            :     /* Calculation */
     187                 :          0 :     tmp1 = cos_U2 * sin_lambda;
     188                 :          0 :     tmp2 = cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda;
     189                 :          0 :     sin_sigma = sqrt( tmp1 * tmp1 + tmp2 * tmp2 );
     190                 :          0 :     cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
     191                 :          0 :     sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;
     192                 :          0 :     cos_alpha = cos( asin( sin_alpha ) );
     193                 :          0 :     sqr_cos_alpha = cos_alpha * cos_alpha;
     194                 :          0 :     cos_2_sigmam = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha;
     195                 :          0 :     sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
     196                 :          0 :     C = f / 16 * sqr_cos_alpha * ( 4 + f * ( 4 - 3 * sqr_cos_alpha ) );
     197                 :          0 :     lambda_prev = lambda;
     198                 :          0 :     sigma = asin( sin_sigma );
     199                 :          0 :     lambda = L +
     200                 :          0 :              ( 1 - C ) * f * sin_alpha
     201                 :          0 :              * ( sigma + C * sin_sigma * ( cos_2_sigmam + C * cos_sigma * ( -1 + 2 * sqr_cos_2_sigmam ) ) );
     202                 :          0 :     delta_lambda = lambda_prev - lambda;
     203                 :          0 :     if ( delta_lambda < 0 ) delta_lambda = -delta_lambda;
     204                 :          0 :     sin_lambda = sin( lambda );
     205                 :          0 :     cos_lambda = cos( lambda );
     206                 :          0 :     remaining_steps--;
     207                 :            :   }  /* Iterate */
     208                 :            : 
     209                 :            :   /* More calculation  */
     210                 :          0 :   sqr_u = sqr_cos_alpha * ( sqr_a - sqr_b ) / sqr_b;
     211                 :          0 :   A = 1 + sqr_u / 16384 * ( 4096 + sqr_u * ( -768 + sqr_u * ( 320 - 175 * sqr_u ) ) );
     212                 :          0 :   B = sqr_u / 1024 * ( 256 + sqr_u * ( -128 + sqr_u * ( 74 - 47 * sqr_u ) ) );
     213                 :          0 :   delta_sigma = B * sin_sigma * (
     214                 :          0 :                   cos_2_sigmam + B / 4 * (
     215                 :          0 :                     cos_sigma * ( -1 + 2 * sqr_cos_2_sigmam ) -
     216                 :          0 :                     B / 6 * cos_2_sigmam * ( -3 + 4 * sin_sigma * sin_sigma ) * ( -3 + 4 * sqr_cos_2_sigmam )
     217                 :            :                   ) );
     218                 :            : 
     219                 :            :   /* Calculate result */
     220                 :          0 :   if ( from_azimuth != 0 )
     221                 :            :   {
     222                 :          0 :     double tan_alpha_1 = cos_U2 * sin_lambda / ( cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda );
     223                 :          0 :     *from_azimuth = atan( tan_alpha_1 );
     224                 :          0 :   }
     225                 :          0 :   if ( to_azimuth != 0 )
     226                 :            :   {
     227                 :          0 :     double tan_alpha_2 = cos_U1 * sin_lambda / ( -sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda );
     228                 :          0 :     *to_azimuth = atan( tan_alpha_2 );
     229                 :          0 :   }
     230                 :            : 
     231                 :          0 :   return b * A * ( sigma - delta_sigma );
     232                 :          0 : }
     233                 :            : 
     234                 :            : /**
     235                 :            :  * \brief Horizontal move of point position
     236                 :            :  */
     237                 :          0 : int nmea_move_horz(
     238                 :            :   const nmeaPOS *start_pos,   //!< Start position in radians
     239                 :            :   nmeaPOS *end_pos,           //!< Result position in radians
     240                 :            :   double azimuth,             //!< Azimuth (degree) [0, 359]
     241                 :            :   double distance             //!< Distance (km)
     242                 :            : )
     243                 :            : {
     244                 :          0 :   nmeaPOS p1 = *start_pos;
     245                 :          0 :   int RetVal = 1;
     246                 :            : 
     247                 :          0 :   distance /= NMEA_EARTHRADIUS_KM; /* Angular distance covered on earth's surface */
     248                 :          0 :   azimuth = nmea_degree2radian( azimuth );
     249                 :            : 
     250                 :          0 :   end_pos->lat = asin(
     251                 :          0 :                    sin( p1.lat ) * cos( distance ) + cos( p1.lat ) * sin( distance ) * cos( azimuth ) );
     252                 :          0 :   end_pos->lon = p1.lon + atan2(
     253                 :          0 :                    sin( azimuth ) * sin( distance ) * cos( p1.lat ), cos( distance ) - sin( p1.lat ) * sin( end_pos->lat ) );
     254                 :            : 
     255                 :          0 :   if ( NMEA_POSIX( isnan )( end_pos->lat ) || NMEA_POSIX( isnan )( end_pos->lon ) )
     256                 :            :   {
     257                 :          0 :     end_pos->lat = 0;
     258                 :          0 :     end_pos->lon = 0;
     259                 :          0 :     RetVal = 0;
     260                 :          0 :   }
     261                 :            : 
     262                 :          0 :   return RetVal;
     263                 :            : }
     264                 :            : 
     265                 :            : /**
     266                 :            :  * \brief Horizontal move of point position
     267                 :            :  * This function uses an algorithm for an oblate spheroid earth model.
     268                 :            :  * The algorithm is described here:
     269                 :            :  * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
     270                 :            :  */
     271                 :          0 : int nmea_move_horz_ellipsoid(
     272                 :            :   const nmeaPOS *start_pos,   //!< Start position in radians
     273                 :            :   nmeaPOS *end_pos,           //!< (O) Result position in radians
     274                 :            :   double azimuth,             //!< Azimuth in radians
     275                 :            :   double distance,            //!< Distance (km)
     276                 :            :   double *end_azimuth         //!< (O) Azimuth at end position in radians
     277                 :            : )
     278                 :            : {
     279                 :            :   /* Variables */
     280                 :            :   double f, a, b, sqr_a, sqr_b;
     281                 :            :   double phi1, tan_U1, sin_U1, cos_U1, s, alpha1, sin_alpha1, cos_alpha1;
     282                 :            :   double sigma1, sin_alpha, sqr_cos_alpha, sqr_u, A, B;
     283                 :            :   double sigma_initial, sigma, sigma_prev, sin_sigma, cos_sigma, cos_2_sigmam, sqr_cos_2_sigmam, delta_sigma;
     284                 :            :   int remaining_steps;
     285                 :            :   double tmp1, phi2, lambda, C, L;
     286                 :            : 
     287                 :            :   /* Check input */
     288                 :          0 :   NMEA_ASSERT( start_pos != 0 );
     289                 :          0 :   NMEA_ASSERT( end_pos != 0 );
     290                 :            : 
     291                 :          0 :   if ( fabs( distance ) < 1e-12 )
     292                 :            :   {
     293                 :            :     /* No move */
     294                 :          0 :     *end_pos = *start_pos;
     295                 :          0 :     if ( end_azimuth != 0 ) *end_azimuth = azimuth;
     296                 :          0 :     return !( NMEA_POSIX( isnan )( end_pos->lat ) || NMEA_POSIX( isnan )( end_pos->lon ) );
     297                 :            :   } /* No move */
     298                 :            : 
     299                 :            :   /* Earth geometry */
     300                 :          0 :   f = NMEA_EARTH_FLATTENING;
     301                 :          0 :   a = NMEA_EARTH_SEMIMAJORAXIS_M;
     302                 :          0 :   b = ( 1 - f ) * a;
     303                 :          0 :   sqr_a = a * a;
     304                 :          0 :   sqr_b = b * b;
     305                 :            : 
     306                 :            :   /* Calculation */
     307                 :          0 :   phi1 = start_pos->lat;
     308                 :          0 :   tan_U1 = ( 1 - f ) * tan( phi1 );
     309                 :          0 :   cos_U1 = 1 / sqrt( 1 + tan_U1 * tan_U1 );
     310                 :          0 :   sin_U1 = tan_U1 * cos_U1;
     311                 :          0 :   s = distance;
     312                 :          0 :   alpha1 = azimuth;
     313                 :          0 :   sin_alpha1 = sin( alpha1 );
     314                 :          0 :   cos_alpha1 = cos( alpha1 );
     315                 :          0 :   sigma1 = atan2( tan_U1, cos_alpha1 );
     316                 :          0 :   sin_alpha = cos_U1 * sin_alpha1;
     317                 :          0 :   sqr_cos_alpha = 1 - sin_alpha * sin_alpha;
     318                 :          0 :   sqr_u = sqr_cos_alpha * ( sqr_a - sqr_b ) / sqr_b;
     319                 :          0 :   A = 1 + sqr_u / 16384 * ( 4096 + sqr_u * ( -768 + sqr_u * ( 320 - 175 * sqr_u ) ) );
     320                 :          0 :   B = sqr_u / 1024 * ( 256 + sqr_u * ( -128 + sqr_u * ( 74 - 47 * sqr_u ) ) );
     321                 :            : 
     322                 :            :   /* Initialize iteration */
     323                 :          0 :   sigma_initial = s / ( b * A );
     324                 :          0 :   sigma = sigma_initial;
     325                 :          0 :   sin_sigma = sin( sigma );
     326                 :          0 :   cos_sigma = cos( sigma );
     327                 :          0 :   cos_2_sigmam = cos( 2 * sigma1 + sigma );
     328                 :          0 :   sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
     329                 :          0 :   delta_sigma = 0;
     330                 :          0 :   sigma_prev = 2 * NMEA_PI;
     331                 :          0 :   remaining_steps = 20;
     332                 :            : 
     333                 :          0 :   while ( ( fabs( sigma - sigma_prev ) > 1e-12 ) && ( remaining_steps > 0 ) )
     334                 :            :   {
     335                 :            :     /* Iterate */
     336                 :          0 :     cos_2_sigmam = cos( 2 * sigma1 + sigma );
     337                 :          0 :     sqr_cos_2_sigmam = cos_2_sigmam * cos_2_sigmam;
     338                 :          0 :     sin_sigma = sin( sigma );
     339                 :          0 :     cos_sigma = cos( sigma );
     340                 :          0 :     delta_sigma = B * sin_sigma * (
     341                 :          0 :                     cos_2_sigmam + B / 4 * (
     342                 :          0 :                       cos_sigma * ( -1 + 2 * sqr_cos_2_sigmam ) -
     343                 :          0 :                       B / 6 * cos_2_sigmam * ( -3 + 4 * sin_sigma * sin_sigma ) * ( -3 + 4 * sqr_cos_2_sigmam )
     344                 :            :                     ) );
     345                 :          0 :     sigma_prev = sigma;
     346                 :          0 :     sigma = sigma_initial + delta_sigma;
     347                 :          0 :     remaining_steps --;
     348                 :            :   } /* Iterate */
     349                 :            : 
     350                 :            :   /* Calculate result */
     351                 :          0 :   tmp1 = ( sin_U1 * sin_sigma - cos_U1 * cos_sigma * cos_alpha1 );
     352                 :          0 :   phi2 = atan2(
     353                 :          0 :            sin_U1 * cos_sigma + cos_U1 * sin_sigma * cos_alpha1,
     354                 :          0 :            ( 1 - f ) * sqrt( sin_alpha * sin_alpha + tmp1 * tmp1 )
     355                 :            :          );
     356                 :          0 :   lambda = atan2(
     357                 :          0 :              sin_sigma * sin_alpha1,
     358                 :          0 :              cos_U1 * cos_sigma - sin_U1 * sin_sigma * cos_alpha1
     359                 :            :            );
     360                 :          0 :   C = f / 16 * sqr_cos_alpha * ( 4 + f * ( 4 - 3 * sqr_cos_alpha ) );
     361                 :          0 :   L = lambda -
     362                 :          0 :       ( 1 - C ) * f * sin_alpha * (
     363                 :          0 :         sigma + C * sin_sigma *
     364                 :          0 :         ( cos_2_sigmam + C * cos_sigma * ( -1 + 2 * sqr_cos_2_sigmam ) )
     365                 :            :       );
     366                 :            : 
     367                 :            :   /* Result */
     368                 :          0 :   end_pos->lon = start_pos->lon + L;
     369                 :          0 :   end_pos->lat = phi2;
     370                 :          0 :   if ( end_azimuth != 0 )
     371                 :            :   {
     372                 :          0 :     *end_azimuth = atan2(
     373                 :          0 :                      sin_alpha, -sin_U1 * sin_sigma + cos_U1 * cos_sigma * cos_alpha1
     374                 :            :                    );
     375                 :          0 :   }
     376                 :          0 :   return !( NMEA_POSIX( isnan )( end_pos->lat ) || NMEA_POSIX( isnan )( end_pos->lon ) );
     377                 :          0 : }
     378                 :            : 
     379                 :            : /**
     380                 :            :  * \brief Convert position from INFO to radians position
     381                 :            :  */
     382                 :          0 : void nmea_info2pos( const nmeaINFO *info, nmeaPOS *pos )
     383                 :            : {
     384                 :          0 :   pos->lat = nmea_ndeg2radian( info->lat );
     385                 :          0 :   pos->lon = nmea_ndeg2radian( info->lon );
     386                 :          0 : }
     387                 :            : 
     388                 :            : /**
     389                 :            :  * \brief Convert radians position to INFOs position
     390                 :            :  */
     391                 :          0 : void nmea_pos2info( const nmeaPOS *pos, nmeaINFO *info )
     392                 :            : {
     393                 :          0 :   info->lat = nmea_radian2ndeg( pos->lat );
     394                 :          0 :   info->lon = nmea_radian2ndeg( pos->lon );
     395                 :          0 : }

Generated by: LCOV version 1.14