LCOV - code coverage report
Current view: top level - ogr - ogr_geo_utils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 49 93 52.7 %
Date: 2024-05-03 15:49:35 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OGR
       4             :  * Purpose:  Geo-computations
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "ogr_geo_utils.h"
      30             : #include "cpl_port.h"
      31             : #include "cpl_error.h"
      32             : 
      33             : constexpr double RAD2METER = (180.0 / M_PI) * 60.0 * 1852.0;
      34             : constexpr double METER2RAD = 1.0 / RAD2METER;
      35             : 
      36             : constexpr double DEG2RAD = M_PI / 180.0;
      37             : constexpr double RAD2DEG = 1.0 / DEG2RAD;
      38             : 
      39        1204 : static double OGR_Safe_acos(double x)
      40             : {
      41        1204 :     if (x > 1)
      42           0 :         x = 1;
      43        1204 :     else if (x < -1)
      44           0 :         x = -1;
      45        1204 :     return acos(x);
      46             : }
      47             : 
      48             : /************************************************************************/
      49             : /*                      OGR_GreatCircle_Distance()                      */
      50             : /************************************************************************/
      51             : 
      52          12 : double OGR_GreatCircle_Distance(double LatA_deg, double LonA_deg,
      53             :                                 double LatB_deg, double LonB_deg)
      54             : {
      55          12 :     const double cosP = cos((LonB_deg - LonA_deg) * DEG2RAD);
      56          12 :     const double LatA_rad = LatA_deg * DEG2RAD;
      57          12 :     const double LatB_rad = LatB_deg * DEG2RAD;
      58          12 :     const double cosa = cos(LatA_rad);
      59          12 :     const double sina = sin(LatA_rad);
      60          12 :     const double cosb = cos(LatB_rad);
      61          12 :     const double sinb = sin(LatB_rad);
      62          12 :     const double cos_angle = sina * sinb + cosa * cosb * cosP;
      63          12 :     return OGR_Safe_acos(cos_angle) * RAD2METER;
      64             : }
      65             : 
      66             : /************************************************************************/
      67             : /*                      OGR_GreatCircle_InitialHeading()                */
      68             : /************************************************************************/
      69             : 
      70           0 : double OGR_GreatCircle_InitialHeading(double LatA_deg, double LonA_deg,
      71             :                                       double LatB_deg, double LonB_deg)
      72             : {
      73           0 :     if (fabs(LatA_deg - 90) < 1e-10 || fabs(LatB_deg + 90) < 1e-10)
      74             :     {
      75           0 :         return 180;
      76             :     }
      77           0 :     else if (fabs(LatA_deg + 90) < 1e-10 || fabs(LatB_deg - 90) < 1e-10)
      78             :     {
      79           0 :         return 0;
      80             :     }
      81           0 :     else if (fabs(fmod(LonA_deg - LonB_deg, 360.0)) < 1e-10 &&
      82           0 :              fabs(LatA_deg - LatB_deg) < 1e-10)
      83             :     {
      84           0 :         return 0;  // Arbitrary number
      85             :     }
      86           0 :     else if (fabs(LatA_deg) < 1e-10 && fabs(LatB_deg) < 1e-10)
      87             :     {
      88           0 :         return (LonB_deg > LonA_deg) ? 90.0 : 270.0;
      89             :     }
      90           0 :     else if (fabs(fmod(LonA_deg - LonB_deg, 360.0)) < 1e-10)
      91             :     {
      92           0 :         return (LatA_deg > LatB_deg) ? 180.0 : 0.0;
      93             :     }
      94             :     else
      95             :     {
      96           0 :         const double LatA_rad = LatA_deg * DEG2RAD;
      97           0 :         const double LatB_rad = LatB_deg * DEG2RAD;
      98             : 
      99           0 :         const double cos_LatA = cos(LatA_rad);
     100           0 :         const double sin_LatA = sin(LatA_rad);
     101             : 
     102           0 :         const double diffG = (LonA_deg - LonB_deg) * DEG2RAD;
     103           0 :         const double cos_diffG = cos(diffG);
     104           0 :         const double sin_diffG = sin(diffG);
     105             : 
     106           0 :         const double denom = sin_LatA * cos_diffG - cos_LatA * tan(LatB_rad);
     107           0 :         if (denom == 0.0)
     108             :         {
     109             :             // Can be the case if Lat_A = -Lat_B and abs(LonA - LonB) = 180
     110           0 :             return 0.0;
     111             :         }
     112             : 
     113           0 :         double track = atan(sin_diffG / denom) * RAD2DEG;
     114             : 
     115           0 :         if (denom > 0.0)
     116             :         {
     117           0 :             track = 180 + track;
     118             :         }
     119           0 :         else if (track < 0)
     120             :         {
     121           0 :             track = 360 + track;
     122             :         }
     123             : 
     124           0 :         return track;
     125             :     }
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                     OGR_GreatCircle_ExtendPosition()                 */
     130             : /************************************************************************/
     131             : 
     132         609 : int OGR_GreatCircle_ExtendPosition(double dfLatA_deg, double dfLonA_deg,
     133             :                                    double dfDistance, double dfHeadingInA,
     134             :                                    double *pdfLatB_deg, double *pdfLonB_deg)
     135             : {
     136         609 :     const double dfHeadingRad = dfHeadingInA * DEG2RAD;
     137         609 :     const double cos_Heading = cos(dfHeadingRad);
     138         609 :     const double sin_Heading = sin(dfHeadingRad);
     139             : 
     140         609 :     const double dfDistanceRad = dfDistance * METER2RAD;
     141         609 :     const double cos_Distance = cos(dfDistanceRad);
     142         609 :     const double sin_Distance = sin(dfDistanceRad);
     143             : 
     144         609 :     const double dfLatA_rad = dfLatA_deg * DEG2RAD;
     145         609 :     const double cos_complement_LatA = sin(dfLatA_rad);
     146         609 :     const double sin_complement_LatA = cos(dfLatA_rad);
     147             : 
     148         609 :     if (dfDistance == 0.0)
     149             :     {
     150           0 :         *pdfLatB_deg = dfLatA_deg;
     151           0 :         *pdfLonB_deg = dfLonA_deg;
     152           0 :         return 1;
     153             :     }
     154             : 
     155         609 :     if (fabs(dfLatA_deg) >= 90.0)
     156             :     {
     157           0 :         *pdfLatB_deg = dfLatA_deg;
     158           0 :         *pdfLonB_deg = dfLonA_deg;
     159           0 :         return 0;
     160             :     }
     161             : 
     162         609 :     if (fabs(sin_Heading) < 1e-8)
     163             :     {
     164          13 :         *pdfLonB_deg = dfLonA_deg;
     165          13 :         if (fabs(fmod(dfHeadingInA + 360.0, 360.0)) < 1e-8)
     166             :         {
     167           8 :             *pdfLatB_deg = dfLatA_deg + dfDistanceRad * RAD2DEG;
     168             :         }
     169             :         else
     170             :         {
     171           5 :             *pdfLatB_deg = dfLatA_deg - dfDistanceRad * RAD2DEG;
     172             :         }
     173          13 :         return 1;
     174             :     }
     175             : 
     176         596 :     if (fabs(cos_complement_LatA) < 1e-8 && fabs(cos_Heading) < 1e-8)
     177             :     {
     178           0 :         *pdfLatB_deg = dfLatA_deg;
     179           0 :         if (fabs(dfHeadingInA - 90.0) < 1e-8)
     180             :         {
     181           0 :             *pdfLonB_deg = dfLonA_deg + dfDistanceRad * RAD2DEG;
     182             :         }
     183             :         else
     184             :         {
     185           0 :             *pdfLonB_deg = dfLonA_deg - dfDistanceRad * RAD2DEG;
     186             :         }
     187           0 :         return 1;
     188             :     }
     189             : 
     190         596 :     const double cos_complement_latB =
     191         596 :         cos_Distance * cos_complement_LatA +
     192         596 :         sin_Distance * sin_complement_LatA * cos_Heading;
     193             : 
     194         596 :     const double complement_latB = OGR_Safe_acos(cos_complement_latB);
     195             : 
     196         596 :     const double dfDenomin = sin(complement_latB) * sin_complement_LatA;
     197         596 :     if (dfDenomin == 0.0)
     198           0 :         CPLDebug("OGR", "OGR_GreatCircle_Distance: dfDenomin == 0.0");
     199         596 :     const double Cos_dG =
     200         596 :         (cos_Distance - cos_complement_latB * cos_complement_LatA) / dfDenomin;
     201         596 :     *pdfLatB_deg = 90 - complement_latB * RAD2DEG;
     202             : 
     203         596 :     const double dG_deg = OGR_Safe_acos(Cos_dG) * RAD2DEG;
     204             : 
     205         596 :     if (sin_Heading < 0)
     206         308 :         *pdfLonB_deg = dfLonA_deg - dG_deg;
     207             :     else
     208         288 :         *pdfLonB_deg = dfLonA_deg + dG_deg;
     209             : 
     210         596 :     if (*pdfLonB_deg > 180)
     211           0 :         *pdfLonB_deg -= 360;
     212         596 :     else if (*pdfLonB_deg <= -180)
     213           0 :         *pdfLonB_deg += 360;
     214             : 
     215         596 :     return 1;
     216             : }

Generated by: LCOV version 1.14