LCOV - code coverage report
Current view: top level - ogr - ogrlinearring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 215 244 88.1 %
Date: 2024-11-21 22:18:42 Functions: 17 20 85.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRLinearRing geometry class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_geometry.h"
      16             : 
      17             : #include <climits>
      18             : #include <cmath>
      19             : #include <cstring>
      20             : #include <limits>
      21             : 
      22             : #include "cpl_error.h"
      23             : #include "ogr_core.h"
      24             : #include "ogr_geometry.h"
      25             : #include "ogr_p.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                  OGRLinearRing( const OGRLinearRing& )               */
      29             : /************************************************************************/
      30             : 
      31             : /**
      32             :  * \brief Copy constructor.
      33             :  *
      34             :  * Note: before GDAL 2.1, only the default implementation of the constructor
      35             :  * existed, which could be unsafe to use.
      36             :  *
      37             :  * @since GDAL 2.1
      38             :  */
      39             : 
      40             : OGRLinearRing::OGRLinearRing(const OGRLinearRing &) = default;
      41             : 
      42             : /************************************************************************/
      43             : /*                           OGRLinearRing()                            */
      44             : /************************************************************************/
      45             : 
      46             : /** Constructor
      47             :  * @param poSrcRing source ring.
      48             :  */
      49           0 : OGRLinearRing::OGRLinearRing(const OGRLinearRing *poSrcRing)
      50             : 
      51             : {
      52           0 :     if (poSrcRing == nullptr)
      53             :     {
      54           0 :         CPLDebug("OGR",
      55             :                  "OGRLinearRing::OGRLinearRing(OGRLinearRing*poSrcRing) - "
      56             :                  "passed in ring is NULL!");
      57           0 :         return;
      58             :     }
      59             : 
      60           0 :     setNumPoints(poSrcRing->getNumPoints(), FALSE);
      61             : 
      62           0 :     memcpy(paoPoints, poSrcRing->paoPoints,
      63           0 :            sizeof(OGRRawPoint) * getNumPoints());
      64             : 
      65           0 :     if (poSrcRing->padfZ)
      66             :     {
      67           0 :         Make3D();
      68           0 :         memcpy(padfZ, poSrcRing->padfZ, sizeof(double) * getNumPoints());
      69             :     }
      70             : }
      71             : 
      72             : /************************************************************************/
      73             : /*                    operator=( const OGRLinearRing& )                 */
      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 : OGRLinearRing &OGRLinearRing::operator=(const OGRLinearRing &other)
      86             : {
      87           5 :     if (this != &other)
      88             :     {
      89           4 :         OGRLineString::operator=(other);
      90             :     }
      91           5 :     return *this;
      92             : }
      93             : 
      94             : /************************************************************************/
      95             : /*                          getGeometryName()                           */
      96             : /************************************************************************/
      97             : 
      98      207294 : const char *OGRLinearRing::getGeometryName() const
      99             : 
     100             : {
     101      207294 :     return "LINEARRING";
     102             : }
     103             : 
     104             : /************************************************************************/
     105             : /*                              WkbSize()                               */
     106             : /*                                                                      */
     107             : /*      Disable this method.                                            */
     108             : /************************************************************************/
     109             : 
     110       62633 : size_t OGRLinearRing::WkbSize() const
     111             : 
     112             : {
     113       62633 :     return 0;
     114             : }
     115             : 
     116             : /************************************************************************/
     117             : /*                           importFromWkb()                            */
     118             : /*                                                                      */
     119             : /*      Disable method for this class.                                  */
     120             : /************************************************************************/
     121             : 
     122           0 : OGRErr OGRLinearRing::importFromWkb(const unsigned char * /*pabyData*/,
     123             :                                     size_t /*nSize*/,
     124             :                                     OGRwkbVariant /*eWkbVariant*/,
     125             :                                     size_t & /* nBytesConsumedOut */)
     126             : 
     127             : {
     128           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     129             : }
     130             : 
     131             : /************************************************************************/
     132             : /*                            exportToWkb()                             */
     133             : /*                                                                      */
     134             : /*      Disable method for this class.                                  */
     135             : /************************************************************************/
     136             : 
     137         898 : OGRErr OGRLinearRing::exportToWkb(CPL_UNUSED unsigned char *pabyData,
     138             :                                   CPL_UNUSED const OGRwkbExportOptions *) const
     139             : 
     140             : {
     141         898 :     return OGRERR_UNSUPPORTED_OPERATION;
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                           _importFromWkb()                           */
     146             : /*                                                                      */
     147             : /*      Helper method for OGRPolygon.  NOT A NORMAL importFromWkb()     */
     148             : /*      method.                                                         */
     149             : /************************************************************************/
     150             : 
     151             : //! @cond Doxygen_Suppress
     152       41363 : OGRErr OGRLinearRing::_importFromWkb(OGRwkbByteOrder eByteOrder, int _flags,
     153             :                                      const unsigned char *pabyData,
     154             :                                      size_t nBytesAvailable,
     155             :                                      size_t &nBytesConsumedOut)
     156             : 
     157             : {
     158       41363 :     nBytesConsumedOut = 0;
     159       41363 :     if (nBytesAvailable < 4 && nBytesAvailable != static_cast<size_t>(-1))
     160          10 :         return OGRERR_NOT_ENOUGH_DATA;
     161             : 
     162             :     /* -------------------------------------------------------------------- */
     163             :     /*      Get the vertex count.                                           */
     164             :     /* -------------------------------------------------------------------- */
     165       41353 :     int nNewNumPoints = 0;
     166             : 
     167       41353 :     memcpy(&nNewNumPoints, pabyData, 4);
     168             : 
     169       41353 :     if (OGR_SWAP(eByteOrder))
     170         134 :         nNewNumPoints = CPL_SWAP32(nNewNumPoints);
     171             : 
     172             :     // Check if the wkb stream buffer is big enough to store
     173             :     // fetched number of points.
     174             :     // 16, 24, or 32 - size of point structure.
     175       41353 :     size_t nPointSize = 0;
     176       41353 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     177       30304 :         nPointSize = 32;
     178       11049 :     else if ((_flags & OGR_G_3D) || (_flags & OGR_G_MEASURED))
     179        2562 :         nPointSize = 24;
     180             :     else
     181        8487 :         nPointSize = 16;
     182             : 
     183       82657 :     if (nNewNumPoints < 0 ||
     184       41303 :         static_cast<size_t>(nNewNumPoints) >
     185       41303 :             std::numeric_limits<size_t>::max() / nPointSize)
     186             :     {
     187          49 :         return OGRERR_CORRUPT_DATA;
     188             :     }
     189       41305 :     const size_t nBufferMinSize = nPointSize * nNewNumPoints;
     190       41305 :     if (nBytesAvailable != static_cast<size_t>(-1) &&
     191       41290 :         nBufferMinSize > nBytesAvailable - 4)
     192             :     {
     193         970 :         CPLError(CE_Failure, CPLE_AppDefined,
     194             :                  "Length of input WKB is too small");
     195         970 :         return OGRERR_NOT_ENOUGH_DATA;
     196             :     }
     197             : 
     198             :     // (Re)Allocation of paoPoints buffer.
     199       40335 :     setNumPoints(nNewNumPoints, FALSE);
     200             : 
     201       40335 :     if (_flags & OGR_G_3D)
     202       31736 :         Make3D();
     203             :     else
     204        8599 :         Make2D();
     205             : 
     206       40333 :     if (_flags & OGR_G_MEASURED)
     207       29399 :         AddM();
     208             :     else
     209       10934 :         RemoveM();
     210             : 
     211       40333 :     nBytesConsumedOut = 4 + nPointCount * nPointSize;
     212             : 
     213             :     /* -------------------------------------------------------------------- */
     214             :     /*      Get the vertices                                                */
     215             :     /* -------------------------------------------------------------------- */
     216       40333 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
     217             :     {
     218      141222 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     219             :         {
     220      111935 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 32 * i, 8);
     221      111935 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 32 * i + 8, 8);
     222      111935 :             memcpy(padfZ + i, pabyData + 4 + 32 * i + 16, 8);
     223      111935 :             memcpy(padfM + i, pabyData + 4 + 32 * i + 24, 8);
     224       29287 :         }
     225             :     }
     226       11046 :     else if (flags & OGR_G_MEASURED)
     227             :     {
     228         619 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     229             :         {
     230         507 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 24 * i, 8);
     231         507 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 24 * i + 8, 8);
     232         507 :             memcpy(padfM + i, pabyData + 4 + 24 * i + 16, 8);
     233             :         }
     234             :     }
     235       10934 :     else if (flags & OGR_G_3D)
     236             :     {
     237       71807 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     238             :         {
     239       69358 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 24 * i, 8);
     240       69358 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 24 * i + 8, 8);
     241       69358 :             memcpy(padfZ + i, pabyData + 4 + 24 * i + 16, 8);
     242             :         }
     243             :     }
     244        8485 :     else if (nPointCount != 0)
     245             :     {
     246        8484 :         memcpy(paoPoints, pabyData + 4, 16 * static_cast<size_t>(nPointCount));
     247             :     }
     248             : 
     249             :     /* -------------------------------------------------------------------- */
     250             :     /*      Byte swap if needed.                                            */
     251             :     /* -------------------------------------------------------------------- */
     252       40333 :     if (OGR_SWAP(eByteOrder))
     253             :     {
     254         780 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     255             :         {
     256         646 :             CPL_SWAPDOUBLE(&(paoPoints[i].x));
     257         646 :             CPL_SWAPDOUBLE(&(paoPoints[i].y));
     258             : 
     259         646 :             if (flags & OGR_G_3D)
     260             :             {
     261          85 :                 CPL_SWAPDOUBLE(padfZ + i);
     262             :             }
     263         646 :             if (flags & OGR_G_MEASURED)
     264             :             {
     265           4 :                 CPL_SWAPDOUBLE(padfM + i);
     266             :             }
     267             :         }
     268             :     }
     269             : 
     270       40333 :     return OGRERR_NONE;
     271             : }
     272             : 
     273             : /************************************************************************/
     274             : /*                            _exportToWkb()                            */
     275             : /*                                                                      */
     276             : /*      Helper method for OGRPolygon.  THIS IS NOT THE NORMAL           */
     277             : /*      exportToWkb() METHOD.                                           */
     278             : /************************************************************************/
     279             : 
     280      256590 : OGRErr OGRLinearRing::_exportToWkb(int _flags, unsigned char *pabyData,
     281             :                                    const OGRwkbExportOptions *psOptions) const
     282             : 
     283             : {
     284             : 
     285             :     /* -------------------------------------------------------------------- */
     286             :     /*      Copy in the raw data.                                           */
     287             :     /* -------------------------------------------------------------------- */
     288      256590 :     memcpy(pabyData, &nPointCount, 4);
     289             : 
     290             :     /* -------------------------------------------------------------------- */
     291             :     /*      Copy in the raw data.                                           */
     292             :     /* -------------------------------------------------------------------- */
     293      256590 :     size_t nWords = 0;
     294      256590 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     295             :     {
     296       13167 :         nWords = 4 * static_cast<size_t>(nPointCount);
     297       63232 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     298             :         {
     299       50065 :             memcpy(pabyData + 4 + i * 32, &(paoPoints[i].x), 8);
     300       50065 :             memcpy(pabyData + 4 + i * 32 + 8, &(paoPoints[i].y), 8);
     301       50065 :             if (padfZ == nullptr)
     302           0 :                 memset(pabyData + 4 + i * 32 + 16, 0, 8);
     303             :             else
     304       50065 :                 memcpy(pabyData + 4 + i * 32 + 16, padfZ + i, 8);
     305       50065 :             if (padfM == nullptr)
     306           0 :                 memset(pabyData + 4 + i * 32 + 24, 0, 8);
     307             :             else
     308       50065 :                 memcpy(pabyData + 4 + i * 32 + 24, padfM + i, 8);
     309             :         }
     310       13167 :         OGRRoundCoordinatesIEEE754XYValues<32>(
     311       13167 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     312       13167 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nZBitPrecision,
     313             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     314       13167 :                                        nPointCount);
     315       13167 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nMBitPrecision,
     316             :                                        pabyData + 4 + 3 * sizeof(uint64_t),
     317       13167 :                                        nPointCount);
     318             :     }
     319      243423 :     else if (_flags & OGR_G_MEASURED)
     320             :     {
     321          51 :         nWords = 3 * static_cast<size_t>(nPointCount);
     322         270 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     323             :         {
     324         219 :             memcpy(pabyData + 4 + i * 24, &(paoPoints[i].x), 8);
     325         219 :             memcpy(pabyData + 4 + i * 24 + 8, &(paoPoints[i].y), 8);
     326         219 :             if (padfM == nullptr)
     327           0 :                 memset(pabyData + 4 + i * 24 + 16, 0, 8);
     328             :             else
     329         219 :                 memcpy(pabyData + 4 + i * 24 + 16, padfM + i, 8);
     330             :         }
     331          51 :         OGRRoundCoordinatesIEEE754XYValues<24>(
     332          51 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     333          51 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nMBitPrecision,
     334             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     335          51 :                                        nPointCount);
     336             :     }
     337      243372 :     else if (_flags & OGR_G_3D)
     338             :     {
     339      160730 :         nWords = 3 * static_cast<size_t>(nPointCount);
     340      839433 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     341             :         {
     342      678703 :             memcpy(pabyData + 4 + i * 24, &(paoPoints[i].x), 8);
     343      678703 :             memcpy(pabyData + 4 + i * 24 + 8, &(paoPoints[i].y), 8);
     344      678703 :             if (padfZ == nullptr)
     345           0 :                 memset(pabyData + 4 + i * 24 + 16, 0, 8);
     346             :             else
     347      678703 :                 memcpy(pabyData + 4 + i * 24 + 16, padfZ + i, 8);
     348             :         }
     349      160730 :         OGRRoundCoordinatesIEEE754XYValues<24>(
     350      160730 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     351      160730 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nZBitPrecision,
     352             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     353      160730 :                                        nPointCount);
     354             :     }
     355             :     else
     356             :     {
     357       82642 :         nWords = 2 * static_cast<size_t>(nPointCount);
     358       82642 :         memcpy(pabyData + 4, paoPoints, 16 * static_cast<size_t>(nPointCount));
     359       82642 :         OGRRoundCoordinatesIEEE754XYValues<16>(
     360       82642 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     361             :     }
     362             : 
     363             :     /* -------------------------------------------------------------------- */
     364             :     /*      Swap if needed.                                                 */
     365             :     /* -------------------------------------------------------------------- */
     366      256585 :     if (OGR_SWAP(psOptions->eByteOrder))
     367             :     {
     368          22 :         const int nCount = CPL_SWAP32(nPointCount);
     369          22 :         memcpy(pabyData, &nCount, 4);
     370             : 
     371         257 :         for (size_t i = 0; i < nWords; i++)
     372             :         {
     373         235 :             CPL_SWAPDOUBLE(pabyData + 4 + 8 * i);
     374             :         }
     375             :     }
     376             : 
     377      256585 :     return OGRERR_NONE;
     378             : }
     379             : 
     380             : /************************************************************************/
     381             : /*                              _WkbSize()                              */
     382             : /*                                                                      */
     383             : /*      Helper method for OGRPolygon.  NOT THE NORMAL WkbSize() METHOD. */
     384             : /************************************************************************/
     385             : 
     386      690491 : size_t OGRLinearRing::_WkbSize(int _flags) const
     387             : 
     388             : {
     389      690491 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     390       38395 :         return 4 + 32 * static_cast<size_t>(nPointCount);
     391      652096 :     else if ((_flags & OGR_G_3D) || (_flags & OGR_G_MEASURED))
     392      480582 :         return 4 + 24 * static_cast<size_t>(nPointCount);
     393             :     else
     394      171514 :         return 4 + 16 * static_cast<size_t>(nPointCount);
     395             : }
     396             : 
     397             : //! @endcond
     398             : 
     399             : /************************************************************************/
     400             : /*                               clone()                                */
     401             : /*                                                                      */
     402             : /*      We override the OGRCurve clone() to ensure that we get the      */
     403             : /*      correct virtual table.                                          */
     404             : /************************************************************************/
     405             : 
     406     1599500 : OGRLinearRing *OGRLinearRing::clone() const
     407             : 
     408             : {
     409     1599500 :     OGRLinearRing *poNewLinearRing = new OGRLinearRing();
     410     1599500 :     poNewLinearRing->assignSpatialReference(getSpatialReference());
     411             : 
     412     1599500 :     poNewLinearRing->setPoints(nPointCount, paoPoints, padfZ, padfM);
     413     1599500 :     poNewLinearRing->flags = flags;
     414             : 
     415     1599500 :     return poNewLinearRing;
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                             reverseWindingOrder()                    */
     420             : /************************************************************************/
     421             : 
     422             : //! @cond Doxygen_Suppress
     423             : /** Reverse order of points.
     424             :  */
     425           0 : void OGRLinearRing::reverseWindingOrder()
     426             : 
     427             : {
     428           0 :     reversePoints();
     429           0 : }
     430             : 
     431             : //! @endcond
     432             : 
     433             : /************************************************************************/
     434             : /*                             closeRing()                              */
     435             : /************************************************************************/
     436             : 
     437      102141 : void OGRLinearRing::closeRings()
     438             : 
     439             : {
     440      102141 :     if (nPointCount < 2)
     441           7 :         return;
     442             : 
     443      183992 :     if (getX(0) != getX(nPointCount - 1) || getY(0) != getY(nPointCount - 1) ||
     444       81863 :         getZ(0) != getZ(nPointCount - 1))
     445             :     {
     446       40541 :         OGRPoint oFirstPoint;
     447       20270 :         getPoint(0, &oFirstPoint);
     448       20268 :         addPoint(&oFirstPoint);
     449             :     }
     450             : }
     451             : 
     452             : /************************************************************************/
     453             : /*                              isPointInRing()                         */
     454             : /************************************************************************/
     455             : 
     456             : /** Returns whether the point is inside the ring.
     457             :  * @param poPoint point
     458             :  * @param bTestEnvelope set to TRUE if the presence of the point inside the
     459             :  *                      ring envelope must be checked first.
     460             :  * @return TRUE or FALSE.
     461             :  */
     462     2620420 : OGRBoolean OGRLinearRing::isPointInRing(const OGRPoint *poPoint,
     463             :                                         int bTestEnvelope) const
     464             : {
     465     2620420 :     if (nullptr == poPoint)
     466             :     {
     467           0 :         CPLDebug("OGR",
     468             :                  "OGRLinearRing::isPointInRing(const OGRPoint* poPoint) - "
     469             :                  "passed point is NULL!");
     470           0 :         return FALSE;
     471             :     }
     472     2620420 :     if (poPoint->IsEmpty())
     473             :     {
     474           1 :         return FALSE;
     475             :     }
     476             : 
     477     2620420 :     const int iNumPoints = getNumPoints();
     478             : 
     479             :     // Simple validation
     480     2620420 :     if (iNumPoints < 4)
     481           0 :         return FALSE;
     482             : 
     483     2620420 :     const double dfTestX = poPoint->getX();
     484     2620420 :     const double dfTestY = poPoint->getY();
     485             : 
     486             :     // Fast test if point is inside extent of the ring.
     487     2620420 :     if (bTestEnvelope)
     488             :     {
     489     2619850 :         OGREnvelope extent;
     490     2619850 :         getEnvelope(&extent);
     491     2619850 :         if (!(dfTestX >= extent.MinX && dfTestX <= extent.MaxX &&
     492     1130800 :               dfTestY >= extent.MinY && dfTestY <= extent.MaxY))
     493             :         {
     494     2335780 :             return FALSE;
     495             :         }
     496             :     }
     497             : 
     498             :     // For every point p in ring,
     499             :     // test if ray starting from given point crosses segment (p - 1, p)
     500      284647 :     int iNumCrossings = 0;
     501             : 
     502      284647 :     double prev_diff_x = getX(0) - dfTestX;
     503      284647 :     double prev_diff_y = getY(0) - dfTestY;
     504             : 
     505     1497560 :     for (int iPoint = 1; iPoint < iNumPoints; iPoint++)
     506             :     {
     507     1212920 :         const double x1 = getX(iPoint) - dfTestX;
     508     1212920 :         const double y1 = getY(iPoint) - dfTestY;
     509             : 
     510     1212920 :         const double x2 = prev_diff_x;
     511     1212920 :         const double y2 = prev_diff_y;
     512             : 
     513     1212920 :         if (((y1 > 0) && (y2 <= 0)) || ((y2 > 0) && (y1 <= 0)))
     514             :         {
     515             :             // Check if ray intersects with segment of the ring
     516      563860 :             const double dfIntersection = (x1 * y2 - x2 * y1) / (y2 - y1);
     517      563860 :             if (0.0 < dfIntersection)
     518             :             {
     519             :                 // Count intersections
     520      276494 :                 iNumCrossings++;
     521             :             }
     522             :         }
     523             : 
     524     1212920 :         prev_diff_x = x1;
     525     1212920 :         prev_diff_y = y1;
     526             :     }
     527             : 
     528             :     // If iNumCrossings number is even, given point is outside the ring,
     529             :     // when the crossings number is odd, the point is inside the ring.
     530      284647 :     return iNumCrossings % 2;  // OGRBoolean
     531             : }
     532             : 
     533             : /************************************************************************/
     534             : /*                       isPointOnRingBoundary()                        */
     535             : /************************************************************************/
     536             : 
     537             : /** Returns whether the point is on the ring boundary.
     538             :  * @param poPoint point
     539             :  * @param bTestEnvelope set to TRUE if the presence of the point inside the
     540             :  *                      ring envelope must be checked first.
     541             :  * @return TRUE or FALSE.
     542             :  */
     543     2378410 : OGRBoolean OGRLinearRing::isPointOnRingBoundary(const OGRPoint *poPoint,
     544             :                                                 int bTestEnvelope) const
     545             : {
     546     2378410 :     if (nullptr == poPoint)
     547             :     {
     548           0 :         CPLDebug("OGR", "OGRLinearRing::isPointOnRingBoundary(const OGRPoint* "
     549             :                         "poPoint) - passed point is NULL!");
     550           0 :         return 0;
     551             :     }
     552             : 
     553     2378410 :     const int iNumPoints = getNumPoints();
     554             : 
     555             :     // Simple validation.
     556     2378410 :     if (iNumPoints < 4)
     557           0 :         return 0;
     558             : 
     559     2378410 :     const double dfTestX = poPoint->getX();
     560     2378410 :     const double dfTestY = poPoint->getY();
     561             : 
     562             :     // Fast test if point is inside extent of the ring
     563     2378410 :     if (bTestEnvelope)
     564             :     {
     565     2377790 :         OGREnvelope extent;
     566     2377790 :         getEnvelope(&extent);
     567     2377790 :         if (!(dfTestX >= extent.MinX && dfTestX <= extent.MaxX &&
     568      888753 :               dfTestY >= extent.MinY && dfTestY <= extent.MaxY))
     569             :         {
     570     2335770 :             return 0;
     571             :         }
     572             :     }
     573             : 
     574       42639 :     double prev_diff_x = dfTestX - getX(0);
     575       42639 :     double prev_diff_y = dfTestY - getY(0);
     576             : 
     577      244834 :     for (int iPoint = 1; iPoint < iNumPoints; iPoint++)
     578             :     {
     579      203860 :         const double dx1 = dfTestX - getX(iPoint);
     580      203860 :         const double dy1 = dfTestY - getY(iPoint);
     581             : 
     582      203860 :         const double dx2 = prev_diff_x;
     583      203860 :         const double dy2 = prev_diff_y;
     584             : 
     585             :         // If the point is on the segment, return immediately.
     586             :         // FIXME? If the test point is not exactly identical to one of
     587             :         // the vertices of the ring, but somewhere on a segment, there's
     588             :         // little chance that we get 0. So that should be tested against some
     589             :         // epsilon.
     590             : 
     591      203860 :         if (dx1 * dy2 - dx2 * dy1 == 0)
     592             :         {
     593             :             // If iPoint and iPointPrev are the same, go on.
     594        2024 :             if (!(dx1 == dx2 && dy1 == dy2))
     595             :             {
     596        1740 :                 const double dx_segment = getX(iPoint) - getX(iPoint - 1);
     597        1740 :                 const double dy_segment = getY(iPoint) - getY(iPoint - 1);
     598        1740 :                 const double crossproduct = dx2 * dx_segment + dy2 * dy_segment;
     599        1740 :                 if (crossproduct >= 0)
     600             :                 {
     601        1738 :                     const double sq_length_seg =
     602        1738 :                         dx_segment * dx_segment + dy_segment * dy_segment;
     603        1738 :                     if (crossproduct <= sq_length_seg)
     604             :                     {
     605        1665 :                         return 1;
     606             :                     }
     607             :                 }
     608             :             }
     609             :         }
     610             : 
     611      202195 :         prev_diff_x = dx1;
     612      202195 :         prev_diff_y = dy1;
     613             :     }
     614             : 
     615       40974 :     return 0;
     616             : }
     617             : 
     618             : /************************************************************************/
     619             : /*                             transform()                              */
     620             : /************************************************************************/
     621             : 
     622         597 : OGRErr OGRLinearRing::transform(OGRCoordinateTransformation *poCT)
     623             : 
     624             : {
     625         597 :     const bool bIsClosed = getNumPoints() > 2 && CPL_TO_BOOL(get_IsClosed());
     626         597 :     OGRErr eErr = OGRLineString::transform(poCT);
     627         597 :     if (bIsClosed && eErr == OGRERR_NONE && !get_IsClosed())
     628             :     {
     629           0 :         CPLDebug("OGR", "Linearring is not closed after coordinate "
     630             :                         "transformation. Forcing last point to be identical to "
     631             :                         "first one");
     632             :         // Force last point to be identical to first point.
     633             :         // This is a safety belt in case the reprojection of the same coordinate
     634             :         // isn't perfectly stable. This can for example happen in very rare
     635             :         // cases when reprojecting a cutline with a RPC transform with a DEM
     636             :         // that is a VRT whose sources are resampled...
     637           0 :         OGRPoint oStartPoint;
     638           0 :         StartPoint(&oStartPoint);
     639             : 
     640           0 :         setPoint(getNumPoints() - 1, &oStartPoint);
     641             :     }
     642         597 :     return eErr;
     643             : }
     644             : 
     645             : /************************************************************************/
     646             : /*                          CastToLineString()                          */
     647             : /************************************************************************/
     648             : 
     649             : /**
     650             :  * \brief Cast to line string.
     651             :  *
     652             :  * The passed in geometry is consumed and a new one returned .
     653             :  *
     654             :  * @param poLR the input geometry - ownership is passed to the method.
     655             :  * @return new geometry.
     656             :  */
     657             : 
     658          66 : OGRLineString *OGRLinearRing::CastToLineString(OGRLinearRing *poLR)
     659             : {
     660          66 :     return TransferMembersAndDestroy(poLR, new OGRLineString());
     661             : }
     662             : 
     663             : //! @cond Doxygen_Suppress
     664             : /************************************************************************/
     665             : /*                     GetCasterToLineString()                          */
     666             : /************************************************************************/
     667             : 
     668          40 : OGRLineString *OGRLinearRing::CasterToLineString(OGRCurve *poCurve)
     669             : {
     670          40 :     return OGRLinearRing::CastToLineString(poCurve->toLinearRing());
     671             : }
     672             : 
     673          40 : OGRCurveCasterToLineString OGRLinearRing::GetCasterToLineString() const
     674             : {
     675          40 :     return OGRLinearRing::CasterToLineString;
     676             : }
     677             : 
     678             : /************************************************************************/
     679             : /*                        GetCasterToLinearRing()                       */
     680             : /************************************************************************/
     681             : 
     682           4 : static OGRLinearRing *CasterToLinearRing(OGRCurve *poCurve)
     683             : {
     684           4 :     return poCurve->toLinearRing();
     685             : }
     686             : 
     687           4 : OGRCurveCasterToLinearRing OGRLinearRing::GetCasterToLinearRing() const
     688             : {
     689           4 :     return ::CasterToLinearRing;
     690             : }
     691             : 
     692             : //! @endcond

Generated by: LCOV version 1.14