LCOV - code coverage report
Current view: top level - ogr - ogr_api.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 461 644 71.6 %
Date: 2026-06-26 10:54:19 Functions: 48 52 92.3 %

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

Generated by: LCOV version 1.14