LCOV - code coverage report
Current view: top level - ogr - ogr_geo_utils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 50 93 53.8 %
Date: 2024-11-21 22:18:42 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             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_geo_utils.h"
      14             : #include "cpl_port.h"
      15             : #include "cpl_error.h"
      16             : 
      17             : constexpr double DEG2RAD = M_PI / 180.0;
      18             : constexpr double RAD2DEG = 1.0 / DEG2RAD;
      19             : 
      20        1222 : static double OGR_Safe_acos(double x)
      21             : {
      22        1222 :     if (x > 1)
      23           0 :         x = 1;
      24        1222 :     else if (x < -1)
      25           0 :         x = -1;
      26        1222 :     return acos(x);
      27             : }
      28             : 
      29             : /************************************************************************/
      30             : /*                      OGR_GreatCircle_Distance()                      */
      31             : /************************************************************************/
      32             : 
      33          12 : double OGR_GreatCircle_Distance(double LatA_deg, double LonA_deg,
      34             :                                 double LatB_deg, double LonB_deg,
      35             :                                 double dfRadius)
      36             : {
      37          12 :     const double cosP = cos((LonB_deg - LonA_deg) * DEG2RAD);
      38          12 :     const double LatA_rad = LatA_deg * DEG2RAD;
      39          12 :     const double LatB_rad = LatB_deg * DEG2RAD;
      40          12 :     const double cosa = cos(LatA_rad);
      41          12 :     const double sina = sin(LatA_rad);
      42          12 :     const double cosb = cos(LatB_rad);
      43          12 :     const double sinb = sin(LatB_rad);
      44          12 :     const double cos_angle = sina * sinb + cosa * cosb * cosP;
      45          12 :     return OGR_Safe_acos(cos_angle) * dfRadius;
      46             : }
      47             : 
      48             : /************************************************************************/
      49             : /*                      OGR_GreatCircle_InitialHeading()                */
      50             : /************************************************************************/
      51             : 
      52           0 : double OGR_GreatCircle_InitialHeading(double LatA_deg, double LonA_deg,
      53             :                                       double LatB_deg, double LonB_deg)
      54             : {
      55           0 :     if (fabs(LatA_deg - 90) < 1e-10 || fabs(LatB_deg + 90) < 1e-10)
      56             :     {
      57           0 :         return 180;
      58             :     }
      59           0 :     else if (fabs(LatA_deg + 90) < 1e-10 || fabs(LatB_deg - 90) < 1e-10)
      60             :     {
      61           0 :         return 0;
      62             :     }
      63           0 :     else if (fabs(fmod(LonA_deg - LonB_deg, 360.0)) < 1e-10 &&
      64           0 :              fabs(LatA_deg - LatB_deg) < 1e-10)
      65             :     {
      66           0 :         return 0;  // Arbitrary number
      67             :     }
      68           0 :     else if (fabs(LatA_deg) < 1e-10 && fabs(LatB_deg) < 1e-10)
      69             :     {
      70           0 :         return (LonB_deg > LonA_deg) ? 90.0 : 270.0;
      71             :     }
      72           0 :     else if (fabs(fmod(LonA_deg - LonB_deg, 360.0)) < 1e-10)
      73             :     {
      74           0 :         return (LatA_deg > LatB_deg) ? 180.0 : 0.0;
      75             :     }
      76             :     else
      77             :     {
      78           0 :         const double LatA_rad = LatA_deg * DEG2RAD;
      79           0 :         const double LatB_rad = LatB_deg * DEG2RAD;
      80             : 
      81           0 :         const double cos_LatA = cos(LatA_rad);
      82           0 :         const double sin_LatA = sin(LatA_rad);
      83             : 
      84           0 :         const double diffG = (LonA_deg - LonB_deg) * DEG2RAD;
      85           0 :         const double cos_diffG = cos(diffG);
      86           0 :         const double sin_diffG = sin(diffG);
      87             : 
      88           0 :         const double denom = sin_LatA * cos_diffG - cos_LatA * tan(LatB_rad);
      89           0 :         if (denom == 0.0)
      90             :         {
      91             :             // Can be the case if Lat_A = -Lat_B and abs(LonA - LonB) = 180
      92           0 :             return 0.0;
      93             :         }
      94             : 
      95           0 :         double track = atan(sin_diffG / denom) * RAD2DEG;
      96             : 
      97           0 :         if (denom > 0.0)
      98             :         {
      99           0 :             track = 180 + track;
     100             :         }
     101           0 :         else if (track < 0)
     102             :         {
     103           0 :             track = 360 + track;
     104             :         }
     105             : 
     106           0 :         return track;
     107             :     }
     108             : }
     109             : 
     110             : /************************************************************************/
     111             : /*                     OGR_GreatCircle_ExtendPosition()                 */
     112             : /************************************************************************/
     113             : 
     114         609 : int OGR_GreatCircle_ExtendPosition(double dfLatA_deg, double dfLonA_deg,
     115             :                                    double dfDistance, double dfHeadingInA,
     116             :                                    double dfRadius, double *pdfLatB_deg,
     117             :                                    double *pdfLonB_deg)
     118             : {
     119         609 :     const double dfHeadingRad = dfHeadingInA * DEG2RAD;
     120         609 :     const double cos_Heading = cos(dfHeadingRad);
     121         609 :     const double sin_Heading = sin(dfHeadingRad);
     122             : 
     123         609 :     const double dfDistanceRad = dfDistance / dfRadius;
     124         609 :     const double cos_Distance = cos(dfDistanceRad);
     125         609 :     const double sin_Distance = sin(dfDistanceRad);
     126             : 
     127         609 :     const double dfLatA_rad = dfLatA_deg * DEG2RAD;
     128         609 :     const double cos_complement_LatA = sin(dfLatA_rad);
     129         609 :     const double sin_complement_LatA = cos(dfLatA_rad);
     130             : 
     131         609 :     if (dfDistance == 0.0)
     132             :     {
     133           0 :         *pdfLatB_deg = dfLatA_deg;
     134           0 :         *pdfLonB_deg = dfLonA_deg;
     135           0 :         return 1;
     136             :     }
     137             : 
     138         609 :     if (fabs(dfLatA_deg) >= 90.0)
     139             :     {
     140           0 :         *pdfLatB_deg = dfLatA_deg;
     141           0 :         *pdfLonB_deg = dfLonA_deg;
     142           0 :         return 0;
     143             :     }
     144             : 
     145         609 :     if (fabs(sin_Heading) < 1e-8)
     146             :     {
     147           4 :         *pdfLonB_deg = dfLonA_deg;
     148           4 :         if (fabs(fmod(dfHeadingInA + 360.0, 360.0)) < 1e-8)
     149             :         {
     150           2 :             *pdfLatB_deg = dfLatA_deg + dfDistanceRad * RAD2DEG;
     151             :         }
     152             :         else
     153             :         {
     154           2 :             *pdfLatB_deg = dfLatA_deg - dfDistanceRad * RAD2DEG;
     155             :         }
     156           4 :         return 1;
     157             :     }
     158             : 
     159         605 :     if (fabs(cos_complement_LatA) < 1e-8 && fabs(cos_Heading) < 1e-8)
     160             :     {
     161           0 :         *pdfLatB_deg = dfLatA_deg;
     162           0 :         if (fabs(dfHeadingInA - 90.0) < 1e-8)
     163             :         {
     164           0 :             *pdfLonB_deg = dfLonA_deg + dfDistanceRad * RAD2DEG;
     165             :         }
     166             :         else
     167             :         {
     168           0 :             *pdfLonB_deg = dfLonA_deg - dfDistanceRad * RAD2DEG;
     169             :         }
     170           0 :         return 1;
     171             :     }
     172             : 
     173         605 :     const double cos_complement_latB =
     174         605 :         cos_Distance * cos_complement_LatA +
     175         605 :         sin_Distance * sin_complement_LatA * cos_Heading;
     176             : 
     177         605 :     const double complement_latB = OGR_Safe_acos(cos_complement_latB);
     178             : 
     179         605 :     const double dfDenomin = sin(complement_latB) * sin_complement_LatA;
     180         605 :     if (dfDenomin == 0.0)
     181           0 :         CPLDebug("OGR", "OGR_GreatCircle_Distance: dfDenomin == 0.0");
     182         605 :     const double Cos_dG =
     183         605 :         (cos_Distance - cos_complement_latB * cos_complement_LatA) / dfDenomin;
     184         605 :     *pdfLatB_deg = 90 - complement_latB * RAD2DEG;
     185             : 
     186         605 :     const double dG_deg = OGR_Safe_acos(Cos_dG) * RAD2DEG;
     187             : 
     188         605 :     if (sin_Heading < 0)
     189         176 :         *pdfLonB_deg = dfLonA_deg - dG_deg;
     190             :     else
     191         429 :         *pdfLonB_deg = dfLonA_deg + dG_deg;
     192             : 
     193         605 :     if (*pdfLonB_deg > 180)
     194           3 :         *pdfLonB_deg -= 360;
     195         602 :     else if (*pdfLonB_deg <= -180)
     196           0 :         *pdfLonB_deg += 360;
     197             : 
     198         605 :     return 1;
     199             : }

Generated by: LCOV version 1.14