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

Generated by: LCOV version 1.14