LCOV - code coverage report
Current view: top level - ogr - ogrlinearring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 224 251 89.2 %
Date: 2024-05-03 15:49:35 Functions: 18 20 90.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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "ogr_geometry.h"
      32             : 
      33             : #include <climits>
      34             : #include <cmath>
      35             : #include <cstring>
      36             : #include <limits>
      37             : 
      38             : #include "cpl_error.h"
      39             : #include "ogr_core.h"
      40             : #include "ogr_geometry.h"
      41             : #include "ogr_p.h"
      42             : 
      43             : /************************************************************************/
      44             : /*                           OGRLinearRing()                            */
      45             : /************************************************************************/
      46             : 
      47             : /** Constructor */
      48             : OGRLinearRing::OGRLinearRing() = default;
      49             : 
      50             : /************************************************************************/
      51             : /*                  OGRLinearRing( const OGRLinearRing& )               */
      52             : /************************************************************************/
      53             : 
      54             : /**
      55             :  * \brief Copy constructor.
      56             :  *
      57             :  * Note: before GDAL 2.1, only the default implementation of the constructor
      58             :  * existed, which could be unsafe to use.
      59             :  *
      60             :  * @since GDAL 2.1
      61             :  */
      62             : 
      63             : OGRLinearRing::OGRLinearRing(const OGRLinearRing &) = default;
      64             : 
      65             : /************************************************************************/
      66             : /*                          ~OGRLinearRing()                            */
      67             : /************************************************************************/
      68             : 
      69             : OGRLinearRing::~OGRLinearRing() = default;
      70             : 
      71             : /************************************************************************/
      72             : /*                           OGRLinearRing()                            */
      73             : /************************************************************************/
      74             : 
      75             : /** Constructor
      76             :  * @param poSrcRing source ring.
      77             :  */
      78           0 : OGRLinearRing::OGRLinearRing(OGRLinearRing *poSrcRing)
      79             : 
      80             : {
      81           0 :     if (poSrcRing == nullptr)
      82             :     {
      83           0 :         CPLDebug("OGR",
      84             :                  "OGRLinearRing::OGRLinearRing(OGRLinearRing*poSrcRing) - "
      85             :                  "passed in ring is NULL!");
      86           0 :         return;
      87             :     }
      88             : 
      89           0 :     setNumPoints(poSrcRing->getNumPoints(), FALSE);
      90             : 
      91           0 :     memcpy(paoPoints, poSrcRing->paoPoints,
      92           0 :            sizeof(OGRRawPoint) * getNumPoints());
      93             : 
      94           0 :     if (poSrcRing->padfZ)
      95             :     {
      96           0 :         Make3D();
      97           0 :         memcpy(padfZ, poSrcRing->padfZ, sizeof(double) * getNumPoints());
      98             :     }
      99             : }
     100             : 
     101             : /************************************************************************/
     102             : /*                    operator=( const OGRLinearRing& )                 */
     103             : /************************************************************************/
     104             : 
     105             : /**
     106             :  * \brief Assignment operator.
     107             :  *
     108             :  * Note: before GDAL 2.1, only the default implementation of the operator
     109             :  * existed, which could be unsafe to use.
     110             :  *
     111             :  * @since GDAL 2.1
     112             :  */
     113             : 
     114           5 : OGRLinearRing &OGRLinearRing::operator=(const OGRLinearRing &other)
     115             : {
     116           5 :     if (this != &other)
     117             :     {
     118           4 :         OGRLineString::operator=(other);
     119             :     }
     120           5 :     return *this;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                          getGeometryName()                           */
     125             : /************************************************************************/
     126             : 
     127      115594 : const char *OGRLinearRing::getGeometryName() const
     128             : 
     129             : {
     130      115594 :     return "LINEARRING";
     131             : }
     132             : 
     133             : /************************************************************************/
     134             : /*                              WkbSize()                               */
     135             : /*                                                                      */
     136             : /*      Disable this method.                                            */
     137             : /************************************************************************/
     138             : 
     139        4652 : size_t OGRLinearRing::WkbSize() const
     140             : 
     141             : {
     142        4652 :     return 0;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                           importFromWkb()                            */
     147             : /*                                                                      */
     148             : /*      Disable method for this class.                                  */
     149             : /************************************************************************/
     150             : 
     151           0 : OGRErr OGRLinearRing::importFromWkb(const unsigned char * /*pabyData*/,
     152             :                                     size_t /*nSize*/,
     153             :                                     OGRwkbVariant /*eWkbVariant*/,
     154             :                                     size_t & /* nBytesConsumedOut */)
     155             : 
     156             : {
     157           0 :     return OGRERR_UNSUPPORTED_OPERATION;
     158             : }
     159             : 
     160             : /************************************************************************/
     161             : /*                            exportToWkb()                             */
     162             : /*                                                                      */
     163             : /*      Disable method for this class.                                  */
     164             : /************************************************************************/
     165             : 
     166         834 : OGRErr OGRLinearRing::exportToWkb(CPL_UNUSED unsigned char *pabyData,
     167             :                                   CPL_UNUSED const OGRwkbExportOptions *) const
     168             : 
     169             : {
     170         834 :     return OGRERR_UNSUPPORTED_OPERATION;
     171             : }
     172             : 
     173             : /************************************************************************/
     174             : /*                           _importFromWkb()                           */
     175             : /*                                                                      */
     176             : /*      Helper method for OGRPolygon.  NOT A NORMAL importFromWkb()     */
     177             : /*      method.                                                         */
     178             : /************************************************************************/
     179             : 
     180             : //! @cond Doxygen_Suppress
     181       40275 : OGRErr OGRLinearRing::_importFromWkb(OGRwkbByteOrder eByteOrder, int _flags,
     182             :                                      const unsigned char *pabyData,
     183             :                                      size_t nBytesAvailable,
     184             :                                      size_t &nBytesConsumedOut)
     185             : 
     186             : {
     187       40275 :     nBytesConsumedOut = 0;
     188       40275 :     if (nBytesAvailable < 4 && nBytesAvailable != static_cast<size_t>(-1))
     189          10 :         return OGRERR_NOT_ENOUGH_DATA;
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      Get the vertex count.                                           */
     193             :     /* -------------------------------------------------------------------- */
     194       40265 :     int nNewNumPoints = 0;
     195             : 
     196       40265 :     memcpy(&nNewNumPoints, pabyData, 4);
     197             : 
     198       40265 :     if (OGR_SWAP(eByteOrder))
     199          72 :         nNewNumPoints = CPL_SWAP32(nNewNumPoints);
     200             : 
     201             :     // Check if the wkb stream buffer is big enough to store
     202             :     // fetched number of points.
     203             :     // 16, 24, or 32 - size of point structure.
     204       40265 :     size_t nPointSize = 0;
     205       40265 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     206       30302 :         nPointSize = 32;
     207        9963 :     else if ((_flags & OGR_G_3D) || (_flags & OGR_G_MEASURED))
     208        1927 :         nPointSize = 24;
     209             :     else
     210        8036 :         nPointSize = 16;
     211             : 
     212       80482 :     if (nNewNumPoints < 0 ||
     213       40216 :         static_cast<size_t>(nNewNumPoints) >
     214       40216 :             std::numeric_limits<size_t>::max() / nPointSize)
     215             :     {
     216          49 :         return OGRERR_CORRUPT_DATA;
     217             :     }
     218       40217 :     const size_t nBufferMinSize = nPointSize * nNewNumPoints;
     219       40217 :     if (nBytesAvailable != static_cast<size_t>(-1) &&
     220       40203 :         nBufferMinSize > nBytesAvailable - 4)
     221             :     {
     222         970 :         CPLError(CE_Failure, CPLE_AppDefined,
     223             :                  "Length of input WKB is too small");
     224         970 :         return OGRERR_NOT_ENOUGH_DATA;
     225             :     }
     226             : 
     227             :     // (Re)Allocation of paoPoints buffer.
     228       39247 :     setNumPoints(nNewNumPoints, FALSE);
     229             : 
     230       39246 :     if (_flags & OGR_G_3D)
     231       31102 :         Make3D();
     232             :     else
     233        8144 :         Make2D();
     234             : 
     235       39245 :     if (_flags & OGR_G_MEASURED)
     236       29395 :         AddM();
     237             :     else
     238        9850 :         RemoveM();
     239             : 
     240       39245 :     nBytesConsumedOut = 4 + nPointCount * nPointSize;
     241             : 
     242             :     /* -------------------------------------------------------------------- */
     243             :     /*      Get the vertices                                                */
     244             :     /* -------------------------------------------------------------------- */
     245       39245 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
     246             :     {
     247      141216 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     248             :         {
     249      111931 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 32 * i, 8);
     250      111931 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 32 * i + 8, 8);
     251      111931 :             memcpy(padfZ + i, pabyData + 4 + 32 * i + 16, 8);
     252      111931 :             memcpy(padfM + i, pabyData + 4 + 32 * i + 24, 8);
     253       29285 :         }
     254             :     }
     255        9960 :     else if (flags & OGR_G_MEASURED)
     256             :     {
     257         613 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     258             :         {
     259         503 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 24 * i, 8);
     260         503 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 24 * i + 8, 8);
     261         503 :             memcpy(padfM + i, pabyData + 4 + 24 * i + 16, 8);
     262             :         }
     263             :     }
     264        9850 :     else if (flags & OGR_G_3D)
     265             :     {
     266       41499 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     267             :         {
     268       39682 :             memcpy(&(paoPoints[i].x), pabyData + 4 + 24 * i, 8);
     269       39682 :             memcpy(&(paoPoints[i].y), pabyData + 4 + 24 * i + 8, 8);
     270       39682 :             memcpy(padfZ + i, pabyData + 4 + 24 * i + 16, 8);
     271             :         }
     272             :     }
     273        8033 :     else if (nPointCount != 0)
     274             :     {
     275        8032 :         memcpy(paoPoints, pabyData + 4, 16 * static_cast<size_t>(nPointCount));
     276             :     }
     277             : 
     278             :     /* -------------------------------------------------------------------- */
     279             :     /*      Byte swap if needed.                                            */
     280             :     /* -------------------------------------------------------------------- */
     281       39245 :     if (OGR_SWAP(eByteOrder))
     282             :     {
     283         420 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     284             :         {
     285         348 :             CPL_SWAPDOUBLE(&(paoPoints[i].x));
     286         348 :             CPL_SWAPDOUBLE(&(paoPoints[i].y));
     287             : 
     288         348 :             if (flags & OGR_G_3D)
     289             :             {
     290          81 :                 CPL_SWAPDOUBLE(padfZ + i);
     291             :             }
     292         348 :             if (flags & OGR_G_MEASURED)
     293             :             {
     294           0 :                 CPL_SWAPDOUBLE(padfM + i);
     295             :             }
     296             :         }
     297             :     }
     298             : 
     299       39245 :     return OGRERR_NONE;
     300             : }
     301             : 
     302             : /************************************************************************/
     303             : /*                            _exportToWkb()                            */
     304             : /*                                                                      */
     305             : /*      Helper method for OGRPolygon.  THIS IS NOT THE NORMAL           */
     306             : /*      exportToWkb() METHOD.                                           */
     307             : /************************************************************************/
     308             : 
     309       97405 : OGRErr OGRLinearRing::_exportToWkb(int _flags, unsigned char *pabyData,
     310             :                                    const OGRwkbExportOptions *psOptions) const
     311             : 
     312             : {
     313             : 
     314             :     /* -------------------------------------------------------------------- */
     315             :     /*      Copy in the raw data.                                           */
     316             :     /* -------------------------------------------------------------------- */
     317       97405 :     memcpy(pabyData, &nPointCount, 4);
     318             : 
     319             :     /* -------------------------------------------------------------------- */
     320             :     /*      Copy in the raw data.                                           */
     321             :     /* -------------------------------------------------------------------- */
     322       97405 :     size_t nWords = 0;
     323       97405 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     324             :     {
     325       13165 :         nWords = 4 * static_cast<size_t>(nPointCount);
     326       63226 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     327             :         {
     328       50061 :             memcpy(pabyData + 4 + i * 32, &(paoPoints[i].x), 8);
     329       50061 :             memcpy(pabyData + 4 + i * 32 + 8, &(paoPoints[i].y), 8);
     330       50061 :             if (padfZ == nullptr)
     331           0 :                 memset(pabyData + 4 + i * 32 + 16, 0, 8);
     332             :             else
     333       50061 :                 memcpy(pabyData + 4 + i * 32 + 16, padfZ + i, 8);
     334       50061 :             if (padfM == nullptr)
     335           0 :                 memset(pabyData + 4 + i * 32 + 24, 0, 8);
     336             :             else
     337       50061 :                 memcpy(pabyData + 4 + i * 32 + 24, padfM + i, 8);
     338             :         }
     339       13165 :         OGRRoundCoordinatesIEEE754XYValues<32>(
     340       13165 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     341       13165 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nZBitPrecision,
     342             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     343       13165 :                                        nPointCount);
     344       13165 :         OGRRoundCoordinatesIEEE754<32>(psOptions->sPrecision.nMBitPrecision,
     345             :                                        pabyData + 4 + 3 * sizeof(uint64_t),
     346       13165 :                                        nPointCount);
     347             :     }
     348       84240 :     else if (_flags & OGR_G_MEASURED)
     349             :     {
     350          49 :         nWords = 3 * static_cast<size_t>(nPointCount);
     351         264 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     352             :         {
     353         215 :             memcpy(pabyData + 4 + i * 24, &(paoPoints[i].x), 8);
     354         215 :             memcpy(pabyData + 4 + i * 24 + 8, &(paoPoints[i].y), 8);
     355         215 :             if (padfM == nullptr)
     356           0 :                 memset(pabyData + 4 + i * 24 + 16, 0, 8);
     357             :             else
     358         215 :                 memcpy(pabyData + 4 + i * 24 + 16, padfM + i, 8);
     359             :         }
     360          49 :         OGRRoundCoordinatesIEEE754XYValues<24>(
     361          49 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     362          49 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nMBitPrecision,
     363             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     364          49 :                                        nPointCount);
     365             :     }
     366       84191 :     else if (_flags & OGR_G_3D)
     367             :     {
     368        3655 :         nWords = 3 * static_cast<size_t>(nPointCount);
     369       53178 :         for (size_t i = 0; i < static_cast<size_t>(nPointCount); i++)
     370             :         {
     371       49523 :             memcpy(pabyData + 4 + i * 24, &(paoPoints[i].x), 8);
     372       49523 :             memcpy(pabyData + 4 + i * 24 + 8, &(paoPoints[i].y), 8);
     373       49523 :             if (padfZ == nullptr)
     374           0 :                 memset(pabyData + 4 + i * 24 + 16, 0, 8);
     375             :             else
     376       49523 :                 memcpy(pabyData + 4 + i * 24 + 16, padfZ + i, 8);
     377             :         }
     378        3655 :         OGRRoundCoordinatesIEEE754XYValues<24>(
     379        3655 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     380        3655 :         OGRRoundCoordinatesIEEE754<24>(psOptions->sPrecision.nZBitPrecision,
     381             :                                        pabyData + 4 + 2 * sizeof(uint64_t),
     382        3655 :                                        nPointCount);
     383             :     }
     384             :     else
     385             :     {
     386       80536 :         nWords = 2 * static_cast<size_t>(nPointCount);
     387       80536 :         memcpy(pabyData + 4, paoPoints, 16 * static_cast<size_t>(nPointCount));
     388       80536 :         OGRRoundCoordinatesIEEE754XYValues<16>(
     389       80536 :             psOptions->sPrecision.nXYBitPrecision, pabyData + 4, nPointCount);
     390             :     }
     391             : 
     392             :     /* -------------------------------------------------------------------- */
     393             :     /*      Swap if needed.                                                 */
     394             :     /* -------------------------------------------------------------------- */
     395       97403 :     if (OGR_SWAP(psOptions->eByteOrder))
     396             :     {
     397          18 :         const int nCount = CPL_SWAP32(nPointCount);
     398          18 :         memcpy(pabyData, &nCount, 4);
     399             : 
     400         229 :         for (size_t i = 0; i < nWords; i++)
     401             :         {
     402         211 :             CPL_SWAPDOUBLE(pabyData + 4 + 8 * i);
     403             :         }
     404             :     }
     405             : 
     406       97403 :     return OGRERR_NONE;
     407             : }
     408             : 
     409             : /************************************************************************/
     410             : /*                              _WkbSize()                              */
     411             : /*                                                                      */
     412             : /*      Helper method for OGRPolygon.  NOT THE NORMAL WkbSize() METHOD. */
     413             : /************************************************************************/
     414             : 
     415      214241 : size_t OGRLinearRing::_WkbSize(int _flags) const
     416             : 
     417             : {
     418      214241 :     if ((_flags & OGR_G_3D) && (_flags & OGR_G_MEASURED))
     419       38391 :         return 4 + 32 * static_cast<size_t>(nPointCount);
     420      175850 :     else if ((_flags & OGR_G_3D) || (_flags & OGR_G_MEASURED))
     421        9581 :         return 4 + 24 * static_cast<size_t>(nPointCount);
     422             :     else
     423      166269 :         return 4 + 16 * static_cast<size_t>(nPointCount);
     424             : }
     425             : 
     426             : //! @endcond
     427             : 
     428             : /************************************************************************/
     429             : /*                               clone()                                */
     430             : /*                                                                      */
     431             : /*      We override the OGRCurve clone() to ensure that we get the      */
     432             : /*      correct virtual table.                                          */
     433             : /************************************************************************/
     434             : 
     435      156286 : OGRLinearRing *OGRLinearRing::clone() const
     436             : 
     437             : {
     438      156286 :     OGRLinearRing *poNewLinearRing = new OGRLinearRing();
     439      156286 :     poNewLinearRing->assignSpatialReference(getSpatialReference());
     440             : 
     441      156285 :     poNewLinearRing->setPoints(nPointCount, paoPoints, padfZ, padfM);
     442      156285 :     poNewLinearRing->flags = flags;
     443             : 
     444      156285 :     return poNewLinearRing;
     445             : }
     446             : 
     447             : /************************************************************************/
     448             : /*                             reverseWindingOrder()                    */
     449             : /************************************************************************/
     450             : 
     451             : /** Reverse order of points.
     452             :  */
     453          43 : void OGRLinearRing::reverseWindingOrder()
     454             : 
     455             : {
     456          86 :     OGRPoint pointA;
     457          86 :     OGRPoint pointB;
     458             : 
     459         329 :     for (int i = 0; i < nPointCount / 2; i++)
     460             :     {
     461         286 :         getPoint(i, &pointA);
     462         286 :         const int pos = nPointCount - i - 1;
     463         286 :         getPoint(pos, &pointB);
     464         286 :         setPoint(i, &pointB);
     465         286 :         setPoint(pos, &pointA);
     466             :     }
     467          43 : }
     468             : 
     469             : /************************************************************************/
     470             : /*                             closeRing()                              */
     471             : /************************************************************************/
     472             : 
     473        7413 : void OGRLinearRing::closeRings()
     474             : 
     475             : {
     476        7413 :     if (nPointCount < 2)
     477           3 :         return;
     478             : 
     479       10870 :     if (getX(0) != getX(nPointCount - 1) || getY(0) != getY(nPointCount - 1) ||
     480        3460 :         getZ(0) != getZ(nPointCount - 1))
     481             :     {
     482        7904 :         OGRPoint oFirstPoint;
     483        3952 :         getPoint(0, &oFirstPoint);
     484        3952 :         addPoint(&oFirstPoint);
     485             :     }
     486             : }
     487             : 
     488             : /************************************************************************/
     489             : /*                              isPointInRing()                         */
     490             : /************************************************************************/
     491             : 
     492             : /** Returns whether the point is inside the ring.
     493             :  * @param poPoint point
     494             :  * @param bTestEnvelope set to TRUE if the presence of the point inside the
     495             :  *                      ring envelope must be checked first.
     496             :  * @return TRUE or FALSE.
     497             :  */
     498     2617470 : OGRBoolean OGRLinearRing::isPointInRing(const OGRPoint *poPoint,
     499             :                                         int bTestEnvelope) const
     500             : {
     501     2617470 :     if (nullptr == poPoint)
     502             :     {
     503           0 :         CPLDebug("OGR",
     504             :                  "OGRLinearRing::isPointInRing(const OGRPoint* poPoint) - "
     505             :                  "passed point is NULL!");
     506           0 :         return FALSE;
     507             :     }
     508     2617470 :     if (poPoint->IsEmpty())
     509             :     {
     510           1 :         return FALSE;
     511             :     }
     512             : 
     513     2617470 :     const int iNumPoints = getNumPoints();
     514             : 
     515             :     // Simple validation
     516     2617470 :     if (iNumPoints < 4)
     517           0 :         return FALSE;
     518             : 
     519     2617470 :     const double dfTestX = poPoint->getX();
     520     2617470 :     const double dfTestY = poPoint->getY();
     521             : 
     522             :     // Fast test if point is inside extent of the ring.
     523     2617470 :     if (bTestEnvelope)
     524             :     {
     525     2616910 :         OGREnvelope extent;
     526     2616910 :         getEnvelope(&extent);
     527     2616910 :         if (!(dfTestX >= extent.MinX && dfTestX <= extent.MaxX &&
     528     1128960 :               dfTestY >= extent.MinY && dfTestY <= extent.MaxY))
     529             :         {
     530     2333250 :             return FALSE;
     531             :         }
     532             :     }
     533             : 
     534             :     // For every point p in ring,
     535             :     // test if ray starting from given point crosses segment (p - 1, p)
     536      284221 :     int iNumCrossings = 0;
     537             : 
     538      284221 :     double prev_diff_x = getX(0) - dfTestX;
     539      284221 :     double prev_diff_y = getY(0) - dfTestY;
     540             : 
     541     1485280 :     for (int iPoint = 1; iPoint < iNumPoints; iPoint++)
     542             :     {
     543     1201060 :         const double x1 = getX(iPoint) - dfTestX;
     544     1201060 :         const double y1 = getY(iPoint) - dfTestY;
     545             : 
     546     1201060 :         const double x2 = prev_diff_x;
     547     1201060 :         const double y2 = prev_diff_y;
     548             : 
     549     1201060 :         if (((y1 > 0) && (y2 <= 0)) || ((y2 > 0) && (y1 <= 0)))
     550             :         {
     551             :             // Check if ray intersects with segment of the ring
     552      563070 :             const double dfIntersection = (x1 * y2 - x2 * y1) / (y2 - y1);
     553      563070 :             if (0.0 < dfIntersection)
     554             :             {
     555             :                 // Count intersections
     556      276115 :                 iNumCrossings++;
     557             :             }
     558             :         }
     559             : 
     560     1201060 :         prev_diff_x = x1;
     561     1201060 :         prev_diff_y = y1;
     562             :     }
     563             : 
     564             :     // If iNumCrossings number is even, given point is outside the ring,
     565             :     // when the crossings number is odd, the point is inside the ring.
     566      284221 :     return iNumCrossings % 2;  // OGRBoolean
     567             : }
     568             : 
     569             : /************************************************************************/
     570             : /*                       isPointOnRingBoundary()                        */
     571             : /************************************************************************/
     572             : 
     573             : /** Returns whether the point is on the ring boundary.
     574             :  * @param poPoint point
     575             :  * @param bTestEnvelope set to TRUE if the presence of the point inside the
     576             :  *                      ring envelope must be checked first.
     577             :  * @return TRUE or FALSE.
     578             :  */
     579     2375790 : OGRBoolean OGRLinearRing::isPointOnRingBoundary(const OGRPoint *poPoint,
     580             :                                                 int bTestEnvelope) const
     581             : {
     582     2375790 :     if (nullptr == poPoint)
     583             :     {
     584           0 :         CPLDebug("OGR", "OGRLinearRing::isPointOnRingBoundary(const OGRPoint* "
     585             :                         "poPoint) - passed point is NULL!");
     586           0 :         return 0;
     587             :     }
     588             : 
     589     2375790 :     const int iNumPoints = getNumPoints();
     590             : 
     591             :     // Simple validation.
     592     2375790 :     if (iNumPoints < 4)
     593           0 :         return 0;
     594             : 
     595     2375790 :     const double dfTestX = poPoint->getX();
     596     2375790 :     const double dfTestY = poPoint->getY();
     597             : 
     598             :     // Fast test if point is inside extent of the ring
     599     2375790 :     if (bTestEnvelope)
     600             :     {
     601     2375180 :         OGREnvelope extent;
     602     2375180 :         getEnvelope(&extent);
     603     2375180 :         if (!(dfTestX >= extent.MinX && dfTestX <= extent.MaxX &&
     604      887238 :               dfTestY >= extent.MinY && dfTestY <= extent.MaxY))
     605             :         {
     606     2333240 :             return 0;
     607             :         }
     608             :     }
     609             : 
     610       42544 :     double prev_diff_x = dfTestX - getX(0);
     611       42544 :     double prev_diff_y = dfTestY - getY(0);
     612             : 
     613      244410 :     for (int iPoint = 1; iPoint < iNumPoints; iPoint++)
     614             :     {
     615      203500 :         const double dx1 = dfTestX - getX(iPoint);
     616      203500 :         const double dy1 = dfTestY - getY(iPoint);
     617             : 
     618      203500 :         const double dx2 = prev_diff_x;
     619      203500 :         const double dy2 = prev_diff_y;
     620             : 
     621             :         // If the point is on the segment, return immediately.
     622             :         // FIXME? If the test point is not exactly identical to one of
     623             :         // the vertices of the ring, but somewhere on a segment, there's
     624             :         // little chance that we get 0. So that should be tested against some
     625             :         // epsilon.
     626             : 
     627      203500 :         if (dx1 * dy2 - dx2 * dy1 == 0)
     628             :         {
     629             :             // If iPoint and iPointPrev are the same, go on.
     630        1993 :             if (!(dx1 == dx2 && dy1 == dy2))
     631             :             {
     632        1709 :                 const double dx_segment = getX(iPoint) - getX(iPoint - 1);
     633        1709 :                 const double dy_segment = getY(iPoint) - getY(iPoint - 1);
     634        1709 :                 const double crossproduct = dx2 * dx_segment + dy2 * dy_segment;
     635        1709 :                 if (crossproduct >= 0)
     636             :                 {
     637        1707 :                     const double sq_length_seg =
     638        1707 :                         dx_segment * dx_segment + dy_segment * dy_segment;
     639        1707 :                     if (crossproduct <= sq_length_seg)
     640             :                     {
     641        1634 :                         return 1;
     642             :                     }
     643             :                 }
     644             :             }
     645             :         }
     646             : 
     647      201866 :         prev_diff_x = dx1;
     648      201866 :         prev_diff_y = dy1;
     649             :     }
     650             : 
     651       40910 :     return 0;
     652             : }
     653             : 
     654             : /************************************************************************/
     655             : /*                             transform()                              */
     656             : /************************************************************************/
     657             : 
     658         604 : OGRErr OGRLinearRing::transform(OGRCoordinateTransformation *poCT)
     659             : 
     660             : {
     661         604 :     const bool bIsClosed = getNumPoints() > 2 && CPL_TO_BOOL(get_IsClosed());
     662         604 :     OGRErr eErr = OGRLineString::transform(poCT);
     663         604 :     if (bIsClosed && eErr == OGRERR_NONE && !get_IsClosed())
     664             :     {
     665           0 :         CPLDebug("OGR", "Linearring is not closed after coordinate "
     666             :                         "transformation. Forcing last point to be identical to "
     667             :                         "first one");
     668             :         // Force last point to be identical to first point.
     669             :         // This is a safety belt in case the reprojection of the same coordinate
     670             :         // isn't perfectly stable. This can for example happen in very rare
     671             :         // cases when reprojecting a cutline with a RPC transform with a DEM
     672             :         // that is a VRT whose sources are resampled...
     673           0 :         OGRPoint oStartPoint;
     674           0 :         StartPoint(&oStartPoint);
     675             : 
     676           0 :         setPoint(getNumPoints() - 1, &oStartPoint);
     677             :     }
     678         604 :     return eErr;
     679             : }
     680             : 
     681             : /************************************************************************/
     682             : /*                          CastToLineString()                          */
     683             : /************************************************************************/
     684             : 
     685             : /**
     686             :  * \brief Cast to line string.
     687             :  *
     688             :  * The passed in geometry is consumed and a new one returned .
     689             :  *
     690             :  * @param poLR the input geometry - ownership is passed to the method.
     691             :  * @return new geometry.
     692             :  */
     693             : 
     694          66 : OGRLineString *OGRLinearRing::CastToLineString(OGRLinearRing *poLR)
     695             : {
     696          66 :     return TransferMembersAndDestroy(poLR, new OGRLineString());
     697             : }
     698             : 
     699             : //! @cond Doxygen_Suppress
     700             : /************************************************************************/
     701             : /*                     GetCasterToLineString()                          */
     702             : /************************************************************************/
     703             : 
     704          40 : OGRLineString *OGRLinearRing::CasterToLineString(OGRCurve *poCurve)
     705             : {
     706          40 :     return OGRLinearRing::CastToLineString(poCurve->toLinearRing());
     707             : }
     708             : 
     709          40 : OGRCurveCasterToLineString OGRLinearRing::GetCasterToLineString() const
     710             : {
     711          40 :     return OGRLinearRing::CasterToLineString;
     712             : }
     713             : 
     714             : /************************************************************************/
     715             : /*                        GetCasterToLinearRing()                       */
     716             : /************************************************************************/
     717             : 
     718           4 : static OGRLinearRing *CasterToLinearRing(OGRCurve *poCurve)
     719             : {
     720           4 :     return poCurve->toLinearRing();
     721             : }
     722             : 
     723           4 : OGRCurveCasterToLinearRing OGRLinearRing::GetCasterToLinearRing() const
     724             : {
     725           4 :     return ::CasterToLinearRing;
     726             : }
     727             : 
     728             : //! @endcond

Generated by: LCOV version 1.14