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