LCOV - code coverage report
Current view: directory - ogr - ogrgeometryfactory.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 607 410 67.5 %
Date: 2010-01-09 Functions: 30 26 86.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgeometryfactory.cpp 18320 2009-12-17 02:22:03Z warmerdam $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Factory for converting geometry to and from well known binary
       6                 :  *           format.
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 1999, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "ogr_geometry.h"
      32                 : #include "ogr_api.h"
      33                 : #include "ogr_p.h"
      34                 : #include "ogr_geos.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ogrgeometryfactory.cpp 18320 2009-12-17 02:22:03Z warmerdam $");
      37                 : 
      38                 : #ifndef PI
      39                 : #define PI  3.14159265358979323846
      40                 : #endif 
      41                 : 
      42                 : /************************************************************************/
      43                 : /*                           createFromWkb()                            */
      44                 : /************************************************************************/
      45                 : 
      46                 : /**
      47                 :  * \brief Create a geometry object of the appropriate type from it's well known binary representation.
      48                 :  *
      49                 :  * Note that if nBytes is passed as zero, no checking can be done on whether
      50                 :  * the pabyData is sufficient.  This can result in a crash if the input
      51                 :  * data is corrupt.  This function returns no indication of the number of
      52                 :  * bytes from the data source actually used to represent the returned
      53                 :  * geometry object.  Use OGRGeometry::WkbSize() on the returned geometry to
      54                 :  * establish the number of bytes it required in WKB format.
      55                 :  *
      56                 :  * Also note that this is a static method, and that there
      57                 :  * is no need to instantiate an OGRGeometryFactory object.  
      58                 :  *
      59                 :  * The C function OGR_G_CreateFromWkb() is the same as this method.
      60                 :  *
      61                 :  * @param pabyData pointer to the input BLOB data.
      62                 :  * @param poSR pointer to the spatial reference to be assigned to the
      63                 :  *             created geometry object.  This may be NULL.
      64                 :  * @param ppoReturn the newly created geometry object will be assigned to the
      65                 :  *                  indicated pointer on return.  This will be NULL in case
      66                 :  *                  of failure.
      67                 :  * @param nBytes the number of bytes available in pabyData, or -1 if it isn't
      68                 :  *               known.
      69                 :  *
      70                 :  * @return OGRERR_NONE if all goes well, otherwise any of
      71                 :  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
      72                 :  * OGRERR_CORRUPT_DATA may be returned.
      73                 :  */
      74                 : 
      75            1564 : OGRErr OGRGeometryFactory::createFromWkb(unsigned char *pabyData,
      76                 :                                          OGRSpatialReference * poSR,
      77                 :                                          OGRGeometry **ppoReturn,
      78                 :                                          int nBytes )
      79                 : 
      80                 : {
      81                 :     OGRwkbGeometryType eGeometryType;
      82                 :     OGRwkbByteOrder eByteOrder;
      83                 :     OGRErr      eErr;
      84                 :     OGRGeometry *poGeom;
      85                 : 
      86            1564 :     *ppoReturn = NULL;
      87                 : 
      88            1564 :     if( nBytes < 9 && nBytes != -1 )
      89            1014 :         return OGRERR_NOT_ENOUGH_DATA;
      90                 : 
      91                 : /* -------------------------------------------------------------------- */
      92                 : /*      Get the byte order byte.  The extra tests are to work around    */
      93                 : /*      bug sin the WKB of DB2 v7.2 as identified by Safe Software.     */
      94                 : /* -------------------------------------------------------------------- */
      95             550 :     eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
      96                 : 
      97                 : 
      98             550 :     if( eByteOrder != wkbXDR && eByteOrder != wkbNDR )
      99                 :     {
     100                 :         CPLDebug( "OGR", 
     101                 :                   "OGRGeometryFactory::createFromWkb() - got corrupt data.\n"
     102                 :                   "%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", 
     103               0 :                   pabyData[0],
     104               0 :                   pabyData[1],
     105               0 :                   pabyData[2],
     106               0 :                   pabyData[3],
     107               0 :                   pabyData[4],
     108               0 :                   pabyData[5],
     109               0 :                   pabyData[6],
     110               0 :                   pabyData[7],
     111               0 :                   pabyData[8]);
     112               0 :         return OGRERR_CORRUPT_DATA;
     113                 :     }
     114                 : 
     115                 : /* -------------------------------------------------------------------- */
     116                 : /*      Get the geometry feature type.  For now we assume that          */
     117                 : /*      geometry type is between 0 and 255 so we only have to fetch     */
     118                 : /*      one byte.                                                       */
     119                 : /* -------------------------------------------------------------------- */
     120             550 :     if( eByteOrder == wkbNDR )
     121             483 :         eGeometryType = (OGRwkbGeometryType) pabyData[1];
     122                 :     else
     123              67 :         eGeometryType = (OGRwkbGeometryType) pabyData[4];
     124                 : 
     125                 : /* -------------------------------------------------------------------- */
     126                 : /*      Instantiate a geometry of the appropriate type, and             */
     127                 : /*      initialize from the input stream.                               */
     128                 : /* -------------------------------------------------------------------- */
     129             550 :     poGeom = createGeometry( eGeometryType );
     130                 :     
     131             550 :     if( poGeom == NULL )
     132               6 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     133                 : 
     134                 : /* -------------------------------------------------------------------- */
     135                 : /*      Import from binary.                                             */
     136                 : /* -------------------------------------------------------------------- */
     137             544 :     eErr = poGeom->importFromWkb( pabyData, nBytes );
     138                 : 
     139                 : /* -------------------------------------------------------------------- */
     140                 : /*      Assign spatial reference system.                                */
     141                 : /* -------------------------------------------------------------------- */
     142             544 :     if( eErr == OGRERR_NONE )
     143                 :     {
     144             544 :         poGeom->assignSpatialReference( poSR );
     145             544 :         *ppoReturn = poGeom;
     146                 :     }
     147                 :     else
     148                 :     {
     149               0 :         delete poGeom;
     150                 :     }
     151                 : 
     152             544 :     return eErr;
     153                 : }
     154                 : 
     155                 : /************************************************************************/
     156                 : /*                        OGR_G_CreateFromWkb()                         */
     157                 : /************************************************************************/
     158                 : /**
     159                 :  * \brief Create a geometry object of the appropriate type from it's well known binary representation.
     160                 :  *
     161                 :  * Note that if nBytes is passed as zero, no checking can be done on whether
     162                 :  * the pabyData is sufficient.  This can result in a crash if the input
     163                 :  * data is corrupt.  This function returns no indication of the number of
     164                 :  * bytes from the data source actually used to represent the returned
     165                 :  * geometry object.  Use OGR_G_WkbSize() on the returned geometry to
     166                 :  * establish the number of bytes it required in WKB format.
     167                 :  *
     168                 :  * The OGRGeometryFactory::createFromWkb() CPP method  is the same as this
     169                 :  * function.
     170                 :  *
     171                 :  * @param pabyData pointer to the input BLOB data.
     172                 :  * @param hSRS handle to the spatial reference to be assigned to the
     173                 :  *             created geometry object.  This may be NULL.
     174                 :  * @param phGeometry the newly created geometry object will 
     175                 :  * be assigned to the indicated handle on return.  This will be NULL in case
     176                 :  * of failure.
     177                 :  * @param nBytes the number of bytes of data available in pabyData, or -1
     178                 :  * if it is not known, but assumed to be sufficient.
     179                 :  *
     180                 :  * @return OGRERR_NONE if all goes well, otherwise any of
     181                 :  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
     182                 :  * OGRERR_CORRUPT_DATA may be returned.
     183                 :  */
     184                 : 
     185              62 : OGRErr CPL_DLL OGR_G_CreateFromWkb( unsigned char *pabyData, 
     186                 :                                     OGRSpatialReferenceH hSRS,
     187                 :                                     OGRGeometryH *phGeometry, 
     188                 :                                     int nBytes )
     189                 : 
     190                 : {
     191                 :     return OGRGeometryFactory::createFromWkb( pabyData, 
     192                 :                                               (OGRSpatialReference *) hSRS,
     193                 :                                               (OGRGeometry **) phGeometry,
     194              62 :                                               nBytes );
     195                 : }
     196                 : 
     197                 : /************************************************************************/
     198                 : /*                           createFromWkt()                            */
     199                 : /************************************************************************/
     200                 : 
     201                 : /**
     202                 :  * \brief Create a geometry object of the appropriate type from it's well known text representation.
     203                 :  *
     204                 :  * The C function OGR_G_CreateFromWkt() is the same as this method.
     205                 :  *
     206                 :  * @param ppszData input zero terminated string containing well known text
     207                 :  *                representation of the geometry to be created.  The pointer
     208                 :  *                is updated to point just beyond that last character consumed.
     209                 :  * @param poSR pointer to the spatial reference to be assigned to the
     210                 :  *             created geometry object.  This may be NULL.
     211                 :  * @param ppoReturn the newly created geometry object will be assigned to the
     212                 :  *                  indicated pointer on return.  This will be NULL if the
     213                 :  *                  method fails. 
     214                 :  *
     215                 :  *  <b>Example:</b>
     216                 :  *
     217                 :  *  <pre>
     218                 :  *    const char* wkt= "POINT(0 0)";
     219                 :  *  
     220                 :  *    // cast because OGR_G_CreateFromWkt will move the pointer 
     221                 :  *    char* pszWkt = (char*) wkt.c_str(); 
     222                 :  *    OGRSpatialReferenceH ref = OSRNewSpatialReference(NULL);
     223                 :  *    OGRGeometryH new_geom;
     224                 :  *    OGRErr err = OGR_G_CreateFromWkt(&pszWkt, ref, &new_geom);
     225                 :  *  </pre>
     226                 :  *
     227                 :  *
     228                 :  *
     229                 :  * @return OGRERR_NONE if all goes well, otherwise any of
     230                 :  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
     231                 :  * OGRERR_CORRUPT_DATA may be returned.
     232                 :  */
     233                 : 
     234           16351 : OGRErr OGRGeometryFactory::createFromWkt(char **ppszData,
     235                 :                                          OGRSpatialReference * poSR,
     236                 :                                          OGRGeometry **ppoReturn )
     237                 : 
     238                 : {
     239                 :     OGRErr      eErr;
     240                 :     char        szToken[OGR_WKT_TOKEN_MAX];
     241           16351 :     char        *pszInput = *ppszData;
     242                 :     OGRGeometry *poGeom;
     243                 : 
     244           16351 :     *ppoReturn = NULL;
     245                 : 
     246                 : /* -------------------------------------------------------------------- */
     247                 : /*      Get the first token, which should be the geometry type.         */
     248                 : /* -------------------------------------------------------------------- */
     249           16351 :     if( OGRWktReadToken( pszInput, szToken ) == NULL )
     250               0 :         return OGRERR_CORRUPT_DATA;
     251                 : 
     252                 : /* -------------------------------------------------------------------- */
     253                 : /*      Instantiate a geometry of the appropriate type.                 */
     254                 : /* -------------------------------------------------------------------- */
     255           16351 :     if( EQUAL(szToken,"POINT") )
     256                 :     {
     257           14881 :         poGeom = new OGRPoint();
     258                 :     }
     259                 : 
     260            1470 :     else if( EQUAL(szToken,"LINESTRING") )
     261                 :     {
     262             128 :         poGeom = new OGRLineString();
     263                 :     }
     264                 : 
     265            1342 :     else if( EQUAL(szToken,"POLYGON") )
     266                 :     {
     267             179 :         poGeom = new OGRPolygon();
     268                 :     }
     269                 :     
     270            1163 :     else if( EQUAL(szToken,"GEOMETRYCOLLECTION") )
     271                 :     {
     272              21 :         poGeom = new OGRGeometryCollection();
     273                 :     }
     274                 :     
     275            1142 :     else if( EQUAL(szToken,"MULTIPOLYGON") )
     276                 :     {
     277              54 :         poGeom = new OGRMultiPolygon();
     278                 :     }
     279                 : 
     280            1088 :     else if( EQUAL(szToken,"MULTIPOINT") )
     281                 :     {
     282              36 :         poGeom = new OGRMultiPoint();
     283                 :     }
     284                 : 
     285            1052 :     else if( EQUAL(szToken,"MULTILINESTRING") )
     286                 :     {
     287              42 :         poGeom = new OGRMultiLineString();
     288                 :     }
     289                 : 
     290                 :     else
     291                 :     {
     292            1010 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     293                 :     }
     294                 : 
     295                 : /* -------------------------------------------------------------------- */
     296                 : /*      Do the import.                                                  */
     297                 : /* -------------------------------------------------------------------- */
     298           15341 :     eErr = poGeom->importFromWkt( &pszInput );
     299                 :     
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      Assign spatial reference system.                                */
     302                 : /* -------------------------------------------------------------------- */
     303           15341 :     if( eErr == OGRERR_NONE )
     304                 :     {
     305           15341 :         poGeom->assignSpatialReference( poSR );
     306           15341 :         *ppoReturn = poGeom;
     307           15341 :         *ppszData = pszInput;
     308                 :     }
     309                 :     else
     310                 :     {
     311               0 :         delete poGeom;
     312                 :     }
     313                 :     
     314           15341 :     return eErr;
     315                 : }
     316                 : 
     317                 : /************************************************************************/
     318                 : /*                        OGR_G_CreateFromWkt()                         */
     319                 : /************************************************************************/
     320                 : /**
     321                 :  * \brief Create a geometry object of the appropriate type from it's well known text representation.
     322                 :  *
     323                 :  * The OGRGeometryFactory::createFromWkt CPP method is the same as this
     324                 :  * function.
     325                 :  *
     326                 :  * @param ppszData input zero terminated string containing well known text
     327                 :  *                representation of the geometry to be created.  The pointer
     328                 :  *                is updated to point just beyond that last character consumed.
     329                 :  * @param hSRS handle to the spatial reference to be assigned to the
     330                 :  *             created geometry object.  This may be NULL.
     331                 :  * @param phGeometry the newly created geometry object will be assigned to the
     332                 :  *                  indicated handle on return.  This will be NULL if the
     333                 :  *                  method fails. 
     334                 :  *
     335                 :  * @return OGRERR_NONE if all goes well, otherwise any of
     336                 :  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
     337                 :  * OGRERR_CORRUPT_DATA may be returned.
     338                 :  */
     339                 : 
     340           15149 : OGRErr CPL_DLL OGR_G_CreateFromWkt( char **ppszData, 
     341                 :                                     OGRSpatialReferenceH hSRS,
     342                 :                                     OGRGeometryH *phGeometry )
     343                 : 
     344                 : {
     345                 :     return OGRGeometryFactory::createFromWkt( ppszData,
     346                 :                                               (OGRSpatialReference *) hSRS,
     347           15149 :                                               (OGRGeometry **) phGeometry );
     348                 : }
     349                 : 
     350                 : /************************************************************************/
     351                 : /*                           createGeometry()                           */
     352                 : /************************************************************************/
     353                 : 
     354                 : /** 
     355                 :  * \brief Create an empty geometry of desired type.
     356                 :  *
     357                 :  * This is equivelent to allocating the desired geometry with new, but
     358                 :  * the allocation is guaranteed to take place in the context of the 
     359                 :  * GDAL/OGR heap. 
     360                 :  *
     361                 :  * This method is the same as the C function OGR_G_CreateGeometry().
     362                 :  *
     363                 :  * @param eGeometryType the type code of the geometry class to be instantiated.
     364                 :  *
     365                 :  * @return the newly create geometry or NULL on failure.
     366                 :  */
     367                 : 
     368                 : OGRGeometry *
     369            1111 : OGRGeometryFactory::createGeometry( OGRwkbGeometryType eGeometryType )
     370                 : 
     371                 : {
     372            1111 :     switch( wkbFlatten(eGeometryType) )
     373                 :     {
     374                 :       case wkbPoint:
     375             140 :           return new OGRPoint();
     376                 : 
     377                 :       case wkbLineString:
     378             265 :           return new OGRLineString();
     379                 : 
     380                 :       case wkbPolygon:
     381             403 :           return new OGRPolygon();
     382                 : 
     383                 :       case wkbGeometryCollection:
     384              18 :           return new OGRGeometryCollection();
     385                 : 
     386                 :       case wkbMultiPolygon:
     387              37 :           return new OGRMultiPolygon();
     388                 : 
     389                 :       case wkbMultiPoint:
     390              20 :           return new OGRMultiPoint();
     391                 : 
     392                 :       case wkbMultiLineString:
     393              26 :           return new OGRMultiLineString();
     394                 : 
     395                 :       case wkbLinearRing:
     396             196 :           return new OGRLinearRing();
     397                 : 
     398                 :       default:
     399               6 :           return NULL;
     400                 :     }
     401                 : }
     402                 : 
     403                 : /************************************************************************/
     404                 : /*                        OGR_G_CreateGeometry()                        */
     405                 : /************************************************************************/
     406                 : /** 
     407                 :  * \brief Create an empty geometry of desired type.
     408                 :  *
     409                 :  * This is equivelent to allocating the desired geometry with new, but
     410                 :  * the allocation is guaranteed to take place in the context of the 
     411                 :  * GDAL/OGR heap. 
     412                 :  *
     413                 :  * This function is the same as the CPP method 
     414                 :  * OGRGeometryFactory::createGeometry.
     415                 :  *
     416                 :  * @param eGeometryType the type code of the geometry to be created.
     417                 :  *
     418                 :  * @return handle to the newly create geometry or NULL on failure.
     419                 :  */
     420                 : 
     421             560 : OGRGeometryH OGR_G_CreateGeometry( OGRwkbGeometryType eGeometryType )
     422                 : 
     423                 : {
     424             560 :     return (OGRGeometryH) OGRGeometryFactory::createGeometry( eGeometryType );
     425                 : }
     426                 : 
     427                 : 
     428                 : /************************************************************************/
     429                 : /*                          destroyGeometry()                           */
     430                 : /************************************************************************/
     431                 : 
     432                 : /**
     433                 :  * \brief Destroy geometry object.
     434                 :  *
     435                 :  * Equivalent to invoking delete on a geometry, but it guaranteed to take 
     436                 :  * place within the context of the GDAL/OGR heap.
     437                 :  *
     438                 :  * This method is the same as the C function OGR_G_DestroyGeometry().
     439                 :  *
     440                 :  * @param poGeom the geometry to deallocate.
     441                 :  */
     442                 : 
     443           15974 : void OGRGeometryFactory::destroyGeometry( OGRGeometry *poGeom )
     444                 : 
     445                 : {
     446           15974 :     delete poGeom;
     447           15974 : }
     448                 : 
     449                 : 
     450                 : /************************************************************************/
     451                 : /*                        OGR_G_DestroyGeometry()                       */
     452                 : /************************************************************************/
     453                 : /**
     454                 :  * \brief Destroy geometry object.
     455                 :  *
     456                 :  * Equivalent to invoking delete on a geometry, but it guaranteed to take 
     457                 :  * place within the context of the GDAL/OGR heap.
     458                 :  *
     459                 :  * This function is the same as the CPP method 
     460                 :  * OGRGeometryFactory::destroyGeometry.
     461                 :  *
     462                 :  * @param hGeom handle to the geometry to delete.
     463                 :  */
     464                 : 
     465           15899 : void OGR_G_DestroyGeometry( OGRGeometryH hGeom )
     466                 : 
     467                 : {
     468           15899 :     OGRGeometryFactory::destroyGeometry( (OGRGeometry *) hGeom );
     469           15899 : }
     470                 : 
     471                 : /************************************************************************/
     472                 : /*                           forceToPolygon()                           */
     473                 : /************************************************************************/
     474                 : 
     475                 : /**
     476                 :  * \brief Convert to polygon.
     477                 :  *
     478                 :  * Tries to force the provided geometry to be a polygon.  Currently
     479                 :  * this just effects a change on multipolygons.  The passed in geometry is
     480                 :  * consumed and a new one returned (or potentially the same one). 
     481                 :  * 
     482                 :  * @return new geometry.
     483                 :  */
     484                 : 
     485              10 : OGRGeometry *OGRGeometryFactory::forceToPolygon( OGRGeometry *poGeom )
     486                 : 
     487                 : {
     488              10 :     if( poGeom == NULL )
     489               0 :         return NULL;
     490                 : 
     491              10 :     if( wkbFlatten(poGeom->getGeometryType()) != wkbGeometryCollection
     492               0 :         || wkbFlatten(poGeom->getGeometryType()) != wkbMultiPolygon )
     493              10 :         return poGeom;
     494                 : 
     495                 :     // build an aggregated polygon from all the polygon rings in the container.
     496               0 :     OGRPolygon *poPolygon = new OGRPolygon();
     497               0 :     OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     498                 :     int iGeom;
     499                 : 
     500               0 :     for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
     501                 :     {
     502               0 :         if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType()) 
     503                 :             != wkbPolygon )
     504               0 :             continue;
     505                 : 
     506               0 :         OGRPolygon *poOldPoly = (OGRPolygon *) poGC->getGeometryRef(iGeom);
     507                 :         int   iRing;
     508                 : 
     509               0 :         poPolygon->addRing( poOldPoly->getExteriorRing() );
     510                 : 
     511               0 :         for( iRing = 0; iRing < poOldPoly->getNumInteriorRings(); iRing++ )
     512               0 :             poPolygon->addRing( poOldPoly->getInteriorRing( iRing ) );
     513                 :     }
     514                 :     
     515               0 :     delete poGC;
     516                 : 
     517               0 :     return poPolygon;
     518                 : }
     519                 : 
     520                 : /************************************************************************/
     521                 : /*                        forceToMultiPolygon()                         */
     522                 : /************************************************************************/
     523                 : 
     524                 : /**
     525                 :  * \brief Convert to multipolygon.
     526                 :  *
     527                 :  * Tries to force the provided geometry to be a multipolygon.  Currently
     528                 :  * this just effects a change on polygons.  The passed in geometry is
     529                 :  * consumed and a new one returned (or potentially the same one). 
     530                 :  * 
     531                 :  * @return new geometry.
     532                 :  */
     533                 : 
     534               0 : OGRGeometry *OGRGeometryFactory::forceToMultiPolygon( OGRGeometry *poGeom )
     535                 : 
     536                 : {
     537               0 :     if( poGeom == NULL )
     538               0 :         return NULL;
     539                 : 
     540                 : /* -------------------------------------------------------------------- */
     541                 : /*      Check for the case of a geometrycollection that can be          */
     542                 : /*      promoted to MultiPolygon.                                       */
     543                 : /* -------------------------------------------------------------------- */
     544               0 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection )
     545                 :     {
     546                 :         int iGeom;
     547               0 :         int bAllPoly = TRUE;
     548               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     549                 : 
     550               0 :         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
     551                 :         {
     552               0 :             if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType())
     553                 :                 != wkbPolygon )
     554               0 :                 bAllPoly = FALSE;
     555                 :         }
     556                 : 
     557               0 :         if( !bAllPoly )
     558               0 :             return poGeom;
     559                 :         
     560               0 :         OGRMultiPolygon *poMP = new OGRMultiPolygon();
     561                 : 
     562               0 :         while( poGC->getNumGeometries() > 0 )
     563                 :         {
     564               0 :             poMP->addGeometryDirectly( poGC->getGeometryRef(0) );
     565               0 :             poGC->removeGeometry( 0, FALSE );
     566                 :         }
     567                 : 
     568               0 :         delete poGC;
     569                 : 
     570               0 :         return poMP;
     571                 :     }
     572                 : 
     573                 : /* -------------------------------------------------------------------- */
     574                 : /*      Eventually we should try to split the polygon into component    */
     575                 : /*      island polygons.  But thats alot of work and can be put off.    */
     576                 : /* -------------------------------------------------------------------- */
     577               0 :     if( wkbFlatten(poGeom->getGeometryType()) != wkbPolygon )
     578               0 :         return poGeom;
     579                 : 
     580               0 :     OGRMultiPolygon *poMP = new OGRMultiPolygon();
     581               0 :     poMP->addGeometryDirectly( poGeom );
     582                 : 
     583               0 :     return poMP;
     584                 : }
     585                 : 
     586                 : /************************************************************************/
     587                 : /*                        forceToMultiPoint()                           */
     588                 : /************************************************************************/
     589                 : 
     590                 : /**
     591                 :  * \brief Convert to multipoint.
     592                 :  *
     593                 :  * Tries to force the provided geometry to be a multipoint.  Currently
     594                 :  * this just effects a change on points.  The passed in geometry is
     595                 :  * consumed and a new one returned (or potentially the same one). 
     596                 :  * 
     597                 :  * @return new geometry.
     598                 :  */
     599                 : 
     600               0 : OGRGeometry *OGRGeometryFactory::forceToMultiPoint( OGRGeometry *poGeom )
     601                 : 
     602                 : {
     603               0 :     if( poGeom == NULL )
     604               0 :         return NULL;
     605                 : 
     606                 : /* -------------------------------------------------------------------- */
     607                 : /*      Check for the case of a geometrycollection that can be          */
     608                 : /*      promoted to MultiPoint.                                         */
     609                 : /* -------------------------------------------------------------------- */
     610               0 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection )
     611                 :     {
     612                 :         int iGeom;
     613               0 :         int bAllPoint = TRUE;
     614               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     615                 : 
     616               0 :         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
     617                 :         {
     618               0 :             if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType())
     619                 :                 != wkbPoint )
     620               0 :                 bAllPoint = FALSE;
     621                 :         }
     622                 : 
     623               0 :         if( !bAllPoint )
     624               0 :             return poGeom;
     625                 :         
     626               0 :         OGRMultiPoint *poMP = new OGRMultiPoint();
     627                 : 
     628               0 :         while( poGC->getNumGeometries() > 0 )
     629                 :         {
     630               0 :             poMP->addGeometryDirectly( poGC->getGeometryRef(0) );
     631               0 :             poGC->removeGeometry( 0, FALSE );
     632                 :         }
     633                 : 
     634               0 :         delete poGC;
     635                 : 
     636               0 :         return poMP;
     637                 :     }
     638                 : 
     639               0 :     if( wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
     640               0 :         return poGeom;
     641                 : 
     642               0 :     OGRMultiPoint *poMP = new OGRMultiPoint();
     643               0 :     poMP->addGeometryDirectly( poGeom );
     644                 : 
     645               0 :     return poMP;
     646                 : }
     647                 : 
     648                 : /************************************************************************/
     649                 : /*                        forceToMultiLinestring()                      */
     650                 : /************************************************************************/
     651                 : 
     652                 : /**
     653                 :  * \brief Convert to multilinestring.
     654                 :  *
     655                 :  * Tries to force the provided geometry to be a multilinestring.
     656                 :  *
     657                 :  * - linestrings are placed in a multilinestring.
     658                 :  * - geometry collections will be converted to multilinestring if they only 
     659                 :  * contain linestrings.
     660                 :  * - polygons will be changed to a collection of linestrings (one per ring).
     661                 :  *
     662                 :  * The passed in geometry is
     663                 :  * consumed and a new one returned (or potentially the same one). 
     664                 :  * 
     665                 :  * @return new geometry.
     666                 :  */
     667                 : 
     668              18 : OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
     669                 : 
     670                 : {
     671              18 :     if( poGeom == NULL )
     672               0 :         return NULL;
     673                 : 
     674                 : /* -------------------------------------------------------------------- */
     675                 : /*      Check for the case of a geometrycollection that can be          */
     676                 : /*      promoted to MultiLineString.                                    */
     677                 : /* -------------------------------------------------------------------- */
     678              18 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection )
     679                 :     {
     680                 :         int iGeom;
     681               0 :         int bAllLines = TRUE;
     682               0 :         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
     683                 : 
     684               0 :         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
     685                 :         {
     686               0 :             if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType())
     687                 :                 != wkbLineString )
     688               0 :                 bAllLines = FALSE;
     689                 :         }
     690                 : 
     691               0 :         if( !bAllLines )
     692               0 :             return poGeom;
     693                 :         
     694               0 :         OGRMultiLineString *poMP = new OGRMultiLineString();
     695                 : 
     696               0 :         while( poGC->getNumGeometries() > 0 )
     697                 :         {
     698               0 :             poMP->addGeometryDirectly( poGC->getGeometryRef(0) );
     699               0 :             poGC->removeGeometry( 0, FALSE );
     700                 :         }
     701                 : 
     702               0 :         delete poGC;
     703                 : 
     704               0 :         return poMP;
     705                 :     }
     706                 : 
     707                 : /* -------------------------------------------------------------------- */
     708                 : /*      Turn a linestring into a multilinestring.                       */
     709                 : /* -------------------------------------------------------------------- */
     710              18 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
     711                 :     {
     712               0 :         OGRMultiLineString *poMP = new OGRMultiLineString();
     713               0 :         poMP->addGeometryDirectly( poGeom );
     714               0 :         return poMP;
     715                 :     }
     716                 : 
     717                 : /* -------------------------------------------------------------------- */
     718                 : /*      Convert polygons into a multilinestring.                        */
     719                 : /* -------------------------------------------------------------------- */
     720              18 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
     721                 :     {
     722               1 :         OGRMultiLineString *poMP = new OGRMultiLineString();
     723               1 :         OGRPolygon *poPoly = (OGRPolygon *) poGeom;
     724                 :         int iRing;
     725                 : 
     726               4 :         for( iRing = 0; iRing < poPoly->getNumInteriorRings()+1; iRing++ )
     727                 :         {
     728                 :             OGRLineString *poNewLS, *poLR;
     729                 : 
     730               1 :             if( iRing == 0 )
     731               1 :                 poLR = poPoly->getExteriorRing();
     732                 :             else
     733               0 :                 poLR = poPoly->getInteriorRing(iRing-1);
     734                 : 
     735               1 :             poNewLS = new OGRLineString();
     736               1 :             poNewLS->addSubLineString( poLR );
     737               1 :             poMP->addGeometryDirectly( poNewLS );
     738                 :         }
     739                 :         
     740               1 :         delete poPoly;
     741                 : 
     742               1 :         return poMP;
     743                 :     }
     744                 : 
     745                 : /* -------------------------------------------------------------------- */
     746                 : /*      Convert multi-polygons into a multilinestring.                  */
     747                 : /* -------------------------------------------------------------------- */
     748              17 :     if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon )
     749                 :     {
     750               0 :         OGRMultiLineString *poMP = new OGRMultiLineString();
     751               0 :         OGRMultiPolygon *poMPoly = (OGRMultiPolygon *) poGeom;
     752                 :         int iPoly;
     753                 : 
     754               0 :         for( iPoly = 0; iPoly < poMPoly->getNumGeometries(); iPoly++ )
     755                 :         {
     756               0 :             OGRPolygon *poPoly = (OGRPolygon*) poMPoly->getGeometryRef(iPoly);
     757                 :             int iRing;
     758                 : 
     759               0 :             for( iRing = 0; iRing < poPoly->getNumInteriorRings()+1; iRing++ )
     760                 :             {
     761                 :                 OGRLineString *poNewLS, *poLR;
     762                 :                 
     763               0 :                 if( iRing == 0 )
     764               0 :                     poLR = poPoly->getExteriorRing();
     765                 :                 else
     766               0 :                     poLR = poPoly->getInteriorRing(iRing-1);
     767                 :                 
     768               0 :                 poNewLS = new OGRLineString();
     769               0 :                 poNewLS->addSubLineString( poLR );
     770               0 :                 poMP->addGeometryDirectly( poNewLS );
     771                 :             }
     772                 :         }
     773               0 :         delete poMPoly;
     774                 : 
     775               0 :         return poMP;
     776                 :     }
     777                 : 
     778              17 :     return poGeom;
     779                 : }
     780                 : 
     781                 : /************************************************************************/
     782                 : /*                          organizePolygons()                          */
     783                 : /************************************************************************/
     784                 : 
     785                 : typedef struct _sPolyExtended sPolyExtended;
     786                 : 
     787                 : struct _sPolyExtended
     788             566 : {
     789                 :     OGRPolygon*     poPolygon;
     790                 :     OGREnvelope     sEnvelope;
     791                 :     OGRLinearRing*  poExteriorRing;
     792                 :     OGRPoint        poAPoint;
     793                 :     int             nInitialIndex;
     794                 :     int             bIsTopLevel;
     795                 :     OGRPolygon*     poEnclosingPolygon;
     796                 :     double          dfArea;
     797                 :     int             bIsCW;
     798                 : };
     799                 : 
     800             337 : static int OGRGeometryFactoryCompareArea(const void* p1, const void* p2)
     801                 : {
     802             337 :     const sPolyExtended* psPoly1 = (const sPolyExtended*) p1;
     803             337 :     const sPolyExtended* psPoly2 = (const sPolyExtended*) p2;
     804             337 :     if (psPoly2->dfArea < psPoly1->dfArea)
     805             188 :         return -1;
     806             149 :     else if (psPoly2->dfArea > psPoly1->dfArea)
     807             134 :         return 1;
     808                 :     else
     809              15 :         return 0;
     810                 : }
     811                 : 
     812             348 : static int OGRGeometryFactoryCompareByIndex(const void* p1, const void* p2)
     813                 : {
     814             348 :     const sPolyExtended* psPoly1 = (const sPolyExtended*) p1;
     815             348 :     const sPolyExtended* psPoly2 = (const sPolyExtended*) p2;
     816             348 :     if (psPoly1->nInitialIndex < psPoly2->nInitialIndex)
     817             208 :         return -1;
     818             140 :     else if (psPoly1->nInitialIndex > psPoly2->nInitialIndex)
     819             140 :         return 1;
     820                 :     else
     821               0 :         return 0;
     822                 : }
     823                 : 
     824                 : #define N_CRITICAL_PART_NUMBER   100
     825                 : 
     826                 : typedef enum
     827                 : {
     828                 :    METHOD_NORMAL,
     829                 :    METHOD_SKIP,
     830                 :    METHOD_ONLY_CCW
     831                 : } OrganizePolygonMethod;
     832                 : 
     833                 : /**
     834                 :  * \brief Organize polygons based on geometries.
     835                 :  *
     836                 :  * Analyse a set of rings (passed as simple polygons), and based on a 
     837                 :  * geometric analysis convert them into a polygon with inner rings, 
     838                 :  * or a MultiPolygon if dealing with more than one polygon.
     839                 :  *
     840                 :  * All the input geometries must be OGRPolygons with only a valid exterior
     841                 :  * ring (at least 4 points) and no interior rings. 
     842                 :  *
     843                 :  * The passed in geometries become the responsibility of the method, but the
     844                 :  * papoPolygons "pointer array" remains owned by the caller.
     845                 :  *
     846                 :  * For faster computation, a polygon is considered to be inside
     847                 :  * another one if a single point of its external ring is included into the other one.
     848                 :  * (unless 'OGR_DEBUG_ORGANIZE_POLYGONS' configuration option is set to TRUE.
     849                 :  * In that case, a slower algorithm that tests exact topological relationships 
     850                 :  * is used if GEOS is available.)
     851                 :  *
     852                 :  * In cases where a big number of polygons is passed to this function, the default processing
     853                 :  * may be really slow. You can skip the processing by adding METHOD=SKIP
     854                 :  * to the option list (the result of the function will be a multi-polygon with all polygons
     855                 :  * as toplevel polygons) or only make it analyze counterclockwise polygons by adding
     856                 :  * METHOD=ONLY_CCW to the option list if you can assume that the outline
     857                 :  * of holes is counterclockwise defined (this is the convention for shapefiles e.g.)
     858                 :  *
     859                 :  * If the OGR_ORGANIZE_POLYGONS configuration option is defined, its value will override
     860                 :  * the value of the METHOD option of papszOptions (usefull to modify the behaviour of the
     861                 :  * shapefile driver)
     862                 :  *
     863                 :  * @param papoPolygons array of geometry pointers - should all be OGRPolygons.
     864                 :  * Ownership of the geometries is passed, but not of the array itself.
     865                 :  * @param nPolygonCount number of items in papoPolygons
     866                 :  * @param pbIsValidGeometry value will be set TRUE if result is valid or 
     867                 :  * FALSE otherwise. 
     868                 :  * @param papszOptions a list of strings for passing options
     869                 :  *
     870                 :  * @return a single resulting geometry (either OGRPolygon or OGRMultiPolygon).
     871                 :  */
     872                 : 
     873              70 : OGRGeometry* OGRGeometryFactory::organizePolygons( OGRGeometry **papoPolygons,
     874                 :                                                    int nPolygonCount,
     875                 :                                                    int *pbIsValidGeometry,
     876                 :                                                    const char** papszOptions )
     877                 : {
     878                 :     int bUseFastVersion;
     879                 :     int i, j;
     880              70 :     OGRGeometry* geom = NULL;
     881              70 :     OrganizePolygonMethod method = METHOD_NORMAL;
     882                 : 
     883                 : /* -------------------------------------------------------------------- */
     884                 : /*      Trivial case of a single polygon.                               */
     885                 : /* -------------------------------------------------------------------- */
     886              70 :     if (nPolygonCount == 1)
     887                 :     {
     888               0 :         geom = papoPolygons[0];
     889               0 :         papoPolygons[0] = NULL;
     890                 : 
     891               0 :         if( pbIsValidGeometry )
     892               0 :             *pbIsValidGeometry = TRUE;
     893                 : 
     894               0 :         return geom;
     895                 :     }
     896                 : 
     897              70 :     if (CSLTestBoolean(CPLGetConfigOption("OGR_DEBUG_ORGANIZE_POLYGONS", "NO")))
     898                 :     {
     899                 :         /* -------------------------------------------------------------------- */
     900                 :         /*      A wee bit of a warning.                                         */
     901                 :         /* -------------------------------------------------------------------- */
     902                 :         static int firstTime = 1;
     903               0 :         if (!haveGEOS() && firstTime)
     904                 :         {
     905                 :             CPLDebug("OGR",
     906                 :                     "In OGR_DEBUG_ORGANIZE_POLYGONS mode, GDAL should be built with GEOS support enabled in order "
     907               0 :                     "OGRGeometryFactory::organizePolygons to provide reliable results on complex polygons.");
     908               0 :             firstTime = 0;
     909                 :         }
     910               0 :         bUseFastVersion = !haveGEOS();
     911                 :     }
     912                 :     else
     913                 :     {
     914              70 :         bUseFastVersion = TRUE;
     915                 :     }
     916                 : 
     917                 : /* -------------------------------------------------------------------- */
     918                 : /*      Setup per polygon envelope and area information.                */
     919                 : /* -------------------------------------------------------------------- */
     920              70 :     sPolyExtended* asPolyEx = new sPolyExtended[nPolygonCount];
     921                 : 
     922              70 :     int go_on = TRUE;
     923              70 :     int bMixedUpGeometries = FALSE;
     924              70 :     int bNonPolygon = FALSE;
     925              70 :     int bFoundCCW = FALSE;
     926                 : 
     927              70 :     const char* pszMethodValue = CSLFetchNameValue( (char**)papszOptions, "METHOD" );
     928              70 :     const char* pszMethodValueOption = CPLGetConfigOption("OGR_ORGANIZE_POLYGONS", NULL);
     929             126 :     if (pszMethodValueOption != NULL && pszMethodValueOption[0] != '\0')
     930               1 :         pszMethodValue = pszMethodValueOption;
     931                 : 
     932              70 :     if (pszMethodValue != NULL)
     933                 :     {
     934              17 :         if (EQUAL(pszMethodValue, "SKIP"))
     935                 :         {
     936               0 :             method = METHOD_SKIP;
     937               0 :             bMixedUpGeometries = TRUE;
     938                 :         }
     939              17 :         else if (EQUAL(pszMethodValue, "ONLY_CCW"))
     940                 :         {
     941              16 :             method = METHOD_ONLY_CCW;
     942                 :         }
     943               1 :         else if (!EQUAL(pszMethodValue, "DEFAULT"))
     944                 :         {
     945                 :             CPLError(CE_Warning, CPLE_AppDefined,
     946               0 :                      "Unrecognized value for METHOD option : %s", pszMethodValue);
     947                 :         }
     948                 :     }
     949                 : 
     950              70 :     int nCountCWPolygon = 0;
     951              70 :     int indexOfCWPolygon = -1;
     952                 : 
     953             353 :     for(i=0;i<nPolygonCount;i++)
     954                 :     {
     955             283 :         asPolyEx[i].nInitialIndex = i;
     956             283 :         asPolyEx[i].poPolygon = (OGRPolygon*)papoPolygons[i];
     957             283 :         papoPolygons[i]->getEnvelope(&asPolyEx[i].sEnvelope);
     958                 : 
     959             849 :         if( wkbFlatten(papoPolygons[i]->getGeometryType()) == wkbPolygon
     960             283 :             && ((OGRPolygon *) papoPolygons[i])->getNumInteriorRings() == 0
     961             283 :             && ((OGRPolygon *)papoPolygons[i])->getExteriorRing()->getNumPoints() >= 4)
     962                 :         {
     963             283 :             asPolyEx[i].dfArea = asPolyEx[i].poPolygon->get_Area();
     964             283 :             asPolyEx[i].poExteriorRing = asPolyEx[i].poPolygon->getExteriorRing();
     965             283 :             asPolyEx[i].poExteriorRing->getPoint(0, &asPolyEx[i].poAPoint);
     966             283 :             asPolyEx[i].bIsCW = asPolyEx[i].poExteriorRing->isClockwise();
     967             283 :             if (asPolyEx[i].bIsCW)
     968                 :             {
     969             213 :                 indexOfCWPolygon = i;
     970             213 :                 nCountCWPolygon ++;
     971                 :             }
     972             283 :             if (!bFoundCCW)
     973             163 :                 bFoundCCW = ! (asPolyEx[i].bIsCW);
     974                 :         }
     975                 :         else
     976                 :         {
     977               0 :             if( !bMixedUpGeometries )
     978                 :             {
     979                 :                 CPLError( 
     980                 :                     CE_Warning, CPLE_AppDefined, 
     981                 :                     "organizePolygons() received an unexpected geometry.\n"
     982                 :                     "Either a polygon with interior rings, or a polygon with less than 4 points,\n"
     983               0 :                     "or a non-Polygon geometry.  Return arguments as a collection." );
     984               0 :                 bMixedUpGeometries = TRUE;
     985                 :             }
     986               0 :             if( wkbFlatten(papoPolygons[i]->getGeometryType()) != wkbPolygon )
     987               0 :                 bNonPolygon = TRUE;
     988                 :         }
     989                 :     }
     990                 : 
     991                 :     /* If we are in ONLY_CCW mode and that we have found that there is only one outer ring, */
     992                 :     /* then it is pretty easy : we can assume that all other rings are inside */
     993              70 :     if (method == METHOD_ONLY_CCW && nCountCWPolygon == 1 && bUseFastVersion)
     994                 :     {
     995               3 :         geom = asPolyEx[indexOfCWPolygon].poPolygon;
     996              10 :         for(i=0; i<nPolygonCount; i++)
     997                 :         {
     998               7 :             if (i != indexOfCWPolygon)
     999                 :             {
    1000               4 :                 ((OGRPolygon*)geom)->addRing(asPolyEx[i].poPolygon->getExteriorRing());
    1001               4 :                 delete asPolyEx[i].poPolygon;
    1002                 :             }
    1003                 :         }
    1004               3 :         delete [] asPolyEx;
    1005               3 :         if (pbIsValidGeometry)
    1006               3 :             *pbIsValidGeometry = TRUE;
    1007               3 :         return geom;
    1008                 :     }
    1009                 : 
    1010                 :     /* Emits a warning if the number of parts is sufficiently big to anticipate for */
    1011                 :     /* very long computation time, and the user didn't specify an explicit method */
    1012              67 :     if (nPolygonCount > N_CRITICAL_PART_NUMBER && method == METHOD_NORMAL && pszMethodValue == NULL)
    1013                 :     {
    1014                 :         static int firstTime = 1;
    1015               0 :         if (firstTime)
    1016                 :         {
    1017               0 :             if (bFoundCCW)
    1018                 :             {
    1019                 :                 CPLError( CE_Warning, CPLE_AppDefined, 
    1020                 :                      "organizePolygons() received a polygon with more than %d parts. "
    1021                 :                      "The processing may be really slow.\n"
    1022                 :                      "You can skip the processing by setting METHOD=SKIP, "
    1023                 :                      "or only make it analyze counter-clock wise parts by setting "
    1024                 :                      "METHOD=ONLY_CCW if you can assume that the "
    1025               0 :                      "outline of holes is counter-clock wise defined", N_CRITICAL_PART_NUMBER);
    1026                 :             }
    1027                 :             else
    1028                 :             {
    1029                 :                 CPLError( CE_Warning, CPLE_AppDefined, 
    1030                 :                         "organizePolygons() received a polygon with more than %d parts. "
    1031                 :                         "The processing may be really slow.\n"
    1032                 :                         "You can skip the processing by setting METHOD=SKIP.",
    1033               0 :                         N_CRITICAL_PART_NUMBER);
    1034                 :             }
    1035               0 :             firstTime = 0;
    1036                 :         }
    1037                 :     }
    1038                 : 
    1039                 : 
    1040                 :     /* This a several steps algorithm :
    1041                 :        1) Sort polygons by descending areas
    1042                 :        2) For each polygon of rank i, find its smallest enclosing polygon
    1043                 :           among the polygons of rank [i-1 ... 0]. If there are no such polygon,
    1044                 :           this is a toplevel polygon. Otherwise, depending on if the enclosing
    1045                 :           polygon is toplevel or not, we can decide if we are toplevel or not
    1046                 :        3) Re-sort the polygons to retrieve their inital order (nicer for some applications)
    1047                 :        4) For each non toplevel polygon (= inner ring), add it to its outer ring
    1048                 :        5) Add the toplevel polygons to the multipolygon
    1049                 : 
    1050                 :        Complexity : O(nPolygonCount^2)
    1051                 :     */
    1052                 : 
    1053                 :     /* Compute how each polygon relate to the other ones
    1054                 :        To save a bit of computation we always begin the computation by a test 
    1055                 :        on the enveloppe. We also take into account the areas to avoid some 
    1056                 :        useless tests.  (A contains B implies envelop(A) contains envelop(B) 
    1057                 :        and area(A) > area(B)) In practise, we can hope that few full geometry 
    1058                 :        intersection of inclusion test is done:
    1059                 :        * if the polygons are well separated geographically (a set of islands 
    1060                 :        for example), no full geometry intersection or inclusion test is done. 
    1061                 :        (the envelopes don't intersect each other)
    1062                 : 
    1063                 :        * if the polygons are 'lake inside an island inside a lake inside an 
    1064                 :        area' and that each polygon is much smaller than its enclosing one, 
    1065                 :        their bounding boxes are stricly contained into each oter, and thus, 
    1066                 :        no full geometry intersection or inclusion test is done
    1067                 :     */
    1068                 : 
    1069              67 :     if (!bMixedUpGeometries)
    1070                 :     {
    1071                 :         /* STEP 1 : Sort polygons by descending area */
    1072              67 :         qsort(asPolyEx, nPolygonCount, sizeof(sPolyExtended), OGRGeometryFactoryCompareArea);
    1073                 :     }
    1074              67 :     papoPolygons = NULL; /* just to use to avoid it afterwards */
    1075                 : 
    1076                 : /* -------------------------------------------------------------------- */
    1077                 : /*      Compute relationships, if things seem well structured.          */
    1078                 : /* -------------------------------------------------------------------- */
    1079                 : 
    1080                 :     /* The first (largest) polygon is necessarily top-level */
    1081              67 :     asPolyEx[0].bIsTopLevel = TRUE;
    1082              67 :     asPolyEx[0].poEnclosingPolygon = NULL;
    1083                 : 
    1084              67 :     int nCountTopLevel = 1;
    1085                 : 
    1086                 :     /* STEP 2 */
    1087             276 :     for(i=1; !bMixedUpGeometries && go_on && i<nPolygonCount; i++)
    1088                 :     {
    1089             209 :         if (method == METHOD_ONLY_CCW && asPolyEx[i].bIsCW)
    1090                 :         {
    1091              20 :             nCountTopLevel ++;
    1092              20 :             asPolyEx[i].bIsTopLevel = TRUE;
    1093              20 :             asPolyEx[i].poEnclosingPolygon = NULL;
    1094              20 :             continue;
    1095                 :         }
    1096                 : 
    1097             409 :         for(j=i-1; go_on && j>=0;j--)
    1098                 :         {
    1099             373 :             int b_i_inside_j = FALSE;
    1100                 : 
    1101             373 :             if (method == METHOD_ONLY_CCW && asPolyEx[j].bIsCW == FALSE)
    1102                 :             {
    1103                 :                 /* In that mode, i which is CCW if we reach here can only be */
    1104                 :                 /* included in a CW polygon */
    1105               5 :                 continue;
    1106                 :             }
    1107                 : 
    1108             368 :             if (asPolyEx[j].sEnvelope.Contains(asPolyEx[i].sEnvelope))
    1109                 :             {
    1110             154 :                 if (bUseFastVersion)
    1111                 :                 {
    1112                 :                     /* Note that isPointInRing only test strict inclusion in the ring */
    1113             154 :                     if (asPolyEx[j].poExteriorRing->isPointInRing(&asPolyEx[i].poAPoint, FALSE))
    1114                 :                     {
    1115             152 :                         b_i_inside_j = TRUE;
    1116                 :                     }
    1117               2 :                     else if (asPolyEx[j].poExteriorRing->isPointOnRingBoundary(&asPolyEx[i].poAPoint, FALSE))
    1118                 :                     {
    1119                 :                         /* If the point of i is on the boundary of j, we will iterate over the other points of i */
    1120               2 :                         int k, nPoints = asPolyEx[i].poExteriorRing->getNumPoints();
    1121               2 :                         for(k=1;k<nPoints;k++)
    1122                 :                         {
    1123               6 :                             OGRPoint point;
    1124               6 :                             asPolyEx[i].poExteriorRing->getPoint(k, &point);
    1125               6 :                             if (asPolyEx[j].poExteriorRing->isPointInRing(&point, FALSE))
    1126                 :                             {
    1127                 :                                 /* If then point is strictly included in j, then i is considered inside j */
    1128               1 :                                 b_i_inside_j = TRUE;
    1129                 :                                 break;
    1130                 :                             }
    1131               5 :                             else if (asPolyEx[j].poExteriorRing->isPointOnRingBoundary(&point, FALSE))
    1132                 :                             {
    1133                 :                                 /* If it is on the boundary of j, iterate again */ 
    1134                 :                             }
    1135                 :                             else
    1136                 :                             {
    1137                 :                                 /* If it is outside, then i cannot be inside j */
    1138                 :                                 break;
    1139                 :                             }
    1140                 :                         }
    1141                 :                     }
    1142                 :                 }
    1143               0 :                 else if (asPolyEx[j].poPolygon->Contains(asPolyEx[i].poPolygon))
    1144                 :                 {
    1145               0 :                     b_i_inside_j = TRUE;
    1146                 :                 }
    1147                 :             }
    1148                 : 
    1149                 : 
    1150             368 :             if (b_i_inside_j)
    1151                 :             {
    1152             153 :                 if (asPolyEx[j].bIsTopLevel)
    1153                 :                 {
    1154                 :                     /* We are a lake */
    1155             119 :                     asPolyEx[i].bIsTopLevel = FALSE;
    1156             119 :                     asPolyEx[i].poEnclosingPolygon = asPolyEx[j].poPolygon;
    1157                 :                 }
    1158                 :                 else
    1159                 :                 {
    1160                 :                     /* We are included in a something not toplevel (a lake), */
    1161                 :                     /* so in OGCSF we are considered as toplevel too */
    1162              34 :                     nCountTopLevel ++;
    1163              34 :                     asPolyEx[i].bIsTopLevel = TRUE;
    1164              34 :                     asPolyEx[i].poEnclosingPolygon = NULL;
    1165                 :                 }
    1166             153 :                 break;
    1167                 :             }
    1168                 :             /* We use Overlaps instead of Intersects to be more 
    1169                 :                tolerant about touching polygons */ 
    1170             215 :             else if ( bUseFastVersion || !asPolyEx[i].sEnvelope.Intersects(asPolyEx[j].sEnvelope)
    1171               0 :                      || !asPolyEx[i].poPolygon->Overlaps(asPolyEx[j].poPolygon) )
    1172                 :             {
    1173                 : 
    1174                 :             }
    1175                 :             else
    1176                 :             {
    1177                 :                 /* Bad... The polygons are intersecting but no one is
    1178                 :                    contained inside the other one. This is a really broken
    1179                 :                    case. We just make a multipolygon with the whole set of
    1180                 :                    polygons */
    1181               0 :                 go_on = FALSE;
    1182                 : #ifdef DEBUG
    1183                 :                 char* wkt1;
    1184                 :                 char* wkt2;
    1185                 :                 asPolyEx[i].poPolygon->exportToWkt(&wkt1);
    1186                 :                 asPolyEx[j].poPolygon->exportToWkt(&wkt2);
    1187                 :                 CPLDebug( "OGR", 
    1188                 :                           "Bad intersection for polygons %d and %d\n"
    1189                 :                           "geom %d: %s\n"
    1190                 :                           "geom %d: %s", 
    1191                 :                           i, j, i, wkt1, j, wkt2 );
    1192                 :                 CPLFree(wkt1);
    1193                 :                 CPLFree(wkt2);
    1194                 : #endif
    1195                 :             }
    1196                 :         }
    1197                 : 
    1198             189 :         if (j < 0)
    1199                 :         {
    1200                 :             /* We come here because we are not included in anything */
    1201                 :             /* We are toplevel */
    1202              36 :             nCountTopLevel ++;
    1203              36 :             asPolyEx[i].bIsTopLevel = TRUE;
    1204              36 :             asPolyEx[i].poEnclosingPolygon = NULL;
    1205                 :         }
    1206                 :     }
    1207                 : 
    1208              67 :     if (pbIsValidGeometry)
    1209              67 :         *pbIsValidGeometry = go_on && !bMixedUpGeometries;
    1210                 : 
    1211                 : /* -------------------------------------------------------------------- */
    1212                 : /*      Things broke down - just turn everything into a multipolygon.   */
    1213                 : /* -------------------------------------------------------------------- */
    1214              67 :     if ( !go_on || bMixedUpGeometries )
    1215                 :     {
    1216               0 :         if( bNonPolygon )
    1217               0 :             geom = new OGRGeometryCollection();
    1218                 :         else
    1219               0 :             geom = new OGRMultiPolygon();
    1220                 : 
    1221               0 :         for( i=0; i < nPolygonCount; i++ )
    1222                 :         {
    1223                 :             ((OGRGeometryCollection*)geom)->
    1224               0 :                 addGeometryDirectly( asPolyEx[i].poPolygon );
    1225                 :         }
    1226                 :     }
    1227                 : 
    1228                 : /* -------------------------------------------------------------------- */
    1229                 : /*      Try to turn into one or more polygons based on the ring         */
    1230                 : /*      relationships.                                                  */
    1231                 : /* -------------------------------------------------------------------- */
    1232                 :     else
    1233                 :     {
    1234                 :         /* STEP 3: Resort in initial order */
    1235              67 :         qsort(asPolyEx, nPolygonCount, sizeof(sPolyExtended), OGRGeometryFactoryCompareByIndex);
    1236                 : 
    1237                 :         /* STEP 4: Add holes as rings of their enclosing polygon */
    1238             343 :         for(i=0;i<nPolygonCount;i++)
    1239                 :         {
    1240             276 :             if (asPolyEx[i].bIsTopLevel == FALSE)
    1241                 :             {
    1242             119 :                 asPolyEx[i].poEnclosingPolygon->addRing(
    1243             238 :                     asPolyEx[i].poPolygon->getExteriorRing());
    1244             119 :                 delete asPolyEx[i].poPolygon;
    1245                 :             }
    1246             157 :             else if (nCountTopLevel == 1)
    1247                 :             {
    1248              19 :                 geom = asPolyEx[i].poPolygon;
    1249                 :             }
    1250                 :         }
    1251                 : 
    1252                 :         /* STEP 5: Add toplevel polygons */
    1253              67 :         if (nCountTopLevel > 1)
    1254                 :         {
    1255             284 :             for(i=0;i<nPolygonCount;i++)
    1256                 :             {
    1257             236 :                 if (asPolyEx[i].bIsTopLevel)
    1258                 :                 {
    1259             138 :                     if (geom == NULL)
    1260                 :                     {
    1261              48 :                         geom = new OGRMultiPolygon();
    1262              48 :                         ((OGRMultiPolygon*)geom)->addGeometryDirectly(asPolyEx[i].poPolygon);
    1263                 :                     }
    1264                 :                     else
    1265                 :                     {
    1266              90 :                         ((OGRMultiPolygon*)geom)->addGeometryDirectly(asPolyEx[i].poPolygon);
    1267                 :                     }
    1268                 :                 }
    1269                 :             }
    1270                 :         }
    1271                 :     }
    1272                 : 
    1273              67 :     delete[] asPolyEx;
    1274                 : 
    1275              67 :     return geom;
    1276                 : }
    1277                 : 
    1278                 : /************************************************************************/
    1279                 : /*                           createFromGML()                            */
    1280                 : /************************************************************************/
    1281                 : 
    1282                 : /**
    1283                 :  * \brief Create geometry from GML.
    1284                 :  *
    1285                 :  * This method translates a fragment of GML containing only the geometry
    1286                 :  * portion into a corresponding OGRGeometry.  There are many limitations
    1287                 :  * on the forms of GML geometries supported by this parser, but they are
    1288                 :  * too numerous to list here. 
    1289                 :  *
    1290                 :  * The C function OGR_G_CreateFromGML() is the same as this method.
    1291                 :  *
    1292                 :  * @param pszData The GML fragment for the geometry.
    1293                 :  *
    1294                 :  * @return a geometry on succes, or NULL on error.  
    1295                 :  */
    1296                 : 
    1297              52 : OGRGeometry *OGRGeometryFactory::createFromGML( const char *pszData )
    1298                 : 
    1299                 : {
    1300                 :     OGRGeometryH hGeom;
    1301                 : 
    1302              52 :     hGeom = OGR_G_CreateFromGML( pszData );
    1303                 :     
    1304              52 :     return (OGRGeometry *) hGeom;
    1305                 : }
    1306                 : 
    1307                 : /************************************************************************/
    1308                 : /*                           createFromGEOS()                           */
    1309                 : /************************************************************************/
    1310                 : 
    1311                 : OGRGeometry *
    1312              23 : OGRGeometryFactory::createFromGEOS( GEOSGeom geosGeom )
    1313                 : 
    1314                 : {
    1315                 : #ifndef HAVE_GEOS 
    1316                 : 
    1317                 :     CPLError( CE_Failure, CPLE_NotSupported, 
    1318                 :               "GEOS support not enabled." );
    1319                 :     return NULL;
    1320                 : 
    1321                 : #else
    1322                 : 
    1323              23 :     size_t nSize = 0;
    1324              23 :     unsigned char *pabyBuf = NULL;
    1325              23 :     OGRGeometry *poGeometry = NULL;
    1326                 : 
    1327              23 :     pabyBuf = GEOSGeomToWKB_buf( geosGeom, &nSize );
    1328              23 :     if( pabyBuf == NULL || nSize == 0 )
    1329                 :     {
    1330               0 :         return NULL;
    1331                 :     }
    1332                 : 
    1333              23 :     if( OGRGeometryFactory::createFromWkb( (unsigned char *) pabyBuf, 
    1334                 :                                            NULL, &poGeometry, (int) nSize )
    1335                 :         != OGRERR_NONE )
    1336                 :     {
    1337               0 :         poGeometry = NULL;
    1338                 :     }
    1339                 : 
    1340              23 :     if( pabyBuf != NULL )
    1341                 :     {
    1342                 : #if GEOS_CAPI_VERSION_MAJOR >= 2 || (GEOS_CAPI_VERSION_MAJOR == 1 && GEOS_CAPI_VERSION_MINOR >= 6)
    1343              23 :         GEOSFree( pabyBuf );
    1344                 : #else
    1345                 :         free( pabyBuf );
    1346                 : #endif
    1347                 :     }
    1348                 : 
    1349              23 :     return poGeometry;
    1350                 : 
    1351                 : #endif /* HAVE_GEOS */
    1352                 : }
    1353                 : 
    1354                 : /************************************************************************/
    1355                 : /*                       getGEOSGeometryFactory()                       */
    1356                 : /************************************************************************/
    1357                 : 
    1358               0 : void *OGRGeometryFactory::getGEOSGeometryFactory() 
    1359                 : 
    1360                 : {
    1361                 :     // XXX - mloskot - What to do with this call
    1362                 :     // after GEOS C++ API has been stripped?
    1363               0 :     return NULL;
    1364                 : }
    1365                 : 
    1366                 : /************************************************************************/
    1367                 : /*                              haveGEOS()                              */
    1368                 : /************************************************************************/
    1369                 : 
    1370                 : /**
    1371                 :  * \brief Test if GEOS enabled.
    1372                 :  *
    1373                 :  * This static method returns TRUE if GEOS support is built into OGR,
    1374                 :  * otherwise it returns FALSE.
    1375                 :  *
    1376                 :  * @return TRUE if available, otherwise FALSE.
    1377                 :  */
    1378                 : 
    1379              34 : int OGRGeometryFactory::haveGEOS()
    1380                 : 
    1381                 : {
    1382                 : #ifndef HAVE_GEOS 
    1383                 :     return FALSE;
    1384                 : #else
    1385              34 :     return TRUE;
    1386                 : #endif
    1387                 : }
    1388                 : 
    1389                 : /************************************************************************/
    1390                 : /*                           createFromFgf()                            */
    1391                 : /************************************************************************/
    1392                 : 
    1393                 : /**
    1394                 :  * \brief Create a geometry object of the appropriate type from it's FGF (FDO Geometry Format) binary representation.
    1395                 :  *
    1396                 :  * Also note that this is a static method, and that there
    1397                 :  * is no need to instantiate an OGRGeometryFactory object.  
    1398                 :  *
    1399                 :  * The C function OGR_G_CreateFromFgf() is the same as this method.
    1400                 :  *
    1401                 :  * @param pabyData pointer to the input BLOB data.
    1402                 :  * @param poSR pointer to the spatial reference to be assigned to the
    1403                 :  *             created geometry object.  This may be NULL.
    1404                 :  * @param ppoReturn the newly created geometry object will be assigned to the
    1405                 :  *                  indicated pointer on return.  This will be NULL in case
    1406                 :  *                  of failure.
    1407                 :  * @param nBytes the number of bytes available in pabyData.
    1408                 :  * @param pnBytesConsumed if not NULL, it will be set to the number of bytes 
    1409                 :  * consumed (at most nBytes).
    1410                 :  *
    1411                 :  * @return OGRERR_NONE if all goes well, otherwise any of
    1412                 :  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
    1413                 :  * OGRERR_CORRUPT_DATA may be returned.
    1414                 :  */
    1415                 : 
    1416              10 : OGRErr OGRGeometryFactory::createFromFgf( unsigned char *pabyData,
    1417                 :                                           OGRSpatialReference * poSR,
    1418                 :                                           OGRGeometry **ppoReturn,
    1419                 :                                           int nBytes,
    1420                 :                                           int *pnBytesConsumed )
    1421                 : 
    1422                 : {
    1423              10 :     OGRErr       eErr = OGRERR_NONE;
    1424              10 :     OGRGeometry *poGeom = NULL;
    1425                 :     GInt32       nGType, nGDim;
    1426              10 :     int          nTupleSize = 0;
    1427              10 :     int          iOrdinal = 0;
    1428                 :     
    1429                 :     (void) iOrdinal;
    1430                 : 
    1431              10 :     *ppoReturn = NULL;
    1432                 : 
    1433              10 :     if( nBytes < 4 )
    1434               0 :         return OGRERR_NOT_ENOUGH_DATA;
    1435                 : 
    1436                 : /* -------------------------------------------------------------------- */
    1437                 : /*      Decode the geometry type.                                       */
    1438                 : /* -------------------------------------------------------------------- */
    1439              10 :     memcpy( &nGType, pabyData + 0, 4 );
    1440                 :     CPL_LSBPTR32( &nGType );
    1441                 : 
    1442              10 :     if( nGType < 0 || nGType > 13 )
    1443               0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1444                 : 
    1445                 : /* -------------------------------------------------------------------- */
    1446                 : /*      Decode the dimentionality if appropriate.                       */
    1447                 : /* -------------------------------------------------------------------- */
    1448              10 :     switch( nGType )
    1449                 :     {
    1450                 :       case 1: // Point
    1451                 :       case 2: // LineString
    1452                 :       case 3: // Polygon
    1453                 :         
    1454               8 :         if( nBytes < 8 )
    1455               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1456                 : 
    1457               8 :         memcpy( &nGDim, pabyData + 4, 4 );
    1458                 :         CPL_LSBPTR32( &nGDim );
    1459                 :         
    1460               8 :         if( nGDim < 0 || nGDim > 3 )
    1461               0 :             return OGRERR_CORRUPT_DATA;
    1462                 : 
    1463               8 :         nTupleSize = 2;
    1464               8 :         if( nGDim & 0x01 ) // Z
    1465               1 :             nTupleSize++;
    1466               8 :         if( nGDim & 0x02 ) // M
    1467               0 :             nTupleSize++;
    1468                 : 
    1469                 :         break;
    1470                 : 
    1471                 :       default:
    1472                 :         break;
    1473                 :     }
    1474                 : 
    1475                 : /* -------------------------------------------------------------------- */
    1476                 : /*      None                                                            */
    1477                 : /* -------------------------------------------------------------------- */
    1478              10 :     if( nGType == 0 ) 
    1479                 :     {
    1480               0 :         if( pnBytesConsumed )
    1481               0 :             *pnBytesConsumed = 4;
    1482                 :     }
    1483                 : 
    1484                 : /* -------------------------------------------------------------------- */
    1485                 : /*      Point                                                           */
    1486                 : /* -------------------------------------------------------------------- */
    1487              10 :     else if( nGType == 1 )
    1488                 :     {
    1489                 :         double  adfTuple[4];
    1490                 : 
    1491               2 :         if( nBytes < nTupleSize * 8 + 8 )
    1492               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1493                 : 
    1494               2 :         memcpy( adfTuple, pabyData + 8, nTupleSize*8 );
    1495                 : #ifdef CPL_MSB
    1496                 :         for( iOrdinal = 0; iOrdinal < nTupleSize; iOrdinal++ )
    1497                 :             CPL_SWAP64PTR( adfTuple + iOrdinal );
    1498                 : #endif
    1499               2 :         if( nTupleSize > 2 )
    1500               1 :             poGeom = new OGRPoint( adfTuple[0], adfTuple[1], adfTuple[2] );
    1501                 :         else
    1502               1 :             poGeom = new OGRPoint( adfTuple[0], adfTuple[1] );
    1503                 : 
    1504               2 :         if( pnBytesConsumed )
    1505               0 :             *pnBytesConsumed = 8 + nTupleSize * 8;
    1506                 :     }
    1507                 : 
    1508                 : /* -------------------------------------------------------------------- */
    1509                 : /*      LineString                                                      */
    1510                 : /* -------------------------------------------------------------------- */
    1511               8 :     else if( nGType == 2 )
    1512                 :     {
    1513                 :         double adfTuple[4];
    1514                 :         GInt32 nPointCount;
    1515                 :         int    iPoint;
    1516                 :         OGRLineString *poLS;
    1517                 : 
    1518               2 :         if( nBytes < 12 )
    1519               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1520                 : 
    1521               2 :         memcpy( &nPointCount, pabyData + 8, 4 );
    1522                 :         CPL_LSBPTR32( &nPointCount );
    1523                 : 
    1524               2 :         if (nPointCount < 0 || nPointCount > INT_MAX / (nTupleSize * 8))
    1525               0 :             return OGRERR_CORRUPT_DATA;
    1526                 : 
    1527               2 :         if( nBytes - 12 < nTupleSize * 8 * nPointCount )
    1528               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1529                 : 
    1530               2 :         poGeom = poLS = new OGRLineString();
    1531               2 :         poLS->setNumPoints( nPointCount );
    1532                 : 
    1533               4 :         for( iPoint = 0; iPoint < nPointCount; iPoint++ )
    1534                 :         {
    1535                 :             memcpy( adfTuple, pabyData + 12 + 8*nTupleSize*iPoint, 
    1536               2 :                     nTupleSize*8 );
    1537                 : #ifdef CPL_MSB
    1538                 :             for( iOrdinal = 0; iOrdinal < nTupleSize; iOrdinal++ )
    1539                 :                 CPL_SWAP64PTR( adfTuple + iOrdinal );
    1540                 : #endif
    1541               2 :             if( nTupleSize > 2 )
    1542               0 :                 poLS->setPoint( iPoint, adfTuple[0], adfTuple[1], adfTuple[2] );
    1543                 :             else
    1544               2 :                 poLS->setPoint( iPoint, adfTuple[0], adfTuple[1] );
    1545                 :         }
    1546                 : 
    1547               2 :         if( pnBytesConsumed )
    1548               0 :             *pnBytesConsumed = 12 + nTupleSize * 8 * nPointCount;
    1549                 :     }
    1550                 : 
    1551                 : /* -------------------------------------------------------------------- */
    1552                 : /*      Polygon                                                         */
    1553                 : /* -------------------------------------------------------------------- */
    1554               6 :     else if( nGType == 3 )
    1555                 :     {
    1556                 :         double adfTuple[4];
    1557                 :         GInt32 nPointCount;
    1558                 :         GInt32 nRingCount;
    1559                 :         int    iPoint, iRing;
    1560                 :         OGRLinearRing *poLR;
    1561                 :         OGRPolygon *poPoly;
    1562                 :         int    nNextByte;
    1563                 : 
    1564               4 :         if( nBytes < 12 )
    1565               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1566                 : 
    1567               4 :         memcpy( &nRingCount, pabyData + 8, 4 );
    1568                 :         CPL_LSBPTR32( &nRingCount );
    1569                 : 
    1570               4 :         if (nRingCount < 0 || nRingCount > INT_MAX / 4)
    1571               0 :             return OGRERR_CORRUPT_DATA;
    1572                 : 
    1573                 :         /* Each ring takes at least 4 bytes */
    1574               4 :         if (nBytes - 12 < nRingCount * 4)
    1575               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1576                 : 
    1577               4 :         nNextByte = 12;
    1578                 :         
    1579               4 :         poGeom = poPoly = new OGRPolygon();
    1580                 : 
    1581              10 :         for( iRing = 0; iRing < nRingCount; iRing++ )
    1582                 :         {
    1583               6 :             if( nBytes - nNextByte < 4 )
    1584               0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1585                 : 
    1586               6 :             memcpy( &nPointCount, pabyData + nNextByte, 4 );
    1587                 :             CPL_LSBPTR32( &nPointCount );
    1588                 : 
    1589               6 :             if (nPointCount < 0 || nPointCount > INT_MAX / (nTupleSize * 8))
    1590               0 :                 return OGRERR_CORRUPT_DATA;
    1591                 : 
    1592               6 :             nNextByte += 4;
    1593                 : 
    1594               6 :             if( nBytes - nNextByte < nTupleSize * 8 * nPointCount )
    1595               0 :                 return OGRERR_NOT_ENOUGH_DATA;
    1596                 : 
    1597               6 :             poLR = new OGRLinearRing();
    1598               6 :             poLR->setNumPoints( nPointCount );
    1599                 :             
    1600              12 :             for( iPoint = 0; iPoint < nPointCount; iPoint++ )
    1601                 :             {
    1602               6 :                 memcpy( adfTuple, pabyData + nNextByte, nTupleSize*8 );
    1603               6 :                 nNextByte += nTupleSize * 8;
    1604                 : 
    1605                 : #ifdef CPL_MSB
    1606                 :                 for( iOrdinal = 0; iOrdinal < nTupleSize; iOrdinal++ )
    1607                 :                     CPL_SWAP64PTR( adfTuple + iOrdinal );
    1608                 : #endif
    1609               6 :                 if( nTupleSize > 2 )
    1610               0 :                     poLR->setPoint( iPoint, adfTuple[0], adfTuple[1], adfTuple[2] );
    1611                 :                 else
    1612               6 :                     poLR->setPoint( iPoint, adfTuple[0], adfTuple[1] );
    1613                 :             }
    1614                 : 
    1615               6 :             poPoly->addRingDirectly( poLR );
    1616                 :         }
    1617                 : 
    1618               4 :         if( pnBytesConsumed )
    1619               2 :             *pnBytesConsumed = nNextByte;
    1620                 :     }
    1621                 : 
    1622                 : /* -------------------------------------------------------------------- */
    1623                 : /*      GeometryCollections of various kinds.                           */
    1624                 : /* -------------------------------------------------------------------- */
    1625               4 :     else if( nGType == 4         // MultiPoint
    1626                 :              || nGType == 5      // MultiLineString
    1627                 :              || nGType == 6      // MultiPolygon
    1628                 :              || nGType == 7 )    // MultiGeometry
    1629                 :     {
    1630               2 :         OGRGeometryCollection *poGC = NULL;
    1631                 :         GInt32 nGeomCount;
    1632                 :         int iGeom, nBytesUsed;
    1633                 : 
    1634               2 :         if( nGType == 4 )
    1635               0 :             poGC = new OGRMultiPoint();
    1636               2 :         else if( nGType == 5 )
    1637               0 :             poGC = new OGRMultiLineString();
    1638               2 :         else if( nGType == 6 )
    1639               0 :             poGC = new OGRMultiPolygon();
    1640               2 :         else if( nGType == 7 )
    1641               2 :             poGC = new OGRGeometryCollection();
    1642                 : 
    1643               2 :         if( nBytes < 8 )
    1644               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1645                 : 
    1646               2 :         memcpy( &nGeomCount, pabyData + 4, 4 );
    1647                 :         CPL_LSBPTR32( &nGeomCount );
    1648                 : 
    1649               2 :         if (nGeomCount < 0 || nGeomCount > INT_MAX / 4)
    1650               0 :             return OGRERR_CORRUPT_DATA;
    1651                 : 
    1652                 :         /* Each geometry takes at least 4 bytes */
    1653               2 :         if (nBytes - 8 < 4 * nGeomCount)
    1654               0 :             return OGRERR_NOT_ENOUGH_DATA;
    1655                 : 
    1656               2 :         nBytesUsed = 8;
    1657                 : 
    1658               4 :         for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
    1659                 :         {
    1660                 :             int nThisGeomSize;
    1661               2 :             OGRGeometry *poThisGeom = NULL;
    1662                 :          
    1663                 :             eErr = createFromFgf( pabyData + nBytesUsed, poSR, &poThisGeom,
    1664               2 :                                   nBytes - nBytesUsed, &nThisGeomSize);
    1665               2 :             if( eErr != OGRERR_NONE )
    1666                 :             {
    1667               0 :                 delete poGC;
    1668               0 :                 return eErr;
    1669                 :             }
    1670                 : 
    1671               2 :             nBytesUsed += nThisGeomSize;
    1672               2 :             eErr = poGC->addGeometryDirectly( poThisGeom );
    1673               2 :             if( eErr != OGRERR_NONE )
    1674                 :             {
    1675               0 :                 delete poGC;
    1676               0 :                 return eErr;
    1677                 :             }
    1678                 :         }
    1679                 : 
    1680               2 :         poGeom = poGC;
    1681               2 :         if( pnBytesConsumed )
    1682               0 :             *pnBytesConsumed = nBytesUsed;
    1683                 :     }
    1684                 : 
    1685                 : /* -------------------------------------------------------------------- */
    1686                 : /*      Currently unsupported geometry.                                 */
    1687                 : /*                                                                      */
    1688                 : /*      We need to add 10/11/12/13 curve types in some fashion.         */
    1689                 : /* -------------------------------------------------------------------- */
    1690                 :     else
    1691                 :     {
    1692               0 :         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
    1693                 :     }
    1694                 : 
    1695                 : /* -------------------------------------------------------------------- */
    1696                 : /*      Assign spatial reference system.                                */
    1697                 : /* -------------------------------------------------------------------- */
    1698              10 :     if( eErr == OGRERR_NONE )
    1699                 :     {
    1700              10 :         if( poGeom != NULL && poSR )
    1701               0 :             poGeom->assignSpatialReference( poSR );
    1702              10 :         *ppoReturn = poGeom;
    1703                 :     }
    1704                 :     else
    1705                 :     {
    1706               0 :         delete poGeom;
    1707                 :     }
    1708                 : 
    1709              10 :     return eErr;
    1710                 : }
    1711                 : 
    1712                 : /************************************************************************/
    1713                 : /*                        OGR_G_CreateFromFgf()                         */
    1714                 : /************************************************************************/
    1715                 : 
    1716               0 : OGRErr CPL_DLL OGR_G_CreateFromFgf( unsigned char *pabyData, 
    1717                 :                                     OGRSpatialReferenceH hSRS,
    1718                 :                                     OGRGeometryH *phGeometry, 
    1719                 :                                     int nBytes, int *pnBytesConsumed )
    1720                 : 
    1721                 : {
    1722                 :     return OGRGeometryFactory::createFromFgf( pabyData, 
    1723                 :                                               (OGRSpatialReference *) hSRS,
    1724                 :                                               (OGRGeometry **) phGeometry,
    1725               0 :                                               nBytes, pnBytesConsumed );
    1726                 : }
    1727                 : 
    1728                 : 
    1729                 : /************************************************************************/
    1730                 : /*                           Add360ToNegLon()                           */
    1731                 : /************************************************************************/
    1732                 : 
    1733               2 : static void Add360ToNegLon( OGRGeometry* poGeom )
    1734                 : {
    1735               2 :     switch (wkbFlatten(poGeom->getGeometryType()))
    1736                 :     {
    1737                 :         case wkbPolygon:
    1738                 :         case wkbMultiLineString:
    1739                 :         case wkbMultiPolygon:
    1740                 :         case wkbGeometryCollection:
    1741                 :         {
    1742               1 :             int nSubGeomCount = OGR_G_GetGeometryCount((OGRGeometryH)poGeom);
    1743               2 :             for( int iGeom = 0; iGeom < nSubGeomCount; iGeom++ )
    1744                 :             {
    1745               1 :                 Add360ToNegLon((OGRGeometry*)OGR_G_GetGeometryRef((OGRGeometryH)poGeom, iGeom));
    1746                 :             }
    1747                 :             
    1748               1 :             break;
    1749                 :         }
    1750                 :             
    1751                 :         case wkbLineString:
    1752                 :         case wkbLinearRing:
    1753                 :         {
    1754               1 :             OGRLineString* poLineString = (OGRLineString* )poGeom;
    1755               1 :             int nPointCount = poLineString->getNumPoints();
    1756               1 :             int nCoordDim = poLineString->getCoordinateDimension();
    1757               6 :             for( int iPoint = 0; iPoint < nPointCount; iPoint++)
    1758                 :             {
    1759               5 :                 if (poLineString->getX(iPoint) < -90)
    1760                 :                 {
    1761               2 :                     if (nCoordDim == 2)
    1762                 :                         poLineString->setPoint(iPoint,
    1763                 :                                          poLineString->getX(iPoint) + 360,
    1764               2 :                                          poLineString->getY(iPoint));
    1765                 :                     else
    1766                 :                         poLineString->setPoint(iPoint,
    1767                 :                                          poLineString->getX(iPoint) + 360,
    1768                 :                                          poLineString->getY(iPoint),
    1769               0 :                                          poLineString->getZ(iPoint));
    1770                 :                 }
    1771                 :             }
    1772                 :             break;
    1773                 :         }
    1774                 :             
    1775                 :         default:
    1776                 :             break;
    1777                 :     }
    1778               2 : }
    1779                 : 
    1780                 : /************************************************************************/
    1781                 : /*                            Sub360ToLon()                             */
    1782                 : /************************************************************************/
    1783                 : 
    1784               2 : static void Sub360ToLon( OGRGeometry* poGeom )
    1785                 : {
    1786               2 :     switch (wkbFlatten(poGeom->getGeometryType()))
    1787                 :     {
    1788                 :         case wkbPolygon:
    1789                 :         case wkbMultiLineString:
    1790                 :         case wkbMultiPolygon:
    1791                 :         case wkbGeometryCollection:
    1792                 :         {
    1793               1 :             int nSubGeomCount = OGR_G_GetGeometryCount((OGRGeometryH)poGeom);
    1794               2 :             for( int iGeom = 0; iGeom < nSubGeomCount; iGeom++ )
    1795                 :             {
    1796               1 :                 Sub360ToLon((OGRGeometry*)OGR_G_GetGeometryRef((OGRGeometryH)poGeom, iGeom));
    1797                 :             }
    1798                 :             
    1799               1 :             break;
    1800                 :         }
    1801                 :             
    1802                 :         case wkbLineString:
    1803                 :         case wkbLinearRing:
    1804                 :         {
    1805               1 :             OGRLineString* poLineString = (OGRLineString* )poGeom;
    1806               1 :             int nPointCount = poLineString->getNumPoints();
    1807               1 :             int nCoordDim = poLineString->getCoordinateDimension();
    1808               6 :             for( int iPoint = 0; iPoint < nPointCount; iPoint++)
    1809                 :             {
    1810               5 :                 if (nCoordDim == 2)
    1811                 :                     poLineString->setPoint(iPoint,
    1812                 :                                      poLineString->getX(iPoint) - 360,
    1813               5 :                                      poLineString->getY(iPoint));
    1814                 :                 else
    1815                 :                     poLineString->setPoint(iPoint,
    1816                 :                                      poLineString->getX(iPoint) - 360,
    1817                 :                                      poLineString->getY(iPoint),
    1818               0 :                                      poLineString->getZ(iPoint));
    1819                 :             }
    1820                 :             break;
    1821                 :         }
    1822                 :             
    1823                 :         default:
    1824                 :             break;
    1825                 :     }
    1826               2 : }
    1827                 : 
    1828                 : /************************************************************************/
    1829                 : /*                        AddSimpleGeomToMulti()                        */
    1830                 : /************************************************************************/
    1831                 : 
    1832               2 : static void AddSimpleGeomToMulti(OGRGeometryCollection* poMulti,
    1833                 :                                  const OGRGeometry* poGeom)
    1834                 : {
    1835               2 :     switch (wkbFlatten(poGeom->getGeometryType()))
    1836                 :     {
    1837                 :         case wkbPolygon:
    1838                 :         case wkbLineString:
    1839               2 :             poMulti->addGeometry(poGeom);
    1840               2 :             break;
    1841                 :             
    1842                 :         case wkbMultiLineString:
    1843                 :         case wkbMultiPolygon:
    1844                 :         case wkbGeometryCollection:
    1845                 :         {
    1846               0 :             int nSubGeomCount = OGR_G_GetGeometryCount((OGRGeometryH)poGeom);
    1847               0 :             for( int iGeom = 0; iGeom < nSubGeomCount; iGeom++ )
    1848                 :             {
    1849                 :                 OGRGeometry* poSubGeom =
    1850               0 :                     (OGRGeometry*)OGR_G_GetGeometryRef((OGRGeometryH)poGeom, iGeom);
    1851               0 :                 AddSimpleGeomToMulti(poMulti, poSubGeom);
    1852                 :             }
    1853                 :             break;
    1854                 :         }
    1855                 :             
    1856                 :         default:
    1857                 :             break;
    1858                 :     }
    1859               2 : }
    1860                 : 
    1861                 : /************************************************************************/
    1862                 : /*                 CutGeometryOnDateLineAndAddToMulti()                 */
    1863                 : /************************************************************************/
    1864                 : 
    1865               1 : static void CutGeometryOnDateLineAndAddToMulti(OGRGeometryCollection* poMulti,
    1866                 :                                                const OGRGeometry* poGeom)
    1867                 : {
    1868               1 :     switch (wkbFlatten(poGeom->getGeometryType()))
    1869                 :     {
    1870                 :         case wkbPolygon:
    1871                 :         case wkbLineString:
    1872                 :         {
    1873               1 :             int bWrapDateline = FALSE;
    1874               1 :             OGREnvelope oEnvelope;
    1875                 :             
    1876               1 :             poGeom->getEnvelope(&oEnvelope);
    1877                 :             
    1878                 :             /* Naive heuristics... Place to improvement... */
    1879               1 :             OGRGeometry* poDupGeom = NULL;
    1880                 :             
    1881               2 :             if (oEnvelope.MinX < -170 && oEnvelope.MaxX > 170)
    1882                 :             {
    1883               1 :                 bWrapDateline = TRUE;
    1884               1 :                 poDupGeom = poGeom->clone();
    1885               1 :                 Add360ToNegLon(poDupGeom);
    1886                 :             }
    1887               0 :             else if (oEnvelope.MinX > 170 && oEnvelope.MaxX > 180)
    1888               0 :                 bWrapDateline = TRUE;
    1889                 : 
    1890               1 :             if (bWrapDateline)
    1891                 :             {
    1892                 : #ifndef HAVE_GEOS
    1893                 :                 CPLError( CE_Failure, CPLE_NotSupported, 
    1894                 :                           "GEOS support not enabled." );
    1895                 : 
    1896                 :                 poMulti->addGeometry(poGeom);
    1897                 : #else
    1898               1 :                 const OGRGeometry* poWorkGeom = (poDupGeom) ? poDupGeom : poGeom;
    1899               1 :                 OGRGeometry* poRectangle1 = NULL;
    1900               1 :                 OGRGeometry* poRectangle2 = NULL;
    1901               1 :                 const char* pszWKT1 = "POLYGON((0 90,180 90,180 -90,0 -90,0 90))";
    1902               1 :                 const char* pszWKT2 = "POLYGON((180 90,360 90,360 -90,180 -90,180 90))";
    1903               1 :                 OGRGeometryFactory::createFromWkt((char**)&pszWKT1, NULL, &poRectangle1);
    1904               1 :                 OGRGeometryFactory::createFromWkt((char**)&pszWKT2, NULL, &poRectangle2);
    1905               1 :                 OGRGeometry* poGeom1 = poWorkGeom->Intersection(poRectangle1);
    1906               1 :                 OGRGeometry* poGeom2 = poWorkGeom->Intersection(poRectangle2);
    1907               1 :                 delete poRectangle1;
    1908               1 :                 delete poRectangle2;
    1909                 :                 
    1910               2 :                 if (poGeom1 != NULL && poGeom2 != NULL)
    1911                 :                 {
    1912               1 :                     AddSimpleGeomToMulti(poMulti, poGeom1);
    1913               1 :                     Sub360ToLon(poGeom2);
    1914               1 :                     AddSimpleGeomToMulti(poMulti, poGeom2);
    1915                 :                 }
    1916                 :                 else
    1917                 :                 {
    1918               0 :                     AddSimpleGeomToMulti(poMulti, poGeom);
    1919                 :                 }
    1920                 :                 
    1921               1 :                 delete poGeom1;
    1922               1 :                 delete poGeom2;
    1923               1 :                 delete poDupGeom;
    1924                 : #endif
    1925                 :             }
    1926                 :             else
    1927                 :             {
    1928               0 :                 poMulti->addGeometry(poGeom);
    1929                 :             }   
    1930               1 :             break;
    1931                 :         }
    1932                 :             
    1933                 :         case wkbMultiLineString:
    1934                 :         case wkbMultiPolygon:
    1935                 :         case wkbGeometryCollection:
    1936                 :         {
    1937               0 :             int nSubGeomCount = OGR_G_GetGeometryCount((OGRGeometryH)poGeom);
    1938               0 :             for( int iGeom = 0; iGeom < nSubGeomCount; iGeom++ )
    1939                 :             {
    1940                 :                 OGRGeometry* poSubGeom =
    1941               0 :                     (OGRGeometry*)OGR_G_GetGeometryRef((OGRGeometryH)poGeom, iGeom);
    1942               0 :                 CutGeometryOnDateLineAndAddToMulti(poMulti, poSubGeom);
    1943                 :             }
    1944                 :             break;
    1945                 :         }
    1946                 :             
    1947                 :         default:
    1948                 :             break;
    1949                 :     }
    1950               1 : }
    1951                 : 
    1952                 : /************************************************************************/
    1953                 : /*                       transformWithOptions()                         */
    1954                 : /************************************************************************/
    1955                 : 
    1956              11 : OGRGeometry* OGRGeometryFactory::transformWithOptions( const OGRGeometry* poSrcGeom,
    1957                 :                                                        OGRCoordinateTransformation *poCT,
    1958                 :                                                        char** papszOptions )
    1959                 : {
    1960              11 :     OGRGeometry* poDstGeom = poSrcGeom->clone();
    1961              11 :     OGRErr eErr = poDstGeom->transform(poCT);
    1962              11 :     if (eErr != OGRERR_NONE)
    1963                 :     {
    1964               0 :         delete poDstGeom;
    1965               0 :         return NULL;
    1966                 :     }
    1967                 :     
    1968              11 :     if (CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "WRAPDATELINE", "NO")))
    1969                 :     {
    1970               1 :         OGRwkbGeometryType eType = wkbFlatten(poSrcGeom->getGeometryType());
    1971                 :         OGRwkbGeometryType eNewType;
    1972               2 :         if (eType == wkbPolygon || eType == wkbMultiPolygon)
    1973               1 :             eNewType = wkbMultiPolygon;
    1974               0 :         else if (eType == wkbLineString || eType == wkbMultiLineString)
    1975               0 :             eNewType = wkbMultiLineString;
    1976                 :         else
    1977               0 :             eNewType = wkbGeometryCollection;
    1978                 :         
    1979                 :         OGRGeometryCollection* poMulti =
    1980               1 :             (OGRGeometryCollection* )createGeometry(eNewType);
    1981                 :             
    1982               1 :         CutGeometryOnDateLineAndAddToMulti(poMulti, poDstGeom);
    1983                 :         
    1984               1 :         if (poMulti->getNumGeometries() == 0)
    1985                 :         {
    1986               0 :             delete poMulti;
    1987                 :         }            
    1988               1 :         else if (poMulti->getNumGeometries() == 1)
    1989                 :         {
    1990               0 :             delete poDstGeom;
    1991               0 :             poDstGeom = poMulti->getGeometryRef(0)->clone();
    1992               0 :             delete poMulti;
    1993                 :         }
    1994                 :         else
    1995                 :         {
    1996               1 :             delete poDstGeom;
    1997               1 :             poDstGeom = poMulti;
    1998                 :         }
    1999                 :     }
    2000                 : 
    2001              11 :     return poDstGeom;
    2002                 : }
    2003                 : 
    2004                 : /************************************************************************/
    2005                 : /*                        approximateArcAngles()                        */
    2006                 : /************************************************************************/
    2007                 : 
    2008                 : /**
    2009                 :  * Stroke arc to linestring.
    2010                 :  *
    2011                 :  * Stroke an arc of a circle to a linestring based on a center
    2012                 :  * point, radius, start angle and end angle, all angles in degrees.
    2013                 :  *
    2014                 :  * If the dfMaxAngleStepSizeDegrees is zero, then a default value will be
    2015                 :  * used.  This is currently 4 degrees unless the user has overridden the
    2016                 :  * value with the OGR_ARC_STEPSIZE configuration variable. 
    2017                 :  *
    2018                 :  * @see CPLSetConfigOption()
    2019                 :  *
    2020                 :  * @param dfCenterX center X
    2021                 :  * @param dfCenterY center Y
    2022                 :  * @param dfZ center Z
    2023                 :  * @param dfPrimaryRadius X radius of ellipse.
    2024                 :  * @param dfSecondaryRadius Y radius of ellipse. 
    2025                 :  * @param dfRotation rotation of the ellipse clockwise.
    2026                 :  * @param dfStartAngle angle to first point on arc (clockwise of X-positive) 
    2027                 :  * @param dfEndAngle angle to last point on arc (clockwise of X-positive) 
    2028                 :  * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
    2029                 :  * arc, zero to use the default setting.
    2030                 :  * 
    2031                 :  * @return OGRLineString geometry representing an approximation of the arc.
    2032                 :  */
    2033                 : 
    2034               7 : OGRGeometry* OGRGeometryFactory::approximateArcAngles( 
    2035                 :     double dfCenterX, double dfCenterY, double dfZ,
    2036                 :     double dfPrimaryRadius, double dfSecondaryRadius, double dfRotation, 
    2037                 :     double dfStartAngle, double dfEndAngle,
    2038                 :     double dfMaxAngleStepSizeDegrees )
    2039                 : 
    2040                 : {
    2041                 :     double             dfSlice;
    2042                 :     int                iPoint, nVertexCount;
    2043               7 :     OGRLineString     *poLine = new OGRLineString();
    2044               7 :     double             dfRotationRadians = dfRotation * PI / 180.0;
    2045                 : 
    2046                 :     // support default arc step setting.
    2047               7 :     if( dfMaxAngleStepSizeDegrees == 0 )
    2048                 :     {
    2049                 :         dfMaxAngleStepSizeDegrees = 
    2050               6 :             atof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4"));
    2051                 :     }
    2052                 : 
    2053                 :     // switch direction 
    2054               7 :     dfStartAngle *= -1;
    2055               7 :     dfEndAngle *= -1;
    2056                 : 
    2057                 :     // Figure out the number of slices to make this into.
    2058                 :     nVertexCount = (int) 
    2059               7 :         ceil(fabs(dfEndAngle - dfStartAngle)/dfMaxAngleStepSizeDegrees) + 1;
    2060               7 :     nVertexCount = MAX(2,nVertexCount);
    2061               7 :     dfSlice = (dfEndAngle-dfStartAngle)/(nVertexCount-1);
    2062                 : 
    2063                 : /* -------------------------------------------------------------------- */
    2064                 : /*      Compute the interpolated points.                                */
    2065                 : /* -------------------------------------------------------------------- */
    2066             427 :     for( iPoint=0; iPoint < nVertexCount; iPoint++ )
    2067                 :     {
    2068                 :         double      dfAngleOnEllipse;
    2069                 :         double      dfArcX, dfArcY;
    2070                 :         double      dfEllipseX, dfEllipseY;
    2071                 : 
    2072             420 :         dfAngleOnEllipse = (dfStartAngle + iPoint * dfSlice) * PI / 180.0;
    2073                 : 
    2074                 :         // Compute position on the unrotated ellipse. 
    2075             420 :         dfEllipseX = cos(dfAngleOnEllipse) * dfPrimaryRadius;
    2076             420 :         dfEllipseY = sin(dfAngleOnEllipse) * dfSecondaryRadius;
    2077                 :         
    2078                 :         // Rotate this position around the center of the ellipse.
    2079                 :         dfArcX = dfCenterX 
    2080                 :             + dfEllipseX * cos(dfRotationRadians) 
    2081             420 :             + dfEllipseY * sin(dfRotationRadians);
    2082                 :         dfArcY = dfCenterY 
    2083                 :             - dfEllipseX * sin(dfRotationRadians)
    2084             420 :             + dfEllipseY * cos(dfRotationRadians);
    2085                 : 
    2086             420 :         poLine->setPoint( iPoint, dfArcX, dfArcY, dfZ );
    2087                 :     }
    2088                 : 
    2089               7 :     return poLine;
    2090                 : }
    2091                 : 
    2092                 : /************************************************************************/
    2093                 : /*                     OGR_G_ApproximateArcAngles()                     */
    2094                 : /************************************************************************/
    2095                 : 
    2096                 : OGRGeometryH CPL_DLL 
    2097               1 : OGR_G_ApproximateArcAngles( 
    2098                 :     double dfCenterX, double dfCenterY, double dfZ,
    2099                 :     double dfPrimaryRadius, double dfSecondaryAxis, double dfRotation, 
    2100                 :     double dfStartAngle, double dfEndAngle,
    2101                 :     double dfMaxAngleStepSizeDegrees )
    2102                 : 
    2103                 : {
    2104                 :     return (OGRGeometryH) OGRGeometryFactory::approximateArcAngles(
    2105                 :         dfCenterX, dfCenterY, dfZ, 
    2106                 :         dfPrimaryRadius, dfSecondaryAxis, dfRotation,
    2107               1 :         dfStartAngle, dfEndAngle, dfMaxAngleStepSizeDegrees );
    2108                 : }

Generated by: LCOV version 1.7