LCOV - code coverage report
Current view: directory - ogr - ogrpolygon.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 398 323 81.2 %
Date: 2011-12-18 Functions: 35 30 85.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpolygon.cpp 22466 2011-05-30 09:24:55Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  The OGRPolygon geometry class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_geometry.h"
      31                 : #include "ogr_p.h"
      32                 : #include "ogr_geos.h"
      33                 : #include "ogr_api.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrpolygon.cpp 22466 2011-05-30 09:24:55Z rouault $");
      36                 : 
      37                 : /************************************************************************/
      38                 : /*                             OGRPolygon()                             */
      39                 : /************************************************************************/
      40                 : 
      41                 : /**
      42                 :  * \brief Create an empty polygon.
      43                 :  */
      44                 : 
      45           13037 : OGRPolygon::OGRPolygon()
      46                 : 
      47                 : {
      48           13037 :     nRingCount = 0;
      49           13037 :     papoRings = NULL;
      50           13037 : }
      51                 : 
      52                 : /************************************************************************/
      53                 : /*                            ~OGRPolygon()                             */
      54                 : /************************************************************************/
      55                 : 
      56           13037 : OGRPolygon::~OGRPolygon()
      57                 : 
      58                 : {
      59           13037 :     empty();
      60           13037 : }
      61                 : 
      62                 : /************************************************************************/
      63                 : /*                               clone()                                */
      64                 : /************************************************************************/
      65                 : 
      66            2517 : OGRGeometry *OGRPolygon::clone() const
      67                 : 
      68                 : {
      69                 :     OGRPolygon  *poNewPolygon;
      70                 : 
      71            2517 :     poNewPolygon = new OGRPolygon;
      72            2517 :     poNewPolygon->assignSpatialReference( getSpatialReference() );
      73                 : 
      74            5189 :     for( int i = 0; i < nRingCount; i++ )
      75                 :     {
      76            2672 :         poNewPolygon->addRing( papoRings[i] );
      77                 :     }
      78                 : 
      79            2517 :     return poNewPolygon;
      80                 : }
      81                 : 
      82                 : /************************************************************************/
      83                 : /*                               empty()                                */
      84                 : /************************************************************************/
      85                 : 
      86           13376 : void OGRPolygon::empty()
      87                 : 
      88                 : {
      89           13376 :     if( papoRings != NULL )
      90                 :     {
      91           26482 :         for( int i = 0; i < nRingCount; i++ )
      92                 :         {
      93           13661 :             delete papoRings[i];
      94                 :         }
      95           12821 :         OGRFree( papoRings );
      96                 :     }
      97                 : 
      98           13376 :     papoRings = NULL;
      99           13376 :     nRingCount = 0;
     100           13376 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                          getGeometryType()                           */
     104                 : /************************************************************************/
     105                 : 
     106            9444 : OGRwkbGeometryType OGRPolygon::getGeometryType() const
     107                 : 
     108                 : {
     109            9444 :     if( getCoordinateDimension() == 3 )
     110            1161 :         return wkbPolygon25D;
     111                 :     else
     112            8283 :         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             700 : const char * OGRPolygon::getGeometryName() const
     143                 : 
     144                 : {
     145             700 :     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            6356 : OGRLinearRing *OGRPolygon::getExteriorRing()
     167                 : 
     168                 : {
     169            6356 :     if( nRingCount > 0 )
     170            6337 :         return papoRings[0];
     171                 :     else
     172              19 :         return NULL;
     173                 : }
     174                 : 
     175            1599 : const OGRLinearRing *OGRPolygon::getExteriorRing() const
     176                 : 
     177                 : {
     178            1599 :     if( nRingCount > 0 )
     179            1575 :         return papoRings[0];
     180                 :     else
     181              24 :         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            4256 : int OGRPolygon::getNumInteriorRings() const
     198                 : 
     199                 : {
     200            4256 :     if( nRingCount > 0 )
     201            4254 :         return nRingCount-1;
     202                 :     else
     203               2 :         return 0;
     204                 : }
     205                 : 
     206                 : /************************************************************************/
     207                 : /*                          getInteriorRing()                           */
     208                 : /************************************************************************/
     209                 : 
     210                 : /**
     211                 :  * \brief Fetch reference to indicated internal ring.
     212                 :  *
     213                 :  * Note that the returned ring pointer is to an internal data object of
     214                 :  * the OGRPolygon.  It should not be modified or deleted by the application,
     215                 :  * and the pointer is only valid till the polygon is next modified.  Use
     216                 :  * the OGRGeometry::clone() method to make a separate copy within the
     217                 :  * application.
     218                 :  *
     219                 :  * Relates to the SFCOM IPolygon::get_InternalRing() method.
     220                 :  *
     221                 :  * @param iRing internal ring index from 0 to getNumInternalRings() - 1.
     222                 :  *
     223                 :  * @return pointer to external ring.  May be NULL if the OGRPolygon is empty.
     224                 :  */
     225                 : 
     226             234 : OGRLinearRing *OGRPolygon::getInteriorRing( int iRing )
     227                 : 
     228                 : {
     229             234 :     if( iRing < 0 || iRing >= nRingCount-1 )
     230               0 :         return NULL;
     231                 :     else
     232             234 :         return papoRings[iRing+1];
     233                 : }
     234                 : 
     235               7 : const OGRLinearRing *OGRPolygon::getInteriorRing( int iRing ) const
     236                 : 
     237                 : {
     238               7 :     if( iRing < 0 || iRing >= nRingCount-1 )
     239               0 :         return NULL;
     240                 :     else
     241               7 :         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            3060 : void OGRPolygon::addRing( OGRLinearRing * poNewRing )
     262                 : 
     263                 : {
     264                 :     papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
     265            3060 :                                                sizeof(void*) * (nRingCount+1));
     266                 : 
     267            3060 :     papoRings[nRingCount] = new OGRLinearRing( poNewRing );
     268                 : 
     269            3060 :     nRingCount++;
     270                 : 
     271            3060 :     if( poNewRing->getCoordinateDimension() == 3 )
     272             172 :         nCoordDimension = 3;
     273            3060 : }
     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            9449 : void OGRPolygon::addRingDirectly( OGRLinearRing * poNewRing )
     293                 : 
     294                 : {
     295                 :     papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
     296            9449 :                                                sizeof(void*) * (nRingCount+1));
     297                 : 
     298            9449 :     papoRings[nRingCount] = poNewRing;
     299                 : 
     300            9449 :     nRingCount++;
     301                 : 
     302                 : 
     303            9449 :     if( poNewRing->getCoordinateDimension() == 3 )
     304            5114 :         nCoordDimension = 3;
     305            9449 : }
     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             976 : int OGRPolygon::WkbSize() const
     315                 : 
     316                 : {
     317             976 :     int         nSize = 9;
     318             976 :     int         b3D = getCoordinateDimension() == 3;
     319                 : 
     320            1960 :     for( int i = 0; i < nRingCount; i++ )
     321                 :     {
     322             984 :         nSize += papoRings[i]->_WkbSize( b3D );
     323                 :     }
     324                 : 
     325             976 :     return nSize;
     326                 : }
     327                 : 
     328                 : /************************************************************************/
     329                 : /*                           importFromWkb()                            */
     330                 : /*                                                                      */
     331                 : /*      Initialize from serialized stream in well known binary          */
     332                 : /*      format.                                                         */
     333                 : /************************************************************************/
     334                 : 
     335             824 : OGRErr OGRPolygon::importFromWkb( unsigned char * pabyData,
     336                 :                                   int nSize )
     337                 : 
     338                 : {
     339                 :     OGRwkbByteOrder     eByteOrder;
     340                 :     int                 nDataOffset, b3D;
     341                 :     
     342             824 :     if( nSize < 9 && nSize != -1 )
     343               0 :         return OGRERR_NOT_ENOUGH_DATA;
     344                 : 
     345                 : /* -------------------------------------------------------------------- */
     346                 : /*      Get the byte order byte.                                        */
     347                 : /* -------------------------------------------------------------------- */
     348             824 :     eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
     349             824 :     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             824 :     if( eByteOrder == wkbNDR )
     361             807 :         eGeometryType = (OGRwkbGeometryType) pabyData[1];
     362                 :     else
     363              17 :         eGeometryType = (OGRwkbGeometryType) pabyData[4];
     364                 : 
     365             824 :     if( eGeometryType != wkbPolygon )
     366               0 :         return OGRERR_CORRUPT_DATA;
     367                 : #endif    
     368                 : 
     369             824 :     if( eByteOrder == wkbNDR )
     370             807 :         b3D = pabyData[4] & 0x80 || pabyData[2] & 0x80;
     371                 :     else
     372              17 :         b3D = pabyData[1] & 0x80 || pabyData[3] & 0x80;
     373                 : 
     374             824 :     if( b3D )
     375             260 :         nCoordDimension = 3;
     376                 :     else
     377             564 :         nCoordDimension = 2;
     378                 : 
     379                 : /* -------------------------------------------------------------------- */
     380                 : /*      Do we already have some rings?                                  */
     381                 : /* -------------------------------------------------------------------- */
     382             824 :     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             824 :     memcpy( &nRingCount, pabyData + 5, 4 );
     395                 :     
     396             824 :     if( OGR_SWAP( eByteOrder ) )
     397              17 :         nRingCount = CPL_SWAP32(nRingCount);
     398                 : 
     399             824 :     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             824 :     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             824 :     papoRings = (OGRLinearRing **) VSIMalloc2(sizeof(void*), nRingCount);
     415             824 :     if (nRingCount != 0 && papoRings == NULL)
     416                 :     {
     417               0 :         nRingCount = 0;
     418               0 :         return OGRERR_NOT_ENOUGH_MEMORY;
     419                 :     }
     420                 : 
     421             824 :     nDataOffset = 9;
     422             824 :     if( nSize != -1 )
     423             824 :         nSize -= nDataOffset;
     424                 : 
     425                 : /* -------------------------------------------------------------------- */
     426                 : /*      Get the rings.                                                  */
     427                 : /* -------------------------------------------------------------------- */
     428            1653 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
     429                 :     {
     430                 :         OGRErr  eErr;
     431                 :         
     432             829 :         papoRings[iRing] = new OGRLinearRing();
     433            2487 :         eErr = papoRings[iRing]->_importFromWkb( eByteOrder, b3D,
     434                 :                                                  pabyData + nDataOffset,
     435            3316 :                                                  nSize );
     436             829 :         if( eErr != OGRERR_NONE )
     437                 :         {
     438               0 :             delete papoRings[iRing];
     439               0 :             nRingCount = iRing;
     440               0 :             return eErr;
     441                 :         }
     442                 : 
     443             829 :         if( nSize != -1 )
     444             829 :             nSize -= papoRings[iRing]->_WkbSize( b3D );
     445                 : 
     446             829 :         nDataOffset += papoRings[iRing]->_WkbSize( b3D );
     447                 :     }
     448                 :     
     449             824 :     return OGRERR_NONE;
     450                 : }
     451                 : 
     452                 : /************************************************************************/
     453                 : /*                            exportToWkb()                             */
     454                 : /*                                                                      */
     455                 : /*      Build a well known binary representation of this object.        */
     456                 : /************************************************************************/
     457                 : 
     458             762 : OGRErr  OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
     459                 :                                  unsigned char * pabyData ) const
     460                 : 
     461                 : {
     462                 :     int         nOffset;
     463             762 :     int         b3D = getCoordinateDimension() == 3;
     464                 :     
     465                 : /* -------------------------------------------------------------------- */
     466                 : /*      Set the byte order.                                             */
     467                 : /* -------------------------------------------------------------------- */
     468             762 :     pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
     469                 : 
     470                 : /* -------------------------------------------------------------------- */
     471                 : /*      Set the geometry feature type.                                  */
     472                 : /* -------------------------------------------------------------------- */
     473             762 :     GUInt32 nGType = getGeometryType();
     474                 :     
     475             762 :     if( eByteOrder == wkbNDR )
     476             747 :         nGType = CPL_LSBWORD32( nGType );
     477                 :     else
     478              15 :         nGType = CPL_MSBWORD32( nGType );
     479                 : 
     480             762 :     memcpy( pabyData + 1, &nGType, 4 );
     481                 :     
     482                 : /* -------------------------------------------------------------------- */
     483                 : /*      Copy in the raw data.                                           */
     484                 : /* -------------------------------------------------------------------- */
     485             762 :     if( OGR_SWAP( eByteOrder ) )
     486                 :     {
     487                 :         int     nCount;
     488                 : 
     489              15 :         nCount = CPL_SWAP32( nRingCount );
     490              15 :         memcpy( pabyData+5, &nCount, 4 );
     491                 :     }
     492                 :     else
     493                 :     {
     494             747 :         memcpy( pabyData+5, &nRingCount, 4 );
     495                 :     }
     496                 :     
     497             762 :     nOffset = 9;
     498                 :     
     499                 : /* ==================================================================== */
     500                 : /*      Serialize each of the rings.                                    */
     501                 : /* ==================================================================== */
     502            1530 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
     503                 :     {
     504            2304 :         papoRings[iRing]->_exportToWkb( eByteOrder, b3D,
     505            3072 :                                         pabyData + nOffset );
     506                 : 
     507             768 :         nOffset += papoRings[iRing]->_WkbSize(b3D);
     508                 :     }
     509                 :     
     510             762 :     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             314 : OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
     521                 : 
     522                 : {
     523                 :     char        szToken[OGR_WKT_TOKEN_MAX];
     524             314 :     const char  *pszInput = *ppszInput;
     525                 : 
     526                 : /* -------------------------------------------------------------------- */
     527                 : /*      Clear existing rings.                                           */
     528                 : /* -------------------------------------------------------------------- */
     529             314 :     empty();
     530                 : 
     531                 : /* -------------------------------------------------------------------- */
     532                 : /*      Read and verify the ``POLYGON'' keyword token.                  */
     533                 : /* -------------------------------------------------------------------- */
     534             314 :     pszInput = OGRWktReadToken( pszInput, szToken );
     535                 : 
     536             314 :     if( !EQUAL(szToken,"POLYGON") )
     537               0 :         return OGRERR_CORRUPT_DATA;
     538                 : 
     539                 : /* -------------------------------------------------------------------- */
     540                 : /*      Check for EMPTY ...                                             */
     541                 : /* -------------------------------------------------------------------- */
     542                 :     const char *pszPreScan;
     543             314 :     int bHasZ = FALSE, bHasM = FALSE;
     544                 : 
     545             314 :     pszPreScan = OGRWktReadToken( pszInput, szToken );
     546             314 :     if( EQUAL(szToken,"EMPTY") )
     547                 :     {
     548              15 :         *ppszInput = (char *) pszPreScan;
     549              15 :         empty();
     550              15 :         return OGRERR_NONE;
     551                 :     }
     552                 : 
     553                 : /* -------------------------------------------------------------------- */
     554                 : /*      Check for Z, M or ZM. Will ignore the Measure                   */
     555                 : /* -------------------------------------------------------------------- */
     556             299 :     else if( EQUAL(szToken,"Z") )
     557                 :     {
     558              15 :         bHasZ = TRUE;
     559                 :     }
     560             284 :     else if( EQUAL(szToken,"M") )
     561                 :     {
     562               2 :         bHasM = TRUE;
     563                 :     }
     564             282 :     else if( EQUAL(szToken,"ZM") )
     565                 :     {
     566               2 :         bHasZ = TRUE;
     567               2 :         bHasM = TRUE;
     568                 :     }
     569                 : 
     570             299 :     if (bHasZ || bHasM)
     571                 :     {
     572              19 :         pszInput = pszPreScan;
     573              19 :         pszPreScan = OGRWktReadToken( pszInput, szToken );
     574              19 :         if( EQUAL(szToken,"EMPTY") )
     575                 :         {
     576               4 :             *ppszInput = (char *) pszPreScan;
     577               4 :             empty();
     578                 :             /* FIXME?: In theory we should store the dimension and M presence */
     579                 :             /* if we want to allow round-trip with ExportToWKT v1.2 */
     580               4 :             return OGRERR_NONE;
     581                 :         }
     582                 :     }
     583                 : 
     584             295 :     if( !EQUAL(szToken,"(") )
     585               4 :         return OGRERR_CORRUPT_DATA;
     586                 : 
     587             291 :     if ( !bHasZ && !bHasM )
     588                 :     {
     589                 :         /* Test for old-style POLYGON(EMPTY) */
     590             278 :         pszPreScan = OGRWktReadToken( pszPreScan, szToken );
     591             278 :         if( EQUAL(szToken,"EMPTY") )
     592                 :         {
     593               7 :             pszPreScan = OGRWktReadToken( pszPreScan, szToken );
     594                 : 
     595               7 :             if( EQUAL(szToken,",") )
     596                 :             {
     597                 :                 /* This is OK according to SFSQL SPEC. */
     598                 :             }
     599               4 :             else if( !EQUAL(szToken,")") )
     600               1 :                 return OGRERR_CORRUPT_DATA;
     601                 :             else
     602                 :             {
     603               3 :                 *ppszInput = (char *) pszPreScan;
     604               3 :                 empty();
     605               3 :                 return OGRERR_NONE;
     606                 :             }
     607                 :         }
     608                 :     }
     609                 : 
     610                 :     /* Skip first '(' */
     611             287 :     pszInput = OGRWktReadToken( pszInput, szToken );
     612                 : 
     613                 : /* ==================================================================== */
     614                 : /*      Read each ring in turn.  Note that we try to reuse the same     */
     615                 : /*      point list buffer from ring to ring to cut down on              */
     616                 : /*      allocate/deallocate overhead.                                   */
     617                 : /* ==================================================================== */
     618             287 :     OGRRawPoint *paoPoints = NULL;
     619             287 :     int         nMaxPoints = 0, nMaxRings = 0;
     620             287 :     double      *padfZ = NULL;
     621                 : 
     622             287 :     nCoordDimension = 2;
     623                 :     
     624             318 :     do
     625                 :     {
     626             341 :         int     nPoints = 0;
     627                 : 
     628             341 :         const char* pszNext = OGRWktReadToken( pszInput, szToken );
     629             341 :         if (EQUAL(szToken,"EMPTY"))
     630                 :         {
     631                 : /* -------------------------------------------------------------------- */
     632                 : /*      Do we need to grow the ring array?                              */
     633                 : /* -------------------------------------------------------------------- */
     634              10 :             if( nRingCount == nMaxRings )
     635                 :             {
     636               8 :                 nMaxRings = nMaxRings * 2 + 1;
     637                 :                 papoRings = (OGRLinearRing **)
     638               8 :                     CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
     639                 :             }
     640              10 :             papoRings[nRingCount] = new OGRLinearRing();
     641              10 :             nRingCount++;
     642                 : 
     643              10 :             pszInput = OGRWktReadToken( pszNext, szToken );
     644              10 :             if ( !EQUAL(szToken, ",") )
     645               5 :                 break;
     646                 : 
     647               5 :             continue;
     648                 :         }
     649                 : 
     650                 : /* -------------------------------------------------------------------- */
     651                 : /*      Read points for one ring from input.                            */
     652                 : /* -------------------------------------------------------------------- */
     653                 :         pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
     654             331 :                                      &nPoints );
     655                 : 
     656             331 :         if( pszInput == NULL || nPoints == 0 )
     657                 :         {
     658              18 :             CPLFree( paoPoints );
     659              18 :             return OGRERR_CORRUPT_DATA;
     660                 :         }
     661                 :         
     662                 : /* -------------------------------------------------------------------- */
     663                 : /*      Do we need to grow the ring array?                              */
     664                 : /* -------------------------------------------------------------------- */
     665             313 :         if( nRingCount == nMaxRings )
     666                 :         {
     667             305 :             nMaxRings = nMaxRings * 2 + 1;
     668                 :             papoRings = (OGRLinearRing **)
     669             305 :                 CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
     670                 :         }
     671                 : 
     672                 : /* -------------------------------------------------------------------- */
     673                 : /*      Create the new ring, and assign to ring list.                   */
     674                 : /* -------------------------------------------------------------------- */
     675             313 :         papoRings[nRingCount] = new OGRLinearRing();
     676                 :         /* Ignore Z array when we have a POLYGON M */
     677             316 :         if (bHasM && !bHasZ)
     678               1 :             papoRings[nRingCount]->setPoints( nPoints, paoPoints, NULL );
     679                 :         else
     680             312 :             papoRings[nRingCount]->setPoints( nPoints, paoPoints, padfZ );
     681                 : 
     682             313 :         nRingCount++;
     683                 : 
     684             313 :         if( padfZ && !(bHasM && !bHasZ) )
     685              61 :             nCoordDimension = 3;
     686                 : 
     687                 : /* -------------------------------------------------------------------- */
     688                 : /*      Read the delimeter following the ring.                          */
     689                 : /* -------------------------------------------------------------------- */
     690                 :         
     691             313 :         pszInput = OGRWktReadToken( pszInput, szToken );
     692             318 :     } while( szToken[0] == ',' );
     693                 : 
     694                 : /* -------------------------------------------------------------------- */
     695                 : /*      freak if we don't get a closing bracket.                        */
     696                 : /* -------------------------------------------------------------------- */
     697             269 :     CPLFree( paoPoints );
     698             269 :     CPLFree( padfZ );
     699                 : 
     700             269 :     if( szToken[0] != ')' )
     701               4 :         return OGRERR_CORRUPT_DATA;
     702                 :     
     703             265 :     *ppszInput = (char *) pszInput;
     704             265 :     return OGRERR_NONE;
     705                 : }
     706                 : 
     707                 : /************************************************************************/
     708                 : /*                            exportToWkt()                             */
     709                 : /*                                                                      */
     710                 : /*      Translate this structure into it's well known text format       */
     711                 : /*      equivelent.  This could be made alot more CPU efficient!        */
     712                 : /************************************************************************/
     713                 : 
     714             346 : OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
     715                 : 
     716                 : {
     717                 :     char        **papszRings;
     718             346 :     int         iRing, nCumulativeLength = 0, nNonEmptyRings = 0;
     719                 :     OGRErr      eErr;
     720             346 :     int         bMustWriteComma = FALSE;
     721                 : 
     722                 : /* -------------------------------------------------------------------- */
     723                 : /*      If we have no valid exterior ring, return POLYGON EMPTY.        */
     724                 : /* -------------------------------------------------------------------- */
     725             668 :     if (getExteriorRing() == NULL ||
     726             322 :         getExteriorRing()->IsEmpty())
     727                 :     {
     728              30 :         *ppszDstText = CPLStrdup("POLYGON EMPTY");
     729              30 :         return OGRERR_NONE;
     730                 :     }
     731                 : 
     732                 : /* -------------------------------------------------------------------- */
     733                 : /*      Build a list of strings containing the stuff for each ring.     */
     734                 : /* -------------------------------------------------------------------- */
     735             316 :     papszRings = (char **) CPLCalloc(sizeof(char *),nRingCount);
     736                 : 
     737             686 :     for( iRing = 0; iRing < nRingCount; iRing++ )
     738                 :     {
     739             370 :         papoRings[iRing]->setCoordinateDimension( getCoordinateDimension() );
     740             370 :         if( papoRings[iRing]->getNumPoints() == 0 )
     741                 :         {
     742               9 :             papszRings[iRing] = NULL;
     743               9 :             continue;
     744                 :         }
     745                 : 
     746             361 :         eErr = papoRings[iRing]->exportToWkt( &(papszRings[iRing]) );
     747             361 :         if( eErr != OGRERR_NONE )
     748               0 :             goto error;
     749                 : 
     750             361 :         CPLAssert( EQUALN(papszRings[iRing],"LINEARRING (", 12) );
     751             361 :         nCumulativeLength += strlen(papszRings[iRing] + 11);
     752                 : 
     753             361 :         nNonEmptyRings++;
     754                 :     }
     755                 : 
     756                 : /* -------------------------------------------------------------------- */
     757                 : /*      Allocate exactly the right amount of space for the              */
     758                 : /*      aggregated string.                                              */
     759                 : /* -------------------------------------------------------------------- */
     760             316 :     *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nNonEmptyRings + 11);
     761                 : 
     762             316 :     if( *ppszDstText == NULL )
     763                 :     {
     764               0 :         eErr = OGRERR_NOT_ENOUGH_MEMORY;
     765               0 :         goto error;
     766                 :     }
     767                 : 
     768                 : /* -------------------------------------------------------------------- */
     769                 : /*      Build up the string, freeing temporary strings as we go.        */
     770                 : /* -------------------------------------------------------------------- */
     771             316 :     strcpy( *ppszDstText, "POLYGON (" );
     772             316 :     nCumulativeLength = strlen(*ppszDstText);
     773                 : 
     774             686 :     for( iRing = 0; iRing < nRingCount; iRing++ )
     775                 :     {                                                           
     776             370 :         if( papszRings[iRing] == NULL )
     777                 :         {
     778               9 :             CPLDebug( "OGR", "OGRPolygon::exportToWkt() - skipping empty ring.");
     779               9 :             continue;
     780                 :         }
     781                 : 
     782             361 :         if( bMustWriteComma )
     783              45 :             (*ppszDstText)[nCumulativeLength++] = ',';
     784             361 :         bMustWriteComma = TRUE;
     785                 :         
     786             361 :         int nRingLen = strlen(papszRings[iRing] + 11);
     787             361 :         memcpy( *ppszDstText + nCumulativeLength, papszRings[iRing] + 11, nRingLen );
     788             361 :         nCumulativeLength += nRingLen;
     789             361 :         VSIFree( papszRings[iRing] );
     790                 :     }
     791                 : 
     792             316 :     (*ppszDstText)[nCumulativeLength++] = ')';
     793             316 :     (*ppszDstText)[nCumulativeLength] = '\0';
     794                 : 
     795             316 :     CPLFree( papszRings );
     796                 : 
     797             316 :     return OGRERR_NONE;
     798                 : 
     799                 : error:
     800               0 :     for( iRing = 0; iRing < nRingCount; iRing++ )
     801               0 :         CPLFree(papszRings[iRing]);
     802               0 :     CPLFree(papszRings);
     803               0 :     return eErr;
     804                 : }
     805                 : 
     806                 : /************************************************************************/
     807                 : /*                           PointOnSurface()                           */
     808                 : /************************************************************************/
     809                 : 
     810               0 : int OGRPolygon::PointOnSurface( OGRPoint *poPoint ) const
     811                 : 
     812                 : {
     813               0 :     if( poPoint == NULL )
     814               0 :         return OGRERR_FAILURE;
     815                 :  
     816                 : #ifndef HAVE_GEOS
     817                 :     return OGRERR_FAILURE;
     818                 : #else
     819               0 :     GEOSGeom hThisGeosGeom = NULL;
     820               0 :     GEOSGeom hOtherGeosGeom = NULL;
     821                 :      
     822               0 :     hThisGeosGeom = exportToGEOS();
     823                 :  
     824               0 :     if( hThisGeosGeom != NULL )
     825                 :     {
     826               0 :       hOtherGeosGeom = GEOSPointOnSurface( hThisGeosGeom );
     827               0 :         GEOSGeom_destroy( hThisGeosGeom );
     828                 : 
     829               0 :         if( hOtherGeosGeom == NULL )
     830               0 :             return OGRERR_FAILURE;
     831                 : 
     832                 :         OGRGeometry *poInsidePointGeom = (OGRGeometry *) 
     833               0 :             OGRGeometryFactory::createFromGEOS( hOtherGeosGeom );
     834                 :  
     835               0 :         GEOSGeom_destroy( hOtherGeosGeom );
     836                 : 
     837               0 :         if (poInsidePointGeom == NULL)
     838               0 :             return OGRERR_FAILURE;
     839               0 :         if (wkbFlatten(poInsidePointGeom->getGeometryType()) != wkbPoint)
     840                 :         {
     841               0 :             delete poInsidePointGeom;
     842               0 :             return OGRERR_FAILURE;
     843                 :         }
     844                 : 
     845               0 :         OGRPoint *poInsidePoint = (OGRPoint *) poInsidePointGeom;
     846               0 :   poPoint->setX( poInsidePoint->getX() );
     847               0 :   poPoint->setY( poInsidePoint->getY() );
     848                 :  
     849               0 :         delete poInsidePointGeom;
     850                 :  
     851               0 :       return OGRERR_NONE;
     852                 :     }
     853                 :     else
     854                 :     {
     855               0 :       return OGRERR_FAILURE;
     856                 :     }
     857                 : #endif /* HAVE_GEOS */
     858                 : }
     859                 : 
     860                 : 
     861                 : /************************************************************************/
     862                 : /*                            getEnvelope()                             */
     863                 : /************************************************************************/
     864                 : 
     865            3636 : void OGRPolygon::getEnvelope( OGREnvelope * psEnvelope ) const
     866                 : 
     867                 : {
     868            3636 :     OGREnvelope         oRingEnv;
     869            3636 :     int                 bExtentSet = FALSE;
     870                 : 
     871            7425 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
     872                 :     {
     873            3789 :         if (!papoRings[iRing]->IsEmpty())
     874                 :         {
     875            3789 :             if (!bExtentSet)
     876                 :             {
     877            3633 :                 papoRings[iRing]->getEnvelope( psEnvelope );
     878            3633 :                 bExtentSet = TRUE;
     879                 :             }
     880                 :             else
     881                 :             {
     882             156 :                 papoRings[iRing]->getEnvelope( &oRingEnv );
     883                 : 
     884             156 :                 if( psEnvelope->MinX > oRingEnv.MinX )
     885               9 :                     psEnvelope->MinX = oRingEnv.MinX;
     886             156 :                 if( psEnvelope->MinY > oRingEnv.MinY )
     887               7 :                     psEnvelope->MinY = oRingEnv.MinY;
     888             156 :                 if( psEnvelope->MaxX < oRingEnv.MaxX )
     889               5 :                     psEnvelope->MaxX = oRingEnv.MaxX;
     890             156 :                 if( psEnvelope->MaxY < oRingEnv.MaxY )
     891               5 :                     psEnvelope->MaxY = oRingEnv.MaxY;
     892                 :             }
     893                 :         }
     894                 :     }
     895                 : 
     896            3636 :     if (!bExtentSet)
     897                 :     {
     898               3 :         psEnvelope->MinX = psEnvelope->MinY = 0;
     899               3 :         psEnvelope->MaxX = psEnvelope->MaxY = 0;
     900                 :     }
     901            3636 : }
     902                 : 
     903                 : /************************************************************************/
     904                 : /*                            getEnvelope()                             */
     905                 : /************************************************************************/
     906                 :  
     907              37 : void OGRPolygon::getEnvelope( OGREnvelope3D * psEnvelope ) const
     908                 : 
     909                 : {
     910              37 :     OGREnvelope3D       oRingEnv;
     911              37 :     int                 bExtentSet = FALSE;
     912                 : 
     913              74 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
     914                 :     {
     915              37 :         if (!papoRings[iRing]->IsEmpty())
     916                 :         {
     917              37 :             if (!bExtentSet)
     918                 :             {
     919              36 :                 papoRings[iRing]->getEnvelope( psEnvelope );
     920              36 :                 bExtentSet = TRUE;
     921                 :             }
     922                 :             else
     923                 :             {
     924               1 :                 papoRings[iRing]->getEnvelope( &oRingEnv );
     925                 : 
     926               1 :                 if( psEnvelope->MinX > oRingEnv.MinX )
     927               0 :                     psEnvelope->MinX = oRingEnv.MinX;
     928               1 :                 if( psEnvelope->MinY > oRingEnv.MinY )
     929               0 :                     psEnvelope->MinY = oRingEnv.MinY;
     930               1 :                 if( psEnvelope->MaxX < oRingEnv.MaxX )
     931               0 :                     psEnvelope->MaxX = oRingEnv.MaxX;
     932               1 :                 if( psEnvelope->MaxY < oRingEnv.MaxY )
     933               0 :                     psEnvelope->MaxY = oRingEnv.MaxY;
     934                 : 
     935               1 :                 if( psEnvelope->MinZ > oRingEnv.MinZ )
     936               1 :                     psEnvelope->MinZ = oRingEnv.MinZ;
     937               1 :                 if( psEnvelope->MaxZ < oRingEnv.MaxZ )
     938               0 :                     psEnvelope->MaxZ = oRingEnv.MaxZ;
     939                 :             }
     940                 :         }
     941                 :     }
     942                 : 
     943              37 :     if (!bExtentSet)
     944                 :     {
     945               1 :         psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
     946               1 :         psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
     947                 :     }
     948              37 : }
     949                 : 
     950                 : /************************************************************************/
     951                 : /*                               Equal()                                */
     952                 : /************************************************************************/
     953                 : 
     954              93 : OGRBoolean OGRPolygon::Equals( OGRGeometry * poOther ) const
     955                 : 
     956                 : {
     957              93 :     OGRPolygon *poOPoly = (OGRPolygon *) poOther;
     958                 : 
     959              93 :     if( poOPoly == this )
     960               0 :         return TRUE;
     961                 :     
     962              93 :     if( poOther->getGeometryType() != getGeometryType() )
     963               0 :         return FALSE;
     964                 : 
     965              93 :     if( getNumInteriorRings() != poOPoly->getNumInteriorRings() )
     966               0 :         return FALSE;
     967                 : 
     968              93 :     if( getExteriorRing() == NULL && poOPoly->getExteriorRing() == NULL )
     969                 :         /* ok */;
     970              93 :     else if( getExteriorRing() == NULL || poOPoly->getExteriorRing() == NULL )
     971               0 :         return FALSE;
     972              93 :     else if( !getExteriorRing()->Equals( poOPoly->getExteriorRing() ) )
     973               0 :         return FALSE;
     974                 :     
     975                 :     // we should eventually test the SRS.
     976                 : 
     977              98 :     for( int iRing = 0; iRing < getNumInteriorRings(); iRing++ )
     978                 :     {
     979               5 :         if( !getInteriorRing(iRing)->Equals(poOPoly->getInteriorRing(iRing)) )
     980               0 :             return FALSE;
     981                 :     }
     982                 : 
     983              93 :     return TRUE;
     984                 : }
     985                 : 
     986                 : /************************************************************************/
     987                 : /*                             transform()                              */
     988                 : /************************************************************************/
     989                 : 
     990              24 : OGRErr OGRPolygon::transform( OGRCoordinateTransformation *poCT )
     991                 : 
     992                 : {
     993                 : #ifdef DISABLE_OGRGEOM_TRANSFORM
     994                 :     return OGRERR_FAILURE;
     995                 : #else
     996              48 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
     997                 :     {
     998                 :         OGRErr  eErr;
     999                 : 
    1000              24 :         eErr = papoRings[iRing]->transform( poCT );
    1001              24 :         if( eErr != OGRERR_NONE )
    1002                 :         {
    1003               0 :             if( iRing != 0 )
    1004                 :             {
    1005                 :                 CPLDebug("OGR", 
    1006                 :                          "OGRPolygon::transform() failed for a ring other\n"
    1007                 :                          "than the first, meaning some rings are transformed\n"
    1008               0 :                          "and some are not!\n" );
    1009                 : 
    1010               0 :                 return OGRERR_FAILURE;
    1011                 :             }
    1012                 : 
    1013               0 :             return eErr;
    1014                 :         }
    1015                 :     }
    1016                 : 
    1017              24 :     assignSpatialReference( poCT->GetTargetCS() );
    1018                 : 
    1019              24 :     return OGRERR_NONE;
    1020                 : #endif
    1021                 : }
    1022                 : 
    1023                 : /************************************************************************/
    1024                 : /*                           IsPointOnSurface()                           */
    1025                 : /************************************************************************/
    1026                 : 
    1027               0 : OGRBoolean OGRPolygon::IsPointOnSurface( const OGRPoint * pt) const
    1028                 : {
    1029               0 :     if ( NULL == pt)
    1030               0 :         return 0;
    1031                 : 
    1032               0 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1033                 :     {
    1034               0 :         if ( papoRings[iRing]->isPointInRing(pt) )
    1035                 :         {
    1036               0 :             return 1;
    1037                 :         }
    1038                 :     }
    1039                 : 
    1040               0 :     return 0;
    1041                 : }
    1042                 : 
    1043                 : /************************************************************************/
    1044                 : /*                             closeRings()                             */
    1045                 : /************************************************************************/
    1046                 : 
    1047             163 : void OGRPolygon::closeRings()
    1048                 : 
    1049                 : {
    1050             326 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1051             163 :         papoRings[iRing]->closeRings();
    1052             163 : }
    1053                 : 
    1054                 : /************************************************************************/
    1055                 : /*                              get_Area()                              */
    1056                 : /************************************************************************/
    1057                 : 
    1058                 : /**
    1059                 :  * \brief Compute area of polygon.
    1060                 :  *
    1061                 :  * The area is computed as the area of the outer ring less the area of all
    1062                 :  * internal rings. 
    1063                 :  *
    1064                 :  * @return computed area.
    1065                 :  */
    1066                 : 
    1067             326 : double OGRPolygon::get_Area() const
    1068                 : 
    1069                 : {
    1070             326 :     double dfArea = 0.0;
    1071                 : 
    1072             326 :     if( getExteriorRing() != NULL )
    1073                 :     {
    1074                 :         int iRing;
    1075                 : 
    1076             326 :         dfArea = getExteriorRing()->get_Area();
    1077                 : 
    1078             328 :         for( iRing = 0; iRing < getNumInteriorRings(); iRing++ )
    1079               2 :             dfArea -= getInteriorRing( iRing )->get_Area();
    1080                 :     }
    1081                 : 
    1082             326 :     return dfArea;
    1083                 : }
    1084                 : 
    1085                 : /************************************************************************/
    1086                 : /*                       setCoordinateDimension()                       */
    1087                 : /************************************************************************/
    1088                 : 
    1089             328 : void OGRPolygon::setCoordinateDimension( int nNewDimension )
    1090                 : 
    1091                 : {
    1092             639 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1093             311 :         papoRings[iRing]->setCoordinateDimension( nNewDimension );
    1094                 : 
    1095             328 :     OGRGeometry::setCoordinateDimension( nNewDimension );
    1096             328 : }
    1097                 : 
    1098                 : 
    1099                 : /************************************************************************/
    1100                 : /*                               IsEmpty()                              */
    1101                 : /************************************************************************/
    1102                 : 
    1103            1774 : OGRBoolean OGRPolygon::IsEmpty(  ) const
    1104                 : {
    1105            1775 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1106            1771 :         if (papoRings[iRing]->IsEmpty() == FALSE)
    1107            1770 :             return FALSE;
    1108               4 :     return TRUE;
    1109                 : }
    1110                 : 
    1111                 : /************************************************************************/
    1112                 : /*                       OGRPolygon::segmentize()                       */
    1113                 : /************************************************************************/
    1114                 : 
    1115              10 : void OGRPolygon::segmentize( double dfMaxLength )
    1116                 : {
    1117              20 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1118              10 :         papoRings[iRing]->segmentize(dfMaxLength);
    1119              10 : }
    1120                 : 
    1121                 : /************************************************************************/
    1122                 : /*                               swapXY()                               */
    1123                 : /************************************************************************/
    1124                 : 
    1125              18 : void OGRPolygon::swapXY()
    1126                 : {
    1127              36 :     for( int iRing = 0; iRing < nRingCount; iRing++ )
    1128              18 :         papoRings[iRing]->swapXY();
    1129              18 : }

Generated by: LCOV version 1.7