LCOV - code coverage report
Current view: directory - ogr - ogrpolygon.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 355 271 76.3 %
Date: 2010-01-09 Functions: 33 30 90.9 %

       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 : }

Generated by: LCOV version 1.7