LCOV - code coverage report
Current view: top level - ogr - ogr_api.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 398 606 65.7 %
Date: 2024-11-21 22:18:42 Functions: 44 52 84.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  C API Functions that don't correspond one-to-one with C++
       5             :  *           methods, such as the "simplified" geometry access functions.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2002, Frank Warmerdam
      10             :  * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "ogr_api.h"
      17             : 
      18             : #include <cstddef>
      19             : 
      20             : #include "cpl_error.h"
      21             : #include "ogr_geometry.h"
      22             : #include "ogr_geos.h"
      23             : 
      24             : static bool bNonLinearGeometriesEnabled = true;
      25             : 
      26             : /************************************************************************/
      27             : /*                         OGRGetGEOSVersion()                          */
      28             : /************************************************************************/
      29             : 
      30             : /** \brief Get the GEOS version
      31             :  *
      32             :  * @param pnMajor Pointer to major version number, or NULL
      33             :  * @param pnMinor Pointer to minor version number, or NULL
      34             :  * @param pnPatch Pointer to patch version number, or NULL
      35             :  * @return TRUE if GDAL is built against GEOS
      36             :  * @since GDAL 3.4.0
      37             :  */
      38             : #ifdef HAVE_GEOS
      39        4886 : bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
      40             : {
      41        4886 :     CPLStringList aosTokens(CSLTokenizeString2(GEOSversion(), ".", 0));
      42             : 
      43        4886 :     if (pnMajor && aosTokens.size() > 0)
      44        4456 :         *pnMajor = std::stoi(aosTokens[0]);
      45        4886 :     if (pnMinor && aosTokens.size() > 1)
      46         215 :         *pnMinor = std::stoi(aosTokens[1]);
      47        4886 :     if (pnPatch && aosTokens.size() > 2)
      48         215 :         *pnPatch = std::stoi(aosTokens[2]);
      49        9772 :     return TRUE;
      50             : }
      51             : #else
      52             : bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
      53             : {
      54             :     if (pnMajor)
      55             :         *pnMajor = 0;
      56             :     if (pnMinor)
      57             :         *pnMinor = 0;
      58             :     if (pnPatch)
      59             :         *pnPatch = 0;
      60             :     return FALSE;
      61             : }
      62             : #endif
      63             : 
      64             : /************************************************************************/
      65             : /*                           ToPointer()                                */
      66             : /************************************************************************/
      67             : 
      68      753362 : static inline OGRGeometry *ToPointer(OGRGeometryH hGeom)
      69             : {
      70      753362 :     return OGRGeometry::FromHandle(hGeom);
      71             : }
      72             : 
      73             : /************************************************************************/
      74             : /*                           ToHandle()                                 */
      75             : /************************************************************************/
      76             : 
      77        9397 : static inline OGRGeometryH ToHandle(OGRGeometry *poGeom)
      78             : {
      79        9397 :     return OGRGeometry::ToHandle(poGeom);
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                        OGR_G_GetPointCount()                         */
      84             : /************************************************************************/
      85             : /**
      86             :  * \brief Fetch number of points from a Point or a LineString/LinearRing
      87             :  * geometry.
      88             :  *
      89             :  * Only wkbPoint[25D] or wkbLineString[25D] may return a valid value.
      90             :  * Other geometry types will silently return 0.
      91             :  *
      92             :  * @param hGeom handle to the geometry from which to get the number of points.
      93             :  * @return the number of points.
      94             :  */
      95             : 
      96       13248 : int OGR_G_GetPointCount(OGRGeometryH hGeom)
      97             : 
      98             : {
      99       13248 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetPointCount", 0);
     100             : 
     101             :     const OGRwkbGeometryType eGType =
     102       13248 :         wkbFlatten(ToPointer(hGeom)->getGeometryType());
     103       13248 :     if (eGType == wkbPoint)
     104             :     {
     105        1936 :         return 1;
     106             :     }
     107       11312 :     else if (OGR_GT_IsCurve(eGType))
     108             :     {
     109        7176 :         return ToPointer(hGeom)->toCurve()->getNumPoints();
     110             :     }
     111             :     else
     112             :     {
     113             :         // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
     114             :         // silent.
     115             :         // CPLError(CE_Failure, CPLE_NotSupported,
     116             :         //          "Incompatible geometry for operation");
     117        4136 :         return 0;
     118             :     }
     119             : }
     120             : 
     121             : /************************************************************************/
     122             : /*                        OGR_G_SetPointCount()                         */
     123             : /************************************************************************/
     124             : /**
     125             :  * \brief Set number of points in a geometry.
     126             :  *
     127             :  * This method primary exists to preset the number of points in a linestring
     128             :  * geometry before setPoint() is used to assign them to avoid reallocating
     129             :  * the array larger with each call to addPoint().
     130             :  *
     131             :  * @param hGeom handle to the geometry.
     132             :  * @param nNewPointCount the new number of points for geometry.
     133             :  */
     134             : 
     135           0 : void OGR_G_SetPointCount(OGRGeometryH hGeom, int nNewPointCount)
     136             : 
     137             : {
     138           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPointCount");
     139             : 
     140           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     141             :     {
     142           0 :         case wkbLineString:
     143             :         case wkbCircularString:
     144             :         {
     145           0 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     146           0 :             poSC->setNumPoints(nNewPointCount);
     147           0 :             break;
     148             :         }
     149           0 :         default:
     150           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     151             :                      "Incompatible geometry for operation");
     152           0 :             break;
     153             :     }
     154             : }
     155             : 
     156             : /************************************************************************/
     157             : /*                        OGR_G_Get_Component()                         */
     158             : /************************************************************************/
     159             : template <typename Getter>
     160       84432 : static double OGR_G_Get_Component(OGRGeometryH hGeom, int i)
     161             : {
     162       84432 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     163             :     {
     164        4546 :         case wkbPoint:
     165             :         {
     166        4546 :             if (i == 0)
     167             :             {
     168        4543 :                 return Getter::get(ToPointer(hGeom)->toPoint());
     169             :             }
     170             :             else
     171             :             {
     172           3 :                 CPLError(CE_Failure, CPLE_NotSupported,
     173             :                          "Only i == 0 is supported");
     174           3 :                 return 0.0;
     175             :             }
     176             :         }
     177             : 
     178       79883 :         case wkbLineString:
     179             :         case wkbCircularString:
     180             :         {
     181       79883 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     182       79883 :             if (i < 0 || i >= poSC->getNumPoints())
     183             :             {
     184           3 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     185           3 :                 return 0.0;
     186             :             }
     187       79880 :             return Getter::get(poSC, i);
     188             :         }
     189             : 
     190           3 :         default:
     191           3 :             CPLError(CE_Failure, CPLE_NotSupported,
     192             :                      "Incompatible geometry for operation");
     193           3 :             return 0.0;
     194             :     }
     195             : }
     196             : 
     197             : /************************************************************************/
     198             : /*                             OGR_G_GetX()                             */
     199             : /************************************************************************/
     200             : /**
     201             :  * \brief Fetch the x coordinate of a point from a Point or a
     202             :  * LineString/LinearRing geometry.
     203             :  *
     204             :  * @param hGeom handle to the geometry from which to get the x coordinate.
     205             :  * @param i point to get the x coordinate.
     206             :  * @return the X coordinate of this point.
     207             :  */
     208             : 
     209       33637 : double OGR_G_GetX(OGRGeometryH hGeom, int i)
     210             : 
     211             : {
     212       33637 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetX", 0);
     213             : 
     214             :     struct Getter
     215             :     {
     216        2411 :         static double get(const OGRPoint *poPoint)
     217             :         {
     218        2411 :             return poPoint->getX();
     219             :         }
     220             : 
     221       31223 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     222             :         {
     223       31223 :             return poSC->getX(l_i);
     224             :         }
     225             :     };
     226             : 
     227       33637 :     return OGR_G_Get_Component<Getter>(hGeom, i);
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                             OGR_G_GetY()                             */
     232             : /************************************************************************/
     233             : /**
     234             :  * \brief Fetch the x coordinate of a point from a Point or a
     235             :  * LineString/LinearRing geometry.
     236             :  *
     237             :  * @param hGeom handle to the geometry from which to get the y coordinate.
     238             :  * @param i point to get the Y coordinate.
     239             :  * @return the Y coordinate of this point.
     240             :  */
     241             : 
     242       32427 : double OGR_G_GetY(OGRGeometryH hGeom, int i)
     243             : 
     244             : {
     245       32427 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetY", 0);
     246             : 
     247             :     struct Getter
     248             :     {
     249        1201 :         static double get(const OGRPoint *poPoint)
     250             :         {
     251        1201 :             return poPoint->getY();
     252             :         }
     253             : 
     254       31223 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     255             :         {
     256       31223 :             return poSC->getY(l_i);
     257             :         }
     258             :     };
     259             : 
     260       32427 :     return OGR_G_Get_Component<Getter>(hGeom, i);
     261             : }
     262             : 
     263             : /************************************************************************/
     264             : /*                             OGR_G_GetZ()                             */
     265             : /************************************************************************/
     266             : /**
     267             :  * \brief Fetch the z coordinate of a point from a Point or a
     268             :  * LineString/LinearRing geometry.
     269             :  *
     270             :  * @param hGeom handle to the geometry from which to get the Z coordinate.
     271             :  * @param i point to get the Z coordinate.
     272             :  * @return the Z coordinate of this point.
     273             :  */
     274             : 
     275       16102 : double OGR_G_GetZ(OGRGeometryH hGeom, int i)
     276             : 
     277             : {
     278       16102 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetZ", 0);
     279             : 
     280             :     struct Getter
     281             :     {
     282         821 :         static double get(const OGRPoint *poPoint)
     283             :         {
     284         821 :             return poPoint->getZ();
     285             :         }
     286             : 
     287       15278 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     288             :         {
     289       15278 :             return poSC->getZ(l_i);
     290             :         }
     291             :     };
     292             : 
     293       16102 :     return OGR_G_Get_Component<Getter>(hGeom, i);
     294             : }
     295             : 
     296             : /************************************************************************/
     297             : /*                             OGR_G_GetM()                             */
     298             : /************************************************************************/
     299             : /**
     300             :  * \brief Fetch the m coordinate of a point from a geometry.
     301             :  *
     302             :  * @param hGeom handle to the geometry from which to get the M coordinate.
     303             :  * @param i point to get the M coordinate.
     304             :  * @return the M coordinate of this point.
     305             :  */
     306             : 
     307        2266 : double OGR_G_GetM(OGRGeometryH hGeom, int i)
     308             : 
     309             : {
     310        2266 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetM", 0);
     311             : 
     312             :     struct Getter
     313             :     {
     314         110 :         static double get(const OGRPoint *poPoint)
     315             :         {
     316         110 :             return poPoint->getM();
     317             :         }
     318             : 
     319        2156 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     320             :         {
     321        2156 :             return poSC->getM(l_i);
     322             :         }
     323             :     };
     324             : 
     325        2266 :     return OGR_G_Get_Component<Getter>(hGeom, i);
     326             : }
     327             : 
     328             : /************************************************************************/
     329             : /*                          OGR_G_GetPoints()                           */
     330             : /************************************************************************/
     331             : 
     332             : /**
     333             :  * \brief Returns all points of line string.
     334             :  *
     335             :  * This method copies all points into user arrays. The user provides the
     336             :  * stride between 2 consecutive elements of the array.
     337             :  *
     338             :  * On some CPU architectures, care must be taken so that the arrays are properly
     339             :  * aligned.
     340             :  *
     341             :  * @param hGeom handle to the geometry from which to get the coordinates.
     342             :  * @param pabyX a buffer of at least (sizeof(double) * nXStride * nPointCount)
     343             :  * bytes, may be NULL.
     344             :  * @param nXStride the number of bytes between 2 elements of pabyX.
     345             :  * @param pabyY a buffer of at least (sizeof(double) * nYStride * nPointCount)
     346             :  * bytes, may be NULL.
     347             :  * @param nYStride the number of bytes between 2 elements of pabyY.
     348             :  * @param pabyZ a buffer of at last size (sizeof(double) * nZStride *
     349             :  * nPointCount) bytes, may be NULL.
     350             :  * @param nZStride the number of bytes between 2 elements of pabyZ.
     351             :  *
     352             :  * @return the number of points
     353             :  *
     354             :  * @since OGR 1.9.0
     355             :  */
     356             : 
     357          11 : int OGR_G_GetPoints(OGRGeometryH hGeom, void *pabyX, int nXStride, void *pabyY,
     358             :                     int nYStride, void *pabyZ, int nZStride)
     359             : {
     360          11 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetPoints", 0);
     361             : 
     362          11 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     363             :     {
     364           4 :         case wkbPoint:
     365             :         {
     366           4 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     367           4 :             if (pabyX)
     368           4 :                 *(static_cast<double *>(pabyX)) = poPoint->getX();
     369           4 :             if (pabyY)
     370           4 :                 *(static_cast<double *>(pabyY)) = poPoint->getY();
     371           4 :             if (pabyZ)
     372           2 :                 *(static_cast<double *>(pabyZ)) = poPoint->getZ();
     373           4 :             return 1;
     374             :         }
     375             :         break;
     376             : 
     377           6 :         case wkbLineString:
     378             :         case wkbCircularString:
     379             :         {
     380           6 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     381           6 :             poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride);
     382           6 :             return poSC->getNumPoints();
     383             :         }
     384             :         break;
     385             : 
     386           1 :         default:
     387           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     388             :                      "Incompatible geometry for operation");
     389           1 :             return 0;
     390             :             break;
     391             :     }
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /*                          OGR_G_GetPointsZM()                         */
     396             : /************************************************************************/
     397             : 
     398             : /**
     399             :  * \brief Returns all points of line string.
     400             :  *
     401             :  * This method copies all points into user arrays. The user provides the
     402             :  * stride between 2 consecutive elements of the array.
     403             :  *
     404             :  * On some CPU architectures, care must be taken so that the arrays are properly
     405             :  * aligned.
     406             :  *
     407             :  * @param hGeom handle to the geometry from which to get the coordinates.
     408             :  * @param pabyX a buffer of at least (nXStride * nPointCount)
     409             :  * bytes, may be NULL.
     410             :  * @param nXStride the number of bytes between 2 elements of pabyX.
     411             :  * @param pabyY a buffer of at least (nYStride * nPointCount)
     412             :  * bytes, may be NULL.
     413             :  * @param nYStride the number of bytes between 2 elements of pabyY.
     414             :  * @param pabyZ a buffer of at last size (nZStride *
     415             :  * nPointCount) bytes, may be NULL.
     416             :  * @param nZStride the number of bytes between 2 elements of pabyZ.
     417             :  * @param pabyM a buffer of at last size (nMStride *
     418             :  * nPointCount) bytes, may be NULL.
     419             :  * @param nMStride the number of bytes between 2 elements of pabyM.
     420             :  *
     421             :  * @return the number of points
     422             :  *
     423             :  * @since OGR 1.9.0
     424             :  */
     425             : 
     426           0 : int OGR_G_GetPointsZM(OGRGeometryH hGeom, void *pabyX, int nXStride,
     427             :                       void *pabyY, int nYStride, void *pabyZ, int nZStride,
     428             :                       void *pabyM, int nMStride)
     429             : {
     430           0 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetPointsZM", 0);
     431             : 
     432           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     433             :     {
     434           0 :         case wkbPoint:
     435             :         {
     436           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     437           0 :             if (pabyX)
     438           0 :                 *static_cast<double *>(pabyX) = poPoint->getX();
     439           0 :             if (pabyY)
     440           0 :                 *static_cast<double *>(pabyY) = poPoint->getY();
     441           0 :             if (pabyZ)
     442           0 :                 *static_cast<double *>(pabyZ) = poPoint->getZ();
     443           0 :             if (pabyM)
     444           0 :                 *static_cast<double *>(pabyM) = poPoint->getM();
     445           0 :             return 1;
     446             :         }
     447             :         break;
     448             : 
     449           0 :         case wkbLineString:
     450             :         case wkbCircularString:
     451             :         {
     452           0 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     453           0 :             poSC->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride,
     454             :                             pabyM, nMStride);
     455           0 :             return poSC->getNumPoints();
     456             :         }
     457             :         break;
     458             : 
     459           0 :         default:
     460           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     461             :                      "Incompatible geometry for operation");
     462           0 :             return 0;
     463             :             break;
     464             :     }
     465             : }
     466             : 
     467             : /************************************************************************/
     468             : /*                           OGR_G_GetPoint()                           */
     469             : /************************************************************************/
     470             : 
     471             : /**
     472             :  * \brief Fetch a point in line string or a point geometry.
     473             :  *
     474             :  * @param hGeom handle to the geometry from which to get the coordinates.
     475             :  * @param i the vertex to fetch, from 0 to getNumPoints()-1, zero for a point.
     476             :  * @param pdfX value of x coordinate.
     477             :  * @param pdfY value of y coordinate.
     478             :  * @param pdfZ value of z coordinate.
     479             :  */
     480             : 
     481         756 : void OGR_G_GetPoint(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
     482             :                     double *pdfZ)
     483             : 
     484             : {
     485         756 :     VALIDATE_POINTER0(hGeom, "OGR_G_GetPoint");
     486             : 
     487         756 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     488             :     {
     489          21 :         case wkbPoint:
     490             :         {
     491          21 :             if (i == 0)
     492             :             {
     493          20 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     494          20 :                 *pdfX = poPoint->getX();
     495          20 :                 *pdfY = poPoint->getY();
     496          20 :                 if (pdfZ != nullptr)
     497          20 :                     *pdfZ = poPoint->getZ();
     498             :             }
     499             :             else
     500             :             {
     501           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
     502             :                          "Only i == 0 is supported");
     503             :             }
     504             :         }
     505          21 :         break;
     506             : 
     507         734 :         case wkbLineString:
     508             :         case wkbCircularString:
     509             :         {
     510         734 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     511         734 :             if (i < 0 || i >= poSC->getNumPoints())
     512             :             {
     513           5 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     514           5 :                 *pdfX = 0.0;
     515           5 :                 *pdfY = 0.0;
     516           5 :                 if (pdfZ != nullptr)
     517           3 :                     *pdfZ = 0.0;
     518             :             }
     519             :             else
     520             :             {
     521         729 :                 *pdfX = poSC->getX(i);
     522         729 :                 *pdfY = poSC->getY(i);
     523         729 :                 if (pdfZ != nullptr)
     524         728 :                     *pdfZ = poSC->getZ(i);
     525             :             }
     526             :         }
     527         734 :         break;
     528             : 
     529           1 :         default:
     530           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     531             :                      "Incompatible geometry for operation");
     532           1 :             break;
     533             :     }
     534             : }
     535             : 
     536             : /************************************************************************/
     537             : /*                           OGR_G_GetPointZM()                         */
     538             : /************************************************************************/
     539             : 
     540             : /**
     541             :  * \brief Fetch a point in line string or a point geometry.
     542             :  *
     543             :  * @param hGeom handle to the geometry from which to get the coordinates.
     544             :  * @param i the vertex to fetch, from 0 to getNumPoints()-1, zero for a point.
     545             :  * @param pdfX value of x coordinate.
     546             :  * @param pdfY value of y coordinate.
     547             :  * @param pdfZ value of z coordinate.
     548             :  * @param pdfM value of m coordinate.
     549             :  */
     550             : 
     551           1 : void OGR_G_GetPointZM(OGRGeometryH hGeom, int i, double *pdfX, double *pdfY,
     552             :                       double *pdfZ, double *pdfM)
     553             : 
     554             : {
     555           1 :     VALIDATE_POINTER0(hGeom, "OGR_G_GetPointZM");
     556             : 
     557           1 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     558             :     {
     559           1 :         case wkbPoint:
     560             :         {
     561           1 :             if (i == 0)
     562             :             {
     563           1 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     564           1 :                 *pdfX = poPoint->getX();
     565           1 :                 *pdfY = poPoint->getY();
     566           1 :                 if (pdfZ != nullptr)
     567           1 :                     *pdfZ = poPoint->getZ();
     568           1 :                 if (pdfM != nullptr)
     569           1 :                     *pdfM = poPoint->getM();
     570             :             }
     571             :             else
     572             :             {
     573           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     574             :                          "Only i == 0 is supported");
     575             :             }
     576             :         }
     577           1 :         break;
     578             : 
     579           0 :         case wkbLineString:
     580             :         case wkbCircularString:
     581             :         {
     582           0 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     583           0 :             if (i < 0 || i >= poSC->getNumPoints())
     584             :             {
     585           0 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     586           0 :                 *pdfX = 0.0;
     587           0 :                 *pdfY = 0.0;
     588           0 :                 if (pdfZ != nullptr)
     589           0 :                     *pdfZ = 0.0;
     590           0 :                 if (pdfM != nullptr)
     591           0 :                     *pdfM = 0.0;
     592             :             }
     593             :             else
     594             :             {
     595           0 :                 *pdfX = poSC->getX(i);
     596           0 :                 *pdfY = poSC->getY(i);
     597           0 :                 if (pdfZ != nullptr)
     598           0 :                     *pdfZ = poSC->getZ(i);
     599           0 :                 if (pdfM != nullptr)
     600           0 :                     *pdfM = poSC->getM(i);
     601             :             }
     602             :         }
     603           0 :         break;
     604             : 
     605           0 :         default:
     606           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     607             :                      "Incompatible geometry for operation");
     608           0 :             break;
     609             :     }
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                           OGR_G_SetPoints()                          */
     614             : /************************************************************************/
     615             : /**
     616             :  * \brief Assign all points in a point or a line string geometry.
     617             :  *
     618             :  * This method clear any existing points assigned to this geometry,
     619             :  * and assigns a whole new set.
     620             :  *
     621             :  * @param hGeom handle to the geometry to set the coordinates.
     622             :  * @param nPointsIn number of points being passed in padfX and padfY.
     623             :  * @param pabyX list of X coordinates (double values) of points being assigned.
     624             :  * @param nXStride the number of bytes between 2 elements of pabyX.
     625             :  * @param pabyY list of Y coordinates (double values) of points being assigned.
     626             :  * @param nYStride the number of bytes between 2 elements of pabyY.
     627             :  * @param pabyZ list of Z coordinates (double values) of points being assigned
     628             :  * (defaults to NULL for 2D objects).
     629             :  * @param nZStride the number of bytes between 2 elements of pabyZ.
     630             :  */
     631             : 
     632           9 : void CPL_DLL OGR_G_SetPoints(OGRGeometryH hGeom, int nPointsIn,
     633             :                              const void *pabyX, int nXStride, const void *pabyY,
     634             :                              int nYStride, const void *pabyZ, int nZStride)
     635             : 
     636             : {
     637           9 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPoints");
     638             : 
     639           9 :     if (pabyX == nullptr || pabyY == nullptr)
     640             :     {
     641           2 :         CPLError(CE_Failure, CPLE_NotSupported,
     642             :                  "pabyX == NULL || pabyY == NULL");
     643           2 :         return;
     644             :     }
     645             : 
     646           7 :     const double *const padfX = static_cast<const double *>(pabyX);
     647           7 :     const double *const padfY = static_cast<const double *>(pabyY);
     648           7 :     const double *const padfZ = static_cast<const double *>(pabyZ);
     649             : 
     650           7 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     651             :     {
     652           2 :         case wkbPoint:
     653             :         {
     654           2 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     655           2 :             poPoint->setX(*padfX);
     656           2 :             poPoint->setY(*padfY);
     657           2 :             if (pabyZ != nullptr)
     658           1 :                 poPoint->setZ(*(padfZ));
     659           2 :             break;
     660             :         }
     661           5 :         case wkbLineString:
     662             :         case wkbCircularString:
     663             :         {
     664           5 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     665             : 
     666           5 :             const int nSizeDouble = static_cast<int>(sizeof(double));
     667           5 :             if (nXStride == nSizeDouble && nYStride == nSizeDouble &&
     668           2 :                 ((nZStride == 0 && pabyZ == nullptr) ||
     669           1 :                  (nZStride == nSizeDouble && pabyZ != nullptr)))
     670             :             {
     671           2 :                 poSC->setPoints(nPointsIn, padfX, padfY, padfZ);
     672             :             }
     673             :             else
     674             :             {
     675           3 :                 poSC->setNumPoints(nPointsIn);
     676             : 
     677             :                 // TODO(schwehr): Create pasX and pasY.
     678           6 :                 for (int i = 0; i < nPointsIn; ++i)
     679             :                 {
     680           3 :                     const double x = *reinterpret_cast<const double *>(
     681           3 :                         static_cast<const char *>(pabyX) + i * nXStride);
     682           3 :                     const double y = *reinterpret_cast<const double *>(
     683           3 :                         static_cast<const char *>(pabyY) + i * nYStride);
     684           3 :                     if (pabyZ)
     685             :                     {
     686           1 :                         const double z = *reinterpret_cast<const double *>(
     687           1 :                             static_cast<const char *>(pabyZ) + i * nZStride);
     688           1 :                         poSC->setPoint(i, x, y, z);
     689             :                     }
     690             :                     else
     691             :                     {
     692           2 :                         poSC->setPoint(i, x, y);
     693             :                     }
     694             :                 }
     695             :             }
     696           5 :             break;
     697             :         }
     698           0 :         default:
     699           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     700             :                      "Incompatible geometry for operation");
     701           0 :             break;
     702             :     }
     703             : }
     704             : 
     705             : /************************************************************************/
     706             : /*                           OGR_G_SetPointsZM()                        */
     707             : /************************************************************************/
     708             : /**
     709             :  * \brief Assign all points in a point or a line string geometry.
     710             :  *
     711             :  * This method clear any existing points assigned to this geometry,
     712             :  * and assigns a whole new set.
     713             :  *
     714             :  * @param hGeom handle to the geometry to set the coordinates.
     715             :  * @param nPointsIn number of points being passed in padfX and padfY.
     716             :  * @param pX list of X coordinates (double values) of points being assigned.
     717             :  * @param nXStride the number of bytes between 2 elements of pX.
     718             :  * @param pY list of Y coordinates (double values) of points being assigned.
     719             :  * @param nYStride the number of bytes between 2 elements of pY.
     720             :  * @param pZ list of Z coordinates (double values) of points being assigned
     721             :  * (if not NULL, upgrades the geometry to have Z coordinate).
     722             :  * @param nZStride the number of bytes between 2 elements of pZ.
     723             :  * @param pM list of M coordinates (double values) of points being assigned
     724             :  * (if not NULL, upgrades the geometry to have M coordinate).
     725             :  * @param nMStride the number of bytes between 2 elements of pM.
     726             :  */
     727             : 
     728           0 : void CPL_DLL OGR_G_SetPointsZM(OGRGeometryH hGeom, int nPointsIn,
     729             :                                const void *pX, int nXStride, const void *pY,
     730             :                                int nYStride, const void *pZ, int nZStride,
     731             :                                const void *pM, int nMStride)
     732             : 
     733             : {
     734           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPointsZM");
     735             : 
     736           0 :     if (pX == nullptr || pY == nullptr)
     737             :     {
     738           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     739             :                  "pabyX == NULL || pabyY == NULL");
     740           0 :         return;
     741             :     }
     742             : 
     743           0 :     const double *const padfX = static_cast<const double *>(pX);
     744           0 :     const double *const padfY = static_cast<const double *>(pY);
     745           0 :     const double *const padfZ = static_cast<const double *>(pZ);
     746           0 :     const double *const padfM = static_cast<const double *>(pM);
     747           0 :     const char *const pabyX = static_cast<const char *>(pX);
     748           0 :     const char *const pabyY = static_cast<const char *>(pY);
     749           0 :     const char *const pabyZ = static_cast<const char *>(pZ);
     750           0 :     const char *const pabyM = static_cast<const char *>(pM);
     751             : 
     752           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     753             :     {
     754           0 :         case wkbPoint:
     755             :         {
     756           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     757           0 :             poPoint->setX(*padfX);
     758           0 :             poPoint->setY(*padfY);
     759           0 :             if (pabyZ)
     760           0 :                 poPoint->setZ(*padfZ);
     761           0 :             if (pabyM)
     762           0 :                 poPoint->setM(*padfM);
     763           0 :             break;
     764             :         }
     765           0 :         case wkbLineString:
     766             :         case wkbCircularString:
     767             :         {
     768           0 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     769             : 
     770           0 :             const int nSizeDouble = static_cast<int>(sizeof(double));
     771           0 :             if (nXStride == nSizeDouble && nYStride == nSizeDouble &&
     772           0 :                 ((nZStride == 0 && padfZ == nullptr) ||
     773           0 :                  (nZStride == nSizeDouble && padfZ != nullptr)) &&
     774           0 :                 ((nMStride == 0 && padfM == nullptr) ||
     775           0 :                  (nMStride == nSizeDouble && padfM != nullptr)))
     776             :             {
     777           0 :                 if (!padfZ && !padfM)
     778           0 :                     poSC->setPoints(nPointsIn, padfX, padfY);
     779           0 :                 else if (pabyZ && !pabyM)
     780           0 :                     poSC->setPoints(nPointsIn, padfX, padfY, padfZ);
     781           0 :                 else if (!pabyZ && pabyM)
     782           0 :                     poSC->setPointsM(nPointsIn, padfX, padfY, padfM);
     783             :                 else
     784           0 :                     poSC->setPoints(nPointsIn, padfX, padfY, padfZ, padfM);
     785             :             }
     786             :             else
     787             :             {
     788           0 :                 poSC->setNumPoints(nPointsIn);
     789             : 
     790           0 :                 if (!pabyM)
     791             :                 {
     792           0 :                     if (!pabyZ)
     793             :                     {
     794           0 :                         for (int i = 0; i < nPointsIn; ++i)
     795             :                         {
     796           0 :                             const double x = *reinterpret_cast<const double *>(
     797           0 :                                 pabyX + i * nXStride);
     798           0 :                             const double y = *reinterpret_cast<const double *>(
     799           0 :                                 pabyY + i * nYStride);
     800           0 :                             poSC->setPoint(i, x, y);
     801             :                         }
     802             :                     }
     803             :                     else
     804             :                     {
     805           0 :                         for (int i = 0; i < nPointsIn; ++i)
     806             :                         {
     807           0 :                             const double x = *reinterpret_cast<const double *>(
     808           0 :                                 pabyX + i * nXStride);
     809           0 :                             const double y = *reinterpret_cast<const double *>(
     810           0 :                                 pabyY + i * nYStride);
     811           0 :                             const double z = *reinterpret_cast<const double *>(
     812           0 :                                 pabyZ + i * nZStride);
     813           0 :                             poSC->setPoint(i, x, y, z);
     814             :                         }
     815             :                     }
     816             :                 }
     817             :                 else
     818             :                 {
     819           0 :                     if (!pabyZ)
     820             :                     {
     821           0 :                         for (int i = 0; i < nPointsIn; ++i)
     822             :                         {
     823           0 :                             const double x = *reinterpret_cast<const double *>(
     824           0 :                                 pabyX + i * nXStride);
     825           0 :                             const double y = *reinterpret_cast<const double *>(
     826           0 :                                 pabyY + i * nYStride);
     827           0 :                             const double m = *reinterpret_cast<const double *>(
     828           0 :                                 pabyM + i * nMStride);
     829           0 :                             poSC->setPointM(i, x, y, m);
     830             :                         }
     831             :                     }
     832             :                     else
     833             :                     {
     834           0 :                         for (int i = 0; i < nPointsIn; ++i)
     835             :                         {
     836           0 :                             const double x = *reinterpret_cast<const double *>(
     837           0 :                                 pabyX + i * nXStride);
     838           0 :                             const double y = *reinterpret_cast<const double *>(
     839           0 :                                 pabyY + i * nYStride);
     840           0 :                             const double z = *reinterpret_cast<const double *>(
     841           0 :                                 pabyZ + i * nZStride);
     842           0 :                             const double m = *reinterpret_cast<const double *>(
     843           0 :                                 pabyM + i * nMStride);
     844           0 :                             poSC->setPoint(i, x, y, z, m);
     845             :                         }
     846             :                     }
     847             :                 }
     848             :             }
     849           0 :             break;
     850             :         }
     851           0 :         default:
     852           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     853             :                      "Incompatible geometry for operation");
     854           0 :             break;
     855             :     }
     856             : }
     857             : 
     858             : /************************************************************************/
     859             : /*                           OGR_G_SetPoint()                           */
     860             : /************************************************************************/
     861             : /**
     862             :  * \brief Set the location of a vertex in a point or linestring geometry.
     863             :  *
     864             :  * If iPoint is larger than the number of existing
     865             :  * points in the linestring, the point count will be increased to
     866             :  * accommodate the request.
     867             :  *
     868             :  * @param hGeom handle to the geometry to add a vertex to.
     869             :  * @param i the index of the vertex to assign (zero based) or
     870             :  *  zero for a point.
     871             :  * @param dfX input X coordinate to assign.
     872             :  * @param dfY input Y coordinate to assign.
     873             :  * @param dfZ input Z coordinate to assign (defaults to zero).
     874             :  */
     875             : 
     876       49903 : void OGR_G_SetPoint(OGRGeometryH hGeom, int i, double dfX, double dfY,
     877             :                     double dfZ)
     878             : 
     879             : {
     880       49903 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPoint");
     881             : 
     882       49903 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     883             :     {
     884         164 :         case wkbPoint:
     885             :         {
     886         164 :             if (i == 0)
     887             :             {
     888         163 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     889         163 :                 poPoint->setX(dfX);
     890         163 :                 poPoint->setY(dfY);
     891         163 :                 poPoint->setZ(dfZ);
     892             :             }
     893             :             else
     894             :             {
     895           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
     896             :                          "Only i == 0 is supported");
     897             :             }
     898             :         }
     899         164 :         break;
     900             : 
     901       49738 :         case wkbLineString:
     902             :         case wkbCircularString:
     903             :         {
     904       49738 :             if (i < 0)
     905             :             {
     906           2 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     907           2 :                 return;
     908             :             }
     909       49736 :             ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ);
     910       49736 :             break;
     911             :         }
     912             : 
     913           1 :         default:
     914           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     915             :                      "Incompatible geometry for operation");
     916           1 :             break;
     917             :     }
     918             : }
     919             : 
     920             : /************************************************************************/
     921             : /*                         OGR_G_SetPoint_2D()                          */
     922             : /************************************************************************/
     923             : /**
     924             :  * \brief Set the location of a vertex in a point or linestring geometry.
     925             :  *
     926             :  * If iPoint is larger than the number of existing
     927             :  * points in the linestring, the point count will be increased to
     928             :  * accommodate the request.
     929             :  *
     930             :  * @param hGeom handle to the geometry to add a vertex to.
     931             :  * @param i the index of the vertex to assign (zero based) or
     932             :  *  zero for a point.
     933             :  * @param dfX input X coordinate to assign.
     934             :  * @param dfY input Y coordinate to assign.
     935             :  */
     936             : 
     937      217172 : void OGR_G_SetPoint_2D(OGRGeometryH hGeom, int i, double dfX, double dfY)
     938             : 
     939             : {
     940      217172 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPoint_2D");
     941             : 
     942      217172 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     943             :     {
     944      160001 :         case wkbPoint:
     945             :         {
     946      160001 :             if (i == 0)
     947             :             {
     948      160000 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     949      160000 :                 poPoint->setX(dfX);
     950      160000 :                 poPoint->setY(dfY);
     951             :             }
     952             :             else
     953             :             {
     954           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
     955             :                          "Only i == 0 is supported");
     956             :             }
     957             :         }
     958      160001 :         break;
     959             : 
     960       57170 :         case wkbLineString:
     961             :         case wkbCircularString:
     962             :         {
     963       57170 :             if (i < 0)
     964             :             {
     965           2 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     966           2 :                 return;
     967             :             }
     968       57168 :             ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY);
     969       57168 :             break;
     970             :         }
     971             : 
     972           1 :         default:
     973           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     974             :                      "Incompatible geometry for operation");
     975           1 :             break;
     976             :     }
     977             : }
     978             : 
     979             : /************************************************************************/
     980             : /*                           OGR_G_SetPointM()                          */
     981             : /************************************************************************/
     982             : /**
     983             :  * \brief Set the location of a vertex in a point or linestring geometry.
     984             :  *
     985             :  * If iPoint is larger than the number of existing
     986             :  * points in the linestring, the point count will be increased to
     987             :  * accommodate the request.
     988             :  *
     989             :  * @param hGeom handle to the geometry to add a vertex to.
     990             :  * @param i the index of the vertex to assign (zero based) or
     991             :  *  zero for a point.
     992             :  * @param dfX input X coordinate to assign.
     993             :  * @param dfY input Y coordinate to assign.
     994             :  * @param dfM input M coordinate to assign.
     995             :  */
     996             : 
     997           0 : void OGR_G_SetPointM(OGRGeometryH hGeom, int i, double dfX, double dfY,
     998             :                      double dfM)
     999             : 
    1000             : {
    1001           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPointM");
    1002             : 
    1003           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1004             :     {
    1005           0 :         case wkbPoint:
    1006             :         {
    1007           0 :             if (i == 0)
    1008             :             {
    1009           0 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1010           0 :                 poPoint->setX(dfX);
    1011           0 :                 poPoint->setY(dfY);
    1012           0 :                 poPoint->setM(dfM);
    1013             :             }
    1014             :             else
    1015             :             {
    1016           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1017             :                          "Only i == 0 is supported");
    1018             :             }
    1019             :         }
    1020           0 :         break;
    1021             : 
    1022           0 :         case wkbLineString:
    1023             :         case wkbCircularString:
    1024             :         {
    1025           0 :             if (i < 0)
    1026             :             {
    1027           0 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
    1028           0 :                 return;
    1029             :             }
    1030           0 :             ToPointer(hGeom)->toSimpleCurve()->setPointM(i, dfX, dfY, dfM);
    1031           0 :             break;
    1032             :         }
    1033             : 
    1034           0 :         default:
    1035           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1036             :                      "Incompatible geometry for operation");
    1037           0 :             break;
    1038             :     }
    1039             : }
    1040             : 
    1041             : /************************************************************************/
    1042             : /*                           OGR_G_SetPointZM()                         */
    1043             : /************************************************************************/
    1044             : /**
    1045             :  * \brief Set the location of a vertex in a point or linestring geometry.
    1046             :  *
    1047             :  * If iPoint is larger than the number of existing
    1048             :  * points in the linestring, the point count will be increased to
    1049             :  * accommodate the request.
    1050             :  *
    1051             :  * @param hGeom handle to the geometry to add a vertex to.
    1052             :  * @param i the index of the vertex to assign (zero based) or
    1053             :  *  zero for a point.
    1054             :  * @param dfX input X coordinate to assign.
    1055             :  * @param dfY input Y coordinate to assign.
    1056             :  * @param dfZ input Z coordinate to assign.
    1057             :  * @param dfM input M coordinate to assign.
    1058             :  */
    1059             : 
    1060           0 : void OGR_G_SetPointZM(OGRGeometryH hGeom, int i, double dfX, double dfY,
    1061             :                       double dfZ, double dfM)
    1062             : 
    1063             : {
    1064           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_SetPointZM");
    1065             : 
    1066           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1067             :     {
    1068           0 :         case wkbPoint:
    1069             :         {
    1070           0 :             if (i == 0)
    1071             :             {
    1072           0 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1073           0 :                 poPoint->setX(dfX);
    1074           0 :                 poPoint->setY(dfY);
    1075           0 :                 poPoint->setZ(dfZ);
    1076           0 :                 poPoint->setM(dfM);
    1077             :             }
    1078             :             else
    1079             :             {
    1080           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1081             :                          "Only i == 0 is supported");
    1082             :             }
    1083             :         }
    1084           0 :         break;
    1085             : 
    1086           0 :         case wkbLineString:
    1087             :         case wkbCircularString:
    1088             :         {
    1089           0 :             if (i < 0)
    1090             :             {
    1091           0 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
    1092           0 :                 return;
    1093             :             }
    1094           0 :             ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ, dfM);
    1095           0 :             break;
    1096             :         }
    1097             : 
    1098           0 :         default:
    1099           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1100             :                      "Incompatible geometry for operation");
    1101           0 :             break;
    1102             :     }
    1103             : }
    1104             : 
    1105             : /************************************************************************/
    1106             : /*                           OGR_G_AddPoint()                           */
    1107             : /************************************************************************/
    1108             : /**
    1109             :  * \brief Add a point to a geometry (line string or point).
    1110             :  *
    1111             :  * The vertex count of the line string is increased by one, and assigned from
    1112             :  * the passed location value.
    1113             :  *
    1114             :  * @param hGeom handle to the geometry to add a point to.
    1115             :  * @param dfX x coordinate of point to add.
    1116             :  * @param dfY y coordinate of point to add.
    1117             :  * @param dfZ z coordinate of point to add.
    1118             :  */
    1119             : 
    1120         254 : void OGR_G_AddPoint(OGRGeometryH hGeom, double dfX, double dfY, double dfZ)
    1121             : 
    1122             : {
    1123         254 :     VALIDATE_POINTER0(hGeom, "OGR_G_AddPoint");
    1124             : 
    1125         254 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1126             :     {
    1127           4 :         case wkbPoint:
    1128             :         {
    1129           4 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1130           4 :             poPoint->setX(dfX);
    1131           4 :             poPoint->setY(dfY);
    1132           4 :             poPoint->setZ(dfZ);
    1133             :         }
    1134           4 :         break;
    1135             : 
    1136         249 :         case wkbLineString:
    1137             :         case wkbCircularString:
    1138         249 :             ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ);
    1139         249 :             break;
    1140             : 
    1141           1 :         default:
    1142           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1143             :                      "Incompatible geometry for operation");
    1144           1 :             break;
    1145             :     }
    1146             : }
    1147             : 
    1148             : /************************************************************************/
    1149             : /*                           OGR_G_AddPoint_2D()                        */
    1150             : /************************************************************************/
    1151             : /**
    1152             :  * \brief Add a point to a geometry (line string or point).
    1153             :  *
    1154             :  * The vertex count of the line string is increased by one, and assigned from
    1155             :  * the passed location value.
    1156             :  *
    1157             :  * @param hGeom handle to the geometry to add a point to.
    1158             :  * @param dfX x coordinate of point to add.
    1159             :  * @param dfY y coordinate of point to add.
    1160             :  */
    1161             : 
    1162        1538 : void OGR_G_AddPoint_2D(OGRGeometryH hGeom, double dfX, double dfY)
    1163             : 
    1164             : {
    1165        1538 :     VALIDATE_POINTER0(hGeom, "OGR_G_AddPoint_2D");
    1166             : 
    1167        1538 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1168             :     {
    1169          74 :         case wkbPoint:
    1170             :         {
    1171          74 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1172          74 :             poPoint->setX(dfX);
    1173          74 :             poPoint->setY(dfY);
    1174             :         }
    1175          74 :         break;
    1176             : 
    1177        1463 :         case wkbLineString:
    1178             :         case wkbCircularString:
    1179        1463 :             ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY);
    1180        1463 :             break;
    1181             : 
    1182           1 :         default:
    1183           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1184             :                      "Incompatible geometry for operation");
    1185           1 :             break;
    1186             :     }
    1187             : }
    1188             : 
    1189             : /************************************************************************/
    1190             : /*                           OGR_G_AddPointM()                          */
    1191             : /************************************************************************/
    1192             : /**
    1193             :  * \brief Add a point to a geometry (line string or point).
    1194             :  *
    1195             :  * The vertex count of the line string is increased by one, and assigned from
    1196             :  * the passed location value.
    1197             :  *
    1198             :  * @param hGeom handle to the geometry to add a point to.
    1199             :  * @param dfX x coordinate of point to add.
    1200             :  * @param dfY y coordinate of point to add.
    1201             :  * @param dfM m coordinate of point to add.
    1202             :  */
    1203             : 
    1204           0 : void OGR_G_AddPointM(OGRGeometryH hGeom, double dfX, double dfY, double dfM)
    1205             : 
    1206             : {
    1207           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_AddPointM");
    1208             : 
    1209           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1210             :     {
    1211           0 :         case wkbPoint:
    1212             :         {
    1213           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1214           0 :             poPoint->setX(dfX);
    1215           0 :             poPoint->setY(dfY);
    1216           0 :             poPoint->setM(dfM);
    1217             :         }
    1218           0 :         break;
    1219             : 
    1220           0 :         case wkbLineString:
    1221             :         case wkbCircularString:
    1222           0 :             ToPointer(hGeom)->toSimpleCurve()->addPointM(dfX, dfY, dfM);
    1223           0 :             break;
    1224             : 
    1225           0 :         default:
    1226           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1227             :                      "Incompatible geometry for operation");
    1228           0 :             break;
    1229             :     }
    1230             : }
    1231             : 
    1232             : /************************************************************************/
    1233             : /*                           OGR_G_AddPointZM()                         */
    1234             : /************************************************************************/
    1235             : /**
    1236             :  * \brief Add a point to a geometry (line string or point).
    1237             :  *
    1238             :  * The vertex count of the line string is increased by one, and assigned from
    1239             :  * the passed location value.
    1240             :  *
    1241             :  * @param hGeom handle to the geometry to add a point to.
    1242             :  * @param dfX x coordinate of point to add.
    1243             :  * @param dfY y coordinate of point to add.
    1244             :  * @param dfZ z coordinate of point to add.
    1245             :  * @param dfM m coordinate of point to add.
    1246             :  */
    1247             : 
    1248           0 : void OGR_G_AddPointZM(OGRGeometryH hGeom, double dfX, double dfY, double dfZ,
    1249             :                       double dfM)
    1250             : 
    1251             : {
    1252           0 :     VALIDATE_POINTER0(hGeom, "OGR_G_AddPointZM");
    1253             : 
    1254           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1255             :     {
    1256           0 :         case wkbPoint:
    1257             :         {
    1258           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1259           0 :             poPoint->setX(dfX);
    1260           0 :             poPoint->setY(dfY);
    1261           0 :             poPoint->setZ(dfZ);
    1262           0 :             poPoint->setM(dfM);
    1263             :         }
    1264           0 :         break;
    1265             : 
    1266           0 :         case wkbLineString:
    1267             :         case wkbCircularString:
    1268           0 :             ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ, dfM);
    1269           0 :             break;
    1270             : 
    1271           0 :         default:
    1272           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1273             :                      "Incompatible geometry for operation");
    1274           0 :             break;
    1275             :     }
    1276             : }
    1277             : 
    1278             : /************************************************************************/
    1279             : /*                       OGR_G_GetGeometryCount()                       */
    1280             : /************************************************************************/
    1281             : /**
    1282             :  * \brief Fetch the number of elements in a geometry or number of geometries in
    1283             :  * container.
    1284             :  *
    1285             :  * Only geometries of type wkbPolygon[25D], wkbMultiPoint[25D],
    1286             :  * wkbMultiLineString[25D], wkbMultiPolygon[25D] or wkbGeometryCollection[25D]
    1287             :  * may return a valid value.  Other geometry types will silently return 0.
    1288             :  *
    1289             :  * For a polygon, the returned number is the number of rings (exterior ring +
    1290             :  * interior rings).
    1291             :  *
    1292             :  * @param hGeom single geometry or geometry container from which to get
    1293             :  * the number of elements.
    1294             :  * @return the number of elements.
    1295             :  */
    1296             : 
    1297       12733 : int OGR_G_GetGeometryCount(OGRGeometryH hGeom)
    1298             : 
    1299             : {
    1300       12733 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryCount", 0);
    1301             : 
    1302       12733 :     const auto poGeom = ToPointer(hGeom);
    1303       12733 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1304       12733 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1305             :     {
    1306        3077 :         if (poGeom->toCurvePolygon()->getExteriorRingCurve() == nullptr)
    1307         183 :             return 0;
    1308             :         else
    1309        2894 :             return poGeom->toCurvePolygon()->getNumInteriorRings() + 1;
    1310             :     }
    1311        9656 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1312             :     {
    1313         231 :         return poGeom->toCompoundCurve()->getNumCurves();
    1314             :     }
    1315        9425 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1316             :     {
    1317        3445 :         return poGeom->toGeometryCollection()->getNumGeometries();
    1318             :     }
    1319        5980 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1320             :     {
    1321          86 :         return poGeom->toPolyhedralSurface()->getNumGeometries();
    1322             :     }
    1323             :     else
    1324             :     {
    1325             :         // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
    1326             :         // silent.
    1327             :         // CPLError(CE_Failure, CPLE_NotSupported,
    1328             :         //          "Incompatible geometry for operation");
    1329        5894 :         return 0;
    1330             :     }
    1331             : }
    1332             : 
    1333             : /************************************************************************/
    1334             : /*                        OGR_G_GetGeometryRef()                        */
    1335             : /************************************************************************/
    1336             : 
    1337             : /**
    1338             :  * \brief Fetch geometry from a geometry container.
    1339             :  *
    1340             :  * This function returns a handle to a geometry within the container.
    1341             :  * The returned geometry remains owned by the container, and should not be
    1342             :  * modified.  The handle is only valid until the next change to the
    1343             :  * geometry container.  Use OGR_G_Clone() to make a copy.
    1344             :  *
    1345             :  * This function relates to the SFCOM
    1346             :  * IGeometryCollection::get_Geometry() method.
    1347             :  *
    1348             :  * This function is the same as the CPP method
    1349             :  * OGRGeometryCollection::getGeometryRef().
    1350             :  *
    1351             :  * For a polygon, OGR_G_GetGeometryRef(iSubGeom) returns the exterior ring
    1352             :  * if iSubGeom == 0, and the interior rings for iSubGeom > 0.
    1353             :  *
    1354             :  * @param hGeom handle to the geometry container from which to get a
    1355             :  * geometry from.
    1356             :  * @param iSubGeom the index of the geometry to fetch, between 0 and
    1357             :  *          getNumGeometries() - 1.
    1358             :  * @return handle to the requested geometry.
    1359             :  */
    1360             : 
    1361        3229 : OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)
    1362             : 
    1363             : {
    1364        3229 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryRef", nullptr);
    1365             : 
    1366        3229 :     const auto poGeom = ToPointer(hGeom);
    1367        3229 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1368        3229 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1369             :     {
    1370        1206 :         if (iSubGeom == 0)
    1371        1124 :             return ToHandle(poGeom->toCurvePolygon()->getExteriorRingCurve());
    1372             :         else
    1373          82 :             return ToHandle(
    1374          82 :                 poGeom->toCurvePolygon()->getInteriorRingCurve(iSubGeom - 1));
    1375             :     }
    1376        2023 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1377             :     {
    1378         232 :         return ToHandle(poGeom->toCompoundCurve()->getCurve(iSubGeom));
    1379             :     }
    1380        1791 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1381             :     {
    1382        1659 :         return ToHandle(
    1383        1659 :             poGeom->toGeometryCollection()->getGeometryRef(iSubGeom));
    1384             :     }
    1385         132 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1386             :     {
    1387         131 :         return ToHandle(
    1388         131 :             poGeom->toPolyhedralSurface()->getGeometryRef(iSubGeom));
    1389             :     }
    1390             :     else
    1391             :     {
    1392           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1393             :                  "Incompatible geometry for operation");
    1394           1 :         return nullptr;
    1395             :     }
    1396             : }
    1397             : 
    1398             : /************************************************************************/
    1399             : /*                         OGR_G_AddGeometry()                          */
    1400             : /************************************************************************/
    1401             : 
    1402             : /**
    1403             :  * \brief Add a geometry to a geometry container.
    1404             :  *
    1405             :  * Some subclasses of OGRGeometryCollection restrict the types of geometry
    1406             :  * that can be added, and may return an error.  The passed geometry is cloned
    1407             :  * to make an internal copy.
    1408             :  *
    1409             :  * There is no SFCOM analog to this method.
    1410             :  *
    1411             :  * This function is the same as the CPP method
    1412             :  * OGRGeometryCollection::addGeometry.
    1413             :  *
    1414             :  * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
    1415             :  * the first added subgeometry will be the exterior ring. The next ones will be
    1416             :  * the interior rings.
    1417             :  *
    1418             :  * @param hGeom existing geometry container.
    1419             :  * @param hNewSubGeom geometry to add to the container.
    1420             :  *
    1421             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
    1422             :  * the geometry type is illegal for the type of existing geometry.
    1423             :  */
    1424             : 
    1425         106 : OGRErr OGR_G_AddGeometry(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
    1426             : 
    1427             : {
    1428         106 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION);
    1429         106 :     VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometry",
    1430             :                       OGRERR_UNSUPPORTED_OPERATION);
    1431             : 
    1432         106 :     OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1433             : 
    1434         106 :     auto poGeom = ToPointer(hGeom);
    1435         106 :     auto poNewSubGeom = ToPointer(hNewSubGeom);
    1436         106 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1437         106 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1438             :     {
    1439          57 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1440          57 :             eErr = poGeom->toCurvePolygon()->addRing(poNewSubGeom->toCurve());
    1441             :     }
    1442          49 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1443             :     {
    1444           2 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1445           2 :             eErr = poGeom->toCompoundCurve()->addCurve(poNewSubGeom->toCurve());
    1446             :     }
    1447          47 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1448             :     {
    1449          41 :         eErr = poGeom->toGeometryCollection()->addGeometry(poNewSubGeom);
    1450             :     }
    1451           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1452             :     {
    1453           5 :         eErr = poGeom->toPolyhedralSurface()->addGeometry(poNewSubGeom);
    1454             :     }
    1455             : 
    1456         106 :     return eErr;
    1457             : }
    1458             : 
    1459             : /************************************************************************/
    1460             : /*                     OGR_G_AddGeometryDirectly()                      */
    1461             : /************************************************************************/
    1462             : /**
    1463             :  * \brief Add a geometry directly to an existing geometry container.
    1464             :  *
    1465             :  * Some subclasses of OGRGeometryCollection restrict the types of geometry
    1466             :  * that can be added, and may return an error.  Ownership of the passed
    1467             :  * geometry is taken by the container rather than cloning as addGeometry()
    1468             :  * does.
    1469             :  *
    1470             :  * This function is the same as the CPP method
    1471             :  * OGRGeometryCollection::addGeometryDirectly.
    1472             :  *
    1473             :  * There is no SFCOM analog to this method.
    1474             :  *
    1475             :  * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
    1476             :  * the first added subgeometry will be the exterior ring. The next ones will be
    1477             :  * the interior rings.
    1478             :  *
    1479             :  * @param hGeom existing geometry.
    1480             :  * @param hNewSubGeom geometry to add to the existing geometry.
    1481             :  *
    1482             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
    1483             :  * the geometry type is illegal for the type of geometry container.
    1484             :  */
    1485             : 
    1486         407 : OGRErr OGR_G_AddGeometryDirectly(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
    1487             : 
    1488             : {
    1489         407 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometryDirectly",
    1490             :                       OGRERR_UNSUPPORTED_OPERATION);
    1491         407 :     VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometryDirectly",
    1492             :                       OGRERR_UNSUPPORTED_OPERATION);
    1493             : 
    1494         407 :     OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1495             : 
    1496         407 :     auto poGeom = ToPointer(hGeom);
    1497         407 :     auto poNewSubGeom = ToPointer(hNewSubGeom);
    1498         407 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1499             : 
    1500         407 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1501             :     {
    1502          60 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1503         120 :             eErr = poGeom->toCurvePolygon()->addRingDirectly(
    1504          60 :                 poNewSubGeom->toCurve());
    1505             :     }
    1506         347 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1507             :     {
    1508           3 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1509           3 :             eErr = poGeom->toCompoundCurve()->addCurveDirectly(
    1510             :                 poNewSubGeom->toCurve());
    1511             :     }
    1512         344 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1513             :     {
    1514             :         eErr =
    1515         340 :             poGeom->toGeometryCollection()->addGeometryDirectly(poNewSubGeom);
    1516             :     }
    1517           4 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1518             :     {
    1519           3 :         eErr = poGeom->toPolyhedralSurface()->addGeometryDirectly(poNewSubGeom);
    1520             :     }
    1521             : 
    1522         407 :     if (eErr != OGRERR_NONE)
    1523           3 :         delete poNewSubGeom;
    1524             : 
    1525         407 :     return eErr;
    1526             : }
    1527             : 
    1528             : /************************************************************************/
    1529             : /*                        OGR_G_RemoveGeometry()                        */
    1530             : /************************************************************************/
    1531             : 
    1532             : /**
    1533             :  * \brief Remove a geometry from an exiting geometry container.
    1534             :  *
    1535             :  * Removing a geometry will cause the geometry count to drop by one, and all
    1536             :  * "higher" geometries will shuffle down one in index.
    1537             :  *
    1538             :  * There is no SFCOM analog to this method.
    1539             :  *
    1540             :  * This function is the same as the CPP method
    1541             :  * OGRGeometryCollection::removeGeometry() for geometry collections,
    1542             :  * OGRCurvePolygon::removeRing() for polygons / curve polygons and
    1543             :  * OGRPolyhedralSurface::removeGeometry() for polyhedral surfaces and TINs.
    1544             :  *
    1545             :  * @param hGeom the existing geometry to delete from.
    1546             :  * @param iGeom the index of the geometry to delete.  A value of -1 is a
    1547             :  * special flag meaning that all geometries should be removed.
    1548             :  *
    1549             :  * @param bDelete if TRUE the geometry will be destroyed, otherwise it will
    1550             :  * not.  The default is TRUE as the existing geometry is considered to own the
    1551             :  * geometries in it.
    1552             :  *
    1553             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
    1554             :  * out of range.
    1555             :  */
    1556             : 
    1557          91 : OGRErr OGR_G_RemoveGeometry(OGRGeometryH hGeom, int iGeom, int bDelete)
    1558             : 
    1559             : {
    1560          91 :     VALIDATE_POINTER1(hGeom, "OGR_G_RemoveGeometry", OGRERR_FAILURE);
    1561             : 
    1562          91 :     const auto poGeom = ToPointer(hGeom);
    1563          91 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1564          91 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1565             :     {
    1566          38 :         return poGeom->toCurvePolygon()->removeRing(iGeom,
    1567          38 :                                                     CPL_TO_BOOL(bDelete));
    1568             :     }
    1569          72 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1570             :     {
    1571          66 :         return poGeom->toGeometryCollection()->removeGeometry(iGeom, bDelete);
    1572             :     }
    1573           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1574             :     {
    1575           5 :         return poGeom->toPolyhedralSurface()->removeGeometry(iGeom, bDelete);
    1576             :     }
    1577             :     else
    1578             :     {
    1579           1 :         return OGRERR_UNSUPPORTED_OPERATION;
    1580             :     }
    1581             : }
    1582             : 
    1583             : /************************************************************************/
    1584             : /*                           OGR_G_Length()                             */
    1585             : /************************************************************************/
    1586             : 
    1587             : /**
    1588             :  * \brief Compute length of a geometry.
    1589             :  *
    1590             :  * Computes the length for OGRCurve or MultiCurve objects.
    1591             :  * For surfaces, compute the sum of the lengths of their exterior
    1592             :  * and interior rings (since 3.10).
    1593             :  * Undefined for all other geometry types (returns zero).
    1594             :  *
    1595             :  * This function utilizes the C++ get_Length() method.
    1596             :  *
    1597             :  * @param hGeom the geometry to operate on.
    1598             :  * @return the length or 0.0 for unsupported geometry types.
    1599             :  *
    1600             :  * @since OGR 1.8.0
    1601             :  *
    1602             :  * @see OGR_G_GeodesicLength() for an alternative method returning lengths
    1603             :  * computed on the ellipsoid, and in meters.
    1604             :  */
    1605             : 
    1606          29 : double OGR_G_Length(OGRGeometryH hGeom)
    1607             : 
    1608             : {
    1609          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetLength", 0);
    1610             : 
    1611          29 :     double dfLength = 0.0;
    1612             : 
    1613          29 :     const auto poGeom = ToPointer(hGeom);
    1614          29 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1615          29 :     if (OGR_GT_IsCurve(eType))
    1616             :     {
    1617          21 :         dfLength = poGeom->toCurve()->get_Length();
    1618             :     }
    1619           8 :     else if (OGR_GT_IsSurface(eType))
    1620             :     {
    1621           2 :         dfLength = poGeom->toSurface()->get_Length();
    1622             :     }
    1623           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1624             :     {
    1625           5 :         dfLength = poGeom->toGeometryCollection()->get_Length();
    1626             :     }
    1627             :     else
    1628             :     {
    1629           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1630             :                  "OGR_G_Length() called against a non-curve geometry type.");
    1631           1 :         dfLength = 0.0;
    1632             :     }
    1633             : 
    1634          29 :     return dfLength;
    1635             : }
    1636             : 
    1637             : /************************************************************************/
    1638             : /*                      OGR_G_GeodesicLength()                          */
    1639             : /************************************************************************/
    1640             : 
    1641             : /**
    1642             :  * \brief Get the length of the curve, considered as a geodesic line on the
    1643             :  * underlying ellipsoid of the SRS attached to the geometry.
    1644             :  *
    1645             :  * The returned length will always be in meters.
    1646             :  *
    1647             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
    1648             :  * follow the shortest route on the surface of the ellipsoid.
    1649             :  *
    1650             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
    1651             :  * the underlying geographic SRS of the geometry' SRS.
    1652             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
    1653             :  *
    1654             :  * Note that geometries with circular arcs will be linearized in their original
    1655             :  * coordinate space first, so the resulting geodesic length will be an
    1656             :  * approximation.
    1657             :  *
    1658             :  * This function utilizes the C++ get_GeodesicLength() method.
    1659             :  *
    1660             :  * @param hGeom the geometry to operate on.
    1661             :  * @return the length or a negative value for unsupported geometry types.
    1662             :  *
    1663             :  * @since OGR 3.10
    1664             :  */
    1665             : 
    1666          26 : double OGR_G_GeodesicLength(OGRGeometryH hGeom)
    1667             : 
    1668             : {
    1669          26 :     VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicLength", -1);
    1670             : 
    1671          26 :     double dfLength = 0.0;
    1672             : 
    1673          26 :     const auto poGeom = ToPointer(hGeom);
    1674          26 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1675          26 :     if (OGR_GT_IsCurve(eType))
    1676             :     {
    1677           9 :         dfLength = poGeom->toCurve()->get_GeodesicLength();
    1678             :     }
    1679          17 :     else if (OGR_GT_IsSurface(eType))
    1680             :     {
    1681          13 :         dfLength = poGeom->toSurface()->get_GeodesicLength();
    1682             :     }
    1683           4 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1684             :     {
    1685           3 :         dfLength = poGeom->toGeometryCollection()->get_GeodesicLength();
    1686             :     }
    1687             :     else
    1688             :     {
    1689           1 :         CPLError(
    1690             :             CE_Failure, CPLE_AppDefined,
    1691             :             "OGR_G_GeodesicLength() called against a non-curve geometry type.");
    1692           1 :         dfLength = -1.0;
    1693             :     }
    1694             : 
    1695          26 :     return dfLength;
    1696             : }
    1697             : 
    1698             : /************************************************************************/
    1699             : /*                           OGR_G_Area()                               */
    1700             : /************************************************************************/
    1701             : 
    1702             : /**
    1703             :  * \brief Compute geometry area.
    1704             :  *
    1705             :  * The returned area is a 2D Cartesian (planar) area in square units of the
    1706             :  * spatial reference system in use, so potentially "square degrees" for a
    1707             :  * geometry expressed in a geographic SRS.
    1708             :  *
    1709             :  * Computes the area for surfaces or closed curves.
    1710             :  * Undefined for all other geometry types (returns 0.0).
    1711             :  *
    1712             :  * This function utilizes the C++ OGRSurface::get_Area() method.
    1713             :  *
    1714             :  * @param hGeom the geometry to operate on.
    1715             :  * @return the area of the geometry in square units of the spatial reference
    1716             :  * system in use, or 0.0 for unsupported geometry types.
    1717             : 
    1718             :  * @see OGR_G_GeodesicArea() for an alternative function returning areas
    1719             :  * computed on the ellipsoid, and in square meters.
    1720             :  *
    1721             :  * @since OGR 1.8.0
    1722             :  */
    1723             : 
    1724        1448 : double OGR_G_Area(OGRGeometryH hGeom)
    1725             : 
    1726             : {
    1727        1448 :     VALIDATE_POINTER1(hGeom, "OGR_G_Area", 0);
    1728             : 
    1729        1448 :     double dfArea = 0.0;
    1730             : 
    1731        1448 :     const auto poGeom = ToPointer(hGeom);
    1732        1448 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1733        1448 :     if (OGR_GT_IsSurface(eType))
    1734             :     {
    1735        1439 :         dfArea = poGeom->toSurface()->get_Area();
    1736             :     }
    1737           9 :     else if (OGR_GT_IsCurve(eType))
    1738             :     {
    1739           3 :         dfArea = poGeom->toCurve()->get_Area();
    1740             :     }
    1741           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1742             :     {
    1743           5 :         dfArea = poGeom->toGeometryCollection()->get_Area();
    1744             :     }
    1745             :     else
    1746             :     {
    1747           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1748             :                  "OGR_G_Area() called against non-surface geometry type.");
    1749             : 
    1750           1 :         dfArea = 0.0;
    1751             :     }
    1752             : 
    1753        1448 :     return dfArea;
    1754             : }
    1755             : 
    1756             : /**
    1757             :  * \brief Compute geometry area (deprecated)
    1758             :  *
    1759             :  * @deprecated
    1760             :  * @see OGR_G_Area()
    1761             :  */
    1762           0 : double OGR_G_GetArea(OGRGeometryH hGeom)
    1763             : 
    1764             : {
    1765           0 :     return OGR_G_Area(hGeom);
    1766             : }
    1767             : 
    1768             : /************************************************************************/
    1769             : /*                         OGR_G_GeodesicArea()                         */
    1770             : /************************************************************************/
    1771             : 
    1772             : /**
    1773             :  * \brief Compute geometry area, considered as a surface on the underlying
    1774             :  * ellipsoid of the SRS attached to the geometry.
    1775             :  *
    1776             :  * The returned area will always be in square meters, and assumes that
    1777             :  * polygon edges describe geodesic lines on the ellipsoid.
    1778             :  *
    1779             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
    1780             :  * follow the shortest route on the surface of the ellipsoid.
    1781             :  *
    1782             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
    1783             :  * the underlying geographic SRS of the geometry' SRS.
    1784             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
    1785             :  *
    1786             :  * Computes the area for surfaces or closed curves.
    1787             :  * Undefined for all other geometry types (returns a negative value).
    1788             :  *
    1789             :  * Note that geometries with circular arcs will be linearized in their original
    1790             :  * coordinate space first, so the resulting geodesic area will be an
    1791             :  * approximation.
    1792             :  *
    1793             :  * This function utilizes the C++ OGRSurface::get_GeodesicArea() method.
    1794             :  *
    1795             :  * @param hGeom the geometry to operate on.
    1796             :  * @return the area, or a negative value in case of error (unsupported geometry
    1797             :  * type, no SRS attached, etc.)
    1798             :  *
    1799             :  * @see OGR_G_Area() for an alternative method returning areas computed in
    1800             :  * 2D Cartesian space.
    1801             :  *
    1802             :  * @since OGR 3.9.0
    1803             :  */
    1804             : 
    1805          29 : double OGR_G_GeodesicArea(OGRGeometryH hGeom)
    1806             : 
    1807             : {
    1808          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicArea", -1);
    1809             : 
    1810          29 :     double dfArea = -1;
    1811             : 
    1812          29 :     const auto poGeom = ToPointer(hGeom);
    1813          29 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1814          29 :     if (OGR_GT_IsSurface(eType))
    1815             :     {
    1816          16 :         dfArea = poGeom->toSurface()->get_GeodesicArea();
    1817             :     }
    1818          13 :     else if (OGR_GT_IsCurve(eType))
    1819             :     {
    1820           8 :         dfArea = poGeom->toCurve()->get_GeodesicArea();
    1821             :     }
    1822           5 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1823             :     {
    1824           4 :         dfArea = poGeom->toGeometryCollection()->get_GeodesicArea();
    1825             :     }
    1826             :     else
    1827             :     {
    1828           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1829             :                  "OGR_G_GeodesicArea() called against non-surface geometry "
    1830             :                  "type.");
    1831             :     }
    1832             : 
    1833          29 :     return dfArea;
    1834             : }
    1835             : 
    1836             : /************************************************************************/
    1837             : /*                         OGR_G_IsClockwise()                          */
    1838             : /************************************************************************/
    1839             : /**
    1840             :  * \brief Returns true if the ring has clockwise winding (or less than 2 points)
    1841             :  *
    1842             :  * Assumes that the ring is closed.
    1843             :  *
    1844             :  * @param hGeom handle to a curve geometry
    1845             :  * @since GDAL 3.8
    1846             :  */
    1847             : 
    1848          33 : bool OGR_G_IsClockwise(OGRGeometryH hGeom)
    1849             : 
    1850             : {
    1851          33 :     VALIDATE_POINTER1(hGeom, "OGR_G_IsClockwise", false);
    1852             : 
    1853          33 :     auto poGeom = OGRGeometry::FromHandle(hGeom);
    1854          33 :     const OGRwkbGeometryType eGType = wkbFlatten(poGeom->getGeometryType());
    1855          33 :     if (OGR_GT_IsCurve(eGType))
    1856             :     {
    1857          32 :         return poGeom->toCurve()->isClockwise();
    1858             :     }
    1859             :     else
    1860             :     {
    1861           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1862             :                  "Incompatible geometry for operation");
    1863           1 :         return false;
    1864             :     }
    1865             : }
    1866             : 
    1867             : /************************************************************************/
    1868             : /*                         OGR_G_HasCurveGeometry()                     */
    1869             : /************************************************************************/
    1870             : 
    1871             : /**
    1872             :  * \brief Returns if this geometry is or has curve geometry.
    1873             :  *
    1874             :  * Returns if a geometry is or has CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
    1875             :  * MULTICURVE or MULTISURFACE in it.
    1876             :  *
    1877             :  * If bLookForNonLinear is set to TRUE, it will be actually looked if the
    1878             :  * geometry or its subgeometries are or contain a non-linear geometry in
    1879             :  * them. In which case, if the method returns TRUE, it means that
    1880             :  * OGR_G_GetLinearGeometry() would return an approximate version of the
    1881             :  * geometry. Otherwise, OGR_G_GetLinearGeometry() would do a conversion, but
    1882             :  * with just converting container type, like COMPOUNDCURVE -> LINESTRING,
    1883             :  * MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON, resulting in a
    1884             :  * "loss-less" conversion.
    1885             :  *
    1886             :  * This function is the same as C++ method OGRGeometry::hasCurveGeometry().
    1887             :  *
    1888             :  * @param hGeom the geometry to operate on.
    1889             :  * @param bLookForNonLinear set it to TRUE to check if the geometry is or
    1890             :  * contains a CIRCULARSTRING.
    1891             :  * @return TRUE if this geometry is or has curve geometry.
    1892             :  *
    1893             :  * @since GDAL 2.0
    1894             :  */
    1895             : 
    1896          29 : int OGR_G_HasCurveGeometry(OGRGeometryH hGeom, int bLookForNonLinear)
    1897             : {
    1898          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_HasCurveGeometry", FALSE);
    1899          29 :     return ToPointer(hGeom)->hasCurveGeometry(bLookForNonLinear);
    1900             : }
    1901             : 
    1902             : /************************************************************************/
    1903             : /*                         OGR_G_GetLinearGeometry()                   */
    1904             : /************************************************************************/
    1905             : 
    1906             : /**
    1907             :  * \brief Return, possibly approximate, linear version of this geometry.
    1908             :  *
    1909             :  * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
    1910             :  * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
    1911             :  *
    1912             :  * The ownership of the returned geometry belongs to the caller.
    1913             :  *
    1914             :  * The reverse function is OGR_G_GetCurveGeometry().
    1915             :  *
    1916             :  * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() and
    1917             :  * CurvePolygon::CurvePolyToPoly() methods.
    1918             :  *
    1919             :  * This function is the same as C++ method OGRGeometry::getLinearGeometry().
    1920             :  *
    1921             :  * @param hGeom the geometry to operate on.
    1922             :  * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
    1923             :  * arc, zero to use the default setting.
    1924             :  * @param papszOptions options as a null-terminated list of strings or NULL.
    1925             :  * See OGRGeometryFactory::curveToLineString() for valid options.
    1926             :  *
    1927             :  * @return a new geometry.
    1928             :  *
    1929             :  * @since GDAL 2.0
    1930             :  */
    1931             : 
    1932        3083 : OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry(OGRGeometryH hGeom,
    1933             :                                              double dfMaxAngleStepSizeDegrees,
    1934             :                                              char **papszOptions)
    1935             : {
    1936        3083 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetLinearGeometry", nullptr);
    1937        6166 :     return ToHandle(ToPointer(hGeom)->getLinearGeometry(
    1938        6166 :         dfMaxAngleStepSizeDegrees, papszOptions));
    1939             : }
    1940             : 
    1941             : /************************************************************************/
    1942             : /*                         OGR_G_GetCurveGeometry()                     */
    1943             : /************************************************************************/
    1944             : 
    1945             : /**
    1946             :  * \brief Return curve version of this geometry.
    1947             :  *
    1948             :  * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE,
    1949             :  * CURVEPOLYGON, MULTICURVE or MULTISURFACE in it, by de-approximating linear
    1950             :  * into curve geometries.
    1951             :  *
    1952             :  * If the geometry has no curve portion, the returned geometry will be a clone
    1953             :  * of it.
    1954             :  *
    1955             :  * The ownership of the returned geometry belongs to the caller.
    1956             :  *
    1957             :  * The reverse function is OGR_G_GetLinearGeometry().
    1958             :  *
    1959             :  * This function is the same as C++ method OGRGeometry::getCurveGeometry().
    1960             :  *
    1961             :  * @param hGeom the geometry to operate on.
    1962             :  * @param papszOptions options as a null-terminated list of strings.
    1963             :  *                     Unused for now. Must be set to NULL.
    1964             :  *
    1965             :  * @return a new geometry.
    1966             :  *
    1967             :  * @since GDAL 2.0
    1968             :  */
    1969             : 
    1970        3064 : OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry(OGRGeometryH hGeom,
    1971             :                                             char **papszOptions)
    1972             : {
    1973        3064 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetCurveGeometry", nullptr);
    1974             : 
    1975        3064 :     return ToHandle(ToPointer(hGeom)->getCurveGeometry(papszOptions));
    1976             : }
    1977             : 
    1978             : /************************************************************************/
    1979             : /*                          OGR_G_Value()                               */
    1980             : /************************************************************************/
    1981             : /**
    1982             :  * \brief Fetch point at given distance along curve.
    1983             :  *
    1984             :  * This function relates to the SF COM ICurve::get_Value() method.
    1985             :  *
    1986             :  * This function is the same as the C++ method OGRCurve::Value().
    1987             :  *
    1988             :  * @param hGeom curve geometry.
    1989             :  * @param dfDistance distance along the curve at which to sample position.
    1990             :  *                   This distance should be between zero and get_Length()
    1991             :  *                   for this curve.
    1992             :  * @return a point or NULL.
    1993             :  *
    1994             :  * @since GDAL 2.0
    1995             :  */
    1996             : 
    1997          22 : OGRGeometryH OGR_G_Value(OGRGeometryH hGeom, double dfDistance)
    1998             : {
    1999          22 :     VALIDATE_POINTER1(hGeom, "OGR_G_Value", nullptr);
    2000             : 
    2001          22 :     const auto poGeom = ToPointer(hGeom);
    2002          22 :     if (OGR_GT_IsCurve(poGeom->getGeometryType()))
    2003             :     {
    2004          22 :         OGRPoint *p = new OGRPoint();
    2005          22 :         poGeom->toCurve()->Value(dfDistance, p);
    2006          22 :         return ToHandle(p);
    2007             :     }
    2008             : 
    2009           0 :     return nullptr;
    2010             : }
    2011             : 
    2012             : /************************************************************************/
    2013             : /*                 OGRSetNonLinearGeometriesEnabledFlag()               */
    2014             : /************************************************************************/
    2015             : 
    2016             : /**
    2017             :  * \brief Set flag to enable/disable returning non-linear geometries in the C
    2018             :  * API.
    2019             :  *
    2020             :  * This flag has only an effect on the OGR_F_GetGeometryRef(),
    2021             :  * OGR_F_GetGeomFieldRef(), OGR_L_GetGeomType(), OGR_GFld_GetType() and
    2022             :  * OGR_FD_GetGeomType() C API, and corresponding methods in the SWIG
    2023             :  * bindings. It is meant as making it simple for applications using the OGR C
    2024             :  * API not to have to deal with non-linear geometries, even if such geometries
    2025             :  * might be returned by drivers. In which case, they will be transformed into
    2026             :  * their closest linear geometry, by doing linear approximation, with
    2027             :  * OGR_G_ForceTo().
    2028             :  *
    2029             :  * Libraries should generally *not* use that method, since that could interfere
    2030             :  * with other libraries or applications.
    2031             :  *
    2032             :  * Note that it *does* not affect the behavior of the C++ API.
    2033             :  *
    2034             :  * @param bFlag TRUE if non-linear geometries might be returned (default value).
    2035             :  *              FALSE to ask for non-linear geometries to be approximated as
    2036             :  *              linear geometries.
    2037             :  *
    2038             :  * @since GDAL 2.0
    2039             :  */
    2040             : 
    2041           2 : void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
    2042             : {
    2043           2 :     bNonLinearGeometriesEnabled = bFlag != FALSE;
    2044           2 : }
    2045             : 
    2046             : /************************************************************************/
    2047             : /*                 OGRGetNonLinearGeometriesEnabledFlag()               */
    2048             : /************************************************************************/
    2049             : 
    2050             : /**
    2051             :  * \brief Get flag to enable/disable returning non-linear geometries in the C
    2052             :  * API.
    2053             :  *
    2054             :  * return TRUE if non-linear geometries might be returned (default value is
    2055             :  * TRUE).
    2056             :  *
    2057             :  * @since GDAL 2.0
    2058             :  * @see OGRSetNonLinearGeometriesEnabledFlag()
    2059             :  */
    2060             : 
    2061       39111 : int OGRGetNonLinearGeometriesEnabledFlag(void)
    2062             : {
    2063       39111 :     return bNonLinearGeometriesEnabled;
    2064             : }

Generated by: LCOV version 1.14