LCOV - code coverage report
Current view: top level - ogr - ogr_api.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 449 640 70.2 %
Date: 2026-02-01 11:59:10 Functions: 47 52 90.4 %

          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        6354 : bool OGRGetGEOSVersion(int *pnMajor, int *pnMinor, int *pnPatch)
      40             : {
      41        6354 :     CPLStringList aosTokens(CSLTokenizeString2(GEOSversion(), ".", 0));
      42             : 
      43        6354 :     if (pnMajor && aosTokens.size() > 0)
      44        5557 :         *pnMajor = std::stoi(aosTokens[0]);
      45        6354 :     if (pnMinor && aosTokens.size() > 1)
      46         405 :         *pnMinor = std::stoi(aosTokens[1]);
      47        6354 :     if (pnPatch && aosTokens.size() > 2)
      48         392 :         *pnPatch = std::stoi(aosTokens[2]);
      49       12708 :     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      818306 : static inline OGRGeometry *ToPointer(OGRGeometryH hGeom)
      69             : {
      70      818306 :     return OGRGeometry::FromHandle(hGeom);
      71             : }
      72             : 
      73             : /************************************************************************/
      74             : /*                              ToHandle()                              */
      75             : /************************************************************************/
      76             : 
      77        9823 : static inline OGRGeometryH ToHandle(OGRGeometry *poGeom)
      78             : {
      79        9823 :     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       14903 : int OGR_G_GetPointCount(OGRGeometryH hGeom)
      97             : 
      98             : {
      99       14903 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetPointCount", 0);
     100             : 
     101             :     const OGRwkbGeometryType eGType =
     102       14903 :         wkbFlatten(ToPointer(hGeom)->getGeometryType());
     103       14903 :     if (eGType == wkbPoint)
     104             :     {
     105        2241 :         return 1;
     106             :     }
     107       12662 :     else if (OGR_GT_IsCurve(eGType))
     108             :     {
     109        7684 :         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        4978 :         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       86833 : static double OGR_G_Get_Component(OGRGeometryH hGeom, int i)
     166             : {
     167       86833 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     168             :     {
     169        4897 :         case wkbPoint:
     170             :         {
     171        4897 :             if (i == 0)
     172             :             {
     173        4894 :                 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       81933 :         case wkbLineString:
     184             :         case wkbCircularString:
     185             :         {
     186       81933 :             OGRSimpleCurve *poSC = ToPointer(hGeom)->toSimpleCurve();
     187       81933 :             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       81930 :             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       34493 : double OGR_G_GetX(OGRGeometryH hGeom, int i)
     215             : 
     216             : {
     217       34493 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetX", 0);
     218             : 
     219             :     struct Getter
     220             :     {
     221        2516 :         static double get(const OGRPoint *poPoint)
     222             :         {
     223        2516 :             return poPoint->getX();
     224             :         }
     225             : 
     226       31974 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     227             :         {
     228       31974 :             return poSC->getX(l_i);
     229             :         }
     230             :     };
     231             : 
     232       34493 :     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       33284 : double OGR_G_GetY(OGRGeometryH hGeom, int i)
     248             : 
     249             : {
     250       33284 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetY", 0);
     251             : 
     252             :     struct Getter
     253             :     {
     254        1307 :         static double get(const OGRPoint *poPoint)
     255             :         {
     256        1307 :             return poPoint->getY();
     257             :         }
     258             : 
     259       31974 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     260             :         {
     261       31974 :             return poSC->getY(l_i);
     262             :         }
     263             :     };
     264             : 
     265       33284 :     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       16760 : double OGR_G_GetZ(OGRGeometryH hGeom, int i)
     281             : 
     282             : {
     283       16760 :     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       15806 :         static double get(const OGRSimpleCurve *poSC, int l_i)
     293             :         {
     294       15806 :             return poSC->getZ(l_i);
     295             :         }
     296             :     };
     297             : 
     298       16760 :     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       49927 : OGRErr OGR_G_SetPoint(OGRGeometryH hGeom, int i, double dfX, double dfY,
     913             :                       double dfZ)
     914             : 
     915             : {
     916       49927 :     VALIDATE_POINTER1(hGeom, "OGR_G_SetPoint", OGRERR_FAILURE);
     917             : 
     918       49927 :     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       49762 :         case wkbLineString:
     939             :         case wkbCircularString:
     940             :         {
     941       49762 :             if (i < 0)
     942             :             {
     943           2 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
     944           2 :                 return OGRERR_FAILURE;
     945             :             }
     946       49760 :             return ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY,
     947       49760 :                                                                dfZ);
     948             :         }
     949             : 
     950           1 :         default:
     951           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     952             :                      "Incompatible geometry for operation");
     953           1 :             return OGRERR_FAILURE;
     954             :     }
     955             : 
     956         163 :     return OGRERR_NONE;
     957             : }
     958             : 
     959             : /************************************************************************/
     960             : /*                         OGR_G_SetPoint_2D()                          */
     961             : /************************************************************************/
     962             : /**
     963             :  * \brief Set the location of a vertex in a point or linestring geometry.
     964             :  *
     965             :  * If iPoint is larger than the number of existing
     966             :  * points in the linestring, the point count will be increased to
     967             :  * accommodate the request.
     968             :  *
     969             :  * @param hGeom handle to the geometry to add a vertex to.
     970             :  * @param i the index of the vertex to assign (zero based) or
     971             :  *  zero for a point.
     972             :  * @param dfX input X coordinate to assign.
     973             :  * @param dfY input Y coordinate to assign.
     974             :  *
     975             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
     976             :  * of error.
     977             :  */
     978             : 
     979      244080 : OGRErr OGR_G_SetPoint_2D(OGRGeometryH hGeom, int i, double dfX, double dfY)
     980             : 
     981             : {
     982      244080 :     VALIDATE_POINTER1(hGeom, "OGR_G_SetPoint_2D", OGRERR_FAILURE);
     983             : 
     984      244080 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
     985             :     {
     986      160005 :         case wkbPoint:
     987             :         {
     988      160005 :             if (i == 0)
     989             :             {
     990      160004 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
     991      160004 :                 poPoint->setX(dfX);
     992      160004 :                 poPoint->setY(dfY);
     993             :             }
     994             :             else
     995             :             {
     996           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
     997             :                          "Only i == 0 is supported");
     998           1 :                 return OGRERR_FAILURE;
     999             :             }
    1000             :         }
    1001      160004 :         break;
    1002             : 
    1003       84074 :         case wkbLineString:
    1004             :         case wkbCircularString:
    1005             :         {
    1006       84074 :             if (i < 0)
    1007             :             {
    1008           2 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
    1009           2 :                 return OGRERR_FAILURE;
    1010             :             }
    1011       84072 :             return ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY);
    1012             :         }
    1013             : 
    1014           1 :         default:
    1015           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1016             :                      "Incompatible geometry for operation");
    1017           1 :             return OGRERR_FAILURE;
    1018             :     }
    1019             : 
    1020      160004 :     return OGRERR_NONE;
    1021             : }
    1022             : 
    1023             : /************************************************************************/
    1024             : /*                          OGR_G_SetPointM()                           */
    1025             : /************************************************************************/
    1026             : /**
    1027             :  * \brief Set the location of a vertex in a point or linestring geometry.
    1028             :  *
    1029             :  * If iPoint is larger than the number of existing
    1030             :  * points in the linestring, the point count will be increased to
    1031             :  * accommodate the request.
    1032             :  *
    1033             :  * The geometry is promoted to include a M component, if it does not already
    1034             :  * have one.
    1035             :  *
    1036             :  * @param hGeom handle to the geometry to add a vertex to.
    1037             :  * @param i the index of the vertex to assign (zero based) or
    1038             :  *  zero for a point.
    1039             :  * @param dfX input X coordinate to assign.
    1040             :  * @param dfY input Y coordinate to assign.
    1041             :  * @param dfM input M coordinate to assign.
    1042             :  *
    1043             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1044             :  * of error.
    1045             :  */
    1046             : 
    1047           4 : OGRErr OGR_G_SetPointM(OGRGeometryH hGeom, int i, double dfX, double dfY,
    1048             :                        double dfM)
    1049             : 
    1050             : {
    1051           4 :     VALIDATE_POINTER1(hGeom, "OGR_G_SetPointM", OGRERR_FAILURE);
    1052             : 
    1053           4 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1054             :     {
    1055           1 :         case wkbPoint:
    1056             :         {
    1057           1 :             if (i == 0)
    1058             :             {
    1059           0 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1060           0 :                 poPoint->setX(dfX);
    1061           0 :                 poPoint->setY(dfY);
    1062           0 :                 poPoint->setM(dfM);
    1063             :             }
    1064             :             else
    1065             :             {
    1066           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1067             :                          "Only i == 0 is supported");
    1068           1 :                 return OGRERR_FAILURE;
    1069             :             }
    1070             :         }
    1071           0 :         break;
    1072             : 
    1073           2 :         case wkbLineString:
    1074             :         case wkbCircularString:
    1075             :         {
    1076           2 :             if (i < 0)
    1077             :             {
    1078           1 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
    1079           1 :                 return OGRERR_FAILURE;
    1080             :             }
    1081           1 :             return ToPointer(hGeom)->toSimpleCurve()->setPointM(i, dfX, dfY,
    1082           1 :                                                                 dfM);
    1083             :         }
    1084             : 
    1085           1 :         default:
    1086           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1087             :                      "Incompatible geometry for operation");
    1088           1 :             return OGRERR_FAILURE;
    1089             :     }
    1090             : 
    1091           0 :     return OGRERR_NONE;
    1092             : }
    1093             : 
    1094             : /************************************************************************/
    1095             : /*                          OGR_G_SetPointZM()                          */
    1096             : /************************************************************************/
    1097             : /**
    1098             :  * \brief Set the location of a vertex in a point or linestring geometry.
    1099             :  *
    1100             :  * If iPoint is larger than the number of existing
    1101             :  * points in the linestring, the point count will be increased to
    1102             :  * accommodate the request.
    1103             :  *
    1104             :  * The geometry is promoted to include a Z and M component, if it does not
    1105             :  * already have them.
    1106             :  *
    1107             :  * @param hGeom handle to the geometry to add a vertex to.
    1108             :  * @param i the index of the vertex to assign (zero based) or
    1109             :  *  zero for a point.
    1110             :  * @param dfX input X coordinate to assign.
    1111             :  * @param dfY input Y coordinate to assign.
    1112             :  * @param dfZ input Z coordinate to assign.
    1113             :  * @param dfM input M coordinate to assign.
    1114             :  *
    1115             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1116             :  * of error.
    1117             :  */
    1118             : 
    1119           4 : OGRErr OGR_G_SetPointZM(OGRGeometryH hGeom, int i, double dfX, double dfY,
    1120             :                         double dfZ, double dfM)
    1121             : 
    1122             : {
    1123           4 :     VALIDATE_POINTER1(hGeom, "OGR_G_SetPointZM", OGRERR_FAILURE);
    1124             : 
    1125           4 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1126             :     {
    1127           1 :         case wkbPoint:
    1128             :         {
    1129           1 :             if (i == 0)
    1130             :             {
    1131           0 :                 OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1132           0 :                 poPoint->setX(dfX);
    1133           0 :                 poPoint->setY(dfY);
    1134           0 :                 poPoint->setZ(dfZ);
    1135           0 :                 poPoint->setM(dfM);
    1136             :             }
    1137             :             else
    1138             :             {
    1139           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1140             :                          "Only i == 0 is supported");
    1141           1 :                 return OGRERR_FAILURE;
    1142             :             }
    1143             :         }
    1144           0 :         break;
    1145             : 
    1146           2 :         case wkbLineString:
    1147             :         case wkbCircularString:
    1148             :         {
    1149           2 :             if (i < 0)
    1150             :             {
    1151           1 :                 CPLError(CE_Failure, CPLE_NotSupported, "Index out of bounds");
    1152           1 :                 return OGRERR_FAILURE;
    1153             :             }
    1154           1 :             if (!ToPointer(hGeom)->toSimpleCurve()->setPoint(i, dfX, dfY, dfZ,
    1155             :                                                              dfM))
    1156           1 :                 return OGRERR_FAILURE;
    1157           0 :             break;
    1158             :         }
    1159             : 
    1160           1 :         default:
    1161           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1162             :                      "Incompatible geometry for operation");
    1163           1 :             return OGRERR_FAILURE;
    1164             :     }
    1165             : 
    1166           0 :     return OGRERR_NONE;
    1167             : }
    1168             : 
    1169             : /************************************************************************/
    1170             : /*                           OGR_G_AddPoint()                           */
    1171             : /************************************************************************/
    1172             : /**
    1173             :  * \brief Add a point to a geometry (line string or point).
    1174             :  *
    1175             :  * The vertex count of the line string is increased by one, and assigned from
    1176             :  * the passed location value.
    1177             :  *
    1178             :  * The geometry is promoted to include a Z component, if it does not already
    1179             :  * have one.
    1180             :  *
    1181             :  * @param hGeom handle to the geometry to add a point to.
    1182             :  * @param dfX x coordinate of point to add.
    1183             :  * @param dfY y coordinate of point to add.
    1184             :  * @param dfZ z coordinate of point to add.
    1185             :  *
    1186             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1187             :  * of error.
    1188             :  */
    1189             : 
    1190         282 : OGRErr OGR_G_AddPoint(OGRGeometryH hGeom, double dfX, double dfY, double dfZ)
    1191             : 
    1192             : {
    1193         282 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint", OGRERR_FAILURE);
    1194             : 
    1195         282 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1196             :     {
    1197          28 :         case wkbPoint:
    1198             :         {
    1199          28 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1200          28 :             poPoint->setX(dfX);
    1201          28 :             poPoint->setY(dfY);
    1202          28 :             poPoint->setZ(dfZ);
    1203             :         }
    1204          28 :         break;
    1205             : 
    1206         253 :         case wkbLineString:
    1207             :         case wkbCircularString:
    1208         253 :             if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ))
    1209           0 :                 return OGRERR_FAILURE;
    1210         253 :             break;
    1211             : 
    1212           1 :         default:
    1213           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1214             :                      "Incompatible geometry for operation");
    1215           1 :             return OGRERR_FAILURE;
    1216             :     }
    1217             : 
    1218         281 :     return OGRERR_NONE;
    1219             : }
    1220             : 
    1221             : /************************************************************************/
    1222             : /*                         OGR_G_AddPoint_2D()                          */
    1223             : /************************************************************************/
    1224             : /**
    1225             :  * \brief Add a point to a geometry (line string or point).
    1226             :  *
    1227             :  * The vertex count of the line string is increased by one, and assigned from
    1228             :  * the passed location value.
    1229             :  *
    1230             :  * If the geometry includes a Z or M component, the value for those components
    1231             :  * for the added point will be 0.
    1232             :  *
    1233             :  * @param hGeom handle to the geometry to add a point to.
    1234             :  * @param dfX x coordinate of point to add.
    1235             :  * @param dfY y coordinate of point to add.
    1236             :  *
    1237             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1238             :  * of error.
    1239             :  */
    1240             : 
    1241        2019 : OGRErr OGR_G_AddPoint_2D(OGRGeometryH hGeom, double dfX, double dfY)
    1242             : 
    1243             : {
    1244        2019 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddPoint_2D", OGRERR_FAILURE);
    1245             : 
    1246        2019 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1247             :     {
    1248         834 :         case wkbPoint:
    1249             :         {
    1250         834 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1251         834 :             poPoint->setX(dfX);
    1252         834 :             poPoint->setY(dfY);
    1253             :         }
    1254         834 :         break;
    1255             : 
    1256        1184 :         case wkbLineString:
    1257             :         case wkbCircularString:
    1258        1184 :             if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY))
    1259           0 :                 return OGRERR_FAILURE;
    1260        1184 :             break;
    1261             : 
    1262           1 :         default:
    1263           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1264             :                      "Incompatible geometry for operation");
    1265           1 :             return OGRERR_FAILURE;
    1266             :     }
    1267             : 
    1268        2018 :     return OGRERR_NONE;
    1269             : }
    1270             : 
    1271             : /************************************************************************/
    1272             : /*                          OGR_G_AddPointM()                           */
    1273             : /************************************************************************/
    1274             : /**
    1275             :  * \brief Add a point to a geometry (line string or point).
    1276             :  *
    1277             :  * The vertex count of the line string is increased by one, and assigned from
    1278             :  * the passed location value.
    1279             :  *
    1280             :  * The geometry is promoted to include a M component, if it does not already
    1281             :  * have one.
    1282             :  *
    1283             :  * @param hGeom handle to the geometry to add a point to.
    1284             :  * @param dfX x coordinate of point to add.
    1285             :  * @param dfY y coordinate of point to add.
    1286             :  * @param dfM m coordinate of point to add.
    1287             :  *
    1288             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1289             :  * of error.
    1290             :  */
    1291             : 
    1292           1 : OGRErr OGR_G_AddPointM(OGRGeometryH hGeom, double dfX, double dfY, double dfM)
    1293             : 
    1294             : {
    1295           1 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddPointM", OGRERR_FAILURE);
    1296             : 
    1297           1 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1298             :     {
    1299           0 :         case wkbPoint:
    1300             :         {
    1301           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1302           0 :             poPoint->setX(dfX);
    1303           0 :             poPoint->setY(dfY);
    1304           0 :             poPoint->setM(dfM);
    1305             :         }
    1306           0 :         break;
    1307             : 
    1308           0 :         case wkbLineString:
    1309             :         case wkbCircularString:
    1310           0 :             if (!ToPointer(hGeom)->toSimpleCurve()->addPointM(dfX, dfY, dfM))
    1311           0 :                 return OGRERR_FAILURE;
    1312           0 :             break;
    1313             : 
    1314           1 :         default:
    1315           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1316             :                      "Incompatible geometry for operation");
    1317           1 :             return OGRERR_FAILURE;
    1318             :     }
    1319             : 
    1320           0 :     return OGRERR_NONE;
    1321             : }
    1322             : 
    1323             : /************************************************************************/
    1324             : /*                          OGR_G_AddPointZM()                          */
    1325             : /************************************************************************/
    1326             : /**
    1327             :  * \brief Add a point to a geometry (line string or point).
    1328             :  *
    1329             :  * The vertex count of the line string is increased by one, and assigned from
    1330             :  * the passed location value.
    1331             :  *
    1332             :  * The geometry is promoted to include a Z and M component, if it does not
    1333             :  * already have them.
    1334             :  *
    1335             :  * @param hGeom handle to the geometry to add a point to.
    1336             :  * @param dfX x coordinate of point to add.
    1337             :  * @param dfY y coordinate of point to add.
    1338             :  * @param dfZ z coordinate of point to add.
    1339             :  * @param dfM m coordinate of point to add.
    1340             :  *
    1341             :  * @return (since 3.13) OGRERR_NONE in case of success, OGRERR_FAILURE in case
    1342             :  * of error.
    1343             :  */
    1344             : 
    1345           0 : OGRErr OGR_G_AddPointZM(OGRGeometryH hGeom, double dfX, double dfY, double dfZ,
    1346             :                         double dfM)
    1347             : 
    1348             : {
    1349           0 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddPointZM", OGRERR_FAILURE);
    1350             : 
    1351           0 :     switch (wkbFlatten(ToPointer(hGeom)->getGeometryType()))
    1352             :     {
    1353           0 :         case wkbPoint:
    1354             :         {
    1355           0 :             OGRPoint *poPoint = ToPointer(hGeom)->toPoint();
    1356           0 :             poPoint->setX(dfX);
    1357           0 :             poPoint->setY(dfY);
    1358           0 :             poPoint->setZ(dfZ);
    1359           0 :             poPoint->setM(dfM);
    1360             :         }
    1361           0 :         break;
    1362             : 
    1363           0 :         case wkbLineString:
    1364             :         case wkbCircularString:
    1365           0 :             if (!ToPointer(hGeom)->toSimpleCurve()->addPoint(dfX, dfY, dfZ,
    1366             :                                                              dfM))
    1367           0 :                 return OGRERR_FAILURE;
    1368           0 :             break;
    1369             : 
    1370           0 :         default:
    1371           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1372             :                      "Incompatible geometry for operation");
    1373           0 :             return OGRERR_FAILURE;
    1374             :     }
    1375             : 
    1376           0 :     return OGRERR_NONE;
    1377             : }
    1378             : 
    1379             : /************************************************************************/
    1380             : /*                       OGR_G_GetGeometryCount()                       */
    1381             : /************************************************************************/
    1382             : /**
    1383             :  * \brief Fetch the number of elements in a geometry or number of geometries in
    1384             :  * container.
    1385             :  *
    1386             :  * Only geometries of type wkbPolygon[25D], wkbMultiPoint[25D],
    1387             :  * wkbMultiLineString[25D], wkbMultiPolygon[25D] or wkbGeometryCollection[25D]
    1388             :  * may return a valid value.  Other geometry types will silently return 0.
    1389             :  *
    1390             :  * For a polygon, the returned number is the number of rings (exterior ring +
    1391             :  * interior rings).
    1392             :  *
    1393             :  * @param hGeom single geometry or geometry container from which to get
    1394             :  * the number of elements.
    1395             :  * @return the number of elements.
    1396             :  */
    1397             : 
    1398       14913 : int OGR_G_GetGeometryCount(OGRGeometryH hGeom)
    1399             : 
    1400             : {
    1401       14913 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryCount", 0);
    1402             : 
    1403       14913 :     const auto poGeom = ToPointer(hGeom);
    1404       14913 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1405       14913 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1406             :     {
    1407        3607 :         if (poGeom->toCurvePolygon()->getExteriorRingCurve() == nullptr)
    1408         255 :             return 0;
    1409             :         else
    1410        3352 :             return poGeom->toCurvePolygon()->getNumInteriorRings() + 1;
    1411             :     }
    1412       11306 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1413             :     {
    1414         237 :         return poGeom->toCompoundCurve()->getNumCurves();
    1415             :     }
    1416       11069 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1417             :     {
    1418        4229 :         return poGeom->toGeometryCollection()->getNumGeometries();
    1419             :     }
    1420        6840 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1421             :     {
    1422          86 :         return poGeom->toPolyhedralSurface()->getNumGeometries();
    1423             :     }
    1424             :     else
    1425             :     {
    1426             :         // autotest/pymod/ogrtest.py calls this method on any geometry. So keep
    1427             :         // silent.
    1428             :         // CPLError(CE_Failure, CPLE_NotSupported,
    1429             :         //          "Incompatible geometry for operation");
    1430        6754 :         return 0;
    1431             :     }
    1432             : }
    1433             : 
    1434             : /************************************************************************/
    1435             : /*                        OGR_G_GetGeometryRef()                        */
    1436             : /************************************************************************/
    1437             : 
    1438             : /**
    1439             :  * \brief Fetch geometry from a geometry container.
    1440             :  *
    1441             :  * This function returns a handle to a geometry within the container.
    1442             :  * The returned geometry remains owned by the container, and should not be
    1443             :  * modified.  The handle is only valid until the next change to the
    1444             :  * geometry container.  Use OGR_G_Clone() to make a copy.
    1445             :  *
    1446             :  * This function relates to the SFCOM
    1447             :  * IGeometryCollection::get_Geometry() method.
    1448             :  *
    1449             :  * This function is the same as the CPP method
    1450             :  * OGRGeometryCollection::getGeometryRef().
    1451             :  *
    1452             :  * For a polygon, OGR_G_GetGeometryRef(iSubGeom) returns the exterior ring
    1453             :  * if iSubGeom == 0, and the interior rings for iSubGeom > 0.
    1454             :  *
    1455             :  * @param hGeom handle to the geometry container from which to get a
    1456             :  * geometry from.
    1457             :  * @param iSubGeom the index of the geometry to fetch, between 0 and
    1458             :  *          getNumGeometries() - 1.
    1459             :  * @return handle to the requested geometry.
    1460             :  */
    1461             : 
    1462        3647 : OGRGeometryH OGR_G_GetGeometryRef(OGRGeometryH hGeom, int iSubGeom)
    1463             : 
    1464             : {
    1465        3647 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetGeometryRef", nullptr);
    1466             : 
    1467        3647 :     const auto poGeom = ToPointer(hGeom);
    1468        3647 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1469        3647 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1470             :     {
    1471        1359 :         if (iSubGeom == 0)
    1472        1264 :             return ToHandle(poGeom->toCurvePolygon()->getExteriorRingCurve());
    1473             :         else
    1474          95 :             return ToHandle(
    1475          95 :                 poGeom->toCurvePolygon()->getInteriorRingCurve(iSubGeom - 1));
    1476             :     }
    1477        2288 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1478             :     {
    1479         232 :         return ToHandle(poGeom->toCompoundCurve()->getCurve(iSubGeom));
    1480             :     }
    1481        2056 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1482             :     {
    1483        1924 :         return ToHandle(
    1484        1924 :             poGeom->toGeometryCollection()->getGeometryRef(iSubGeom));
    1485             :     }
    1486         132 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1487             :     {
    1488         131 :         return ToHandle(
    1489         131 :             poGeom->toPolyhedralSurface()->getGeometryRef(iSubGeom));
    1490             :     }
    1491             :     else
    1492             :     {
    1493           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1494             :                  "Incompatible geometry for operation");
    1495           1 :         return nullptr;
    1496             :     }
    1497             : }
    1498             : 
    1499             : /************************************************************************/
    1500             : /*                         OGR_G_AddGeometry()                          */
    1501             : /************************************************************************/
    1502             : 
    1503             : /**
    1504             :  * \brief Add a geometry to a geometry container.
    1505             :  *
    1506             :  * Some subclasses of OGRGeometryCollection restrict the types of geometry
    1507             :  * that can be added, and may return an error.  The passed geometry is cloned
    1508             :  * to make an internal copy.
    1509             :  *
    1510             :  * There is no SFCOM analog to this method.
    1511             :  *
    1512             :  * This function is the same as the CPP method
    1513             :  * OGRGeometryCollection::addGeometry.
    1514             :  *
    1515             :  * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
    1516             :  * the first added subgeometry will be the exterior ring. The next ones will be
    1517             :  * the interior rings.
    1518             :  *
    1519             :  * @param hGeom existing geometry container.
    1520             :  * @param hNewSubGeom geometry to add to the container.
    1521             :  *
    1522             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
    1523             :  * the geometry type is illegal for the type of existing geometry.
    1524             :  */
    1525             : 
    1526         106 : OGRErr OGR_G_AddGeometry(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
    1527             : 
    1528             : {
    1529         106 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION);
    1530         106 :     VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometry",
    1531             :                       OGRERR_UNSUPPORTED_OPERATION);
    1532             : 
    1533         106 :     OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1534             : 
    1535         106 :     auto poGeom = ToPointer(hGeom);
    1536         106 :     auto poNewSubGeom = ToPointer(hNewSubGeom);
    1537         106 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1538         106 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1539             :     {
    1540          57 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1541          57 :             eErr = poGeom->toCurvePolygon()->addRing(poNewSubGeom->toCurve());
    1542             :     }
    1543          49 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1544             :     {
    1545           2 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1546           2 :             eErr = poGeom->toCompoundCurve()->addCurve(poNewSubGeom->toCurve());
    1547             :     }
    1548          47 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1549             :     {
    1550          41 :         eErr = poGeom->toGeometryCollection()->addGeometry(poNewSubGeom);
    1551             :     }
    1552           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1553             :     {
    1554           5 :         eErr = poGeom->toPolyhedralSurface()->addGeometry(poNewSubGeom);
    1555             :     }
    1556             : 
    1557         106 :     return eErr;
    1558             : }
    1559             : 
    1560             : /************************************************************************/
    1561             : /*                     OGR_G_AddGeometryDirectly()                      */
    1562             : /************************************************************************/
    1563             : /**
    1564             :  * \brief Add a geometry directly to an existing geometry container.
    1565             :  *
    1566             :  * Some subclasses of OGRGeometryCollection restrict the types of geometry
    1567             :  * that can be added, and may return an error.  Ownership of the passed
    1568             :  * geometry is taken by the container rather than cloning as addGeometry()
    1569             :  * does.
    1570             :  *
    1571             :  * This function is the same as the CPP method
    1572             :  * OGRGeometryCollection::addGeometryDirectly.
    1573             :  *
    1574             :  * There is no SFCOM analog to this method.
    1575             :  *
    1576             :  * For a polygon, hNewSubGeom must be a linearring. If the polygon is empty,
    1577             :  * the first added subgeometry will be the exterior ring. The next ones will be
    1578             :  * the interior rings.
    1579             :  *
    1580             :  * @param hGeom existing geometry.
    1581             :  * @param hNewSubGeom geometry to add to the existing geometry.
    1582             :  *
    1583             :  * @return OGRERR_NONE if successful, or OGRERR_UNSUPPORTED_GEOMETRY_TYPE if
    1584             :  * the geometry type is illegal for the type of geometry container.
    1585             :  */
    1586             : 
    1587         357 : OGRErr OGR_G_AddGeometryDirectly(OGRGeometryH hGeom, OGRGeometryH hNewSubGeom)
    1588             : 
    1589             : {
    1590         357 :     VALIDATE_POINTER1(hGeom, "OGR_G_AddGeometryDirectly",
    1591             :                       OGRERR_UNSUPPORTED_OPERATION);
    1592         357 :     VALIDATE_POINTER1(hNewSubGeom, "OGR_G_AddGeometryDirectly",
    1593             :                       OGRERR_UNSUPPORTED_OPERATION);
    1594             : 
    1595         357 :     OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1596             : 
    1597         357 :     auto poGeom = ToPointer(hGeom);
    1598         357 :     auto poNewSubGeom = ToPointer(hNewSubGeom);
    1599         357 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1600             : 
    1601         357 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1602             :     {
    1603           2 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1604           4 :             eErr = poGeom->toCurvePolygon()->addRingDirectly(
    1605           2 :                 poNewSubGeom->toCurve());
    1606             :     }
    1607         355 :     else if (OGR_GT_IsSubClassOf(eType, wkbCompoundCurve))
    1608             :     {
    1609           3 :         if (OGR_GT_IsCurve(wkbFlatten(poNewSubGeom->getGeometryType())))
    1610           3 :             eErr = poGeom->toCompoundCurve()->addCurveDirectly(
    1611             :                 poNewSubGeom->toCurve());
    1612             :     }
    1613         352 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1614             :     {
    1615             :         eErr =
    1616         348 :             poGeom->toGeometryCollection()->addGeometryDirectly(poNewSubGeom);
    1617             :     }
    1618           4 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1619             :     {
    1620           3 :         eErr = poGeom->toPolyhedralSurface()->addGeometryDirectly(poNewSubGeom);
    1621             :     }
    1622             : 
    1623         357 :     if (eErr != OGRERR_NONE)
    1624           3 :         delete poNewSubGeom;
    1625             : 
    1626         357 :     return eErr;
    1627             : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                        OGR_G_RemoveGeometry()                        */
    1631             : /************************************************************************/
    1632             : 
    1633             : /**
    1634             :  * \brief Remove a geometry from an exiting geometry container.
    1635             :  *
    1636             :  * Removing a geometry will cause the geometry count to drop by one, and all
    1637             :  * "higher" geometries will shuffle down one in index.
    1638             :  *
    1639             :  * There is no SFCOM analog to this method.
    1640             :  *
    1641             :  * This function is the same as the CPP method
    1642             :  * OGRGeometryCollection::removeGeometry() for geometry collections,
    1643             :  * OGRCurvePolygon::removeRing() for polygons / curve polygons and
    1644             :  * OGRPolyhedralSurface::removeGeometry() for polyhedral surfaces and TINs.
    1645             :  *
    1646             :  * @param hGeom the existing geometry to delete from.
    1647             :  * @param iGeom the index of the geometry to delete.  A value of -1 is a
    1648             :  * special flag meaning that all geometries should be removed.
    1649             :  *
    1650             :  * @param bDelete if TRUE the geometry will be destroyed, otherwise it will
    1651             :  * not.  The default is TRUE as the existing geometry is considered to own the
    1652             :  * geometries in it.
    1653             :  *
    1654             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is
    1655             :  * out of range.
    1656             :  */
    1657             : 
    1658         115 : OGRErr OGR_G_RemoveGeometry(OGRGeometryH hGeom, int iGeom, int bDelete)
    1659             : 
    1660             : {
    1661         115 :     VALIDATE_POINTER1(hGeom, "OGR_G_RemoveGeometry", OGRERR_FAILURE);
    1662             : 
    1663         115 :     const auto poGeom = ToPointer(hGeom);
    1664         115 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1665         115 :     if (OGR_GT_IsSubClassOf(eType, wkbCurvePolygon))
    1666             :     {
    1667          38 :         return poGeom->toCurvePolygon()->removeRing(iGeom,
    1668          38 :                                                     CPL_TO_BOOL(bDelete));
    1669             :     }
    1670          96 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1671             :     {
    1672          90 :         return poGeom->toGeometryCollection()->removeGeometry(iGeom, bDelete);
    1673             :     }
    1674           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbPolyhedralSurface))
    1675             :     {
    1676           5 :         return poGeom->toPolyhedralSurface()->removeGeometry(iGeom, bDelete);
    1677             :     }
    1678             :     else
    1679             :     {
    1680           1 :         return OGRERR_UNSUPPORTED_OPERATION;
    1681             :     }
    1682             : }
    1683             : 
    1684             : /************************************************************************/
    1685             : /*                            OGR_G_Length()                            */
    1686             : /************************************************************************/
    1687             : 
    1688             : /**
    1689             :  * \brief Compute length of a geometry.
    1690             :  *
    1691             :  * Computes the length for OGRCurve or MultiCurve objects.
    1692             :  * For surfaces, compute the sum of the lengths of their exterior
    1693             :  * and interior rings (since 3.10).
    1694             :  * Undefined for all other geometry types (returns zero).
    1695             :  *
    1696             :  * This function utilizes the C++ get_Length() method.
    1697             :  *
    1698             :  * @param hGeom the geometry to operate on.
    1699             :  * @return the length or 0.0 for unsupported geometry types.
    1700             :  *
    1701             :  *
    1702             :  * @see OGR_G_GeodesicLength() for an alternative method returning lengths
    1703             :  * computed on the ellipsoid, and in meters.
    1704             :  */
    1705             : 
    1706          29 : double OGR_G_Length(OGRGeometryH hGeom)
    1707             : 
    1708             : {
    1709          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetLength", 0);
    1710             : 
    1711          29 :     double dfLength = 0.0;
    1712             : 
    1713          29 :     const auto poGeom = ToPointer(hGeom);
    1714          29 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1715          29 :     if (OGR_GT_IsCurve(eType))
    1716             :     {
    1717          21 :         dfLength = poGeom->toCurve()->get_Length();
    1718             :     }
    1719           8 :     else if (OGR_GT_IsSurface(eType))
    1720             :     {
    1721           2 :         dfLength = poGeom->toSurface()->get_Length();
    1722             :     }
    1723           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1724             :     {
    1725           5 :         dfLength = poGeom->toGeometryCollection()->get_Length();
    1726             :     }
    1727             :     else
    1728             :     {
    1729           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1730             :                  "OGR_G_Length() called against a non-curve geometry type.");
    1731           1 :         dfLength = 0.0;
    1732             :     }
    1733             : 
    1734          29 :     return dfLength;
    1735             : }
    1736             : 
    1737             : /************************************************************************/
    1738             : /*                        OGR_G_GeodesicLength()                        */
    1739             : /************************************************************************/
    1740             : 
    1741             : /**
    1742             :  * \brief Get the length of the curve, considered as a geodesic line on the
    1743             :  * underlying ellipsoid of the SRS attached to the geometry.
    1744             :  *
    1745             :  * The returned length will always be in meters.
    1746             :  *
    1747             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
    1748             :  * follow the shortest route on the surface of the ellipsoid.
    1749             :  *
    1750             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
    1751             :  * the underlying geographic SRS of the geometry' SRS.
    1752             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
    1753             :  *
    1754             :  * Note that geometries with circular arcs will be linearized in their original
    1755             :  * coordinate space first, so the resulting geodesic length will be an
    1756             :  * approximation.
    1757             :  *
    1758             :  * This function utilizes the C++ get_GeodesicLength() method.
    1759             :  *
    1760             :  * @param hGeom the geometry to operate on.
    1761             :  * @return the length or a negative value for unsupported geometry types.
    1762             :  *
    1763             :  * @since OGR 3.10
    1764             :  */
    1765             : 
    1766          29 : double OGR_G_GeodesicLength(OGRGeometryH hGeom)
    1767             : 
    1768             : {
    1769          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicLength", -1);
    1770             : 
    1771          29 :     double dfLength = 0.0;
    1772             : 
    1773          29 :     const auto poGeom = ToPointer(hGeom);
    1774          29 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1775          29 :     if (OGR_GT_IsCurve(eType))
    1776             :     {
    1777          12 :         dfLength = poGeom->toCurve()->get_GeodesicLength();
    1778             :     }
    1779          17 :     else if (OGR_GT_IsSurface(eType))
    1780             :     {
    1781          13 :         dfLength = poGeom->toSurface()->get_GeodesicLength();
    1782             :     }
    1783           4 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1784             :     {
    1785           3 :         dfLength = poGeom->toGeometryCollection()->get_GeodesicLength();
    1786             :     }
    1787             :     else
    1788             :     {
    1789           1 :         CPLError(
    1790             :             CE_Failure, CPLE_AppDefined,
    1791             :             "OGR_G_GeodesicLength() called against a non-curve geometry type.");
    1792           1 :         dfLength = -1.0;
    1793             :     }
    1794             : 
    1795          29 :     return dfLength;
    1796             : }
    1797             : 
    1798             : /************************************************************************/
    1799             : /*                             OGR_G_Area()                             */
    1800             : /************************************************************************/
    1801             : 
    1802             : /**
    1803             :  * \brief Compute geometry area.
    1804             :  *
    1805             :  * The returned area is a 2D Cartesian (planar) area in square units of the
    1806             :  * spatial reference system in use, so potentially "square degrees" for a
    1807             :  * geometry expressed in a geographic SRS.
    1808             :  *
    1809             :  * Computes the area for surfaces or closed curves.
    1810             :  * Undefined for all other geometry types (returns 0.0).
    1811             :  *
    1812             :  * This function utilizes the C++ OGRSurface::get_Area() method.
    1813             :  *
    1814             :  * @param hGeom the geometry to operate on.
    1815             :  * @return the area of the geometry in square units of the spatial reference
    1816             :  * system in use, or 0.0 for unsupported geometry types.
    1817             : 
    1818             :  * @see OGR_G_GeodesicArea() for an alternative function returning areas
    1819             :  * computed on the ellipsoid, and in square meters.
    1820             :  *
    1821             :  */
    1822             : 
    1823        1475 : double OGR_G_Area(OGRGeometryH hGeom)
    1824             : 
    1825             : {
    1826        1475 :     VALIDATE_POINTER1(hGeom, "OGR_G_Area", 0);
    1827             : 
    1828        1475 :     double dfArea = 0.0;
    1829             : 
    1830        1475 :     const auto poGeom = ToPointer(hGeom);
    1831        1475 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1832        1475 :     if (OGR_GT_IsSurface(eType))
    1833             :     {
    1834        1466 :         dfArea = poGeom->toSurface()->get_Area();
    1835             :     }
    1836           9 :     else if (OGR_GT_IsCurve(eType))
    1837             :     {
    1838           3 :         dfArea = poGeom->toCurve()->get_Area();
    1839             :     }
    1840           6 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1841             :     {
    1842           5 :         dfArea = poGeom->toGeometryCollection()->get_Area();
    1843             :     }
    1844             :     else
    1845             :     {
    1846           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1847             :                  "OGR_G_Area() called against non-surface geometry type.");
    1848             : 
    1849           1 :         dfArea = 0.0;
    1850             :     }
    1851             : 
    1852        1475 :     return dfArea;
    1853             : }
    1854             : 
    1855             : /**
    1856             :  * \brief Compute geometry area (deprecated)
    1857             :  *
    1858             :  * @deprecated
    1859             :  * @see OGR_G_Area()
    1860             :  */
    1861           0 : double OGR_G_GetArea(OGRGeometryH hGeom)
    1862             : 
    1863             : {
    1864           0 :     return OGR_G_Area(hGeom);
    1865             : }
    1866             : 
    1867             : /************************************************************************/
    1868             : /*                         OGR_G_GeodesicArea()                         */
    1869             : /************************************************************************/
    1870             : 
    1871             : /**
    1872             :  * \brief Compute geometry area, considered as a surface on the underlying
    1873             :  * ellipsoid of the SRS attached to the geometry.
    1874             :  *
    1875             :  * The returned area will always be in square meters, and assumes that
    1876             :  * polygon edges describe geodesic lines on the ellipsoid.
    1877             :  *
    1878             :  * <a href="https://geographiclib.sourceforge.io/html/python/geodesics.html">Geodesics</a>
    1879             :  * follow the shortest route on the surface of the ellipsoid.
    1880             :  *
    1881             :  * If the geometry' SRS is not a geographic one, geometries are reprojected to
    1882             :  * the underlying geographic SRS of the geometry' SRS.
    1883             :  * OGRSpatialReference::GetDataAxisToSRSAxisMapping() is honored.
    1884             :  *
    1885             :  * Computes the area for surfaces or closed curves.
    1886             :  * Undefined for all other geometry types (returns a negative value).
    1887             :  *
    1888             :  * Note that geometries with circular arcs will be linearized in their original
    1889             :  * coordinate space first, so the resulting geodesic area will be an
    1890             :  * approximation.
    1891             :  *
    1892             :  * This function utilizes the C++ OGRSurface::get_GeodesicArea() method.
    1893             :  *
    1894             :  * @param hGeom the geometry to operate on.
    1895             :  * @return the area, or a negative value in case of error (unsupported geometry
    1896             :  * type, no SRS attached, etc.)
    1897             :  *
    1898             :  * @see OGR_G_Area() for an alternative method returning areas computed in
    1899             :  * 2D Cartesian space.
    1900             :  *
    1901             :  * @since OGR 3.9.0
    1902             :  */
    1903             : 
    1904          33 : double OGR_G_GeodesicArea(OGRGeometryH hGeom)
    1905             : 
    1906             : {
    1907          33 :     VALIDATE_POINTER1(hGeom, "OGR_G_GeodesicArea", -1);
    1908             : 
    1909          33 :     double dfArea = -1;
    1910             : 
    1911          33 :     const auto poGeom = ToPointer(hGeom);
    1912          33 :     const OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1913          33 :     if (OGR_GT_IsSurface(eType))
    1914             :     {
    1915          20 :         dfArea = poGeom->toSurface()->get_GeodesicArea();
    1916             :     }
    1917          13 :     else if (OGR_GT_IsCurve(eType))
    1918             :     {
    1919           8 :         dfArea = poGeom->toCurve()->get_GeodesicArea();
    1920             :     }
    1921           5 :     else if (OGR_GT_IsSubClassOf(eType, wkbGeometryCollection))
    1922             :     {
    1923           4 :         dfArea = poGeom->toGeometryCollection()->get_GeodesicArea();
    1924             :     }
    1925             :     else
    1926             :     {
    1927           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    1928             :                  "OGR_G_GeodesicArea() called against non-surface geometry "
    1929             :                  "type.");
    1930             :     }
    1931             : 
    1932          33 :     return dfArea;
    1933             : }
    1934             : 
    1935             : /************************************************************************/
    1936             : /*                         OGR_G_IsClockwise()                          */
    1937             : /************************************************************************/
    1938             : /**
    1939             :  * \brief Returns true if the ring has clockwise winding (or less than 2 points)
    1940             :  *
    1941             :  * Assumes that the ring is closed.
    1942             :  *
    1943             :  * @param hGeom handle to a curve geometry
    1944             :  * @since GDAL 3.8
    1945             :  */
    1946             : 
    1947          33 : bool OGR_G_IsClockwise(OGRGeometryH hGeom)
    1948             : 
    1949             : {
    1950          33 :     VALIDATE_POINTER1(hGeom, "OGR_G_IsClockwise", false);
    1951             : 
    1952          33 :     auto poGeom = OGRGeometry::FromHandle(hGeom);
    1953          33 :     const OGRwkbGeometryType eGType = wkbFlatten(poGeom->getGeometryType());
    1954          33 :     if (OGR_GT_IsCurve(eGType))
    1955             :     {
    1956          32 :         return poGeom->toCurve()->isClockwise();
    1957             :     }
    1958             :     else
    1959             :     {
    1960           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    1961             :                  "Incompatible geometry for operation");
    1962           1 :         return false;
    1963             :     }
    1964             : }
    1965             : 
    1966             : /************************************************************************/
    1967             : /*                       OGR_G_HasCurveGeometry()                       */
    1968             : /************************************************************************/
    1969             : 
    1970             : /**
    1971             :  * \brief Returns if this geometry is or has curve geometry.
    1972             :  *
    1973             :  * Returns if a geometry is or has CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
    1974             :  * MULTICURVE or MULTISURFACE in it.
    1975             :  *
    1976             :  * If bLookForNonLinear is set to TRUE, it will be actually looked if the
    1977             :  * geometry or its subgeometries are or contain a non-linear geometry in
    1978             :  * them. In which case, if the method returns TRUE, it means that
    1979             :  * OGR_G_GetLinearGeometry() would return an approximate version of the
    1980             :  * geometry. Otherwise, OGR_G_GetLinearGeometry() would do a conversion, but
    1981             :  * with just converting container type, like COMPOUNDCURVE -> LINESTRING,
    1982             :  * MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON, resulting in a
    1983             :  * "loss-less" conversion.
    1984             :  *
    1985             :  * This function is the same as C++ method OGRGeometry::hasCurveGeometry().
    1986             :  *
    1987             :  * @param hGeom the geometry to operate on.
    1988             :  * @param bLookForNonLinear set it to TRUE to check if the geometry is or
    1989             :  * contains a CIRCULARSTRING.
    1990             :  * @return TRUE if this geometry is or has curve geometry.
    1991             :  *
    1992             :  */
    1993             : 
    1994          29 : int OGR_G_HasCurveGeometry(OGRGeometryH hGeom, int bLookForNonLinear)
    1995             : {
    1996          29 :     VALIDATE_POINTER1(hGeom, "OGR_G_HasCurveGeometry", FALSE);
    1997          29 :     return ToPointer(hGeom)->hasCurveGeometry(bLookForNonLinear);
    1998             : }
    1999             : 
    2000             : /************************************************************************/
    2001             : /*                      OGR_G_GetLinearGeometry()                       */
    2002             : /************************************************************************/
    2003             : 
    2004             : /**
    2005             :  * \brief Return, possibly approximate, linear version of this geometry.
    2006             :  *
    2007             :  * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
    2008             :  * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
    2009             :  *
    2010             :  * The ownership of the returned geometry belongs to the caller.
    2011             :  *
    2012             :  * The reverse function is OGR_G_GetCurveGeometry().
    2013             :  *
    2014             :  * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() and
    2015             :  * CurvePolygon::CurvePolyToPoly() methods.
    2016             :  *
    2017             :  * This function is the same as C++ method OGRGeometry::getLinearGeometry().
    2018             :  *
    2019             :  * @param hGeom the geometry to operate on.
    2020             :  * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
    2021             :  * arc, zero to use the default setting.
    2022             :  * @param papszOptions options as a null-terminated list of strings or NULL.
    2023             :  * See OGRGeometryFactory::curveToLineString() for valid options.
    2024             :  *
    2025             :  * @return a new geometry.
    2026             :  *
    2027             :  */
    2028             : 
    2029        3088 : OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry(OGRGeometryH hGeom,
    2030             :                                              double dfMaxAngleStepSizeDegrees,
    2031             :                                              CSLConstList papszOptions)
    2032             : {
    2033        3088 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetLinearGeometry", nullptr);
    2034        6176 :     return ToHandle(ToPointer(hGeom)->getLinearGeometry(
    2035        6176 :         dfMaxAngleStepSizeDegrees, papszOptions));
    2036             : }
    2037             : 
    2038             : /************************************************************************/
    2039             : /*                       OGR_G_GetCurveGeometry()                       */
    2040             : /************************************************************************/
    2041             : 
    2042             : /**
    2043             :  * \brief Return curve version of this geometry.
    2044             :  *
    2045             :  * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE,
    2046             :  * CURVEPOLYGON, MULTICURVE or MULTISURFACE in it, by de-approximating linear
    2047             :  * into curve geometries.
    2048             :  *
    2049             :  * If the geometry has no curve portion, the returned geometry will be a clone
    2050             :  * of it.
    2051             :  *
    2052             :  * The ownership of the returned geometry belongs to the caller.
    2053             :  *
    2054             :  * The reverse function is OGR_G_GetLinearGeometry().
    2055             :  *
    2056             :  * This function is the same as C++ method OGRGeometry::getCurveGeometry().
    2057             :  *
    2058             :  * @param hGeom the geometry to operate on.
    2059             :  * @param papszOptions options as a null-terminated list of strings.
    2060             :  *                     Unused for now. Must be set to NULL.
    2061             :  *
    2062             :  * @return a new geometry.
    2063             :  *
    2064             :  */
    2065             : 
    2066        3067 : OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry(OGRGeometryH hGeom,
    2067             :                                             CSLConstList papszOptions)
    2068             : {
    2069        3067 :     VALIDATE_POINTER1(hGeom, "OGR_G_GetCurveGeometry", nullptr);
    2070             : 
    2071        3067 :     return ToHandle(ToPointer(hGeom)->getCurveGeometry(papszOptions));
    2072             : }
    2073             : 
    2074             : /************************************************************************/
    2075             : /*                            OGR_G_Value()                             */
    2076             : /************************************************************************/
    2077             : /**
    2078             :  * \brief Fetch point at given distance along curve.
    2079             :  *
    2080             :  * This function relates to the SF COM ICurve::get_Value() method.
    2081             :  *
    2082             :  * This function is the same as the C++ method OGRCurve::Value().
    2083             :  *
    2084             :  * @param hGeom curve geometry.
    2085             :  * @param dfDistance distance along the curve at which to sample position.
    2086             :  *                   This distance should be between zero and get_Length()
    2087             :  *                   for this curve.
    2088             :  * @return a point or NULL.
    2089             :  *
    2090             :  */
    2091             : 
    2092          22 : OGRGeometryH OGR_G_Value(OGRGeometryH hGeom, double dfDistance)
    2093             : {
    2094          22 :     VALIDATE_POINTER1(hGeom, "OGR_G_Value", nullptr);
    2095             : 
    2096          22 :     const auto poGeom = ToPointer(hGeom);
    2097          22 :     if (OGR_GT_IsCurve(poGeom->getGeometryType()))
    2098             :     {
    2099          22 :         OGRPoint *p = new OGRPoint();
    2100          22 :         poGeom->toCurve()->Value(dfDistance, p);
    2101          22 :         return ToHandle(p);
    2102             :     }
    2103             : 
    2104           0 :     return nullptr;
    2105             : }
    2106             : 
    2107             : /************************************************************************/
    2108             : /*                OGRSetNonLinearGeometriesEnabledFlag()                */
    2109             : /************************************************************************/
    2110             : 
    2111             : /**
    2112             :  * \brief Set flag to enable/disable returning non-linear geometries in the C
    2113             :  * API.
    2114             :  *
    2115             :  * This flag has only an effect on the OGR_F_GetGeometryRef(),
    2116             :  * OGR_F_GetGeomFieldRef(), OGR_L_GetGeomType(), OGR_GFld_GetType() and
    2117             :  * OGR_FD_GetGeomType() C API, and corresponding methods in the SWIG
    2118             :  * bindings. It is meant as making it simple for applications using the OGR C
    2119             :  * API not to have to deal with non-linear geometries, even if such geometries
    2120             :  * might be returned by drivers. In which case, they will be transformed into
    2121             :  * their closest linear geometry, by doing linear approximation, with
    2122             :  * OGR_G_ForceTo().
    2123             :  *
    2124             :  * Libraries should generally *not* use that method, since that could interfere
    2125             :  * with other libraries or applications.
    2126             :  *
    2127             :  * Note that it *does* not affect the behavior of the C++ API.
    2128             :  *
    2129             :  * @param bFlag TRUE if non-linear geometries might be returned (default value).
    2130             :  *              FALSE to ask for non-linear geometries to be approximated as
    2131             :  *              linear geometries.
    2132             :  *
    2133             :  */
    2134             : 
    2135           2 : void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
    2136             : {
    2137           2 :     bNonLinearGeometriesEnabled = bFlag != FALSE;
    2138           2 : }
    2139             : 
    2140             : /************************************************************************/
    2141             : /*                OGRGetNonLinearGeometriesEnabledFlag()                */
    2142             : /************************************************************************/
    2143             : 
    2144             : /**
    2145             :  * \brief Get flag to enable/disable returning non-linear geometries in the C
    2146             :  * API.
    2147             :  *
    2148             :  * return TRUE if non-linear geometries might be returned (default value is
    2149             :  * TRUE).
    2150             :  *
    2151             :  * @see OGRSetNonLinearGeometriesEnabledFlag()
    2152             :  */
    2153             : 
    2154       40390 : int OGRGetNonLinearGeometriesEnabledFlag(void)
    2155             : {
    2156       40390 :     return bNonLinearGeometriesEnabled;
    2157             : }

Generated by: LCOV version 1.14