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