1 : /******************************************************************************
2 : * $Id: ogrpolygon.cpp 22466 2011-05-30 09:24:55Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: The OGRPolygon geometry class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
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 "ogr_geometry.h"
31 : #include "ogr_p.h"
32 : #include "ogr_geos.h"
33 : #include "ogr_api.h"
34 :
35 : CPL_CVSID("$Id: ogrpolygon.cpp 22466 2011-05-30 09:24:55Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRPolygon() */
39 : /************************************************************************/
40 :
41 : /**
42 : * \brief Create an empty polygon.
43 : */
44 :
45 230725 : OGRPolygon::OGRPolygon()
46 :
47 : {
48 230725 : nRingCount = 0;
49 230725 : papoRings = NULL;
50 230725 : }
51 :
52 : /************************************************************************/
53 : /* ~OGRPolygon() */
54 : /************************************************************************/
55 :
56 230725 : OGRPolygon::~OGRPolygon()
57 :
58 : {
59 230725 : empty();
60 230725 : }
61 :
62 : /************************************************************************/
63 : /* clone() */
64 : /************************************************************************/
65 :
66 104372 : OGRGeometry *OGRPolygon::clone() const
67 :
68 : {
69 : OGRPolygon *poNewPolygon;
70 :
71 104372 : poNewPolygon = new OGRPolygon;
72 104372 : poNewPolygon->assignSpatialReference( getSpatialReference() );
73 :
74 209122 : for( int i = 0; i < nRingCount; i++ )
75 : {
76 104750 : poNewPolygon->addRing( papoRings[i] );
77 : }
78 :
79 104372 : return poNewPolygon;
80 : }
81 :
82 : /************************************************************************/
83 : /* empty() */
84 : /************************************************************************/
85 :
86 256071 : void OGRPolygon::empty()
87 :
88 : {
89 256071 : if( papoRings != NULL )
90 : {
91 462226 : for( int i = 0; i < nRingCount; i++ )
92 : {
93 232013 : delete papoRings[i];
94 : }
95 230213 : OGRFree( papoRings );
96 : }
97 :
98 256071 : papoRings = NULL;
99 256071 : nRingCount = 0;
100 256071 : }
101 :
102 : /************************************************************************/
103 : /* getGeometryType() */
104 : /************************************************************************/
105 :
106 185795 : OGRwkbGeometryType OGRPolygon::getGeometryType() const
107 :
108 : {
109 185795 : if( getCoordinateDimension() == 3 )
110 3094 : return wkbPolygon25D;
111 : else
112 182701 : return wkbPolygon;
113 : }
114 :
115 : /************************************************************************/
116 : /* getDimension() */
117 : /************************************************************************/
118 :
119 0 : int OGRPolygon::getDimension() const
120 :
121 : {
122 0 : return 2;
123 : }
124 :
125 : /************************************************************************/
126 : /* flattenTo2D() */
127 : /************************************************************************/
128 :
129 26 : void OGRPolygon::flattenTo2D()
130 :
131 : {
132 52 : for( int iRing = 0; iRing < nRingCount; iRing++ )
133 26 : papoRings[iRing]->flattenTo2D();
134 :
135 26 : nCoordDimension = 2;
136 26 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 1504 : const char * OGRPolygon::getGeometryName() const
143 :
144 : {
145 1504 : return "POLYGON";
146 : }
147 :
148 : /************************************************************************/
149 : /* getExteriorRing() */
150 : /************************************************************************/
151 :
152 : /**
153 : * \brief Fetch reference to external polygon ring.
154 : *
155 : * Note that the returned ring pointer is to an internal data object of
156 : * the OGRPolygon. It should not be modified or deleted by the application,
157 : * and the pointer is only valid till the polygon is next modified. Use
158 : * the OGRGeometry::clone() method to make a separate copy within the
159 : * application.
160 : *
161 : * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
162 : *
163 : * @return pointer to external ring. May be NULL if the OGRPolygon is empty.
164 : */
165 :
166 220719 : OGRLinearRing *OGRPolygon::getExteriorRing()
167 :
168 : {
169 220719 : if( nRingCount > 0 )
170 220681 : return papoRings[0];
171 : else
172 38 : return NULL;
173 : }
174 :
175 161914 : const OGRLinearRing *OGRPolygon::getExteriorRing() const
176 :
177 : {
178 161914 : if( nRingCount > 0 )
179 161846 : return papoRings[0];
180 : else
181 68 : return NULL;
182 : }
183 :
184 : /************************************************************************/
185 : /* getNumInteriorRings() */
186 : /************************************************************************/
187 :
188 : /**
189 : * \brief Fetch the number of internal rings.
190 : *
191 : * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
192 : *
193 : * @return count of internal rings, zero or more.
194 : */
195 :
196 :
197 191847 : int OGRPolygon::getNumInteriorRings() const
198 :
199 : {
200 191847 : if( nRingCount > 0 )
201 191843 : return nRingCount-1;
202 : else
203 4 : return 0;
204 : }
205 :
206 : /************************************************************************/
207 : /* getInteriorRing() */
208 : /************************************************************************/
209 :
210 : /**
211 : * \brief Fetch reference to indicated internal ring.
212 : *
213 : * Note that the returned ring pointer is to an internal data object of
214 : * the OGRPolygon. It should not be modified or deleted by the application,
215 : * and the pointer is only valid till the polygon is next modified. Use
216 : * the OGRGeometry::clone() method to make a separate copy within the
217 : * application.
218 : *
219 : * Relates to the SFCOM IPolygon::get_InternalRing() method.
220 : *
221 : * @param iRing internal ring index from 0 to getNumInternalRings() - 1.
222 : *
223 : * @return pointer to external ring. May be NULL if the OGRPolygon is empty.
224 : */
225 :
226 476 : OGRLinearRing *OGRPolygon::getInteriorRing( int iRing )
227 :
228 : {
229 476 : if( iRing < 0 || iRing >= nRingCount-1 )
230 0 : return NULL;
231 : else
232 476 : return papoRings[iRing+1];
233 : }
234 :
235 14 : const OGRLinearRing *OGRPolygon::getInteriorRing( int iRing ) const
236 :
237 : {
238 14 : if( iRing < 0 || iRing >= nRingCount-1 )
239 0 : return NULL;
240 : else
241 14 : return papoRings[iRing+1];
242 : }
243 :
244 : /************************************************************************/
245 : /* addRing() */
246 : /************************************************************************/
247 :
248 : /**
249 : * \brief Add a ring to a polygon.
250 : *
251 : * If the polygon has no external ring (it is empty) this will be used as
252 : * the external ring, otherwise it is used as an internal ring. The passed
253 : * OGRLinearRing remains the responsibility of the caller (an internal copy
254 : * is made).
255 : *
256 : * This method has no SFCOM analog.
257 : *
258 : * @param poNewRing ring to be added to the polygon.
259 : */
260 :
261 130170 : void OGRPolygon::addRing( OGRLinearRing * poNewRing )
262 :
263 : {
264 : papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
265 130170 : sizeof(void*) * (nRingCount+1));
266 :
267 130170 : papoRings[nRingCount] = new OGRLinearRing( poNewRing );
268 :
269 130170 : nRingCount++;
270 :
271 130170 : if( poNewRing->getCoordinateDimension() == 3 )
272 360 : nCoordDimension = 3;
273 130170 : }
274 :
275 : /************************************************************************/
276 : /* addRingDirectly() */
277 : /************************************************************************/
278 :
279 : /**
280 : * \brief Add a ring to a polygon.
281 : *
282 : * If the polygon has no external ring (it is empty) this will be used as
283 : * the external ring, otherwise it is used as an internal ring. Ownership
284 : * of the passed ring is assumed by the OGRPolygon, but otherwise this
285 : * method operates the same as OGRPolygon::AddRing().
286 : *
287 : * This method has no SFCOM analog.
288 : *
289 : * @param poNewRing ring to be added to the polygon.
290 : */
291 :
292 74325 : void OGRPolygon::addRingDirectly( OGRLinearRing * poNewRing )
293 :
294 : {
295 : papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
296 74325 : sizeof(void*) * (nRingCount+1));
297 :
298 74325 : papoRings[nRingCount] = poNewRing;
299 :
300 74325 : nRingCount++;
301 :
302 :
303 74325 : if( poNewRing->getCoordinateDimension() == 3 )
304 10616 : nCoordDimension = 3;
305 74325 : }
306 :
307 : /************************************************************************/
308 : /* WkbSize() */
309 : /* */
310 : /* Return the size of this object in well known binary */
311 : /* representation including the byte order, and type information. */
312 : /************************************************************************/
313 :
314 5464 : int OGRPolygon::WkbSize() const
315 :
316 : {
317 5464 : int nSize = 9;
318 5464 : int b3D = getCoordinateDimension() == 3;
319 :
320 11000 : for( int i = 0; i < nRingCount; i++ )
321 : {
322 5536 : nSize += papoRings[i]->_WkbSize( b3D );
323 : }
324 :
325 5464 : return nSize;
326 : }
327 :
328 : /************************************************************************/
329 : /* importFromWkb() */
330 : /* */
331 : /* Initialize from serialized stream in well known binary */
332 : /* format. */
333 : /************************************************************************/
334 :
335 2158 : OGRErr OGRPolygon::importFromWkb( unsigned char * pabyData,
336 : int nSize )
337 :
338 : {
339 : OGRwkbByteOrder eByteOrder;
340 : int nDataOffset, b3D;
341 :
342 2158 : if( nSize < 9 && nSize != -1 )
343 0 : return OGRERR_NOT_ENOUGH_DATA;
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Get the byte order byte. */
347 : /* -------------------------------------------------------------------- */
348 2158 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
349 2158 : if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
350 0 : return OGRERR_CORRUPT_DATA;
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Get the geometry feature type. For now we assume that */
354 : /* geometry type is between 0 and 255 so we only have to fetch */
355 : /* one byte. */
356 : /* -------------------------------------------------------------------- */
357 : #ifdef DEBUG
358 : OGRwkbGeometryType eGeometryType;
359 :
360 2158 : if( eByteOrder == wkbNDR )
361 2124 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
362 : else
363 34 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
364 :
365 2158 : if( eGeometryType != wkbPolygon )
366 0 : return OGRERR_CORRUPT_DATA;
367 : #endif
368 :
369 2158 : if( eByteOrder == wkbNDR )
370 2124 : b3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
371 : else
372 34 : b3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
373 :
374 2158 : if( b3D )
375 540 : nCoordDimension = 3;
376 : else
377 1618 : nCoordDimension = 2;
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Do we already have some rings? */
381 : /* -------------------------------------------------------------------- */
382 2158 : if( nRingCount != 0 )
383 : {
384 0 : for( int iRing = 0; iRing < nRingCount; iRing++ )
385 0 : delete papoRings[iRing];
386 :
387 0 : OGRFree( papoRings );
388 0 : papoRings = NULL;
389 : }
390 :
391 : /* -------------------------------------------------------------------- */
392 : /* Get the ring count. */
393 : /* -------------------------------------------------------------------- */
394 2158 : memcpy( &nRingCount, pabyData + 5, 4 );
395 :
396 2158 : if( OGR_SWAP( eByteOrder ) )
397 34 : nRingCount = CPL_SWAP32(nRingCount);
398 :
399 2158 : if (nRingCount < 0 || nRingCount > INT_MAX / 4)
400 : {
401 0 : nRingCount = 0;
402 0 : return OGRERR_CORRUPT_DATA;
403 : }
404 :
405 : /* Each ring has a minimum of 4 bytes (point count) */
406 2158 : if (nSize != -1 && nSize - 9 < nRingCount * 4)
407 : {
408 : CPLError( CE_Failure, CPLE_AppDefined,
409 0 : "Length of input WKB is too small" );
410 0 : nRingCount = 0;
411 0 : return OGRERR_NOT_ENOUGH_DATA;
412 : }
413 :
414 2158 : papoRings = (OGRLinearRing **) VSIMalloc2(sizeof(void*), nRingCount);
415 2158 : if (nRingCount != 0 && papoRings == NULL)
416 : {
417 0 : nRingCount = 0;
418 0 : return OGRERR_NOT_ENOUGH_MEMORY;
419 : }
420 :
421 2158 : nDataOffset = 9;
422 2158 : if( nSize != -1 )
423 2158 : nSize -= nDataOffset;
424 :
425 : /* -------------------------------------------------------------------- */
426 : /* Get the rings. */
427 : /* -------------------------------------------------------------------- */
428 4366 : for( int iRing = 0; iRing < nRingCount; iRing++ )
429 : {
430 : OGRErr eErr;
431 :
432 2208 : papoRings[iRing] = new OGRLinearRing();
433 6624 : eErr = papoRings[iRing]->_importFromWkb( eByteOrder, b3D,
434 : pabyData + nDataOffset,
435 8832 : nSize );
436 2208 : if( eErr != OGRERR_NONE )
437 : {
438 0 : delete papoRings[iRing];
439 0 : nRingCount = iRing;
440 0 : return eErr;
441 : }
442 :
443 2208 : if( nSize != -1 )
444 2208 : nSize -= papoRings[iRing]->_WkbSize( b3D );
445 :
446 2208 : nDataOffset += papoRings[iRing]->_WkbSize( b3D );
447 : }
448 :
449 2158 : return OGRERR_NONE;
450 : }
451 :
452 : /************************************************************************/
453 : /* exportToWkb() */
454 : /* */
455 : /* Build a well known binary representation of this object. */
456 : /************************************************************************/
457 :
458 4772 : OGRErr OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
459 : unsigned char * pabyData ) const
460 :
461 : {
462 : int nOffset;
463 4772 : int b3D = getCoordinateDimension() == 3;
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* Set the byte order. */
467 : /* -------------------------------------------------------------------- */
468 4772 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Set the geometry feature type. */
472 : /* -------------------------------------------------------------------- */
473 4772 : GUInt32 nGType = getGeometryType();
474 :
475 4772 : if( eByteOrder == wkbNDR )
476 4742 : nGType = CPL_LSBWORD32( nGType );
477 : else
478 30 : nGType = CPL_MSBWORD32( nGType );
479 :
480 4772 : memcpy( pabyData + 1, &nGType, 4 );
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* Copy in the raw data. */
484 : /* -------------------------------------------------------------------- */
485 4772 : if( OGR_SWAP( eByteOrder ) )
486 : {
487 : int nCount;
488 :
489 30 : nCount = CPL_SWAP32( nRingCount );
490 30 : memcpy( pabyData+5, &nCount, 4 );
491 : }
492 : else
493 : {
494 4742 : memcpy( pabyData+5, &nRingCount, 4 );
495 : }
496 :
497 4772 : nOffset = 9;
498 :
499 : /* ==================================================================== */
500 : /* Serialize each of the rings. */
501 : /* ==================================================================== */
502 9580 : for( int iRing = 0; iRing < nRingCount; iRing++ )
503 : {
504 14424 : papoRings[iRing]->_exportToWkb( eByteOrder, b3D,
505 19232 : pabyData + nOffset );
506 :
507 4808 : nOffset += papoRings[iRing]->_WkbSize(b3D);
508 : }
509 :
510 4772 : return OGRERR_NONE;
511 : }
512 :
513 : /************************************************************************/
514 : /* importFromWkt() */
515 : /* */
516 : /* Instantiate from well known text format. Currently this is */
517 : /* `POLYGON ((x y, x y, ...),(x y, ...),...)'. */
518 : /************************************************************************/
519 :
520 25296 : OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
521 :
522 : {
523 : char szToken[OGR_WKT_TOKEN_MAX];
524 25296 : const char *pszInput = *ppszInput;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Clear existing rings. */
528 : /* -------------------------------------------------------------------- */
529 25296 : empty();
530 :
531 : /* -------------------------------------------------------------------- */
532 : /* Read and verify the ``POLYGON'' keyword token. */
533 : /* -------------------------------------------------------------------- */
534 25296 : pszInput = OGRWktReadToken( pszInput, szToken );
535 :
536 25296 : if( !EQUAL(szToken,"POLYGON") )
537 0 : return OGRERR_CORRUPT_DATA;
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Check for EMPTY ... */
541 : /* -------------------------------------------------------------------- */
542 : const char *pszPreScan;
543 25296 : int bHasZ = FALSE, bHasM = FALSE;
544 :
545 25296 : pszPreScan = OGRWktReadToken( pszInput, szToken );
546 25296 : if( EQUAL(szToken,"EMPTY") )
547 : {
548 30 : *ppszInput = (char *) pszPreScan;
549 30 : empty();
550 30 : return OGRERR_NONE;
551 : }
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Check for Z, M or ZM. Will ignore the Measure */
555 : /* -------------------------------------------------------------------- */
556 25266 : else if( EQUAL(szToken,"Z") )
557 : {
558 30 : bHasZ = TRUE;
559 : }
560 25236 : else if( EQUAL(szToken,"M") )
561 : {
562 4 : bHasM = TRUE;
563 : }
564 25232 : else if( EQUAL(szToken,"ZM") )
565 : {
566 4 : bHasZ = TRUE;
567 4 : bHasM = TRUE;
568 : }
569 :
570 25266 : if (bHasZ || bHasM)
571 : {
572 38 : pszInput = pszPreScan;
573 38 : pszPreScan = OGRWktReadToken( pszInput, szToken );
574 38 : if( EQUAL(szToken,"EMPTY") )
575 : {
576 8 : *ppszInput = (char *) pszPreScan;
577 8 : empty();
578 : /* FIXME?: In theory we should store the dimension and M presence */
579 : /* if we want to allow round-trip with ExportToWKT v1.2 */
580 8 : return OGRERR_NONE;
581 : }
582 : }
583 :
584 25258 : if( !EQUAL(szToken,"(") )
585 8 : return OGRERR_CORRUPT_DATA;
586 :
587 25250 : if ( !bHasZ && !bHasM )
588 : {
589 : /* Test for old-style POLYGON(EMPTY) */
590 25224 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
591 25224 : if( EQUAL(szToken,"EMPTY") )
592 : {
593 14 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
594 :
595 14 : if( EQUAL(szToken,",") )
596 : {
597 : /* This is OK according to SFSQL SPEC. */
598 : }
599 8 : else if( !EQUAL(szToken,")") )
600 2 : return OGRERR_CORRUPT_DATA;
601 : else
602 : {
603 6 : *ppszInput = (char *) pszPreScan;
604 6 : empty();
605 6 : return OGRERR_NONE;
606 : }
607 : }
608 : }
609 :
610 : /* Skip first '(' */
611 25242 : pszInput = OGRWktReadToken( pszInput, szToken );
612 :
613 : /* ==================================================================== */
614 : /* Read each ring in turn. Note that we try to reuse the same */
615 : /* point list buffer from ring to ring to cut down on */
616 : /* allocate/deallocate overhead. */
617 : /* ==================================================================== */
618 25242 : OGRRawPoint *paoPoints = NULL;
619 25242 : int nMaxPoints = 0, nMaxRings = 0;
620 25242 : double *padfZ = NULL;
621 :
622 25242 : nCoordDimension = 2;
623 :
624 25300 : do
625 : {
626 25346 : int nPoints = 0;
627 :
628 25346 : const char* pszNext = OGRWktReadToken( pszInput, szToken );
629 25346 : if (EQUAL(szToken,"EMPTY"))
630 : {
631 : /* -------------------------------------------------------------------- */
632 : /* Do we need to grow the ring array? */
633 : /* -------------------------------------------------------------------- */
634 20 : if( nRingCount == nMaxRings )
635 : {
636 16 : nMaxRings = nMaxRings * 2 + 1;
637 : papoRings = (OGRLinearRing **)
638 16 : CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
639 : }
640 20 : papoRings[nRingCount] = new OGRLinearRing();
641 20 : nRingCount++;
642 :
643 20 : pszInput = OGRWktReadToken( pszNext, szToken );
644 20 : if ( !EQUAL(szToken, ",") )
645 10 : break;
646 :
647 10 : continue;
648 : }
649 :
650 : /* -------------------------------------------------------------------- */
651 : /* Read points for one ring from input. */
652 : /* -------------------------------------------------------------------- */
653 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
654 25326 : &nPoints );
655 :
656 25326 : if( pszInput == NULL || nPoints == 0 )
657 : {
658 36 : CPLFree( paoPoints );
659 36 : return OGRERR_CORRUPT_DATA;
660 : }
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Do we need to grow the ring array? */
664 : /* -------------------------------------------------------------------- */
665 25290 : if( nRingCount == nMaxRings )
666 : {
667 25278 : nMaxRings = nMaxRings * 2 + 1;
668 : papoRings = (OGRLinearRing **)
669 25278 : CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
670 : }
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Create the new ring, and assign to ring list. */
674 : /* -------------------------------------------------------------------- */
675 25290 : papoRings[nRingCount] = new OGRLinearRing();
676 : /* Ignore Z array when we have a POLYGON M */
677 25296 : if (bHasM && !bHasZ)
678 2 : papoRings[nRingCount]->setPoints( nPoints, paoPoints, NULL );
679 : else
680 25288 : papoRings[nRingCount]->setPoints( nPoints, paoPoints, padfZ );
681 :
682 25290 : nRingCount++;
683 :
684 25290 : if( padfZ && !(bHasM && !bHasZ) )
685 130 : nCoordDimension = 3;
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Read the delimeter following the ring. */
689 : /* -------------------------------------------------------------------- */
690 :
691 25290 : pszInput = OGRWktReadToken( pszInput, szToken );
692 25300 : } while( szToken[0] == ',' );
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* freak if we don't get a closing bracket. */
696 : /* -------------------------------------------------------------------- */
697 25206 : CPLFree( paoPoints );
698 25206 : CPLFree( padfZ );
699 :
700 25206 : if( szToken[0] != ')' )
701 8 : return OGRERR_CORRUPT_DATA;
702 :
703 25198 : *ppszInput = (char *) pszInput;
704 25198 : return OGRERR_NONE;
705 : }
706 :
707 : /************************************************************************/
708 : /* exportToWkt() */
709 : /* */
710 : /* Translate this structure into it's well known text format */
711 : /* equivelent. This could be made alot more CPU efficient! */
712 : /************************************************************************/
713 :
714 990 : OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
715 :
716 : {
717 : char **papszRings;
718 990 : int iRing, nCumulativeLength = 0, nNonEmptyRings = 0;
719 : OGRErr eErr;
720 990 : int bMustWriteComma = FALSE;
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* If we have no valid exterior ring, return POLYGON EMPTY. */
724 : /* -------------------------------------------------------------------- */
725 1912 : if (getExteriorRing() == NULL ||
726 922 : getExteriorRing()->IsEmpty())
727 : {
728 80 : *ppszDstText = CPLStrdup("POLYGON EMPTY");
729 80 : return OGRERR_NONE;
730 : }
731 :
732 : /* -------------------------------------------------------------------- */
733 : /* Build a list of strings containing the stuff for each ring. */
734 : /* -------------------------------------------------------------------- */
735 910 : papszRings = (char **) CPLCalloc(sizeof(char *),nRingCount);
736 :
737 1928 : for( iRing = 0; iRing < nRingCount; iRing++ )
738 : {
739 1018 : papoRings[iRing]->setCoordinateDimension( getCoordinateDimension() );
740 1018 : if( papoRings[iRing]->getNumPoints() == 0 )
741 : {
742 18 : papszRings[iRing] = NULL;
743 18 : continue;
744 : }
745 :
746 1000 : eErr = papoRings[iRing]->exportToWkt( &(papszRings[iRing]) );
747 1000 : if( eErr != OGRERR_NONE )
748 0 : goto error;
749 :
750 1000 : CPLAssert( EQUALN(papszRings[iRing],"LINEARRING (", 12) );
751 1000 : nCumulativeLength += strlen(papszRings[iRing] + 11);
752 :
753 1000 : nNonEmptyRings++;
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Allocate exactly the right amount of space for the */
758 : /* aggregated string. */
759 : /* -------------------------------------------------------------------- */
760 910 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nNonEmptyRings + 11);
761 :
762 910 : if( *ppszDstText == NULL )
763 : {
764 0 : eErr = OGRERR_NOT_ENOUGH_MEMORY;
765 0 : goto error;
766 : }
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Build up the string, freeing temporary strings as we go. */
770 : /* -------------------------------------------------------------------- */
771 910 : strcpy( *ppszDstText, "POLYGON (" );
772 910 : nCumulativeLength = strlen(*ppszDstText);
773 :
774 1928 : for( iRing = 0; iRing < nRingCount; iRing++ )
775 : {
776 1018 : if( papszRings[iRing] == NULL )
777 : {
778 18 : CPLDebug( "OGR", "OGRPolygon::exportToWkt() - skipping empty ring.");
779 18 : continue;
780 : }
781 :
782 1000 : if( bMustWriteComma )
783 90 : (*ppszDstText)[nCumulativeLength++] = ',';
784 1000 : bMustWriteComma = TRUE;
785 :
786 1000 : int nRingLen = strlen(papszRings[iRing] + 11);
787 1000 : memcpy( *ppszDstText + nCumulativeLength, papszRings[iRing] + 11, nRingLen );
788 1000 : nCumulativeLength += nRingLen;
789 1000 : VSIFree( papszRings[iRing] );
790 : }
791 :
792 910 : (*ppszDstText)[nCumulativeLength++] = ')';
793 910 : (*ppszDstText)[nCumulativeLength] = '\0';
794 :
795 910 : CPLFree( papszRings );
796 :
797 910 : return OGRERR_NONE;
798 :
799 : error:
800 0 : for( iRing = 0; iRing < nRingCount; iRing++ )
801 0 : CPLFree(papszRings[iRing]);
802 0 : CPLFree(papszRings);
803 0 : return eErr;
804 : }
805 :
806 : /************************************************************************/
807 : /* PointOnSurface() */
808 : /************************************************************************/
809 :
810 0 : int OGRPolygon::PointOnSurface( OGRPoint *poPoint ) const
811 :
812 : {
813 0 : if( poPoint == NULL )
814 0 : return OGRERR_FAILURE;
815 :
816 : #ifndef HAVE_GEOS
817 : return OGRERR_FAILURE;
818 : #else
819 0 : GEOSGeom hThisGeosGeom = NULL;
820 0 : GEOSGeom hOtherGeosGeom = NULL;
821 :
822 0 : hThisGeosGeom = exportToGEOS();
823 :
824 0 : if( hThisGeosGeom != NULL )
825 : {
826 0 : hOtherGeosGeom = GEOSPointOnSurface( hThisGeosGeom );
827 0 : GEOSGeom_destroy( hThisGeosGeom );
828 :
829 0 : if( hOtherGeosGeom == NULL )
830 0 : return OGRERR_FAILURE;
831 :
832 : OGRGeometry *poInsidePointGeom = (OGRGeometry *)
833 0 : OGRGeometryFactory::createFromGEOS( hOtherGeosGeom );
834 :
835 0 : GEOSGeom_destroy( hOtherGeosGeom );
836 :
837 0 : if (poInsidePointGeom == NULL)
838 0 : return OGRERR_FAILURE;
839 0 : if (wkbFlatten(poInsidePointGeom->getGeometryType()) != wkbPoint)
840 : {
841 0 : delete poInsidePointGeom;
842 0 : return OGRERR_FAILURE;
843 : }
844 :
845 0 : OGRPoint *poInsidePoint = (OGRPoint *) poInsidePointGeom;
846 0 : poPoint->setX( poInsidePoint->getX() );
847 0 : poPoint->setY( poInsidePoint->getY() );
848 :
849 0 : delete poInsidePointGeom;
850 :
851 0 : return OGRERR_NONE;
852 : }
853 : else
854 : {
855 0 : return OGRERR_FAILURE;
856 : }
857 : #endif /* HAVE_GEOS */
858 : }
859 :
860 :
861 : /************************************************************************/
862 : /* getEnvelope() */
863 : /************************************************************************/
864 :
865 112660 : void OGRPolygon::getEnvelope( OGREnvelope * psEnvelope ) const
866 :
867 : {
868 112660 : OGREnvelope oRingEnv;
869 112660 : int bExtentSet = FALSE;
870 :
871 225636 : for( int iRing = 0; iRing < nRingCount; iRing++ )
872 : {
873 112976 : if (!papoRings[iRing]->IsEmpty())
874 : {
875 112976 : if (!bExtentSet)
876 : {
877 112654 : papoRings[iRing]->getEnvelope( psEnvelope );
878 112654 : bExtentSet = TRUE;
879 : }
880 : else
881 : {
882 322 : papoRings[iRing]->getEnvelope( &oRingEnv );
883 :
884 322 : if( psEnvelope->MinX > oRingEnv.MinX )
885 16 : psEnvelope->MinX = oRingEnv.MinX;
886 322 : if( psEnvelope->MinY > oRingEnv.MinY )
887 14 : psEnvelope->MinY = oRingEnv.MinY;
888 322 : if( psEnvelope->MaxX < oRingEnv.MaxX )
889 6 : psEnvelope->MaxX = oRingEnv.MaxX;
890 322 : if( psEnvelope->MaxY < oRingEnv.MaxY )
891 6 : psEnvelope->MaxY = oRingEnv.MaxY;
892 : }
893 : }
894 : }
895 :
896 112660 : if (!bExtentSet)
897 : {
898 6 : psEnvelope->MinX = psEnvelope->MinY = 0;
899 6 : psEnvelope->MaxX = psEnvelope->MaxY = 0;
900 : }
901 112660 : }
902 :
903 : /************************************************************************/
904 : /* getEnvelope() */
905 : /************************************************************************/
906 :
907 156 : void OGRPolygon::getEnvelope( OGREnvelope3D * psEnvelope ) const
908 :
909 : {
910 156 : OGREnvelope3D oRingEnv;
911 156 : int bExtentSet = FALSE;
912 :
913 312 : for( int iRing = 0; iRing < nRingCount; iRing++ )
914 : {
915 156 : if (!papoRings[iRing]->IsEmpty())
916 : {
917 156 : if (!bExtentSet)
918 : {
919 154 : papoRings[iRing]->getEnvelope( psEnvelope );
920 154 : bExtentSet = TRUE;
921 : }
922 : else
923 : {
924 2 : papoRings[iRing]->getEnvelope( &oRingEnv );
925 :
926 2 : if( psEnvelope->MinX > oRingEnv.MinX )
927 0 : psEnvelope->MinX = oRingEnv.MinX;
928 2 : if( psEnvelope->MinY > oRingEnv.MinY )
929 0 : psEnvelope->MinY = oRingEnv.MinY;
930 2 : if( psEnvelope->MaxX < oRingEnv.MaxX )
931 0 : psEnvelope->MaxX = oRingEnv.MaxX;
932 2 : if( psEnvelope->MaxY < oRingEnv.MaxY )
933 0 : psEnvelope->MaxY = oRingEnv.MaxY;
934 :
935 2 : if( psEnvelope->MinZ > oRingEnv.MinZ )
936 2 : psEnvelope->MinZ = oRingEnv.MinZ;
937 2 : if( psEnvelope->MaxZ < oRingEnv.MaxZ )
938 0 : psEnvelope->MaxZ = oRingEnv.MaxZ;
939 : }
940 : }
941 : }
942 :
943 156 : if (!bExtentSet)
944 : {
945 2 : psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
946 2 : psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
947 : }
948 156 : }
949 :
950 : /************************************************************************/
951 : /* Equal() */
952 : /************************************************************************/
953 :
954 52870 : OGRBoolean OGRPolygon::Equals( OGRGeometry * poOther ) const
955 :
956 : {
957 52870 : OGRPolygon *poOPoly = (OGRPolygon *) poOther;
958 :
959 52870 : if( poOPoly == this )
960 0 : return TRUE;
961 :
962 52870 : if( poOther->getGeometryType() != getGeometryType() )
963 0 : return FALSE;
964 :
965 52870 : if( getNumInteriorRings() != poOPoly->getNumInteriorRings() )
966 0 : return FALSE;
967 :
968 52870 : if( getExteriorRing() == NULL && poOPoly->getExteriorRing() == NULL )
969 : /* ok */;
970 52870 : else if( getExteriorRing() == NULL || poOPoly->getExteriorRing() == NULL )
971 0 : return FALSE;
972 52870 : else if( !getExteriorRing()->Equals( poOPoly->getExteriorRing() ) )
973 28018 : return FALSE;
974 :
975 : // we should eventually test the SRS.
976 :
977 24862 : for( int iRing = 0; iRing < getNumInteriorRings(); iRing++ )
978 : {
979 10 : if( !getInteriorRing(iRing)->Equals(poOPoly->getInteriorRing(iRing)) )
980 0 : return FALSE;
981 : }
982 :
983 24852 : return TRUE;
984 : }
985 :
986 : /************************************************************************/
987 : /* transform() */
988 : /************************************************************************/
989 :
990 48 : OGRErr OGRPolygon::transform( OGRCoordinateTransformation *poCT )
991 :
992 : {
993 : #ifdef DISABLE_OGRGEOM_TRANSFORM
994 : return OGRERR_FAILURE;
995 : #else
996 96 : for( int iRing = 0; iRing < nRingCount; iRing++ )
997 : {
998 : OGRErr eErr;
999 :
1000 48 : eErr = papoRings[iRing]->transform( poCT );
1001 48 : if( eErr != OGRERR_NONE )
1002 : {
1003 0 : if( iRing != 0 )
1004 : {
1005 : CPLDebug("OGR",
1006 : "OGRPolygon::transform() failed for a ring other\n"
1007 : "than the first, meaning some rings are transformed\n"
1008 0 : "and some are not!\n" );
1009 :
1010 0 : return OGRERR_FAILURE;
1011 : }
1012 :
1013 0 : return eErr;
1014 : }
1015 : }
1016 :
1017 48 : assignSpatialReference( poCT->GetTargetCS() );
1018 :
1019 48 : return OGRERR_NONE;
1020 : #endif
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* IsPointOnSurface() */
1025 : /************************************************************************/
1026 :
1027 0 : OGRBoolean OGRPolygon::IsPointOnSurface( const OGRPoint * pt) const
1028 : {
1029 0 : if ( NULL == pt)
1030 0 : return 0;
1031 :
1032 0 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1033 : {
1034 0 : if ( papoRings[iRing]->isPointInRing(pt) )
1035 : {
1036 0 : return 1;
1037 : }
1038 : }
1039 :
1040 0 : return 0;
1041 : }
1042 :
1043 : /************************************************************************/
1044 : /* closeRings() */
1045 : /************************************************************************/
1046 :
1047 408 : void OGRPolygon::closeRings()
1048 :
1049 : {
1050 816 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1051 408 : papoRings[iRing]->closeRings();
1052 408 : }
1053 :
1054 : /************************************************************************/
1055 : /* get_Area() */
1056 : /************************************************************************/
1057 :
1058 : /**
1059 : * \brief Compute area of polygon.
1060 : *
1061 : * The area is computed as the area of the outer ring less the area of all
1062 : * internal rings.
1063 : *
1064 : * @return computed area.
1065 : */
1066 :
1067 696 : double OGRPolygon::get_Area() const
1068 :
1069 : {
1070 696 : double dfArea = 0.0;
1071 :
1072 696 : if( getExteriorRing() != NULL )
1073 : {
1074 : int iRing;
1075 :
1076 696 : dfArea = getExteriorRing()->get_Area();
1077 :
1078 700 : for( iRing = 0; iRing < getNumInteriorRings(); iRing++ )
1079 4 : dfArea -= getInteriorRing( iRing )->get_Area();
1080 : }
1081 :
1082 696 : return dfArea;
1083 : }
1084 :
1085 : /************************************************************************/
1086 : /* setCoordinateDimension() */
1087 : /************************************************************************/
1088 :
1089 1036 : void OGRPolygon::setCoordinateDimension( int nNewDimension )
1090 :
1091 : {
1092 2038 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1093 1002 : papoRings[iRing]->setCoordinateDimension( nNewDimension );
1094 :
1095 1036 : OGRGeometry::setCoordinateDimension( nNewDimension );
1096 1036 : }
1097 :
1098 :
1099 : /************************************************************************/
1100 : /* IsEmpty() */
1101 : /************************************************************************/
1102 :
1103 28930 : OGRBoolean OGRPolygon::IsEmpty( ) const
1104 : {
1105 28932 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1106 28924 : if (papoRings[iRing]->IsEmpty() == FALSE)
1107 28922 : return FALSE;
1108 8 : return TRUE;
1109 : }
1110 :
1111 : /************************************************************************/
1112 : /* OGRPolygon::segmentize() */
1113 : /************************************************************************/
1114 :
1115 20 : void OGRPolygon::segmentize( double dfMaxLength )
1116 : {
1117 40 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1118 20 : papoRings[iRing]->segmentize(dfMaxLength);
1119 20 : }
1120 :
1121 : /************************************************************************/
1122 : /* swapXY() */
1123 : /************************************************************************/
1124 :
1125 36 : void OGRPolygon::swapXY()
1126 : {
1127 72 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1128 36 : papoRings[iRing]->swapXY();
1129 36 : }
|