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
|