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

Generated by: LCOV version 1.14