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

Generated by: LCOV version 1.14