LCOV - code coverage report
Current view: top level - ogr - ogrcompoundcurve.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 297 307 96.7 %
Date: 2024-11-21 22:18:42 Functions: 59 59 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRCompoundCurve geometry class.
       5             :  * Author:   Even Rouault, even dot rouault at spatialys dot com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_geometry.h"
      15             : 
      16             : #include <cmath>
      17             : #include <cstddef>
      18             : 
      19             : #include "cpl_error.h"
      20             : #include "ogr_core.h"
      21             : #include "ogr_geometry.h"
      22             : #include "ogr_p.h"
      23             : #include "ogr_spatialref.h"
      24             : 
      25             : /************************************************************************/
      26             : /*             OGRCompoundCurve( const OGRCompoundCurve& )              */
      27             : /************************************************************************/
      28             : 
      29             : /**
      30             :  * \brief Copy constructor.
      31             :  *
      32             :  * Note: before GDAL 2.1, only the default implementation of the constructor
      33             :  * existed, which could be unsafe to use.
      34             :  *
      35             :  * @since GDAL 2.1
      36             :  */
      37             : 
      38             : OGRCompoundCurve::OGRCompoundCurve(const OGRCompoundCurve &) = default;
      39             : 
      40             : /************************************************************************/
      41             : /*                 operator=( const OGRCompoundCurve&)                  */
      42             : /************************************************************************/
      43             : 
      44             : /**
      45             :  * \brief Assignment operator.
      46             :  *
      47             :  * Note: before GDAL 2.1, only the default implementation of the operator
      48             :  * existed, which could be unsafe to use.
      49             :  *
      50             :  * @since GDAL 2.1
      51             :  */
      52             : 
      53           5 : OGRCompoundCurve &OGRCompoundCurve::operator=(const OGRCompoundCurve &other)
      54             : {
      55           5 :     if (this != &other)
      56             :     {
      57           4 :         OGRCurve::operator=(other);
      58             : 
      59           4 :         oCC = other.oCC;
      60             :     }
      61           5 :     return *this;
      62             : }
      63             : 
      64             : /************************************************************************/
      65             : /*                               clone()                                */
      66             : /************************************************************************/
      67             : 
      68         260 : OGRCompoundCurve *OGRCompoundCurve::clone() const
      69             : 
      70             : {
      71         260 :     return new (std::nothrow) OGRCompoundCurve(*this);
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /*                          getGeometryType()                           */
      76             : /************************************************************************/
      77             : 
      78        6283 : OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
      79             : 
      80             : {
      81        6283 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
      82        4659 :         return wkbCompoundCurveZM;
      83        1624 :     else if (flags & OGR_G_MEASURED)
      84          11 :         return wkbCompoundCurveM;
      85        1613 :     else if (flags & OGR_G_3D)
      86         166 :         return wkbCompoundCurveZ;
      87             :     else
      88        1447 :         return wkbCompoundCurve;
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                          getGeometryName()                           */
      93             : /************************************************************************/
      94             : 
      95         951 : const char *OGRCompoundCurve::getGeometryName() const
      96             : 
      97             : {
      98         951 :     return "COMPOUNDCURVE";
      99             : }
     100             : 
     101             : /************************************************************************/
     102             : /*                              WkbSize()                               */
     103             : /************************************************************************/
     104         891 : size_t OGRCompoundCurve::WkbSize() const
     105             : {
     106         891 :     return oCC.WkbSize();
     107             : }
     108             : 
     109             : /************************************************************************/
     110             : /*                       addCurveDirectlyFromWkt()                      */
     111             : /************************************************************************/
     112             : 
     113        1725 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb(OGRGeometry *poSelf,
     114             :                                                  OGRCurve *poCurve)
     115             : {
     116        1725 :     OGRCompoundCurve *poCC = poSelf->toCompoundCurve();
     117        1725 :     return poCC->addCurveDirectlyInternal(poCurve, DEFAULT_TOLERANCE_EPSILON,
     118        1725 :                                           FALSE);
     119             : }
     120             : 
     121             : /************************************************************************/
     122             : /*                           importFromWkb()                            */
     123             : /************************************************************************/
     124             : 
     125        1956 : OGRErr OGRCompoundCurve::importFromWkb(const unsigned char *pabyData,
     126             :                                        size_t nSize, OGRwkbVariant eWkbVariant,
     127             :                                        size_t &nBytesConsumedOut)
     128             : {
     129        1956 :     OGRwkbByteOrder eByteOrder = wkbNDR;
     130        1956 :     size_t nDataOffset = 0;
     131             :     // coverity[tainted_data]
     132        1956 :     OGRErr eErr = oCC.importPreambleFromWkb(this, pabyData, nSize, nDataOffset,
     133             :                                             eByteOrder, 9, eWkbVariant);
     134        1956 :     if (eErr != OGRERR_NONE)
     135          56 :         return eErr;
     136             : 
     137        1900 :     eErr = oCC.importBodyFromWkb(this, pabyData + nDataOffset, nSize,
     138             :                                  false,  // bAcceptCompoundCurve
     139             :                                  addCurveDirectlyFromWkb, eWkbVariant,
     140             :                                  nBytesConsumedOut);
     141        1900 :     if (eErr == OGRERR_NONE)
     142        1720 :         nBytesConsumedOut += nDataOffset;
     143        1900 :     return eErr;
     144             : }
     145             : 
     146             : /************************************************************************/
     147             : /*                            exportToWkb()                             */
     148             : /************************************************************************/
     149             : 
     150         880 : OGRErr OGRCompoundCurve::exportToWkb(unsigned char *pabyData,
     151             :                                      const OGRwkbExportOptions *psOptions) const
     152             : {
     153             :     OGRwkbExportOptions sOptions(psOptions ? *psOptions
     154         880 :                                            : OGRwkbExportOptions());
     155             : 
     156             :     // Does not make sense for new geometries, so patch it.
     157         880 :     if (sOptions.eWkbVariant == wkbVariantOldOgc)
     158          14 :         sOptions.eWkbVariant = wkbVariantIso;
     159        1760 :     return oCC.exportToWkb(this, pabyData, &sOptions);
     160             : }
     161             : 
     162             : /************************************************************************/
     163             : /*                       addCurveDirectlyFromWkt()                      */
     164             : /************************************************************************/
     165             : 
     166         472 : OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt(OGRGeometry *poSelf,
     167             :                                                  OGRCurve *poCurve)
     168             : {
     169         472 :     return poSelf->toCompoundCurve()->addCurveDirectly(poCurve);
     170             : }
     171             : 
     172             : /************************************************************************/
     173             : /*                           importFromWkt()                            */
     174             : /************************************************************************/
     175             : 
     176         299 : OGRErr OGRCompoundCurve::importFromWkt(const char **ppszInput)
     177             : {
     178         299 :     return importCurveCollectionFromWkt(ppszInput,
     179             :                                         FALSE,  // bAllowEmptyComponent
     180             :                                         TRUE,   // bAllowLineString
     181             :                                         TRUE,   // bAllowCurve
     182             :                                         FALSE,  // bAllowCompoundCurve
     183         299 :                                         addCurveDirectlyFromWkt);
     184             : }
     185             : 
     186             : /************************************************************************/
     187             : /*                            exportToWkt()                             */
     188             : /************************************************************************/
     189         104 : std::string OGRCompoundCurve::exportToWkt(const OGRWktOptions &opts,
     190             :                                           OGRErr *err) const
     191             : {
     192         104 :     return oCC.exportToWkt(this, opts, err);
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                               empty()                                */
     197             : /************************************************************************/
     198             : 
     199        2259 : void OGRCompoundCurve::empty()
     200             : {
     201        2259 :     oCC.empty(this);
     202        2259 : }
     203             : 
     204             : /************************************************************************/
     205             : /*                            getEnvelope()                             */
     206             : /************************************************************************/
     207             : 
     208          18 : void OGRCompoundCurve::getEnvelope(OGREnvelope *psEnvelope) const
     209             : {
     210          18 :     oCC.getEnvelope(psEnvelope);
     211          18 : }
     212             : 
     213             : /************************************************************************/
     214             : /*                            getEnvelope()                             */
     215             : /************************************************************************/
     216             : 
     217          40 : void OGRCompoundCurve::getEnvelope(OGREnvelope3D *psEnvelope) const
     218             : {
     219          40 :     oCC.getEnvelope(psEnvelope);
     220          40 : }
     221             : 
     222             : /************************************************************************/
     223             : /*                               IsEmpty()                              */
     224             : /************************************************************************/
     225             : 
     226         735 : OGRBoolean OGRCompoundCurve::IsEmpty() const
     227             : {
     228         735 :     return oCC.IsEmpty();
     229             : }
     230             : 
     231             : /************************************************************************/
     232             : /*                             get_Length()                             */
     233             : /*                                                                      */
     234             : /*      For now we return a simple euclidean 2D distance.               */
     235             : /************************************************************************/
     236             : 
     237           5 : double OGRCompoundCurve::get_Length() const
     238             : {
     239           5 :     double dfLength = 0.0;
     240           9 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     241           4 :         dfLength += oCC.papoCurves[iGeom]->get_Length();
     242           5 :     return dfLength;
     243             : }
     244             : 
     245             : /************************************************************************/
     246             : /*                             StartPoint()                             */
     247             : /************************************************************************/
     248             : 
     249         402 : void OGRCompoundCurve::StartPoint(OGRPoint *p) const
     250             : {
     251         402 :     CPLAssert(oCC.nCurveCount > 0);
     252         402 :     oCC.papoCurves[0]->StartPoint(p);
     253         402 : }
     254             : 
     255             : /************************************************************************/
     256             : /*                              EndPoint()                              */
     257             : /************************************************************************/
     258             : 
     259         392 : void OGRCompoundCurve::EndPoint(OGRPoint *p) const
     260             : {
     261         392 :     CPLAssert(oCC.nCurveCount > 0);
     262         392 :     oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(p);
     263         392 : }
     264             : 
     265             : /************************************************************************/
     266             : /*                               Value()                                */
     267             : /************************************************************************/
     268             : 
     269           5 : void OGRCompoundCurve::Value(double dfDistance, OGRPoint *poPoint) const
     270             : {
     271             : 
     272           5 :     if (dfDistance < 0)
     273             :     {
     274           1 :         StartPoint(poPoint);
     275           1 :         return;
     276             :     }
     277             : 
     278           4 :     double dfLength = 0.0;
     279           7 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     280             :     {
     281           6 :         const double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
     282           6 :         if (dfSegLength > 0)
     283             :         {
     284           6 :             if ((dfLength <= dfDistance) &&
     285           6 :                 ((dfLength + dfSegLength) >= dfDistance))
     286             :             {
     287           3 :                 oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
     288             : 
     289           3 :                 return;
     290             :             }
     291             : 
     292           3 :             dfLength += dfSegLength;
     293             :         }
     294             :     }
     295             : 
     296           1 :     EndPoint(poPoint);
     297             : }
     298             : 
     299             : /************************************************************************/
     300             : /*                         CurveToLineInternal()                        */
     301             : /************************************************************************/
     302             : 
     303             : OGRLineString *
     304         681 : OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
     305             :                                       const char *const *papszOptions,
     306             :                                       int bIsLinearRing) const
     307             : {
     308             :     OGRLineString *const poLine =
     309         681 :         bIsLinearRing ? new OGRLinearRing() : new OGRLineString();
     310         681 :     poLine->assignSpatialReference(getSpatialReference());
     311        2096 :     for (int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++)
     312             :     {
     313        2830 :         OGRLineString *poSubLS = oCC.papoCurves[iGeom]->CurveToLine(
     314        1415 :             dfMaxAngleStepSizeDegrees, papszOptions);
     315        1415 :         poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
     316        1415 :         delete poSubLS;
     317             :     }
     318         681 :     return poLine;
     319             : }
     320             : 
     321             : /************************************************************************/
     322             : /*                          CurveToLine()                               */
     323             : /************************************************************************/
     324             : 
     325             : OGRLineString *
     326         667 : OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
     327             :                               const char *const *papszOptions) const
     328             : {
     329         667 :     return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
     330             : }
     331             : 
     332             : /************************************************************************/
     333             : /*                               Equals()                                */
     334             : /************************************************************************/
     335             : 
     336         882 : OGRBoolean OGRCompoundCurve::Equals(const OGRGeometry *poOther) const
     337             : {
     338         882 :     if (poOther == this)
     339           1 :         return TRUE;
     340             : 
     341         881 :     if (poOther->getGeometryType() != getGeometryType())
     342           1 :         return FALSE;
     343             : 
     344         880 :     return oCC.Equals(&(poOther->toCompoundCurve()->oCC));
     345             : }
     346             : 
     347             : /************************************************************************/
     348             : /*                       setCoordinateDimension()                       */
     349             : /************************************************************************/
     350             : 
     351        2265 : bool OGRCompoundCurve::setCoordinateDimension(int nNewDimension)
     352             : {
     353        2265 :     return oCC.setCoordinateDimension(this, nNewDimension);
     354             : }
     355             : 
     356        4097 : bool OGRCompoundCurve::set3D(OGRBoolean bIs3D)
     357             : {
     358        4097 :     return oCC.set3D(this, bIs3D);
     359             : }
     360             : 
     361        6259 : bool OGRCompoundCurve::setMeasured(OGRBoolean bIsMeasured)
     362             : {
     363        6259 :     return oCC.setMeasured(this, bIsMeasured);
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                       assignSpatialReference()                       */
     368             : /************************************************************************/
     369             : 
     370        2455 : void OGRCompoundCurve::assignSpatialReference(const OGRSpatialReference *poSR)
     371             : {
     372        2455 :     oCC.assignSpatialReference(this, poSR);
     373        2455 : }
     374             : 
     375             : /************************************************************************/
     376             : /*                          getNumCurves()                              */
     377             : /************************************************************************/
     378             : 
     379             : /**
     380             :  * \brief Return the number of curves.
     381             :  *
     382             :  * Note that the number of curves making this compound curve.
     383             :  *
     384             :  * Relates to the ISO SQL/MM ST_NumCurves() function.
     385             :  *
     386             :  * @return number of curves.
     387             :  */
     388             : 
     389         989 : int OGRCompoundCurve::getNumCurves() const
     390             : {
     391         989 :     return oCC.nCurveCount;
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /*                           getCurve()                                 */
     396             : /************************************************************************/
     397             : 
     398             : /**
     399             :  * \brief Fetch reference to indicated internal ring.
     400             :  *
     401             :  * Note that the returned curve pointer is to an internal data object of the
     402             :  * OGRCompoundCurve.  It should not be modified or deleted by the application,
     403             :  * and the pointer is only valid till the polygon is next modified.  Use the
     404             :  * OGRGeometry::clone() method to make a separate copy within the application.
     405             :  *
     406             :  * Relates to the ISO SQL/MM ST_CurveN() function.
     407             :  *
     408             :  * @param iRing curve index from 0 to getNumCurves() - 1.
     409             :  *
     410             :  * @return pointer to curve.  May be NULL.
     411             :  */
     412             : 
     413         245 : OGRCurve *OGRCompoundCurve::getCurve(int iRing)
     414             : {
     415         245 :     return oCC.getCurve(iRing);
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                           getCurve()                                 */
     420             : /************************************************************************/
     421             : 
     422             : /**
     423             :  * \brief Fetch reference to indicated internal ring.
     424             :  *
     425             :  * Note that the returned curve pointer is to an internal data object of the
     426             :  * OGRCompoundCurve.  It should not be modified or deleted by the application,
     427             :  * and the pointer is only valid till the polygon is next modified.  Use the
     428             :  * OGRGeometry::clone() method to make a separate copy within the application.
     429             :  *
     430             :  * Relates to the ISO SQL/MM ST_CurveN() function.
     431             :  *
     432             :  * @param iCurve curve index from 0 to getNumCurves() - 1.
     433             :  *
     434             :  * @return pointer to curve.  May be NULL.
     435             :  */
     436             : 
     437         229 : const OGRCurve *OGRCompoundCurve::getCurve(int iCurve) const
     438             : {
     439         229 :     return oCC.getCurve(iCurve);
     440             : }
     441             : 
     442             : /************************************************************************/
     443             : /*                           stealCurve()                               */
     444             : /************************************************************************/
     445             : 
     446             : /**
     447             :  * \brief "Steal" reference to curve.
     448             :  *
     449             :  * @param iCurve curve index from 0 to getNumCurves() - 1.
     450             :  *
     451             :  * @return pointer to curve.  May be NULL.
     452             :  */
     453             : 
     454           5 : OGRCurve *OGRCompoundCurve::stealCurve(int iCurve)
     455             : {
     456           5 :     return oCC.stealCurve(iCurve);
     457             : }
     458             : 
     459             : /************************************************************************/
     460             : /*                            addCurve()                                */
     461             : /************************************************************************/
     462             : 
     463             : /**
     464             :  * \brief Add a curve to the container.
     465             :  *
     466             :  * The passed geometry is cloned to make an internal copy.
     467             :  *
     468             :  * There is no ISO SQL/MM analog to this method.
     469             :  *
     470             :  * This method is the same as the C function OGR_G_AddGeometry().
     471             :  *
     472             :  * @param poCurve geometry to add to the container.
     473             :  * @param dfToleranceEps relative tolerance when checking that the first point
     474             :  * of a segment matches then end point of the previous one. Default value:
     475             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     476             :  *
     477             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     478             :  * (for example if curves are not contiguous)
     479             :  */
     480             : 
     481          23 : OGRErr OGRCompoundCurve::addCurve(const OGRCurve *poCurve,
     482             :                                   double dfToleranceEps)
     483             : {
     484          23 :     OGRCurve *poClonedCurve = poCurve->clone();
     485          23 :     const OGRErr eErr = addCurveDirectly(poClonedCurve, dfToleranceEps);
     486          23 :     if (eErr != OGRERR_NONE)
     487           0 :         delete poClonedCurve;
     488          23 :     return eErr;
     489             : }
     490             : 
     491             : /************************************************************************/
     492             : /*                          addCurveDirectly()                          */
     493             : /************************************************************************/
     494             : 
     495             : /**
     496             :  * \brief Add a curve directly to the container.
     497             :  *
     498             :  * Ownership of the passed geometry is taken by the container rather than
     499             :  * cloning as addCurve() does, but only if the method is successful.
     500             :  * If the method fails, ownership still belongs to the caller.
     501             :  *
     502             :  * There is no ISO SQL/MM analog to this method.
     503             :  *
     504             :  * This method is the same as the C function OGR_G_AddGeometryDirectly().
     505             :  *
     506             :  * @param poCurve geometry to add to the container.
     507             :  * @param dfToleranceEps relative tolerance when checking that the first point
     508             :  * of a segment matches then end point of the previous one. Default value:
     509             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     510             :  *
     511             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     512             :  * (for example if curves are not contiguous)
     513             :  */
     514        1124 : OGRErr OGRCompoundCurve::addCurveDirectly(OGRCurve *poCurve,
     515             :                                           double dfToleranceEps)
     516             : {
     517        1124 :     return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE);
     518             : }
     519             : 
     520        2940 : OGRErr OGRCompoundCurve::addCurveDirectlyInternal(OGRCurve *poCurve,
     521             :                                                   double dfToleranceEps,
     522             :                                                   int bNeedRealloc)
     523             : {
     524        2940 :     if (poCurve->getNumPoints() == 1)
     525             :     {
     526           5 :         CPLError(CE_Failure, CPLE_AppDefined,
     527             :                  "Invalid curve: not enough points");
     528           5 :         return OGRERR_FAILURE;
     529             :     }
     530             : 
     531             :     const OGRwkbGeometryType eCurveType =
     532        2935 :         wkbFlatten(poCurve->getGeometryType());
     533        2935 :     if (EQUAL(poCurve->getGeometryName(), "LINEARRING"))
     534             :     {
     535           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
     536           0 :         return OGRERR_FAILURE;
     537             :     }
     538        2935 :     else if (eCurveType == wkbCompoundCurve)
     539             :     {
     540           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     541             :                  "Cannot add a compound curve inside a compound curve");
     542           1 :         return OGRERR_FAILURE;
     543             :     }
     544             : 
     545        2934 :     if (oCC.nCurveCount > 0)
     546             :     {
     547         982 :         if (oCC.papoCurves[oCC.nCurveCount - 1]->IsEmpty() ||
     548         491 :             poCurve->IsEmpty())
     549             :         {
     550           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
     551           3 :             return OGRERR_FAILURE;
     552             :         }
     553             : 
     554         491 :         OGRPoint oEnd;
     555         491 :         OGRPoint start;
     556         491 :         oCC.papoCurves[oCC.nCurveCount - 1]->EndPoint(&oEnd);
     557         491 :         poCurve->StartPoint(&start);
     558         491 :         if (fabs(oEnd.getX() - start.getX()) >
     559         491 :                 dfToleranceEps * fabs(start.getX()) ||
     560         485 :             fabs(oEnd.getY() - start.getY()) >
     561        1460 :                 dfToleranceEps * fabs(start.getY()) ||
     562         484 :             fabs(oEnd.getZ() - start.getZ()) >
     563         484 :                 dfToleranceEps * fabs(start.getZ()))
     564             :         {
     565           7 :             poCurve->EndPoint(&start);
     566           7 :             if (fabs(oEnd.getX() - start.getX()) >
     567           7 :                     dfToleranceEps * fabs(start.getX()) ||
     568           4 :                 fabs(oEnd.getY() - start.getY()) >
     569          15 :                     dfToleranceEps * fabs(start.getY()) ||
     570           4 :                 fabs(oEnd.getZ() - start.getZ()) >
     571           4 :                     dfToleranceEps * fabs(start.getZ()))
     572             :             {
     573           3 :                 CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
     574           3 :                 return OGRERR_FAILURE;
     575             :             }
     576             : 
     577           4 :             CPLDebug("GML", "reversing curve");
     578           4 :             poCurve->toSimpleCurve()->reversePoints();
     579             :         }
     580             :         // Patch so that it matches exactly.
     581         488 :         poCurve->toSimpleCurve()->setPoint(0, &oEnd);
     582             :     }
     583             : 
     584        2931 :     return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
     585             : }
     586             : 
     587             : /************************************************************************/
     588             : /*                          addCurve()                                  */
     589             : /************************************************************************/
     590             : 
     591             : /**
     592             :  * \brief Add a curve directly to the container.
     593             :  *
     594             :  * There is no ISO SQL/MM analog to this method.
     595             :  *
     596             :  * This method is the same as the C function OGR_G_AddGeometryDirectly().
     597             :  *
     598             :  * @param poCurve geometry to add to the container.
     599             :  * @param dfToleranceEps relative tolerance when checking that the first point
     600             :  * of a segment matches then end point of the previous one. Default value:
     601             :  * OGRCompoundCurve::DEFAULT_TOLERANCE_EPSILON.
     602             :  *
     603             :  * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
     604             :  * (for example if curves are not contiguous)
     605             :  */
     606          91 : OGRErr OGRCompoundCurve::addCurve(std::unique_ptr<OGRCurve> poCurve,
     607             :                                   double dfToleranceEps)
     608             : {
     609          91 :     OGRCurve *poCurvePtr = poCurve.release();
     610          91 :     OGRErr eErr = addCurveDirectlyInternal(poCurvePtr, dfToleranceEps, TRUE);
     611          91 :     if (eErr != OGRERR_NONE)
     612           1 :         delete poCurvePtr;
     613          91 :     return eErr;
     614             : }
     615             : 
     616             : /************************************************************************/
     617             : /*                             transform()                              */
     618             : /************************************************************************/
     619             : 
     620           3 : OGRErr OGRCompoundCurve::transform(OGRCoordinateTransformation *poCT)
     621             : {
     622           3 :     return oCC.transform(this, poCT);
     623             : }
     624             : 
     625             : /************************************************************************/
     626             : /*                            flattenTo2D()                             */
     627             : /************************************************************************/
     628             : 
     629           2 : void OGRCompoundCurve::flattenTo2D()
     630             : {
     631           2 :     oCC.flattenTo2D(this);
     632           2 : }
     633             : 
     634             : /************************************************************************/
     635             : /*                              segmentize()                            */
     636             : /************************************************************************/
     637             : 
     638           1 : bool OGRCompoundCurve::segmentize(double dfMaxLength)
     639             : {
     640           1 :     return oCC.segmentize(dfMaxLength);
     641             : }
     642             : 
     643             : /************************************************************************/
     644             : /*                               swapXY()                               */
     645             : /************************************************************************/
     646             : 
     647           1 : void OGRCompoundCurve::swapXY()
     648             : {
     649           1 :     oCC.swapXY();
     650           1 : }
     651             : 
     652             : /************************************************************************/
     653             : /*                         hasCurveGeometry()                           */
     654             : /************************************************************************/
     655             : 
     656        2200 : OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
     657             : {
     658        2200 :     if (bLookForNonLinear)
     659             :     {
     660          37 :         return oCC.hasCurveGeometry(bLookForNonLinear);
     661             :     }
     662             : 
     663        2163 :     return TRUE;
     664             : }
     665             : 
     666             : /************************************************************************/
     667             : /*                         getLinearGeometry()                        */
     668             : /************************************************************************/
     669             : 
     670             : OGRGeometry *
     671         309 : OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
     672             :                                     const char *const *papszOptions) const
     673             : {
     674         309 :     return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
     675             : }
     676             : 
     677             : /************************************************************************/
     678             : /*                           getNumPoints()                             */
     679             : /************************************************************************/
     680             : 
     681         236 : int OGRCompoundCurve::getNumPoints() const
     682             : {
     683         236 :     int nPoints = 0;
     684         699 :     for (int i = 0; i < oCC.nCurveCount; i++)
     685             :     {
     686         463 :         nPoints += oCC.papoCurves[i]->getNumPoints();
     687         463 :         if (i != 0)
     688         234 :             nPoints--;
     689             :     }
     690         236 :     return nPoints;
     691             : }
     692             : 
     693             : /************************************************************************/
     694             : /*                      OGRCompoundCurvePointIterator                   */
     695             : /************************************************************************/
     696             : 
     697             : class OGRCompoundCurvePointIterator final : public OGRPointIterator
     698             : {
     699             :     CPL_DISALLOW_COPY_ASSIGN(OGRCompoundCurvePointIterator)
     700             : 
     701             :     const OGRCompoundCurve *poCC = nullptr;
     702             :     int iCurCurve = 0;
     703             :     OGRPointIterator *poCurveIter = nullptr;
     704             : 
     705             :   public:
     706          87 :     explicit OGRCompoundCurvePointIterator(const OGRCompoundCurve *poCCIn)
     707          87 :         : poCC(poCCIn)
     708             :     {
     709          87 :     }
     710             : 
     711         174 :     ~OGRCompoundCurvePointIterator() override
     712          87 :     {
     713          87 :         delete poCurveIter;
     714         174 :     }
     715             : 
     716             :     OGRBoolean getNextPoint(OGRPoint *p) override;
     717             : };
     718             : 
     719             : /************************************************************************/
     720             : /*                            getNextPoint()                            */
     721             : /************************************************************************/
     722             : 
     723         513 : OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint *p)
     724             : {
     725         513 :     if (iCurCurve == poCC->getNumCurves())
     726           0 :         return FALSE;
     727         513 :     if (poCurveIter == nullptr)
     728          87 :         poCurveIter = poCC->getCurve(0)->getPointIterator();
     729         513 :     if (!poCurveIter->getNextPoint(p))
     730             :     {
     731         126 :         iCurCurve++;
     732         126 :         if (iCurCurve == poCC->getNumCurves())
     733          56 :             return FALSE;
     734          70 :         delete poCurveIter;
     735          70 :         poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
     736             :         // Skip first point.
     737          70 :         return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p);
     738             :     }
     739         387 :     return TRUE;
     740             : }
     741             : 
     742             : /************************************************************************/
     743             : /*                         getPointIterator()                           */
     744             : /************************************************************************/
     745             : 
     746          87 : OGRPointIterator *OGRCompoundCurve::getPointIterator() const
     747             : {
     748          87 :     return new OGRCompoundCurvePointIterator(this);
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                         CastToLineString()                        */
     753             : /************************************************************************/
     754             : 
     755             : //! @cond Doxygen_Suppress
     756           9 : OGRLineString *OGRCompoundCurve::CastToLineString(OGRCompoundCurve *poCC)
     757             : {
     758          30 :     for (int i = 0; i < poCC->oCC.nCurveCount; i++)
     759             :     {
     760          42 :         poCC->oCC.papoCurves[i] =
     761          21 :             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
     762          21 :         if (poCC->oCC.papoCurves[i] == nullptr)
     763             :         {
     764           0 :             delete poCC;
     765           0 :             return nullptr;
     766             :         }
     767             :     }
     768             : 
     769           9 :     if (poCC->oCC.nCurveCount == 1)
     770             :     {
     771           2 :         OGRLineString *poLS = poCC->oCC.papoCurves[0]->toLineString();
     772           2 :         poLS->assignSpatialReference(poCC->getSpatialReference());
     773           2 :         poCC->oCC.papoCurves[0] = nullptr;
     774           2 :         delete poCC;
     775           2 :         return poLS;
     776             :     }
     777             : 
     778           7 :     OGRLineString *poLS = poCC->CurveToLineInternal(0, nullptr, FALSE);
     779           7 :     delete poCC;
     780           7 :     return poLS;
     781             : }
     782             : 
     783             : /************************************************************************/
     784             : /*                           CastToLinearRing()                         */
     785             : /************************************************************************/
     786             : 
     787             : /**
     788             :  * \brief Cast to linear ring.
     789             :  *
     790             :  * The passed in geometry is consumed and a new one returned (or NULL in case
     791             :  * of failure)
     792             :  *
     793             :  * @param poCC the input geometry - ownership is passed to the method.
     794             :  * @return new geometry.
     795             :  */
     796             : 
     797          21 : OGRLinearRing *OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve *poCC)
     798             : {
     799          66 :     for (int i = 0; i < poCC->oCC.nCurveCount; i++)
     800             :     {
     801          90 :         poCC->oCC.papoCurves[i] =
     802          45 :             OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
     803          45 :         if (poCC->oCC.papoCurves[i] == nullptr)
     804             :         {
     805           0 :             delete poCC;
     806           0 :             return nullptr;
     807             :         }
     808             :     }
     809             : 
     810          21 :     if (poCC->oCC.nCurveCount == 1)
     811             :     {
     812             :         OGRLinearRing *poLR =
     813          14 :             OGRCurve::CastToLinearRing(poCC->oCC.papoCurves[0]);
     814          14 :         if (poLR != nullptr)
     815             :         {
     816          14 :             poLR->assignSpatialReference(poCC->getSpatialReference());
     817             :         }
     818          14 :         poCC->oCC.papoCurves[0] = nullptr;
     819          14 :         delete poCC;
     820          14 :         return poLR;
     821             :     }
     822             : 
     823             :     OGRLinearRing *poLR =
     824           7 :         poCC->CurveToLineInternal(0, nullptr, TRUE)->toLinearRing();
     825           7 :     delete poCC;
     826           7 :     return poLR;
     827             : }
     828             : 
     829             : /************************************************************************/
     830             : /*                     GetCasterToLineString()                          */
     831             : /************************************************************************/
     832             : 
     833           9 : OGRLineString *OGRCompoundCurve::CasterToLineString(OGRCurve *poCurve)
     834             : {
     835           9 :     OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
     836           9 :     return OGRCompoundCurve::CastToLineString(poCC);
     837             : }
     838             : 
     839           9 : OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const
     840             : {
     841           9 :     return OGRCompoundCurve::CasterToLineString;
     842             : }
     843             : 
     844             : /************************************************************************/
     845             : /*                        GetCasterToLinearRing()                       */
     846             : /************************************************************************/
     847             : 
     848          21 : OGRLinearRing *OGRCompoundCurve::CasterToLinearRing(OGRCurve *poCurve)
     849             : {
     850          21 :     OGRCompoundCurve *poCC = poCurve->toCompoundCurve();
     851          21 :     return OGRCompoundCurve::CastToLinearRing(poCC);
     852             : }
     853             : 
     854          21 : OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const
     855             : {
     856          21 :     return OGRCompoundCurve::CasterToLinearRing;
     857             : }
     858             : 
     859             : //! @endcond
     860             : 
     861             : /************************************************************************/
     862             : /*                           get_Area()                                 */
     863             : /************************************************************************/
     864             : 
     865          41 : double OGRCompoundCurve::get_Area() const
     866             : {
     867          41 :     if (IsEmpty() || !get_IsClosed())
     868           0 :         return 0;
     869             : 
     870             :     // Optimization for convex rings.
     871          41 :     if (IsConvex())
     872             :     {
     873             :         // Compute area of shape without the circular segments.
     874          27 :         OGRPointIterator *poIter = getPointIterator();
     875          54 :         OGRLineString oLS;
     876          27 :         oLS.setNumPoints(getNumPoints());
     877          27 :         OGRPoint p;
     878         192 :         for (int i = 0; poIter->getNextPoint(&p); i++)
     879             :         {
     880         165 :             oLS.setPoint(i, p.getX(), p.getY());
     881             :         }
     882          27 :         double dfArea = oLS.get_Area();
     883          27 :         delete poIter;
     884             : 
     885             :         // Add the area of the spherical segments.
     886          27 :         dfArea += get_AreaOfCurveSegments();
     887             : 
     888          27 :         return dfArea;
     889             :     }
     890             : 
     891          14 :     OGRLineString *poLS = CurveToLine();
     892          14 :     double dfArea = poLS->get_Area();
     893          14 :     delete poLS;
     894             : 
     895          14 :     return dfArea;
     896             : }
     897             : 
     898             : /************************************************************************/
     899             : /*                        get_GeodesicArea()                            */
     900             : /************************************************************************/
     901             : 
     902           3 : double OGRCompoundCurve::get_GeodesicArea(
     903             :     const OGRSpatialReference *poSRSOverride) const
     904             : {
     905           3 :     if (IsEmpty())
     906           1 :         return 0;
     907             : 
     908           2 :     if (!get_IsClosed())
     909             :     {
     910           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Non-closed geometry");
     911           1 :         return -1;
     912             :     }
     913             : 
     914           1 :     if (!poSRSOverride)
     915           1 :         poSRSOverride = getSpatialReference();
     916             : 
     917           2 :     auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
     918           1 :     return poLS->get_GeodesicArea(poSRSOverride);
     919             : }
     920             : 
     921             : /************************************************************************/
     922             : /*                        get_GeodesicLength()                          */
     923             : /************************************************************************/
     924             : 
     925           2 : double OGRCompoundCurve::get_GeodesicLength(
     926             :     const OGRSpatialReference *poSRSOverride) const
     927             : {
     928           2 :     if (IsEmpty())
     929           1 :         return 0;
     930             : 
     931           1 :     if (!poSRSOverride)
     932           1 :         poSRSOverride = getSpatialReference();
     933             : 
     934           2 :     auto poLS = std::unique_ptr<OGRLineString>(CurveToLine());
     935           1 :     return poLS->get_GeodesicLength(poSRSOverride);
     936             : }
     937             : 
     938             : /************************************************************************/
     939             : /*                       get_AreaOfCurveSegments()                      */
     940             : /************************************************************************/
     941             : 
     942             : /** Return area of curve segments
     943             :  * @return area.
     944             :  */
     945          27 : double OGRCompoundCurve::get_AreaOfCurveSegments() const
     946             : {
     947          27 :     double dfArea = 0;
     948          82 :     for (int i = 0; i < getNumCurves(); i++)
     949             :     {
     950          55 :         const OGRCurve *poPart = getCurve(i);
     951          55 :         dfArea += poPart->get_AreaOfCurveSegments();
     952             :     }
     953          27 :     return dfArea;
     954             : }
     955             : 
     956             : /************************************************************************/
     957             : /*                           hasEmptyParts()                            */
     958             : /************************************************************************/
     959             : 
     960           3 : bool OGRCompoundCurve::hasEmptyParts() const
     961             : {
     962           3 :     return oCC.hasEmptyParts();
     963             : }
     964             : 
     965             : /************************************************************************/
     966             : /*                          removeEmptyParts()                          */
     967             : /************************************************************************/
     968             : 
     969           2 : void OGRCompoundCurve::removeEmptyParts()
     970             : {
     971           2 :     oCC.removeEmptyParts();
     972           2 : }
     973             : 
     974             : /************************************************************************/
     975             : /*                           reversePoints()                            */
     976             : /************************************************************************/
     977             : 
     978             : /**
     979             :  * \brief Reverse point order.
     980             :  *
     981             :  * This method updates the points in this curve in place
     982             :  * reversing the point ordering (first for last, etc) and component ordering.
     983             :  *
     984             :  * @since 3.10
     985             :  */
     986           1 : void OGRCompoundCurve::reversePoints()
     987             : 
     988             : {
     989           1 :     oCC.reversePoints();
     990           1 : }

Generated by: LCOV version 1.14