LCOV - code coverage report
Current view: top level - include/math - geo.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 16 16
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /** \file geo.hpp
       2              :  * \author Jared R. Males
       3              :  * \brief Utilities for working with angles
       4              :  * \ingroup gen_math_files
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2015, 2016, 2017, 2018 Jared R. Males (jaredmales@gmail.com)
      10              : //
      11              : // This file is part of mxlib.
      12              : //
      13              : // mxlib is free software: you can redistribute it and/or modify
      14              : // it under the terms of the GNU General Public License as published by
      15              : // the Free Software Foundation, either version 3 of the License, or
      16              : // (at your option) any later version.
      17              : //
      18              : // mxlib is distributed in the hope that it will be useful,
      19              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : // GNU General Public License for more details.
      22              : //
      23              : // You should have received a copy of the GNU General Public License
      24              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      25              : //***********************************************************************//
      26              : 
      27              : #ifndef math_geo_hpp
      28              : #define math_geo_hpp
      29              : 
      30              : #include <vector>
      31              : 
      32              : #include <cmath>
      33              : 
      34              : #include "constants.hpp"
      35              : 
      36              : namespace mx
      37              : {
      38              : namespace math
      39              : {
      40              : 
      41              : /// Calculate the semi-latus rectum of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
      42              : /**
      43              :  * \ingroup geo
      44              :  */
      45              : #define semilatrect( a, e )                                                                                            \
      46              :     ( e == 0.0 ? a : ( e == 1.0 ? 2. * a : ( e < 1. ? a * ( 1 - e * e ) : a * ( e * e - 1 ) ) ) )
      47              : 
      48              : /// Calculate the focal parameter of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
      49              : /**
      50              :  * \ingroup geo
      51              :  */
      52              : #define focus( a, e )                                                                                                  \
      53              :     ( e == 0.0 ? 1e34 : ( e == 1.0 ? 2. * a : ( e < 1. ? a * ( 1 - e * e ) / e : a * ( e * e - 1 ) / e ) ) )
      54              : 
      55              : /// Calculate the semi-major axis of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>, given the
      56              : /// focal parameter and the eccentricity
      57              : /**
      58              :  * \ingroup geo
      59              :  */
      60              : #define semimaj( p, e ) ( e == 1.0 ? 1e34 : ( e < 1 ? p * e / ( 1 - e * e ) : p * e / ( e * e - 1 ) ) )
      61              : 
      62              : /// Calculate the eccentricity of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a> given the
      63              : /// semi-major axis and the focal parameter
      64              : /**
      65              :  * \ingroup geo
      66              :  */
      67              : #define eccent( a, p )                                                                                                 \
      68              :     ( a == 0.0 ? 1e34                                                                                                  \
      69              :                : ( p >= 1e9 ? 0.0                                                                                      \
      70              :                             : ( p > 0 ? ( -p / ( 2 * a ) + 0.5 * std::sqrt( p * p / ( a * a ) + 4 ) )                  \
      71              :                                       : ( p / ( 2 * a ) + 0.5 * std::sqrt( p * p / ( a * a ) + 4 ) ) ) ) )
      72              : 
      73              : /// Type specifying angles in radians
      74              : /**
      75              :  */
      76              : struct radians;
      77              : 
      78              : /// Type specifying angles in degrees
      79              : /**
      80              :  */
      81              : struct degrees;
      82              : 
      83              : /// Type holding constants related to angle calculations in degrees
      84              : template <typename degrad, typename realT>
      85              : struct degradT;
      86              : 
      87              : /// Type holding constants related to angle calculations in degrees
      88              : /**
      89              :  */
      90              : template <typename _realT>
      91              : struct degradT<degrees, _realT>
      92              : {
      93              :     typedef _realT realT;
      94              :     static constexpr realT scale =
      95              :         static_cast<realT>( 180 ) / pi<realT>(); // Scale factor to convert from radians to this unit.
      96              :     static constexpr realT degrees = 1;
      97              :     static constexpr realT radians = pi<realT>() / static_cast<realT>( 180 );
      98              :     static constexpr realT full = static_cast<realT>( 360.0 );
      99              :     static constexpr realT half = static_cast<realT>( 180.0 );
     100              : };
     101              : 
     102              : template <typename realT>
     103              : using degreesT = degradT<degrees, realT>;
     104              : 
     105              : /// Type holding constants related to angle calculations in radians
     106              : /**
     107              :  */
     108              : template <typename _realT>
     109              : struct degradT<radians, _realT>
     110              : {
     111              :     typedef _realT realT;
     112              :     static constexpr realT scale = 1; // Scale factor to convert from radians to this unit.
     113              :     static constexpr realT degrees = static_cast<realT>( 180 ) / pi<realT>();
     114              :     static constexpr realT radians = 1;
     115              :     static constexpr realT full = two_pi<realT>();
     116              :     static constexpr realT half = pi<realT>();
     117              : };
     118              : 
     119              : template <typename realT>
     120              : using radiansT = degradT<radians, realT>;
     121              : 
     122              : /// Convert from degrees to radians
     123              : /**
     124              :  *
     125              :  * \param q is the angle to convert
     126              :  *
     127              :  * \return the angle q converted to radians
     128              :  *
     129              :  *
     130              :  * \ingroup geo
     131              :  */
     132              : template <typename realT>
     133           45 : realT dtor( realT q )
     134              : {
     135           45 :     return q * degradT<degrees, realT>::radians;
     136              : }
     137              : 
     138              : /// Convert from radians to degrees
     139              : /**
     140              :  *
     141              :  * \param q is the angle to convert
     142              :  *
     143              :  * \return the angle q converted to degrees
     144              :  *
     145              :  * \ingroup geo
     146              :  */
     147              : template <typename realT>
     148     11534338 : realT rtod( realT q )
     149              : {
     150     11534338 :     return q * degradT<radians, realT>::degrees;
     151              : }
     152              : 
     153              : /// Calculate the angle modulo full-circle, normalizing to a positive value.
     154              : /** The output will be betweeen 0 and 360 (or 0 and 2pi).
     155              :  *
     156              :  * \returns the value of q normalized to 0 <= q < 360[2pi]
     157              :  *
     158              :  * \tparam degrad controls whether this is in degrees (0, default) or radians (1)
     159              :  * \tparam realT is the type in which to do arithmetic
     160              :  *
     161              :  * \ingroup geo
     162              :  */
     163              : template <class angleT>
     164           23 : typename angleT::realT angleMod( typename angleT::realT q /**< [in] the angle */ )
     165              : {
     166              :     static_assert( std::is_floating_point<typename angleT::realT>::value,
     167              :                    "angleMod: angleT::realT must be floating point" );
     168              : 
     169           23 :     q = fmod( q, angleT::full );
     170              : 
     171           23 :     if( q < 0 )
     172            1 :         q += angleT::full;
     173              : 
     174           23 :     return q;
     175              : }
     176              : 
     177              : /// Calculate the difference between two angles, correctly across 0/360.
     178              : /** Calculates \f$ dq = q2- q1 \f$, but accounts for crossing 0/360.  This implies
     179              :  * that \f$ dq \le 180 \f$.
     180              :  *
     181              :  *
     182              :  * \returns the difference of q2 and q1
     183              :  *
     184              :  * \tparam angleT controls whether this is in degrees (0, default) or radians (1)
     185              :  * \tparam realT is the type in which to do arithmetic
     186              :  *
     187              :  *
     188              :  * \ingroup geo
     189              :  */
     190              : template <class angleT>
     191     11535137 : typename angleT::realT angleDiff( typename angleT::realT q1, ///< [in] angle to subtract from q2.
     192              :                                   typename angleT::realT q2  ///< [in] angle to subtract q1 from.
     193              : )
     194              : {
     195              :     static_assert( std::is_floating_point<typename angleT::realT>::value, "angleDiff: realT must be floating point" );
     196              : 
     197     11535137 :     typename angleT::realT dq = q2 - q1;
     198              : 
     199     11535137 :     if( std::abs( dq ) > angleT::half )
     200              :     {
     201      5241994 :         if( dq < 0 )
     202              :         {
     203           18 :             dq = dq + static_cast<typename angleT::realT>( 2 ) * angleT::half;
     204              :         }
     205              :         else
     206              :         {
     207      5241976 :             dq = dq - static_cast<typename angleT::realT>( 2 ) * angleT::half;
     208              :         }
     209              :     }
     210              : 
     211     11535137 :     return dq;
     212              : }
     213              : 
     214              : /// Calculate the mean of a set of angles, correctly across 0/360.
     215              : /** Calculates the mean by decomposing into vectors and averaging the components. This accounts for crossing 0/360.
     216              :  *
     217              :  * \returns the mean angle
     218              :  *
     219              :  * \tparam angleT is the angle type, either radians<realT> or degrees<realT>.  angleT::realT is the type in which to do
     220              :  * arithmetic.
     221              :  *
     222              :  * \ingroup geo
     223              :  */
     224              : template <class angleT>
     225              : typename angleT::realT
     226              : angleMean( const std::vector<typename angleT::realT> &q /**< [in] vector of angles to average.*/ )
     227              : {
     228              :     static_assert( std::is_floating_point<typename angleT::realT>::value, "angleMean: realT must be floating point" );
     229              : 
     230              :     typename angleT::realT s = 0;
     231              :     typename angleT::realT c = 0;
     232              : 
     233              :     for( int i = 0; i < q.size(); ++i )
     234              :     {
     235              :         s += sin( q[i] / angleT::scale );
     236              :         c += cos( q[i] / angleT::scale );
     237              :     }
     238              : 
     239              :     s /= q.size();
     240              :     c /= q.size();
     241              : 
     242              :     return atan2( s, c ) * angleT::scale;
     243              : }
     244              : 
     245              : /// Make a vector of angles continuous, fixing the 0/360 crossing.
     246              : /** The vector is modified so it is continuous.
     247              :  *
     248              :  *
     249              :  * \tparam degrad controls whether angles are degrees (false) or radians (true)
     250              :  * \tparam realT is the type in which to do arithmetic
     251              :  *
     252              :  *  \ingroup geo
     253              :  */
     254              : template <int degrad = 0, typename realT>
     255              : int continueAngles( std::vector<realT> &angles, ///< [in] the vector of angles
     256              :                     realT threshold = 0.75 ///< [in] [optional] the fraction of a full circle at which to consider a
     257              :                                            ///< difference in angle discontinuous.
     258              : )
     259              : {
     260              :     realT full;
     261              : 
     262              :     if( degrad )
     263              :         full = two_pi<realT>();
     264              :     else
     265              :         full = static_cast<realT>( 360 );
     266              : 
     267              :     threshold *= full;
     268              : 
     269              :     realT adj = 0;
     270              : 
     271              :     if( fabs( angles[1] - angles[0] ) > threshold )
     272              :     {
     273              :         if( angles[1] > angles[0] )
     274              :             adj = -full;
     275              :         else
     276              :             adj = full;
     277              : 
     278              :         angles[1] += adj;
     279              :     }
     280              : 
     281              :     if( angles.size() == 2 )
     282              :         return 0;
     283              : 
     284              :     for( int i = 2; i < angles.size(); ++i )
     285              :     {
     286              :         angles[i] += adj;
     287              : 
     288              :         if( fabs( angles[i] - angles[i - 1] ) > threshold )
     289              :         {
     290              :             if( angles[i] > angles[i - 1] )
     291              :                 adj += -full;
     292              :             else
     293              :                 adj += full;
     294              : 
     295              :             angles[i] += adj;
     296              :         }
     297              :     }
     298              : 
     299              :     return 0;
     300              : }
     301              : 
     302              : /// Rotate a point about the origin.
     303              : /** The rotation is counter-clockwise for positive angles.
     304              :  *
     305              :  * \tparam realT a real floating point type
     306              :  *
     307              :  *  \ingroup geo
     308              :  */
     309              : template <typename realT>
     310              : void rotatePoint( realT &x0, ///< [in.out] the x-coordinate of the point to rotate.  On exit contains the rotated value.
     311              :                   realT &y0, ///< [in.out] the y-coordinate of the point to rotate.  On exit contains the rotated value.
     312              :                   realT angle ///< [in] the angle by which to rotate [radians]
     313              : )
     314              : {
     315              :     realT x1;
     316              :     realT y1;
     317              : 
     318              :     realT cq = cos( angle );
     319              :     realT sq = sin( angle );
     320              : 
     321              :     x1 = x0 * cq - y0 * sq;
     322              :     y1 = x0 * sq + y0 * cq;
     323              : 
     324              :     x0 = x1;
     325              :     y0 = y1;
     326              : }
     327              : 
     328              : } // namespace math
     329              : } // namespace mx
     330              : 
     331              : #endif // math_geo_hpp
        

Generated by: LCOV version 2.0-1