1 : /******************************************************************************
2 : * $Id: ogrpolygon.cpp 24895 2012-09-02 18:12:08Z 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 24895 2012-09-02 18:12:08Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRPolygon() */
39 : /************************************************************************/
40 :
41 : /**
42 : * \brief Create an empty polygon.
43 : */
44 :
45 144368 : OGRPolygon::OGRPolygon()
46 :
47 : {
48 144368 : nRingCount = 0;
49 144368 : papoRings = NULL;
50 144368 : }
51 :
52 : /************************************************************************/
53 : /* ~OGRPolygon() */
54 : /************************************************************************/
55 :
56 144368 : OGRPolygon::~OGRPolygon()
57 :
58 : {
59 144368 : empty();
60 144368 : }
61 :
62 : /************************************************************************/
63 : /* clone() */
64 : /************************************************************************/
65 :
66 63494 : OGRGeometry *OGRPolygon::clone() const
67 :
68 : {
69 : OGRPolygon *poNewPolygon;
70 :
71 63494 : poNewPolygon = new OGRPolygon;
72 63494 : poNewPolygon->assignSpatialReference( getSpatialReference() );
73 :
74 127285 : for( int i = 0; i < nRingCount; i++ )
75 : {
76 63791 : poNewPolygon->addRing( papoRings[i] );
77 : }
78 :
79 63494 : return poNewPolygon;
80 : }
81 :
82 : /************************************************************************/
83 : /* empty() */
84 : /************************************************************************/
85 :
86 157086 : void OGRPolygon::empty()
87 :
88 : {
89 157086 : if( papoRings != NULL )
90 : {
91 290510 : for( int i = 0; i < nRingCount; i++ )
92 : {
93 146420 : delete papoRings[i];
94 : }
95 144090 : OGRFree( papoRings );
96 : }
97 :
98 157086 : papoRings = NULL;
99 157086 : nRingCount = 0;
100 157086 : }
101 :
102 : /************************************************************************/
103 : /* getGeometryType() */
104 : /************************************************************************/
105 :
106 163899 : OGRwkbGeometryType OGRPolygon::getGeometryType() const
107 :
108 : {
109 163899 : if( getCoordinateDimension() == 3 )
110 1604 : return wkbPolygon25D;
111 : else
112 162295 : 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 13 : void OGRPolygon::flattenTo2D()
130 :
131 : {
132 26 : for( int iRing = 0; iRing < nRingCount; iRing++ )
133 13 : papoRings[iRing]->flattenTo2D();
134 :
135 13 : nCoordDimension = 2;
136 13 : }
137 :
138 : /************************************************************************/
139 : /* getGeometryName() */
140 : /************************************************************************/
141 :
142 1633 : const char * OGRPolygon::getGeometryName() const
143 :
144 : {
145 1633 : 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 144372 : OGRLinearRing *OGRPolygon::getExteriorRing()
167 :
168 : {
169 144372 : if( nRingCount > 0 )
170 144348 : return papoRings[0];
171 : else
172 24 : return NULL;
173 : }
174 :
175 114086 : const OGRLinearRing *OGRPolygon::getExteriorRing() const
176 :
177 : {
178 114086 : if( nRingCount > 0 )
179 114051 : return papoRings[0];
180 : else
181 35 : 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 132584 : int OGRPolygon::getNumInteriorRings() const
198 :
199 : {
200 132584 : if( nRingCount > 0 )
201 132582 : return nRingCount-1;
202 : else
203 2 : 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 358 : OGRLinearRing *OGRPolygon::getInteriorRing( int iRing )
227 :
228 : {
229 358 : if( iRing < 0 || iRing >= nRingCount-1 )
230 0 : return NULL;
231 : else
232 358 : return papoRings[iRing+1];
233 : }
234 :
235 99 : const OGRLinearRing *OGRPolygon::getInteriorRing( int iRing ) const
236 :
237 : {
238 99 : if( iRing < 0 || iRing >= nRingCount-1 )
239 0 : return NULL;
240 : else
241 99 : 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 82666 : void OGRPolygon::addRing( OGRLinearRing * poNewRing )
262 :
263 : {
264 : papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
265 82666 : sizeof(void*) * (nRingCount+1));
266 :
267 82666 : papoRings[nRingCount] = new OGRLinearRing( poNewRing );
268 :
269 82666 : nRingCount++;
270 :
271 82666 : if( poNewRing->getCoordinateDimension() == 3 )
272 194 : nCoordDimension = 3;
273 82666 : }
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 49377 : void OGRPolygon::addRingDirectly( OGRLinearRing * poNewRing )
293 :
294 : {
295 : papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
296 49377 : sizeof(void*) * (nRingCount+1));
297 :
298 49377 : papoRings[nRingCount] = poNewRing;
299 :
300 49377 : nRingCount++;
301 :
302 :
303 49377 : if( poNewRing->getCoordinateDimension() == 3 )
304 6487 : nCoordDimension = 3;
305 49377 : }
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 20628 : int OGRPolygon::WkbSize() const
315 :
316 : {
317 20628 : int nSize = 9;
318 20628 : int b3D = getCoordinateDimension() == 3;
319 :
320 42010 : for( int i = 0; i < nRingCount; i++ )
321 : {
322 21382 : nSize += papoRings[i]->_WkbSize( b3D );
323 : }
324 :
325 20628 : return nSize;
326 : }
327 :
328 : /************************************************************************/
329 : /* importFromWkb() */
330 : /* */
331 : /* Initialize from serialized stream in well known binary */
332 : /* format. */
333 : /************************************************************************/
334 :
335 1656 : OGRErr OGRPolygon::importFromWkb( unsigned char * pabyData,
336 : int nSize )
337 :
338 : {
339 : OGRwkbByteOrder eByteOrder;
340 : int nDataOffset, b3D;
341 :
342 1656 : if( nSize < 9 && nSize != -1 )
343 0 : return OGRERR_NOT_ENOUGH_DATA;
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* Get the byte order byte. */
347 : /* -------------------------------------------------------------------- */
348 1656 : eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
349 1656 : 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 1656 : if( eByteOrder == wkbNDR )
361 1639 : eGeometryType = (OGRwkbGeometryType) pabyData[1];
362 : else
363 17 : eGeometryType = (OGRwkbGeometryType) pabyData[4];
364 :
365 1656 : if( eGeometryType != wkbPolygon )
366 0 : return OGRERR_CORRUPT_DATA;
367 : #endif
368 :
369 1656 : if( eByteOrder == wkbNDR )
370 1639 : b3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
371 : else
372 17 : b3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
373 :
374 1656 : if( b3D )
375 294 : nCoordDimension = 3;
376 : else
377 1362 : nCoordDimension = 2;
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Do we already have some rings? */
381 : /* -------------------------------------------------------------------- */
382 1656 : 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 1656 : memcpy( &nRingCount, pabyData + 5, 4 );
395 :
396 1656 : if( OGR_SWAP( eByteOrder ) )
397 17 : nRingCount = CPL_SWAP32(nRingCount);
398 :
399 1656 : 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 1656 : 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 1656 : papoRings = (OGRLinearRing **) VSIMalloc2(sizeof(void*), nRingCount);
415 1656 : if (nRingCount != 0 && papoRings == NULL)
416 : {
417 0 : nRingCount = 0;
418 0 : return OGRERR_NOT_ENOUGH_MEMORY;
419 : }
420 :
421 1656 : nDataOffset = 9;
422 1656 : if( nSize != -1 )
423 1656 : nSize -= nDataOffset;
424 :
425 : /* -------------------------------------------------------------------- */
426 : /* Get the rings. */
427 : /* -------------------------------------------------------------------- */
428 3337 : for( int iRing = 0; iRing < nRingCount; iRing++ )
429 : {
430 : OGRErr eErr;
431 :
432 1681 : papoRings[iRing] = new OGRLinearRing();
433 5043 : eErr = papoRings[iRing]->_importFromWkb( eByteOrder, b3D,
434 : pabyData + nDataOffset,
435 6724 : nSize );
436 1681 : if( eErr != OGRERR_NONE )
437 : {
438 0 : delete papoRings[iRing];
439 0 : nRingCount = iRing;
440 0 : return eErr;
441 : }
442 :
443 1681 : if( nSize != -1 )
444 1681 : nSize -= papoRings[iRing]->_WkbSize( b3D );
445 :
446 1681 : nDataOffset += papoRings[iRing]->_WkbSize( b3D );
447 : }
448 :
449 1656 : return OGRERR_NONE;
450 : }
451 :
452 : /************************************************************************/
453 : /* exportToWkb() */
454 : /* */
455 : /* Build a well known binary representation of this object. */
456 : /************************************************************************/
457 :
458 20249 : OGRErr OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
459 : unsigned char * pabyData ) const
460 :
461 : {
462 : int nOffset;
463 20249 : int b3D = getCoordinateDimension() == 3;
464 :
465 : /* -------------------------------------------------------------------- */
466 : /* Set the byte order. */
467 : /* -------------------------------------------------------------------- */
468 20249 : pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Set the geometry feature type. */
472 : /* -------------------------------------------------------------------- */
473 20249 : GUInt32 nGType = getGeometryType();
474 :
475 20249 : if( eByteOrder == wkbNDR )
476 20234 : nGType = CPL_LSBWORD32( nGType );
477 : else
478 15 : nGType = CPL_MSBWORD32( nGType );
479 :
480 20249 : memcpy( pabyData + 1, &nGType, 4 );
481 :
482 : /* -------------------------------------------------------------------- */
483 : /* Copy in the raw data. */
484 : /* -------------------------------------------------------------------- */
485 20249 : if( OGR_SWAP( eByteOrder ) )
486 : {
487 : int nCount;
488 :
489 15 : nCount = CPL_SWAP32( nRingCount );
490 15 : memcpy( pabyData+5, &nCount, 4 );
491 : }
492 : else
493 : {
494 20234 : memcpy( pabyData+5, &nRingCount, 4 );
495 : }
496 :
497 20249 : nOffset = 9;
498 :
499 : /* ==================================================================== */
500 : /* Serialize each of the rings. */
501 : /* ==================================================================== */
502 41234 : for( int iRing = 0; iRing < nRingCount; iRing++ )
503 : {
504 62955 : papoRings[iRing]->_exportToWkb( eByteOrder, b3D,
505 83940 : pabyData + nOffset );
506 :
507 20985 : nOffset += papoRings[iRing]->_WkbSize(b3D);
508 : }
509 :
510 20249 : 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 12687 : OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
521 :
522 : {
523 : char szToken[OGR_WKT_TOKEN_MAX];
524 12687 : const char *pszInput = *ppszInput;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Clear existing rings. */
528 : /* -------------------------------------------------------------------- */
529 12687 : empty();
530 :
531 : /* -------------------------------------------------------------------- */
532 : /* Read and verify the ``POLYGON'' keyword token. */
533 : /* -------------------------------------------------------------------- */
534 12687 : pszInput = OGRWktReadToken( pszInput, szToken );
535 :
536 12687 : if( !EQUAL(szToken,"POLYGON") )
537 0 : return OGRERR_CORRUPT_DATA;
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Check for EMPTY ... */
541 : /* -------------------------------------------------------------------- */
542 : const char *pszPreScan;
543 12687 : int bHasZ = FALSE, bHasM = FALSE;
544 :
545 12687 : pszPreScan = OGRWktReadToken( pszInput, szToken );
546 12687 : if( EQUAL(szToken,"EMPTY") )
547 : {
548 21 : *ppszInput = (char *) pszPreScan;
549 21 : empty();
550 21 : return OGRERR_NONE;
551 : }
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Check for Z, M or ZM. Will ignore the Measure */
555 : /* -------------------------------------------------------------------- */
556 12666 : else if( EQUAL(szToken,"Z") )
557 : {
558 15 : bHasZ = TRUE;
559 : }
560 12651 : else if( EQUAL(szToken,"M") )
561 : {
562 2 : bHasM = TRUE;
563 : }
564 12649 : else if( EQUAL(szToken,"ZM") )
565 : {
566 2 : bHasZ = TRUE;
567 2 : bHasM = TRUE;
568 : }
569 :
570 12666 : if (bHasZ || bHasM)
571 : {
572 19 : pszInput = pszPreScan;
573 19 : pszPreScan = OGRWktReadToken( pszInput, szToken );
574 19 : if( EQUAL(szToken,"EMPTY") )
575 : {
576 4 : *ppszInput = (char *) pszPreScan;
577 4 : 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 4 : return OGRERR_NONE;
581 : }
582 : }
583 :
584 12662 : if( !EQUAL(szToken,"(") )
585 4 : return OGRERR_CORRUPT_DATA;
586 :
587 12658 : if ( !bHasZ && !bHasM )
588 : {
589 : /* Test for old-style POLYGON(EMPTY) */
590 12645 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
591 12645 : if( EQUAL(szToken,"EMPTY") )
592 : {
593 7 : pszPreScan = OGRWktReadToken( pszPreScan, szToken );
594 :
595 7 : if( EQUAL(szToken,",") )
596 : {
597 : /* This is OK according to SFSQL SPEC. */
598 : }
599 4 : else if( !EQUAL(szToken,")") )
600 1 : return OGRERR_CORRUPT_DATA;
601 : else
602 : {
603 3 : *ppszInput = (char *) pszPreScan;
604 3 : empty();
605 3 : return OGRERR_NONE;
606 : }
607 : }
608 : }
609 :
610 : /* Skip first '(' */
611 12654 : 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 12654 : OGRRawPoint *paoPoints = NULL;
619 12654 : int nMaxPoints = 0, nMaxRings = 0;
620 12654 : double *padfZ = NULL;
621 :
622 12654 : nCoordDimension = 2;
623 :
624 12691 : do
625 : {
626 12714 : int nPoints = 0;
627 :
628 12714 : const char* pszNext = OGRWktReadToken( pszInput, szToken );
629 12714 : if (EQUAL(szToken,"EMPTY"))
630 : {
631 : /* -------------------------------------------------------------------- */
632 : /* Do we need to grow the ring array? */
633 : /* -------------------------------------------------------------------- */
634 10 : if( nRingCount == nMaxRings )
635 : {
636 8 : nMaxRings = nMaxRings * 2 + 1;
637 : papoRings = (OGRLinearRing **)
638 8 : CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
639 : }
640 10 : papoRings[nRingCount] = new OGRLinearRing();
641 10 : nRingCount++;
642 :
643 10 : pszInput = OGRWktReadToken( pszNext, szToken );
644 10 : if ( !EQUAL(szToken, ",") )
645 5 : break;
646 :
647 5 : continue;
648 : }
649 :
650 : /* -------------------------------------------------------------------- */
651 : /* Read points for one ring from input. */
652 : /* -------------------------------------------------------------------- */
653 : pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
654 12704 : &nPoints );
655 :
656 12704 : if( pszInput == NULL || nPoints == 0 )
657 : {
658 18 : CPLFree( paoPoints );
659 18 : return OGRERR_CORRUPT_DATA;
660 : }
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Do we need to grow the ring array? */
664 : /* -------------------------------------------------------------------- */
665 12686 : if( nRingCount == nMaxRings )
666 : {
667 12680 : nMaxRings = nMaxRings * 2 + 1;
668 : papoRings = (OGRLinearRing **)
669 12680 : CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
670 : }
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Create the new ring, and assign to ring list. */
674 : /* -------------------------------------------------------------------- */
675 12686 : papoRings[nRingCount] = new OGRLinearRing();
676 : /* Ignore Z array when we have a POLYGON M */
677 12689 : if (bHasM && !bHasZ)
678 1 : papoRings[nRingCount]->setPoints( nPoints, paoPoints, NULL );
679 : else
680 12685 : papoRings[nRingCount]->setPoints( nPoints, paoPoints, padfZ );
681 :
682 12686 : nRingCount++;
683 :
684 12686 : if( padfZ && !(bHasM && !bHasZ) )
685 66 : nCoordDimension = 3;
686 :
687 : /* -------------------------------------------------------------------- */
688 : /* Read the delimeter following the ring. */
689 : /* -------------------------------------------------------------------- */
690 :
691 12686 : pszInput = OGRWktReadToken( pszInput, szToken );
692 12691 : } while( szToken[0] == ',' );
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* freak if we don't get a closing bracket. */
696 : /* -------------------------------------------------------------------- */
697 12636 : CPLFree( paoPoints );
698 12636 : CPLFree( padfZ );
699 :
700 12636 : if( szToken[0] != ')' )
701 4 : return OGRERR_CORRUPT_DATA;
702 :
703 12632 : *ppszInput = (char *) pszInput;
704 12632 : 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 522 : OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
715 :
716 : {
717 : char **papszRings;
718 522 : int iRing, nCumulativeLength = 0, nNonEmptyRings = 0;
719 : OGRErr eErr;
720 522 : int bMustWriteComma = FALSE;
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* If we have no valid exterior ring, return POLYGON EMPTY. */
724 : /* -------------------------------------------------------------------- */
725 1009 : if (getExteriorRing() == NULL ||
726 487 : getExteriorRing()->IsEmpty())
727 : {
728 42 : *ppszDstText = CPLStrdup("POLYGON EMPTY");
729 42 : return OGRERR_NONE;
730 : }
731 :
732 : /* -------------------------------------------------------------------- */
733 : /* Build a list of strings containing the stuff for each ring. */
734 : /* -------------------------------------------------------------------- */
735 480 : papszRings = (char **) CPLCalloc(sizeof(char *),nRingCount);
736 :
737 1016 : for( iRing = 0; iRing < nRingCount; iRing++ )
738 : {
739 536 : papoRings[iRing]->setCoordinateDimension( getCoordinateDimension() );
740 536 : if( papoRings[iRing]->getNumPoints() == 0 )
741 : {
742 12 : papszRings[iRing] = NULL;
743 12 : continue;
744 : }
745 :
746 524 : eErr = papoRings[iRing]->exportToWkt( &(papszRings[iRing]) );
747 524 : if( eErr != OGRERR_NONE )
748 0 : goto error;
749 :
750 524 : CPLAssert( EQUALN(papszRings[iRing],"LINEARRING (", 12) );
751 524 : nCumulativeLength += strlen(papszRings[iRing] + 11);
752 :
753 524 : nNonEmptyRings++;
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Allocate exactly the right amount of space for the */
758 : /* aggregated string. */
759 : /* -------------------------------------------------------------------- */
760 480 : *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nNonEmptyRings + 11);
761 :
762 480 : 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 480 : strcpy( *ppszDstText, "POLYGON (" );
772 480 : nCumulativeLength = strlen(*ppszDstText);
773 :
774 1016 : for( iRing = 0; iRing < nRingCount; iRing++ )
775 : {
776 536 : if( papszRings[iRing] == NULL )
777 : {
778 12 : CPLDebug( "OGR", "OGRPolygon::exportToWkt() - skipping empty ring.");
779 12 : continue;
780 : }
781 :
782 524 : if( bMustWriteComma )
783 44 : (*ppszDstText)[nCumulativeLength++] = ',';
784 524 : bMustWriteComma = TRUE;
785 :
786 524 : int nRingLen = strlen(papszRings[iRing] + 11);
787 524 : memcpy( *ppszDstText + nCumulativeLength, papszRings[iRing] + 11, nRingLen );
788 524 : nCumulativeLength += nRingLen;
789 524 : VSIFree( papszRings[iRing] );
790 : }
791 :
792 480 : (*ppszDstText)[nCumulativeLength++] = ')';
793 480 : (*ppszDstText)[nCumulativeLength] = '\0';
794 :
795 480 : CPLFree( papszRings );
796 :
797 480 : 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 0 : OGRGeometryH hInsidePoint = OGR_G_PointOnSurface( (OGRGeometryH) this );
817 0 : if( hInsidePoint == NULL )
818 0 : return OGRERR_FAILURE;
819 :
820 0 : OGRPoint *poInsidePoint = (OGRPoint *) hInsidePoint;
821 0 : if( poInsidePoint->IsEmpty() )
822 0 : poPoint->empty();
823 : else
824 : {
825 0 : poPoint->setX( poInsidePoint->getX() );
826 0 : poPoint->setY( poInsidePoint->getY() );
827 : }
828 :
829 0 : return OGRERR_NONE;
830 : }
831 :
832 :
833 : /************************************************************************/
834 : /* getEnvelope() */
835 : /************************************************************************/
836 :
837 74901 : void OGRPolygon::getEnvelope( OGREnvelope * psEnvelope ) const
838 :
839 : {
840 74901 : OGREnvelope oRingEnv;
841 74901 : int bExtentSet = FALSE;
842 :
843 150887 : for( int iRing = 0; iRing < nRingCount; iRing++ )
844 : {
845 75986 : if (!papoRings[iRing]->IsEmpty())
846 : {
847 75986 : if (!bExtentSet)
848 : {
849 74897 : papoRings[iRing]->getEnvelope( psEnvelope );
850 74897 : bExtentSet = TRUE;
851 : }
852 : else
853 : {
854 1089 : papoRings[iRing]->getEnvelope( &oRingEnv );
855 :
856 1089 : if( psEnvelope->MinX > oRingEnv.MinX )
857 5 : psEnvelope->MinX = oRingEnv.MinX;
858 1089 : if( psEnvelope->MinY > oRingEnv.MinY )
859 4 : psEnvelope->MinY = oRingEnv.MinY;
860 1089 : if( psEnvelope->MaxX < oRingEnv.MaxX )
861 6 : psEnvelope->MaxX = oRingEnv.MaxX;
862 1089 : if( psEnvelope->MaxY < oRingEnv.MaxY )
863 6 : psEnvelope->MaxY = oRingEnv.MaxY;
864 : }
865 : }
866 : }
867 :
868 74901 : if (!bExtentSet)
869 : {
870 4 : psEnvelope->MinX = psEnvelope->MinY = 0;
871 4 : psEnvelope->MaxX = psEnvelope->MaxY = 0;
872 : }
873 74901 : }
874 :
875 : /************************************************************************/
876 : /* getEnvelope() */
877 : /************************************************************************/
878 :
879 89 : void OGRPolygon::getEnvelope( OGREnvelope3D * psEnvelope ) const
880 :
881 : {
882 89 : OGREnvelope3D oRingEnv;
883 89 : int bExtentSet = FALSE;
884 :
885 178 : for( int iRing = 0; iRing < nRingCount; iRing++ )
886 : {
887 89 : if (!papoRings[iRing]->IsEmpty())
888 : {
889 89 : if (!bExtentSet)
890 : {
891 88 : papoRings[iRing]->getEnvelope( psEnvelope );
892 88 : bExtentSet = TRUE;
893 : }
894 : else
895 : {
896 1 : papoRings[iRing]->getEnvelope( &oRingEnv );
897 :
898 1 : if( psEnvelope->MinX > oRingEnv.MinX )
899 0 : psEnvelope->MinX = oRingEnv.MinX;
900 1 : if( psEnvelope->MinY > oRingEnv.MinY )
901 0 : psEnvelope->MinY = oRingEnv.MinY;
902 1 : if( psEnvelope->MaxX < oRingEnv.MaxX )
903 0 : psEnvelope->MaxX = oRingEnv.MaxX;
904 1 : if( psEnvelope->MaxY < oRingEnv.MaxY )
905 0 : psEnvelope->MaxY = oRingEnv.MaxY;
906 :
907 1 : if( psEnvelope->MinZ > oRingEnv.MinZ )
908 1 : psEnvelope->MinZ = oRingEnv.MinZ;
909 1 : if( psEnvelope->MaxZ < oRingEnv.MaxZ )
910 0 : psEnvelope->MaxZ = oRingEnv.MaxZ;
911 : }
912 : }
913 : }
914 :
915 89 : if (!bExtentSet)
916 : {
917 1 : psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
918 1 : psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
919 : }
920 89 : }
921 :
922 : /************************************************************************/
923 : /* Equal() */
924 : /************************************************************************/
925 :
926 37919 : OGRBoolean OGRPolygon::Equals( OGRGeometry * poOther ) const
927 :
928 : {
929 37919 : OGRPolygon *poOPoly = (OGRPolygon *) poOther;
930 :
931 37919 : if( poOPoly == this )
932 0 : return TRUE;
933 :
934 37919 : if( poOther->getGeometryType() != getGeometryType() )
935 0 : return FALSE;
936 :
937 37919 : if( getNumInteriorRings() != poOPoly->getNumInteriorRings() )
938 1396 : return FALSE;
939 :
940 36523 : if( getExteriorRing() == NULL && poOPoly->getExteriorRing() == NULL )
941 : /* ok */;
942 36523 : else if( getExteriorRing() == NULL || poOPoly->getExteriorRing() == NULL )
943 0 : return FALSE;
944 36523 : else if( !getExteriorRing()->Equals( poOPoly->getExteriorRing() ) )
945 23031 : return FALSE;
946 :
947 : // we should eventually test the SRS.
948 :
949 13589 : for( int iRing = 0; iRing < getNumInteriorRings(); iRing++ )
950 : {
951 97 : if( !getInteriorRing(iRing)->Equals(poOPoly->getInteriorRing(iRing)) )
952 0 : return FALSE;
953 : }
954 :
955 13492 : return TRUE;
956 : }
957 :
958 : /************************************************************************/
959 : /* transform() */
960 : /************************************************************************/
961 :
962 27 : OGRErr OGRPolygon::transform( OGRCoordinateTransformation *poCT )
963 :
964 : {
965 : #ifdef DISABLE_OGRGEOM_TRANSFORM
966 : return OGRERR_FAILURE;
967 : #else
968 55 : for( int iRing = 0; iRing < nRingCount; iRing++ )
969 : {
970 : OGRErr eErr;
971 :
972 28 : eErr = papoRings[iRing]->transform( poCT );
973 28 : if( eErr != OGRERR_NONE )
974 : {
975 0 : if( iRing != 0 )
976 : {
977 : CPLDebug("OGR",
978 : "OGRPolygon::transform() failed for a ring other\n"
979 : "than the first, meaning some rings are transformed\n"
980 0 : "and some are not!\n" );
981 :
982 0 : return OGRERR_FAILURE;
983 : }
984 :
985 0 : return eErr;
986 : }
987 : }
988 :
989 27 : assignSpatialReference( poCT->GetTargetCS() );
990 :
991 27 : return OGRERR_NONE;
992 : #endif
993 : }
994 :
995 : /************************************************************************/
996 : /* IsPointOnSurface() */
997 : /************************************************************************/
998 :
999 0 : OGRBoolean OGRPolygon::IsPointOnSurface( const OGRPoint * pt) const
1000 : {
1001 0 : if ( NULL == pt)
1002 0 : return 0;
1003 :
1004 0 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1005 : {
1006 0 : if ( papoRings[iRing]->isPointInRing(pt) )
1007 : {
1008 0 : return 1;
1009 : }
1010 : }
1011 :
1012 0 : return 0;
1013 : }
1014 :
1015 : /************************************************************************/
1016 : /* closeRings() */
1017 : /************************************************************************/
1018 :
1019 204 : void OGRPolygon::closeRings()
1020 :
1021 : {
1022 408 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1023 204 : papoRings[iRing]->closeRings();
1024 204 : }
1025 :
1026 : /************************************************************************/
1027 : /* get_Area() */
1028 : /************************************************************************/
1029 :
1030 : /**
1031 : * \brief Compute area of polygon.
1032 : *
1033 : * The area is computed as the area of the outer ring less the area of all
1034 : * internal rings.
1035 : *
1036 : * @return computed area.
1037 : */
1038 :
1039 1754 : double OGRPolygon::get_Area() const
1040 :
1041 : {
1042 1754 : double dfArea = 0.0;
1043 :
1044 1754 : if( getExteriorRing() != NULL )
1045 : {
1046 : int iRing;
1047 :
1048 1754 : dfArea = getExteriorRing()->get_Area();
1049 :
1050 1756 : for( iRing = 0; iRing < getNumInteriorRings(); iRing++ )
1051 2 : dfArea -= getInteriorRing( iRing )->get_Area();
1052 : }
1053 :
1054 1754 : return dfArea;
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* setCoordinateDimension() */
1059 : /************************************************************************/
1060 :
1061 613 : void OGRPolygon::setCoordinateDimension( int nNewDimension )
1062 :
1063 : {
1064 1209 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1065 596 : papoRings[iRing]->setCoordinateDimension( nNewDimension );
1066 :
1067 613 : OGRGeometry::setCoordinateDimension( nNewDimension );
1068 613 : }
1069 :
1070 :
1071 : /************************************************************************/
1072 : /* IsEmpty() */
1073 : /************************************************************************/
1074 :
1075 14885 : OGRBoolean OGRPolygon::IsEmpty( ) const
1076 : {
1077 14886 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1078 14868 : if (papoRings[iRing]->IsEmpty() == FALSE)
1079 14867 : return FALSE;
1080 18 : return TRUE;
1081 : }
1082 :
1083 : /************************************************************************/
1084 : /* OGRPolygon::segmentize() */
1085 : /************************************************************************/
1086 :
1087 10 : void OGRPolygon::segmentize( double dfMaxLength )
1088 : {
1089 20 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1090 10 : papoRings[iRing]->segmentize(dfMaxLength);
1091 10 : }
1092 :
1093 : /************************************************************************/
1094 : /* swapXY() */
1095 : /************************************************************************/
1096 :
1097 24 : void OGRPolygon::swapXY()
1098 : {
1099 48 : for( int iRing = 0; iRing < nRingCount; iRing++ )
1100 24 : papoRings[iRing]->swapXY();
1101 24 : }
|