LCOV - code coverage report
Current view: directory - ogr - gml2ogrgeometry.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 859 688 80.1 %
Date: 2012-04-28 Functions: 12 12 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gml2ogrgeometry.cpp 23863 2012-02-01 19:20:54Z rouault $
       3                 :  *
       4                 :  * Project:  GML Reader
       5                 :  * Purpose:  Code to translate between GML and OGR geometry forms.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2002, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  * 
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  * 
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  *****************************************************************************
      29                 :  *
      30                 :  * Independent Security Audit 2003/04/17 Andrey Kiselev:
      31                 :  *   Completed audit of this module. All functions may be used without buffer
      32                 :  *   overflows and stack corruptions with any kind of input data.
      33                 :  *
      34                 :  * Security Audit 2003/03/28 warmerda:
      35                 :  *   Completed security audit.  I believe that this module may be safely used 
      36                 :  *   to parse, arbitrary GML potentially provided by a hostile source without
      37                 :  *   compromising the system.
      38                 :  *
      39                 :  */
      40                 : 
      41                 : #include "cpl_minixml.h"
      42                 : #include "ogr_geometry.h"
      43                 : #include "ogr_api.h"
      44                 : #include "cpl_error.h"
      45                 : #include "cpl_string.h"
      46                 : #include <ctype.h>
      47                 : #include "ogr_p.h"
      48                 : 
      49                 : #ifndef PI
      50                 : #define PI  3.14159265358979323846
      51                 : #endif
      52                 : 
      53                 : 
      54                 : /************************************************************************/
      55                 : /*                        GMLGetCoordTokenPos()                         */
      56                 : /************************************************************************/
      57                 : 
      58          139660 : static const char* GMLGetCoordTokenPos(const char* pszStr,
      59                 :                                        const char** ppszNextToken)
      60                 : {
      61                 :     char ch;
      62           65790 :     while(TRUE)
      63                 :     {
      64          139660 :         ch = *pszStr;
      65          139660 :         if (ch == '\0')
      66                 :         {
      67             150 :             *ppszNextToken = NULL;
      68             150 :             return NULL;
      69                 :         }
      70          139510 :         else if (!(ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ' || ch == ','))
      71                 :             break;
      72           65790 :         pszStr ++;
      73                 :     }
      74                 : 
      75           73720 :     const char* pszToken = pszStr;
      76          857958 :     while((ch = *pszStr) != '\0')
      77                 :     {
      78          775946 :         if (ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ' || ch == ',')
      79                 :         {
      80           65428 :             *ppszNextToken = pszStr;
      81           65428 :             return pszToken;
      82                 :         }
      83          710518 :         pszStr ++;
      84                 :     }
      85            8292 :     *ppszNextToken = NULL;
      86            8292 :     return pszToken;
      87                 : }
      88                 : 
      89                 : /************************************************************************/
      90                 : /*                           BareGMLElement()                           */
      91                 : /*                                                                      */
      92                 : /*      Returns the passed string with any namespace prefix             */
      93                 : /*      stripped off.                                                   */
      94                 : /************************************************************************/
      95                 : 
      96           85304 : static const char *BareGMLElement( const char *pszInput )
      97                 : 
      98                 : {
      99                 :     const char *pszReturn;
     100                 : 
     101           85304 :     pszReturn = strchr( pszInput, ':' );
     102           85304 :     if( pszReturn == NULL )
     103           83202 :         pszReturn = pszInput;
     104                 :     else
     105            2102 :         pszReturn++;
     106                 : 
     107           85304 :     return pszReturn;
     108                 : }
     109                 : 
     110                 : /************************************************************************/
     111                 : /*                          FindBareXMLChild()                          */
     112                 : /*                                                                      */
     113                 : /*      Find a child node with the indicated "bare" name, that is       */
     114                 : /*      after any namespace qualifiers have been stripped off.          */
     115                 : /************************************************************************/
     116                 : 
     117           30608 : static const CPLXMLNode *FindBareXMLChild( const CPLXMLNode *psParent, 
     118                 :                                            const char *pszBareName )
     119                 : 
     120                 : {
     121           30608 :     const CPLXMLNode *psCandidate = psParent->psChild;
     122                 : 
     123           87840 :     while( psCandidate != NULL )
     124                 :     {
     125           46752 :         if( psCandidate->eType == CXT_Element
     126                 :             && EQUAL(BareGMLElement(psCandidate->pszValue), pszBareName) )
     127           20128 :             return psCandidate;
     128                 : 
     129           26624 :         psCandidate = psCandidate->psNext;
     130                 :     }
     131                 : 
     132           10480 :     return NULL;
     133                 : }
     134                 : 
     135                 : /************************************************************************/
     136                 : /*                           GetElementText()                           */
     137                 : /************************************************************************/
     138                 : 
     139            8814 : static const char *GetElementText( const CPLXMLNode *psElement )
     140                 : 
     141                 : {
     142            8814 :     if( psElement == NULL )
     143               0 :         return NULL;
     144                 : 
     145            8814 :     const CPLXMLNode *psChild = psElement->psChild;
     146                 : 
     147           19322 :     while( psChild != NULL )
     148                 :     {
     149           10500 :         if( psChild->eType == CXT_Text )
     150            8806 :             return psChild->pszValue;
     151                 : 
     152            1694 :         psChild = psChild->psNext;
     153                 :     }
     154                 :     
     155               8 :     return NULL;
     156                 : }
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                           GetChildElement()                          */
     160                 : /************************************************************************/
     161                 : 
     162            6066 : static const CPLXMLNode *GetChildElement( const CPLXMLNode *psElement )
     163                 : 
     164                 : {
     165            6066 :     if( psElement == NULL )
     166               0 :         return NULL;
     167                 : 
     168            6066 :     const CPLXMLNode *psChild = psElement->psChild;
     169                 : 
     170           12134 :     while( psChild != NULL )
     171                 :     {
     172            6058 :         if( psChild->eType == CXT_Element )
     173            6056 :             return psChild;
     174                 : 
     175               2 :         psChild = psChild->psNext;
     176                 :     }
     177                 : 
     178              10 :     return NULL;
     179                 : }
     180                 : 
     181                 : /************************************************************************/
     182                 : /*                    GetElementOrientation()                           */
     183                 : /*     Returns true for positive orientation.                           */
     184                 : /************************************************************************/
     185                 : 
     186            1424 : int GetElementOrientation( const CPLXMLNode *psElement )
     187                 : {
     188            1424 :     if( psElement == NULL )
     189               0 :         return TRUE;
     190                 : 
     191            1424 :     const CPLXMLNode *psChild = psElement->psChild;
     192                 : 
     193            3816 :     while( psChild != NULL )
     194                 :     {
     195            1424 :         if( psChild->eType == CXT_Attribute &&
     196                 :             EQUAL(psChild->pszValue,"orientation") )
     197             456 :                 return EQUAL(psChild->psChild->pszValue,"+");
     198                 : 
     199             968 :         psChild = psChild->psNext;
     200                 :     }
     201                 :     
     202             968 :     return TRUE;
     203                 : }
     204                 : 
     205                 : /************************************************************************/
     206                 : /*                              AddPoint()                              */
     207                 : /*                                                                      */
     208                 : /*      Add a point to the passed geometry.                             */
     209                 : /************************************************************************/
     210                 : 
     211           37608 : static int AddPoint( OGRGeometry *poGeometry, 
     212                 :                      double dfX, double dfY, double dfZ, int nDimension )
     213                 : 
     214                 : {
     215           37608 :     OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
     216           37608 :     if( eType == wkbPoint )
     217                 :     {
     218             900 :         OGRPoint *poPoint = (OGRPoint *) poGeometry;
     219                 : 
     220             900 :         if( !poPoint->IsEmpty() )
     221                 :         {
     222                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     223               4 :                       "More than one coordinate for <Point> element.");
     224               4 :             return FALSE;
     225                 :         }
     226                 :             
     227             896 :         poPoint->setX( dfX );
     228             896 :         poPoint->setY( dfY );
     229             896 :         if( nDimension == 3 )
     230              24 :             poPoint->setZ( dfZ );
     231                 : 
     232             896 :         return TRUE;
     233                 :     }
     234                 :                 
     235           36708 :     else if( eType == wkbLineString )
     236                 :     {
     237           36708 :         if( nDimension == 3 )
     238             108 :             ((OGRLineString *) poGeometry)->addPoint( dfX, dfY, dfZ );
     239                 :         else
     240           36600 :             ((OGRLineString *) poGeometry)->addPoint( dfX, dfY );
     241                 : 
     242           36708 :         return TRUE;
     243                 :     }
     244                 : 
     245                 :     else
     246                 :     {
     247               0 :         CPLAssert( FALSE );
     248               0 :         return FALSE;                                                   
     249                 :     }
     250                 : }
     251                 : 
     252                 : /************************************************************************/
     253                 : /*                        ParseGMLCoordinates()                         */
     254                 : /************************************************************************/
     255                 : 
     256            8522 : static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeometry )
     257                 : 
     258                 : {
     259            8522 :     const CPLXMLNode *psCoordinates = FindBareXMLChild( psGeomNode, "coordinates" );
     260            8522 :     int iCoord = 0;
     261                 : 
     262                 : /* -------------------------------------------------------------------- */
     263                 : /*      Handle <coordinates> case.                                      */
     264                 : /* -------------------------------------------------------------------- */
     265            8522 :     if( psCoordinates != NULL )
     266                 :     {
     267             350 :         const char *pszCoordString = GetElementText( psCoordinates );
     268             350 :         char chCS = ',';
     269                 : 
     270             350 :         if( pszCoordString == NULL )
     271                 :         {
     272               2 :             poGeometry->empty();
     273               2 :             return TRUE;
     274                 :         }
     275                 : 
     276            1482 :         while( *pszCoordString != '\0' )
     277                 :         {
     278             790 :             double dfX, dfY, dfZ = 0.0;
     279             790 :             int nDimension = 2;
     280                 : 
     281                 :             // parse out 2 or 3 tuple. 
     282             790 :             dfX = OGRFastAtof( pszCoordString );
     283            9664 :             while( *pszCoordString != '\0'
     284                 :                    && *pszCoordString != ','
     285                 :                    && !isspace((unsigned char)*pszCoordString) )
     286            8084 :                 pszCoordString++;
     287                 : 
     288             790 :             if( *pszCoordString == '\0' )
     289                 :             {
     290                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     291               2 :                         "Corrupt <coordinates> value." );
     292               2 :                 return FALSE;
     293                 :             }
     294             788 :             else if( chCS == ',' && isspace((unsigned char)*pszCoordString) )
     295                 :             {
     296                 :                 /* In theory, the coordinates inside a coordinate tuple should be */
     297                 :                 /* separated by a comma. However it has been found in the wild */
     298                 :                 /* that the coordinates are in rare cases separated by a space, and the tuples by a comma */
     299                 :                 /* See https://52north.org/twiki/bin/view/Processing/WPS-IDWExtension-ObservationCollectionExample */
     300                 :                 /* or http://agisdemo.faa.gov/aixmServices/getAllFeaturesByLocatorId?locatorId=DFW */
     301               4 :                 chCS = ' ';
     302                 :             }
     303                 : 
     304             788 :             pszCoordString++;
     305             788 :             dfY = OGRFastAtof( pszCoordString );
     306            9662 :             while( *pszCoordString != '\0' 
     307                 :                    && *pszCoordString != ','
     308                 :                    && !isspace((unsigned char)*pszCoordString) )
     309            8086 :                 pszCoordString++;
     310                 : 
     311             788 :             if( *pszCoordString == chCS )
     312                 :             {
     313              50 :                 pszCoordString++;
     314              50 :                 dfZ = OGRFastAtof( pszCoordString );
     315              50 :                 nDimension = 3;
     316             150 :                 while( *pszCoordString != '\0' 
     317                 :                        && *pszCoordString != ','
     318                 :                        && !isspace((unsigned char)*pszCoordString) )
     319              50 :                 pszCoordString++;
     320                 :             }
     321                 : 
     322             788 :             if ( chCS == ' ' && *pszCoordString == ',' )
     323                 :             {
     324               0 :                 pszCoordString++;
     325                 :             }
     326                 : 
     327            2076 :             while( isspace((unsigned char)*pszCoordString) )
     328             500 :                 pszCoordString++;
     329                 : 
     330             788 :             if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
     331               2 :                 return FALSE;
     332                 : 
     333             786 :             iCoord++;
     334                 :         }
     335                 : 
     336             344 :         return iCoord > 0;
     337                 :     }
     338                 : 
     339                 : /* -------------------------------------------------------------------- */
     340                 : /*      Is this a "pos"?  GML 3 construct.                              */
     341                 : /*      Parse if it exist a series of pos elements (this would allow    */
     342                 : /*      the correct parsing of gml3.1.1 geomtries such as linestring    */
     343                 : /*      defined with pos elements.                                      */
     344                 : /* -------------------------------------------------------------------- */
     345                 :     const CPLXMLNode *psPos;
     346                 :     
     347            8172 :     int bHasFoundPosElement = FALSE;
     348           18036 :     for( psPos = psGeomNode->psChild;
     349                 :          psPos != NULL;
     350                 :          psPos = psPos->psNext )
     351                 :     {
     352            9870 :         if( psPos->eType != CXT_Element  )
     353            1402 :             continue;
     354                 : 
     355            8468 :         const char* pszSubElement = BareGMLElement(psPos->pszValue);
     356                 : 
     357            8468 :         if( EQUAL(pszSubElement, "pointProperty") )
     358                 :         {
     359                 :             const CPLXMLNode *psPointPropertyIter;
     360               4 :             for( psPointPropertyIter = psPos->psChild;
     361                 :                  psPointPropertyIter != NULL;
     362                 :                  psPointPropertyIter = psPointPropertyIter->psNext )
     363                 :             {
     364               2 :                 if( psPointPropertyIter->eType != CXT_Element  )
     365               0 :                     continue;
     366                 : 
     367               2 :                 if (EQUAL(BareGMLElement(psPointPropertyIter->pszValue),"Point") )
     368                 :                 {
     369               2 :                     OGRPoint oPoint;
     370               2 :                     if( ParseGMLCoordinates( psPointPropertyIter, &oPoint ) )
     371                 :                     {
     372                 :                         int bSuccess = AddPoint( poGeometry, oPoint.getX(),
     373                 :                                                  oPoint.getY(), oPoint.getZ(),
     374               2 :                                                  oPoint.getCoordinateDimension() );
     375               2 :                         if (bSuccess)
     376               2 :                             bHasFoundPosElement = TRUE;
     377                 :                         else
     378               0 :                             return FALSE;
     379               0 :                     }
     380                 :                 }
     381                 :             }
     382               2 :             continue;
     383                 :         }
     384                 : 
     385            8466 :         if( !EQUAL(pszSubElement,"pos") )
     386            7518 :             continue;
     387                 : 
     388             948 :         const char* pszPos = GetElementText( psPos );
     389             948 :         if (pszPos == NULL)
     390                 :         {
     391               2 :             poGeometry->empty();
     392               2 :             return TRUE;
     393                 :         }
     394                 : 
     395             946 :         const char* pszCur = pszPos;
     396                 :         const char* pszX = (pszCur != NULL) ?
     397             946 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     398                 :         const char* pszY = (pszCur != NULL) ?
     399             946 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     400                 :         const char* pszZ = (pszCur != NULL) ?
     401             946 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     402                 : 
     403             946 :         if (pszY == NULL)
     404                 :         {
     405                 :             CPLError( CE_Failure, CPLE_AppDefined,
     406                 :                       "Did not get 2+ values in <gml:pos>%s</gml:pos> tuple.",
     407               2 :                       pszPos ? pszPos : "" );
     408               2 :             return FALSE;
     409                 :         }
     410                 : 
     411             944 :         double dfX = OGRFastAtof(pszX);
     412             944 :         double dfY = OGRFastAtof(pszY);
     413             944 :         double dfZ = (pszZ != NULL) ? OGRFastAtof(pszZ) : 0.0;
     414             944 :         int bSuccess = AddPoint( poGeometry, dfX, dfY, dfZ, (pszZ != NULL) ? 3 : 2 );
     415                 : 
     416             944 :         if (bSuccess)
     417             942 :             bHasFoundPosElement = TRUE;
     418                 :         else
     419               2 :             return FALSE;
     420                 :     }
     421                 : 
     422            8166 :     if (bHasFoundPosElement)
     423             634 :         return TRUE;
     424                 : 
     425                 : /* -------------------------------------------------------------------- */
     426                 : /*      Is this a "posList"?  GML 3 construct (SF profile).             */
     427                 : /* -------------------------------------------------------------------- */
     428            7532 :     const CPLXMLNode *psPosList = FindBareXMLChild( psGeomNode, "posList" );
     429                 :     
     430            7532 :     if( psPosList != NULL )
     431                 :     {
     432            7500 :         int bSuccess = FALSE;
     433                 :         const CPLXMLNode* psChild;
     434            7500 :         int nDimension = 2;
     435                 : 
     436                 :         /* Try to detect the presence of an srsDimension attribute */
     437                 :         /* This attribute is only availabe for gml3.1.1 but not */
     438                 :         /* available for gml3.1 SF*/
     439            7500 :         psChild = psPosList->psChild;
     440           15000 :         while (psChild != NULL)
     441                 :         {
     442            7498 :             if (psChild->eType == CXT_Attribute &&
     443                 :                 EQUAL(psChild->pszValue, "srsDimension"))
     444                 :             {
     445            1516 :                 nDimension = atoi(psChild->psChild->pszValue);
     446            1516 :                 break;
     447                 :             }
     448            5982 :             else if (psChild->eType != CXT_Attribute)
     449                 :             {
     450            5982 :                 break;
     451                 :             }
     452               0 :             psChild = psChild->psNext;
     453                 :         }
     454                 : 
     455            7500 :         if (nDimension != 2 && nDimension != 3)
     456                 :         {
     457                 :             CPLError( CE_Failure, CPLE_AppDefined,
     458               2 :                       "srsDimension = %d not supported", nDimension);
     459               2 :             return FALSE;
     460                 :         }
     461                 : 
     462            7498 :         const char* pszPosList = GetElementText( psPosList );
     463            7498 :         if (pszPosList == NULL)
     464                 :         {
     465               2 :             poGeometry->empty();
     466               2 :             return TRUE;
     467                 :         }
     468                 : 
     469            7496 :         const char* pszCur = pszPosList;
     470           28530 :         while (TRUE)
     471                 :         {
     472           36026 :             const char* pszX = GMLGetCoordTokenPos(pszCur, &pszCur);
     473           36026 :             if (pszX == NULL && bSuccess)
     474             150 :                 break;
     475                 :             const char* pszY = (pszCur != NULL) ?
     476           35876 :                     GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     477                 :             const char* pszZ = (nDimension == 3 && pszCur != NULL) ?
     478           35876 :                     GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     479                 : 
     480           35876 :             if (pszY == NULL || (nDimension == 3 && pszZ == NULL))
     481                 :             {
     482                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     483                 :                         "Did not get at least %d values or invalid number of \n"
     484                 :                         "set of coordinates <gml:posList>%s</gml:posList>",
     485               6 :                         nDimension, pszPosList ? pszPosList : "");
     486               6 :                 return FALSE;
     487                 :             }
     488                 : 
     489           35870 :             double dfX = OGRFastAtof(pszX);
     490           35870 :             double dfY = OGRFastAtof(pszY);
     491           35870 :             double dfZ = (pszZ != NULL) ? OGRFastAtof(pszZ) : 0.0;
     492           35870 :             bSuccess = AddPoint( poGeometry, dfX, dfY, dfZ, nDimension );
     493                 : 
     494           35870 :             if (bSuccess == FALSE || pszCur == NULL)
     495            7340 :                 break;
     496                 :         }
     497                 : 
     498            7490 :         return bSuccess;
     499                 :     }
     500                 :     
     501                 : 
     502                 : /* -------------------------------------------------------------------- */
     503                 : /*      Handle form with a list of <coord> items each with an <X>,      */
     504                 : /*      and <Y> element.                                                */
     505                 : /* -------------------------------------------------------------------- */
     506                 :     const CPLXMLNode *psCoordNode;
     507                 : 
     508              48 :     for( psCoordNode = psGeomNode->psChild; 
     509                 :          psCoordNode != NULL;
     510                 :          psCoordNode = psCoordNode->psNext )
     511                 :     {
     512              22 :         if( psCoordNode->eType != CXT_Element 
     513                 :             || !EQUAL(BareGMLElement(psCoordNode->pszValue),"coord") )
     514              12 :             continue;
     515                 : 
     516                 :         const CPLXMLNode *psXNode, *psYNode, *psZNode;
     517              10 :         double dfX, dfY, dfZ = 0.0;
     518              10 :         int nDimension = 2;
     519                 : 
     520              10 :         psXNode = FindBareXMLChild( psCoordNode, "X" );
     521              10 :         psYNode = FindBareXMLChild( psCoordNode, "Y" );
     522              10 :         psZNode = FindBareXMLChild( psCoordNode, "Z" );
     523                 : 
     524              10 :         if( psXNode == NULL || psYNode == NULL 
     525                 :             || GetElementText(psXNode) == NULL
     526                 :             || GetElementText(psYNode) == NULL
     527                 :             || (psZNode != NULL && GetElementText(psZNode) == NULL) )
     528                 :         {
     529                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     530               6 :                       "Corrupt <coord> element, missing <X> or <Y> element?" );
     531               6 :             return FALSE;
     532                 :         }
     533                 : 
     534               4 :         dfX = OGRFastAtof( GetElementText(psXNode) );
     535               4 :         dfY = OGRFastAtof( GetElementText(psYNode) );
     536                 : 
     537               4 :         if( psZNode != NULL && GetElementText(psZNode) != NULL )
     538                 :         {
     539               0 :             dfZ = OGRFastAtof( GetElementText(psZNode) );
     540               0 :             nDimension = 3;
     541                 :         }
     542                 : 
     543               4 :         if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
     544               0 :             return FALSE;
     545                 : 
     546               4 :         iCoord++;
     547                 :     }
     548                 : 
     549              26 :     return iCoord > 0.0;
     550                 : }
     551                 : 
     552                 : #ifdef HAVE_GEOS
     553                 : /************************************************************************/
     554                 : /*                         GML2FaceExtRing()                            */
     555                 : /*                                                                      */
     556                 : /*      Identifies the "good" Polygon whithin the collection returned   */
     557                 : /*      by GEOSPolygonize()                                             */
     558                 : /*      short rationale: GEOSPolygonize() will possibily return a       */
     559                 : /*      collection of many Polygons; only one is the "good" one,        */
     560                 : /*      (including both exterior- and interior-rings)                   */
     561                 : /*      any other simply represents a single "hole", and should be      */
     562                 : /*      consequently ignored at all.                                    */
     563                 : /************************************************************************/
     564                 : 
     565             132 : static OGRPolygon *GML2FaceExtRing( OGRGeometry *poGeom )
     566                 : {
     567             132 :     OGRPolygon *poPolygon = NULL;
     568             132 :   int bError = FALSE;
     569             132 :     OGRGeometryCollection *poColl = (OGRGeometryCollection *)poGeom;
     570             132 :     int iCount = poColl->getNumGeometries();
     571             132 :   int iExterior = 0;
     572             132 :   int iInterior = 0;
     573                 : 
     574             292 :     for( int ig = 0; ig < iCount; ig++)
     575                 :     {
     576                 :         /* a collection of Polygons is expected to be found */
     577             160 :         OGRGeometry * poChild = (OGRGeometry*)poColl->getGeometryRef(ig);
     578             160 :         if( poChild == NULL)
     579                 :         {
     580               0 :             bError = TRUE;
     581               0 :             continue;
     582                 :         }
     583             160 :         if( wkbFlatten( poChild->getGeometryType()) == wkbPolygon )
     584                 :         {
     585             160 :             OGRPolygon *poPg = (OGRPolygon *)poChild;
     586             160 :             if( poPg->getNumInteriorRings() > 0 )
     587              20 :                 iExterior++;
     588                 :             else
     589             140 :                 iInterior++;
     590                 :         }
     591                 :         else
     592               0 :             bError = TRUE;
     593                 :     }
     594                 : 
     595             132 :     if( bError == FALSE && iCount > 0 )
     596                 :     {
     597             244 :        if( iCount == 1 && iExterior == 0 && iInterior == 1)
     598                 :         {
     599                 :             /* there is a single Polygon within the collection */
     600             112 :             OGRPolygon * poPg = (OGRPolygon*)poColl->getGeometryRef(0 );
     601             112 :             poPolygon = (OGRPolygon *)poPg->clone();
     602                 :         }
     603                 :         else
     604                 :         {
     605              20 :             if( iExterior == 1 && iInterior == iCount - 1 )
     606                 :             {
     607                 :                 /* searching the unique Polygon containing holes */
     608              68 :                 for ( int ig = 0; ig < iCount; ig++)
     609                 :                 {
     610              48 :                     OGRPolygon * poPg = (OGRPolygon*)poColl->getGeometryRef(ig);
     611              48 :                     if( poPg->getNumInteriorRings() > 0 )
     612              20 :                         poPolygon = (OGRPolygon *)poPg->clone();
     613                 :                 }
     614                 :             }
     615                 :         }
     616                 :     }
     617                 : 
     618             132 :     return poPolygon;
     619                 : }
     620                 : #endif
     621                 : 
     622                 : /************************************************************************/
     623                 : /*                      GML2OGRGeometry_XMLNode()                       */
     624                 : /*                                                                      */
     625                 : /*      Translates the passed XMLnode and it's children into an         */
     626                 : /*      OGRGeometry.  This is used recursively for geometry             */
     627                 : /*      collections.                                                    */
     628                 : /************************************************************************/
     629                 : 
     630           26030 : OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     631                 :                                       int bGetSecondaryGeometryOption,
     632                 :                                       int nRecLevel,
     633                 :                                       int bIgnoreGSG,
     634                 :                                       int bOrientation,
     635                 :                                       int bFaceHoleNegative ) 
     636                 : 
     637                 : {
     638           26030 :     const char *pszBaseGeometry = BareGMLElement( psNode->pszValue );
     639           26030 :     if (bGetSecondaryGeometryOption < 0)
     640            1006 :         bGetSecondaryGeometryOption = CSLTestBoolean(CPLGetConfigOption("GML_GET_SECONDARY_GEOM", "NO"));
     641           26030 :     int bGetSecondaryGeometry = bIgnoreGSG ? FALSE : bGetSecondaryGeometryOption;
     642                 : 
     643                 :     /* Arbitrary value, but certainly large enough for reasonable usages ! */
     644           26030 :     if( nRecLevel == 32 )
     645                 :     {
     646                 :         CPLError( CE_Failure, CPLE_AppDefined,
     647                 :                     "Too many recursiong level (%d) while parsing GML geometry.",
     648               2 :                     nRecLevel );
     649               2 :         return NULL;
     650                 :     }
     651                 : 
     652           26028 :     if( bGetSecondaryGeometry )
     653               0 :         if( !( EQUAL(pszBaseGeometry,"directedEdge") ||
     654                 :                EQUAL(pszBaseGeometry,"TopoCurve") ) )
     655               0 :             return NULL;
     656                 : 
     657                 : /* -------------------------------------------------------------------- */
     658                 : /*      Polygon / PolygonPatch / Triangle / Rectangle                   */
     659                 : /* -------------------------------------------------------------------- */
     660           26028 :     if( EQUAL(pszBaseGeometry,"Polygon") ||
     661                 :         EQUAL(pszBaseGeometry,"PolygonPatch") ||
     662                 :         EQUAL(pszBaseGeometry,"Triangle") ||
     663                 :         EQUAL(pszBaseGeometry,"Rectangle"))
     664                 :     {
     665                 :         const CPLXMLNode *psChild;
     666             922 :         OGRPolygon *poPolygon = new OGRPolygon();
     667                 :         OGRLinearRing *poRing;
     668                 : 
     669                 :         // Find outer ring.
     670             922 :         psChild = FindBareXMLChild( psNode, "outerBoundaryIs" );
     671             922 :         if (psChild == NULL)
     672             890 :            psChild = FindBareXMLChild( psNode, "exterior");
     673                 : 
     674             922 :         if( psChild == NULL || psChild->psChild == NULL )
     675                 :         {
     676                 :             /* <gml:Polygon/> is invalid GML2, but valid GML3, so be tolerant */
     677               8 :             return poPolygon;
     678                 :         }
     679                 : 
     680                 :         // Translate outer ring and add to polygon.
     681                 :         poRing = (OGRLinearRing *) 
     682                 :             GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
     683             914 :                                      nRecLevel + 1 );
     684             914 :         if( poRing == NULL )
     685                 :         {
     686               4 :             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior ring");
     687               4 :             delete poPolygon;
     688               4 :             return NULL;
     689                 :         }
     690                 : 
     691             910 :         if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
     692                 :         {
     693                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     694                 :                       "%s: Got %.500s geometry as outerBoundaryIs instead of LINEARRING.",
     695               2 :                       pszBaseGeometry, poRing->getGeometryName() );
     696               2 :             delete poPolygon;
     697               2 :             delete poRing;
     698               2 :             return NULL;
     699                 :         }
     700                 : 
     701             908 :         poPolygon->addRingDirectly( poRing );
     702                 : 
     703                 :         // Find all inner rings 
     704            2024 :         for( psChild = psNode->psChild; 
     705                 :              psChild != NULL;
     706                 :              psChild = psChild->psNext ) 
     707                 :         {
     708            1120 :             if( psChild->eType == CXT_Element
     709                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"innerBoundaryIs") ||
     710                 :                     EQUAL(BareGMLElement(psChild->pszValue),"interior")))
     711                 :             {
     712              52 :                 if (psChild->psChild != NULL)
     713                 :                     poRing = (OGRLinearRing *) 
     714                 :                         GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
     715              50 :                                                  nRecLevel + 1);
     716                 :                 else
     717               2 :                     poRing = NULL;
     718              52 :                 if (poRing == NULL)
     719                 :                 {
     720               2 :                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid interior ring");
     721               2 :                     delete poPolygon;
     722               2 :                     return NULL;
     723                 :                 }
     724              50 :                 if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
     725                 :                 {
     726                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     727                 :                               "%s: Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
     728               2 :                               pszBaseGeometry, poRing->getGeometryName() );
     729               2 :                     delete poPolygon;
     730               2 :                     delete poRing;
     731               2 :                     return NULL;
     732                 :                 }
     733                 : 
     734              48 :                 poPolygon->addRingDirectly( poRing );
     735                 :             }
     736                 :         }
     737                 : 
     738             904 :         return poPolygon;
     739                 :     }
     740                 : 
     741                 : /* -------------------------------------------------------------------- */
     742                 : /*      LinearRing                                                      */
     743                 : /* -------------------------------------------------------------------- */
     744           25106 :     if( EQUAL(pszBaseGeometry,"LinearRing") )
     745                 :     {
     746             280 :         OGRLinearRing   *poLinearRing = new OGRLinearRing();
     747                 :         
     748             280 :         if( !ParseGMLCoordinates( psNode, poLinearRing ) )
     749                 :         {
     750               2 :             delete poLinearRing;
     751               2 :             return NULL;
     752                 :         }
     753                 : 
     754             278 :         return poLinearRing;
     755                 :     }
     756                 : 
     757                 : /* -------------------------------------------------------------------- */
     758                 : /*      Ring GML3                                                       */
     759                 : /* -------------------------------------------------------------------- */
     760           24826 :     if( EQUAL(pszBaseGeometry,"Ring") )
     761                 :     {
     762             688 :         OGRLinearRing   *poLinearRing = new OGRLinearRing();
     763                 :         const CPLXMLNode *psChild;
     764                 : 
     765            6474 :         for( psChild = psNode->psChild; 
     766                 :              psChild != NULL; psChild = psChild->psNext )
     767                 :         {
     768            5792 :             if( psChild->eType == CXT_Element
     769                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
     770                 :             {
     771            5790 :                 const CPLXMLNode* psCurveChild = GetChildElement(psChild);
     772                 :                 OGRLineString *poLS;
     773            5790 :                 if (psCurveChild != NULL)
     774                 :                     poLS = (OGRLineString *) 
     775                 :                         GML2OGRGeometry_XMLNode( psCurveChild, bGetSecondaryGeometryOption,
     776            5788 :                                                  nRecLevel + 1);
     777                 :                 else
     778               2 :                     poLS = NULL;
     779                 : 
     780           11576 :                 if( poLS == NULL 
     781            5786 :                     || wkbFlatten(poLS->getGeometryType()) != wkbLineString )
     782                 :                 {
     783               6 :                     delete poLS;
     784               6 :                     delete poLinearRing;
     785               6 :                     return NULL;
     786                 :                 }
     787                 : 
     788                 :                 // we might need to take steps to avoid duplicate points...
     789            5784 :                 poLinearRing->addSubLineString( poLS );
     790            5784 :                 delete poLS;
     791                 :             }
     792                 :         }
     793                 : 
     794             682 :         return poLinearRing;
     795                 :     }
     796                 : 
     797                 : /* -------------------------------------------------------------------- */
     798                 : /*      LineString                                                      */
     799                 : /* -------------------------------------------------------------------- */
     800           24138 :     if( EQUAL(pszBaseGeometry,"LineString")
     801                 :         || EQUAL(pszBaseGeometry,"LineStringSegment") )
     802                 :     {
     803            7288 :         OGRLineString   *poLine = new OGRLineString();
     804                 :         
     805            7288 :         if( !ParseGMLCoordinates( psNode, poLine ) )
     806                 :         {
     807              20 :             delete poLine;
     808              20 :             return NULL;
     809                 :         }
     810                 : 
     811            7268 :         return poLine;
     812                 :     }
     813                 : 
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Arc/Circle : we approximate them by linear segments             */
     816                 : /* -------------------------------------------------------------------- */
     817           16850 :     if( EQUAL(pszBaseGeometry,"Arc") ||
     818                 :         EQUAL(pszBaseGeometry,"Circle") )
     819                 :     {
     820              32 :         OGRLineString   *poLine = new OGRLineString();
     821                 : 
     822              62 :         if( !ParseGMLCoordinates( psNode, poLine ) ||
     823                 :             poLine->getNumPoints() != 3 )
     824                 :         {
     825               4 :             delete poLine;
     826               4 :             return NULL;
     827                 :         }
     828                 : 
     829              28 :         double x0 = poLine->getX(0);
     830              28 :         double y0 = poLine->getY(0);
     831              28 :         double x1 = poLine->getX(1);
     832              28 :         double y1 = poLine->getY(1);
     833              28 :         double x2 = poLine->getX(2);
     834              28 :         double y2 = poLine->getY(2);
     835              28 :         double dx01 = x1 - x0;
     836              28 :         double dy01 = y1 - y0;
     837              28 :         double dx12 = x2 - x1;
     838              28 :         double dy12 = y2 - y1;
     839              28 :         double c01 = dx01 * (x0 + x1) / 2 + dy01 * (y0 + y1) / 2;
     840              28 :         double c12 = dx12 * (x1 + x2) / 2 + dy12 * (y1 + y2) / 2;
     841              28 :         double det = dx01 * dy12 - dx12 * dy01;
     842              28 :         if (det == 0)
     843                 :         {
     844               2 :             return poLine;
     845                 :         }
     846              26 :         double cx =  (c01 * dy12 - c12 * dy01) / det;
     847              26 :         double cy =  (- c01 * dx12 + c12 * dx01) / det;
     848                 : 
     849              26 :         double alpha0 = atan2(y0 - cy, x0 - cx);
     850              26 :         double alpha1 = atan2(y1 - cy, x1 - cx);
     851              26 :         double alpha2 = atan2(y2 - cy, x2 - cx);
     852                 :         double alpha3;
     853              26 :         double R = sqrt((x0 - cx) * (x0 - cx) + (y0 - cy) * (y0 - cy));
     854                 : 
     855                 :         /* if det is negative, the orientation if clockwise */
     856              26 :         if (det < 0)
     857                 :         {
     858              14 :             if (alpha1 > alpha0)
     859               2 :                 alpha1 -= 2 * PI;
     860              14 :             if (alpha2 > alpha1)
     861               4 :                 alpha2 -= 2 * PI;
     862              14 :             alpha3 = alpha0 - 2 * PI;
     863                 :         }
     864                 :         else
     865                 :         {
     866              12 :             if (alpha1 < alpha0)
     867               0 :                 alpha1 += 2 * PI;
     868              12 :             if (alpha2 < alpha1)
     869               4 :                 alpha2 += 2 * PI;
     870              12 :             alpha3 = alpha0 + 2 * PI;
     871                 :         }
     872                 : 
     873                 :         CPLAssert((alpha0 <= alpha1 && alpha1 <= alpha2 && alpha2 <= alpha3) ||
     874              26 :                   (alpha0 >= alpha1 && alpha1 >= alpha2 && alpha2 >= alpha3));
     875                 : 
     876              26 :         int nSign = (det >= 0) ? 1 : -1;
     877                 : 
     878                 :         double alpha;
     879                 :         double dfStep =
     880              26 :             atof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4")) / 180 * PI;
     881              26 :         if (dfStep <= 0.1)
     882               6 :             dfStep = 4. / 180 * PI;
     883                 : 
     884              26 :         poLine->setNumPoints(0);
     885                 : 
     886              26 :         dfStep *= nSign;
     887                 : 
     888              26 :         poLine->addPoint(x0, y0);
     889                 : 
     890              54 :         for(alpha = alpha0 + dfStep; (alpha - alpha1) * nSign < 0; alpha += dfStep)
     891                 :         {
     892              28 :             poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     893                 :         }
     894                 : 
     895              26 :         poLine->addPoint(x1, y1);
     896                 : 
     897              58 :         for(alpha = alpha1 + dfStep; (alpha - alpha2) * nSign < 0; alpha += dfStep)
     898                 :         {
     899              32 :             poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     900                 :         }
     901                 : 
     902              26 :         if (EQUAL(pszBaseGeometry,"Circle"))
     903                 :         {
     904               6 :             for(alpha = alpha2; (alpha - alpha3) * nSign < 0; alpha += dfStep)
     905                 :             {
     906               4 :                 poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     907                 :             }
     908               2 :             poLine->addPoint(x0, y0);
     909                 :         }
     910                 :         else
     911                 :         {
     912              24 :             poLine->addPoint(x2, y2);
     913                 :         }
     914                 : 
     915              26 :         return poLine;
     916                 :     }
     917                 : 
     918                 : /* -------------------------------------------------------------------- */
     919                 : /*      PointType                                                       */
     920                 : /* -------------------------------------------------------------------- */
     921           16818 :     if( EQUAL(pszBaseGeometry,"PointType") 
     922                 :         || EQUAL(pszBaseGeometry,"Point")
     923                 :         || EQUAL(pszBaseGeometry,"ConnectionPoint") )
     924                 :     {
     925             914 :         OGRPoint *poPoint = new OGRPoint();
     926                 :         
     927             914 :         if( !ParseGMLCoordinates( psNode, poPoint ) )
     928                 :         {
     929              20 :             delete poPoint;
     930              20 :             return NULL;
     931                 :         }
     932                 : 
     933             894 :         return poPoint;
     934                 :     }
     935                 : 
     936                 : /* -------------------------------------------------------------------- */
     937                 : /*      Box                                                             */
     938                 : /* -------------------------------------------------------------------- */
     939           15904 :     if( EQUAL(pszBaseGeometry,"BoxType") || EQUAL(pszBaseGeometry,"Box") )
     940                 :     {
     941               6 :         OGRLineString  oPoints;
     942                 : 
     943               6 :         if( !ParseGMLCoordinates( psNode, &oPoints ) )
     944               2 :             return NULL;
     945                 : 
     946               4 :         if( oPoints.getNumPoints() < 2 )
     947               2 :             return NULL;
     948                 : 
     949               2 :         OGRLinearRing *poBoxRing = new OGRLinearRing();
     950               4 :         OGRPolygon *poBoxPoly = new OGRPolygon();
     951                 : 
     952               2 :         poBoxRing->setNumPoints( 5 );
     953                 :         poBoxRing->setPoint( 
     954               2 :             0, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
     955                 :         poBoxRing->setPoint( 
     956               2 :             1, oPoints.getX(1), oPoints.getY(0), oPoints.getZ(0) );
     957                 :         poBoxRing->setPoint( 
     958               2 :             2, oPoints.getX(1), oPoints.getY(1), oPoints.getZ(1) );
     959                 :         poBoxRing->setPoint( 
     960               2 :             3, oPoints.getX(0), oPoints.getY(1), oPoints.getZ(0) );
     961                 :         poBoxRing->setPoint( 
     962               2 :             4, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
     963                 : 
     964               2 :         poBoxPoly->addRingDirectly( poBoxRing );
     965                 : 
     966               2 :         return poBoxPoly;
     967                 :     }
     968                 : 
     969                 : /* ------------------------const CPLXMLNode *psChild;-------------------------------------------- */
     970                 : /*      MultiPolygon / MultiSurface / CompositeSurface                  */
     971                 : /*                                                                      */
     972                 : /* For CompositeSurface, this is a very rough approximation to deal with*/
     973                 : /* it as a MultiPolygon, because it can several faces of a 3D volume... */
     974                 : /* -------------------------------------------------------------------- */
     975           15898 :     if( EQUAL(pszBaseGeometry,"MultiPolygon") ||
     976                 :         EQUAL(pszBaseGeometry,"MultiSurface") ||
     977                 :         EQUAL(pszBaseGeometry,"CompositeSurface") )
     978                 :     {
     979                 :         const CPLXMLNode *psChild;
     980              96 :         OGRMultiPolygon *poMPoly = new OGRMultiPolygon();
     981                 : 
     982                 :         // Iterate over children
     983             278 :         for( psChild = psNode->psChild; 
     984                 :              psChild != NULL;
     985                 :              psChild = psChild->psNext ) 
     986                 :         {
     987             188 :             if( psChild->eType == CXT_Element
     988                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"polygonMember") ||
     989                 :                     EQUAL(BareGMLElement(psChild->pszValue),"surfaceMember")) )
     990                 :             {
     991              84 :                 const CPLXMLNode* psSurfaceChild = GetChildElement(psChild);
     992                 :                 OGRPolygon *poPolygon;
     993                 : 
     994              84 :                 if (psSurfaceChild != NULL)
     995                 :                     poPolygon = (OGRPolygon *) 
     996                 :                         GML2OGRGeometry_XMLNode( psSurfaceChild, bGetSecondaryGeometryOption,
     997              82 :                                                  nRecLevel + 1);
     998                 :                 else
     999               2 :                     poPolygon = NULL;
    1000                 : 
    1001              84 :                 if( poPolygon == NULL )
    1002                 :                 {
    1003                 :                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1004               4 :                               BareGMLElement(psChild->pszValue));
    1005               4 :                     delete poMPoly;
    1006               4 :                     return NULL;
    1007                 :                 }
    1008                 : 
    1009              80 :                 if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") )
    1010                 :                 {
    1011                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1012                 :                               "Got %.500s geometry as polygonMember instead of MULTIPOLYGON.",
    1013               2 :                               poPolygon->getGeometryName() );
    1014               2 :                     delete poPolygon;
    1015               2 :                     delete poMPoly;
    1016               2 :                     return NULL;
    1017                 :                 }
    1018                 : 
    1019              78 :                 poMPoly->addGeometryDirectly( poPolygon );
    1020                 :             }
    1021             104 :             else if (psChild->eType == CXT_Element
    1022                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"surfaceMembers") )
    1023                 :             {
    1024                 :                 const CPLXMLNode *psChild2;
    1025              24 :                 for( psChild2 = psChild->psChild;
    1026                 :                      psChild2 != NULL;
    1027                 :                      psChild2 = psChild2->psNext )
    1028                 :                 {
    1029              12 :                     if( psChild2->eType == CXT_Element
    1030                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"Surface") ||
    1031                 :                             EQUAL(BareGMLElement(psChild2->pszValue),"Polygon") ||
    1032                 :                             EQUAL(BareGMLElement(psChild2->pszValue),"PolygonPatch")) )
    1033                 :                     {
    1034                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
    1035              10 :                                                                        nRecLevel + 1);
    1036              10 :                         if (poGeom == NULL)
    1037                 :                         {
    1038                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1039               0 :                                     BareGMLElement(psChild2->pszValue));
    1040               0 :                             delete poMPoly;
    1041               0 :                             return NULL;
    1042                 :                         }
    1043                 : 
    1044              10 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    1045                 :                         {
    1046               8 :                             poMPoly->addGeometryDirectly( (OGRPolygon*) poGeom );
    1047                 :                         }
    1048               2 :                         else if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    1049                 :                         {
    1050               2 :                             OGRMultiPolygon* poMPoly2 = (OGRMultiPolygon*) poGeom;
    1051                 :                             int i;
    1052               6 :                             for(i=0;i<poMPoly2->getNumGeometries();i++)
    1053                 :                             {
    1054               4 :                                 poMPoly->addGeometry(poMPoly2->getGeometryRef(i));
    1055                 :                             }
    1056               2 :                             delete poGeom;
    1057                 :                         }
    1058                 :                         else
    1059                 :                         {
    1060                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1061                 :                                     "Got %.500s geometry as polygonMember instead of POLYGON/MULTIPOLYGON.",
    1062               0 :                                     poGeom->getGeometryName() );
    1063               0 :                             delete poGeom;
    1064               0 :                             delete poMPoly;
    1065               0 :                             return NULL;
    1066                 :                         }
    1067                 :                     }
    1068                 :                 }
    1069                 :             }
    1070                 :         }
    1071                 : 
    1072              90 :         return poMPoly;
    1073                 :     }
    1074                 : 
    1075                 : /* -------------------------------------------------------------------- */
    1076                 : /*      MultiPoint                                                      */
    1077                 : /* -------------------------------------------------------------------- */
    1078           15802 :     if( EQUAL(pszBaseGeometry,"MultiPoint") )
    1079                 :     {
    1080                 :         const CPLXMLNode *psChild;
    1081              32 :         OGRMultiPoint *poMP = new OGRMultiPoint();
    1082                 : 
    1083                 :         // collect points.
    1084              86 :         for( psChild = psNode->psChild; 
    1085                 :              psChild != NULL;
    1086                 :              psChild = psChild->psNext ) 
    1087                 :         {
    1088              60 :             if( psChild->eType == CXT_Element
    1089                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"pointMember") )
    1090                 :             {
    1091              30 :                 const CPLXMLNode* psPointChild = GetChildElement(psChild);
    1092                 :                 OGRPoint *poPoint;
    1093                 : 
    1094              30 :                 if (psPointChild != NULL)
    1095                 :                     poPoint = (OGRPoint *) 
    1096                 :                         GML2OGRGeometry_XMLNode( psPointChild, bGetSecondaryGeometryOption,
    1097              28 :                                                  nRecLevel + 1);
    1098                 :                 else
    1099               2 :                     poPoint = NULL;
    1100              58 :                 if( poPoint == NULL 
    1101              28 :                     || wkbFlatten(poPoint->getGeometryType()) != wkbPoint )
    1102                 :                 {
    1103                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1104                 :                               "MultiPoint: Got %.500s geometry as pointMember instead of POINT",
    1105               4 :                               poPoint ? poPoint->getGeometryName() : "NULL" );
    1106               4 :                     delete poPoint;
    1107               4 :                     delete poMP;
    1108               4 :                     return NULL;
    1109                 :                 }
    1110                 : 
    1111              26 :                 poMP->addGeometryDirectly( poPoint );
    1112                 :             }
    1113              30 :             else if (psChild->eType == CXT_Element
    1114                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"pointMembers") )
    1115                 :             {
    1116                 :                 const CPLXMLNode *psChild2;
    1117              14 :                 for( psChild2 = psChild->psChild;
    1118                 :                      psChild2 != NULL;
    1119                 :                      psChild2 = psChild2->psNext )
    1120                 :                 {
    1121               8 :                     if( psChild2->eType == CXT_Element
    1122                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"Point")) )
    1123                 :                     {
    1124                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
    1125               6 :                                                                        nRecLevel + 1);
    1126               6 :                         if (poGeom == NULL)
    1127                 :                         {
    1128                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1129               2 :                                     BareGMLElement(psChild2->pszValue));
    1130               2 :                             delete poMP;
    1131               2 :                             return NULL;
    1132                 :                         }
    1133                 : 
    1134               4 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1135                 :                         {
    1136               4 :                             poMP->addGeometryDirectly( (OGRPoint *)poGeom );
    1137                 :                         }
    1138                 :                         else
    1139                 :                         {
    1140                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1141                 :                                     "Got %.500s geometry as pointMember instead of POINT.",
    1142               0 :                                     poGeom->getGeometryName() );
    1143               0 :                             delete poGeom;
    1144               0 :                             delete poMP;
    1145               0 :                             return NULL;
    1146                 :                         }
    1147                 :                     }
    1148                 :                 }
    1149                 :             }
    1150                 :         }
    1151                 : 
    1152              26 :         return poMP;
    1153                 :     }
    1154                 : 
    1155                 : /* -------------------------------------------------------------------- */
    1156                 : /*      MultiLineString                                                 */
    1157                 : /* -------------------------------------------------------------------- */
    1158           15770 :     if( EQUAL(pszBaseGeometry,"MultiLineString") )
    1159                 :     {
    1160                 :         const CPLXMLNode *psChild;
    1161              10 :         OGRMultiLineString *poMLS = new OGRMultiLineString();
    1162                 : 
    1163                 :         // collect lines
    1164              20 :         for( psChild = psNode->psChild; 
    1165                 :              psChild != NULL;
    1166                 :              psChild = psChild->psNext ) 
    1167                 :         {
    1168              14 :             if( psChild->eType == CXT_Element
    1169                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"lineStringMember") )
    1170                 :             {
    1171              12 :                 const CPLXMLNode* psLineStringChild = GetChildElement(psChild);
    1172                 :                 OGRGeometry *poGeom;
    1173                 : 
    1174              12 :                 if (psLineStringChild != NULL)
    1175                 :                     poGeom = GML2OGRGeometry_XMLNode( psLineStringChild, bGetSecondaryGeometryOption,
    1176              10 :                                                       nRecLevel + 1);
    1177                 :                 else
    1178               2 :                     poGeom = NULL;
    1179              22 :                 if( poGeom == NULL 
    1180              10 :                     || wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1181                 :                 {
    1182                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1183                 :                               "MultiLineString: Got %.500s geometry as Member instead of LINESTRING.",
    1184               4 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1185               4 :                     delete poGeom;
    1186               4 :                     delete poMLS;
    1187               4 :                     return NULL;
    1188                 :                 }
    1189                 : 
    1190               8 :                 poMLS->addGeometryDirectly( poGeom );
    1191                 :             }
    1192                 :         }
    1193                 : 
    1194               6 :         return poMLS;
    1195                 :     }
    1196                 : 
    1197                 : 
    1198                 : /* -------------------------------------------------------------------- */
    1199                 : /*      MultiCurve                                                      */
    1200                 : /* -------------------------------------------------------------------- */
    1201           15760 :     if( EQUAL(pszBaseGeometry,"MultiCurve") )
    1202                 :     {
    1203                 :         const CPLXMLNode *psChild, *psCurve;
    1204              38 :         OGRMultiLineString *poMLS = new OGRMultiLineString();
    1205                 : 
    1206                 :         // collect curveMembers
    1207              90 :         for( psChild = psNode->psChild; 
    1208                 :              psChild != NULL;
    1209                 :              psChild = psChild->psNext ) 
    1210                 :         {
    1211              64 :             if( psChild->eType == CXT_Element
    1212                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
    1213                 :             {
    1214                 :                 OGRGeometry *poGeom;
    1215                 : 
    1216                 :                 // There can be only one curve under a curveMember.
    1217                 :                 // Currently "Curve" and "LineString" are handled.
    1218              30 :                 psCurve = FindBareXMLChild( psChild, "Curve" );
    1219              30 :                 if( psCurve == NULL )
    1220              20 :                     psCurve = FindBareXMLChild( psChild, "LineString" );
    1221              30 :                 if( psCurve == NULL )
    1222                 :                 {
    1223                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1224               4 :                               "Failed to get curve element in curveMember" );
    1225               4 :                     delete poMLS;
    1226               4 :                     return NULL;
    1227                 :                 }
    1228                 :                 poGeom = GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
    1229              26 :                                                   nRecLevel + 1);
    1230              46 :                 if( poGeom == NULL ||
    1231              20 :                     ( wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) )
    1232                 :                 {
    1233                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1234                 :                               "MultiCurve: Got %.500s geometry as Member instead of LINESTRING.",
    1235               6 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1236               6 :                     if( poGeom != NULL ) delete poGeom;
    1237               6 :                     delete poMLS;
    1238               6 :                     return NULL;
    1239                 :                 }
    1240                 : 
    1241              20 :                 poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
    1242                 :             }
    1243              34 :             else if (psChild->eType == CXT_Element
    1244                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMembers") )
    1245                 :             {
    1246                 :                 const CPLXMLNode *psChild2;
    1247              16 :                 for( psChild2 = psChild->psChild;
    1248                 :                      psChild2 != NULL;
    1249                 :                      psChild2 = psChild2->psNext )
    1250                 :                 {
    1251               8 :                     if( psChild2->eType == CXT_Element
    1252                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"LineString")) )
    1253                 :                     {
    1254                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
    1255               6 :                                                                        nRecLevel + 1);
    1256               6 :                         if (poGeom == NULL)
    1257                 :                         {
    1258                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1259               2 :                                     BareGMLElement(psChild2->pszValue));
    1260               2 :                             delete poMLS;
    1261               2 :                             return NULL;
    1262                 :                         }
    1263                 : 
    1264               4 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1265                 :                         {
    1266               4 :                             poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
    1267                 :                         }
    1268                 :                         else
    1269                 :                         {
    1270                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1271                 :                                     "Got %.500s geometry as curveMember instead of LINESTRING.",
    1272               0 :                                     poGeom->getGeometryName() );
    1273               0 :                             delete poGeom;
    1274               0 :                             delete poMLS;
    1275               0 :                             return NULL;
    1276                 :                         }
    1277                 :                     }
    1278                 :                 }
    1279                 :             }
    1280                 :         }
    1281              26 :         return poMLS;
    1282                 :     }
    1283                 : 
    1284                 : /* -------------------------------------------------------------------- */
    1285                 : /*      Curve                                                      */
    1286                 : /* -------------------------------------------------------------------- */
    1287           15722 :     if( EQUAL(pszBaseGeometry,"Curve") )
    1288                 :     {
    1289                 :         const CPLXMLNode *psChild;
    1290                 : 
    1291            6452 :         psChild = FindBareXMLChild( psNode, "segments");
    1292            6452 :         if( psChild == NULL )
    1293                 :         {
    1294                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1295              10 :                       "GML3 Curve geometry lacks segments element." );
    1296              10 :             return NULL;
    1297                 :         }
    1298                 : 
    1299                 :         OGRGeometry *poGeom;
    1300                 : 
    1301                 :         poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1302            6442 :                                           nRecLevel + 1);
    1303           12884 :         if( poGeom == NULL ||
    1304            6442 :             wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1305                 :         {
    1306                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1307                 :                 "Curve: Got %.500s geometry as Member instead of segments.",
    1308               0 :                 poGeom ? poGeom->getGeometryName() : "NULL" );
    1309               0 :             if( poGeom != NULL ) delete poGeom;
    1310               0 :             return NULL;
    1311                 :         }
    1312                 : 
    1313            6442 :         return poGeom;
    1314                 :     }
    1315                 : 
    1316                 : /* -------------------------------------------------------------------- */
    1317                 : /*      segments                                                        */
    1318                 : /* -------------------------------------------------------------------- */
    1319            9270 :     if( EQUAL(pszBaseGeometry,"segments") )
    1320                 :     {
    1321                 :         const CPLXMLNode *psChild;
    1322            6452 :         OGRLineString *poLS = new OGRLineString();
    1323                 : 
    1324           12902 :         for( psChild = psNode->psChild; 
    1325                 :              psChild != NULL;
    1326                 :              psChild = psChild->psNext ) 
    1327                 : 
    1328                 :         {
    1329            6450 :             if( psChild->eType == CXT_Element
    1330                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"LineStringSegment") ||
    1331                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Arc") ||
    1332                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Circle")) )
    1333                 :             {
    1334                 :                 OGRGeometry *poGeom;
    1335                 : 
    1336                 :                 poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1337            6444 :                                                   nRecLevel + 1);
    1338           12882 :                 if( poGeom != NULL &&
    1339            6438 :                     wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1340                 :                 {
    1341                 :                     CPLError( CE_Failure, CPLE_AppDefined,
    1342                 :                               "segments: Got %.500s geometry as Member instead of LINESTRING.",
    1343               0 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1344               0 :                     delete poGeom;
    1345               0 :                     delete poLS;
    1346               0 :                     return NULL;
    1347                 :                 }
    1348            6444 :                 if( poGeom != NULL )
    1349                 :                 {
    1350            6438 :                     OGRLineString *poAddLS = (OGRLineString *)poGeom;
    1351            6438 :                     if( poLS->getNumPoints() > 0 && poAddLS->getNumPoints() > 0
    1352                 :                         && fabs(poLS->getX(poLS->getNumPoints()-1)
    1353                 :                                 - poAddLS->getX(0)) < 1e-14
    1354                 :                         && fabs(poLS->getY(poLS->getNumPoints()-1)
    1355                 :                                 - poAddLS->getY(0)) < 1e-14
    1356                 :                         && fabs(poLS->getZ(poLS->getNumPoints()-1)
    1357                 :                                 - poAddLS->getZ(0)) < 1e-14) 
    1358                 :                     {
    1359                 :                         // Skip the first point of the new linestring to avoid
    1360                 :                         // invalidate duplicate points (#4451)
    1361               2 :                         poLS->addSubLineString( poAddLS, 1 );
    1362                 :                     }
    1363                 :                     else
    1364                 :                     {
    1365                 :                         // Add the whole new line string
    1366            6436 :                         poLS->addSubLineString( poAddLS );
    1367                 :                     }
    1368            6438 :                     delete poGeom;
    1369                 :                 }
    1370                 :             }
    1371                 :         }
    1372                 : 
    1373            6452 :         return poLS;
    1374                 :     }
    1375                 : 
    1376                 : /* -------------------------------------------------------------------- */
    1377                 : /*      MultiGeometry                                                   */
    1378                 : /* CAUTION: OGR < 1.8.0 produced GML with GeometryCollection, which is  */
    1379                 : /* not a valid GML 2 keyword! The right name is MultiGeometry. Let's be */
    1380                 : /* tolerant with the non compliant files we produced...                 */
    1381                 : /* -------------------------------------------------------------------- */
    1382            2818 :     if( EQUAL(pszBaseGeometry,"MultiGeometry") ||
    1383                 :         EQUAL(pszBaseGeometry,"GeometryCollection") )
    1384                 :     {
    1385                 :         const CPLXMLNode *psChild;
    1386             140 :         OGRGeometryCollection *poGC = new OGRGeometryCollection();
    1387                 : 
    1388                 :         // collect geoms
    1389             224 :         for( psChild = psNode->psChild; 
    1390                 :              psChild != NULL;
    1391                 :              psChild = psChild->psNext ) 
    1392                 :         {
    1393             152 :             if( psChild->eType == CXT_Element
    1394                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"geometryMember") )
    1395                 :             {
    1396             150 :                 const CPLXMLNode* psGeometryChild = GetChildElement(psChild);
    1397                 :                 OGRGeometry *poGeom;
    1398                 : 
    1399             150 :                 if (psGeometryChild != NULL)
    1400                 :                     poGeom = GML2OGRGeometry_XMLNode( psGeometryChild, bGetSecondaryGeometryOption,
    1401             148 :                                                       nRecLevel + 1 );
    1402                 :                 else
    1403               2 :                     poGeom = NULL;
    1404             150 :                 if( poGeom == NULL )
    1405                 :                 {
    1406                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1407              68 :                               "GeometryCollection: Failed to get geometry in geometryMember" );
    1408              68 :                     delete poGeom;
    1409              68 :                     delete poGC;
    1410              68 :                     return NULL;
    1411                 :                 }
    1412                 : 
    1413              82 :                 poGC->addGeometryDirectly( poGeom );
    1414                 :             }
    1415                 :         }
    1416                 : 
    1417              72 :         return poGC;
    1418                 :     }
    1419                 : 
    1420                 : /* -------------------------------------------------------------------- */
    1421                 : /*      Directed Edge                                              */
    1422                 : /* -------------------------------------------------------------------- */
    1423            2678 :     if( EQUAL(pszBaseGeometry,"directedEdge") )
    1424                 :     {
    1425                 :         const CPLXMLNode *psEdge,
    1426                 :                          *psdirectedNode,
    1427                 :                          *psNodeElement,
    1428                 :                          *pspointProperty,
    1429                 :                          *psPoint,
    1430                 :                          *psCurveProperty,
    1431                 :                          *psCurve;
    1432            1384 :         int               bEdgeOrientation = TRUE,
    1433            1384 :                           bNodeOrientation = TRUE;
    1434                 :         OGRGeometry      *poGeom;
    1435                 :         OGRLineString    *poLineString;
    1436            1384 :         OGRPoint         *poPositiveNode = NULL, *poNegativeNode = NULL;
    1437                 :         OGRMultiPoint    *poMP;
    1438                 :     
    1439            1384 :         bEdgeOrientation = GetElementOrientation(psNode);
    1440                 : 
    1441                 :         //collect edge
    1442            1384 :         psEdge = FindBareXMLChild(psNode,"Edge");
    1443            1384 :         if( psEdge == NULL )
    1444                 :         {
    1445                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1446               0 :                       "Failed to get Edge element in directedEdge" );
    1447               0 :             return NULL;
    1448                 :         }
    1449                 : 
    1450            1384 :         if( bGetSecondaryGeometry )
    1451                 :         {
    1452               0 :             psdirectedNode = FindBareXMLChild(psEdge,"directedNode");
    1453               0 :             if( psdirectedNode == NULL ) goto nonode;
    1454                 : 
    1455               0 :             bNodeOrientation = GetElementOrientation( psdirectedNode );
    1456                 : 
    1457               0 :             psNodeElement = FindBareXMLChild(psdirectedNode,"Node");
    1458               0 :             if( psNodeElement == NULL ) goto nonode;
    1459                 : 
    1460               0 :             pspointProperty = FindBareXMLChild(psNodeElement,"pointProperty");
    1461               0 :             if( pspointProperty == NULL )
    1462               0 :                 pspointProperty = FindBareXMLChild(psNodeElement,"connectionPointProperty");
    1463               0 :             if( pspointProperty == NULL ) goto nonode;
    1464                 : 
    1465               0 :             psPoint = FindBareXMLChild(pspointProperty,"Point");
    1466               0 :             if( psPoint == NULL )
    1467               0 :                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
    1468               0 :             if( psPoint == NULL ) goto nonode;
    1469                 : 
    1470                 :             poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
    1471               0 :                                               nRecLevel + 1, TRUE );
    1472               0 :             if( poGeom == NULL
    1473               0 :                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
    1474                 :             {
    1475                 : /*                CPLError( CE_Failure, CPLE_AppDefined, 
    1476                 :                       "Got %.500s geometry as Member instead of POINT.",
    1477                 :                       poGeom ? poGeom->getGeometryName() : "NULL" );*/
    1478               0 :                 if( poGeom != NULL) delete poGeom;
    1479               0 :                 goto nonode;
    1480                 :             }
    1481                 : 
    1482               0 :             if( ( bNodeOrientation == bEdgeOrientation ) != bOrientation )
    1483               0 :                 poPositiveNode = (OGRPoint *)poGeom;
    1484                 :             else
    1485               0 :                 poNegativeNode = (OGRPoint *)poGeom;
    1486                 : 
    1487                 :             // look for the other node
    1488               0 :             psdirectedNode = psdirectedNode->psNext;
    1489               0 :             while( psdirectedNode != NULL &&
    1490                 :                    !EQUAL( psdirectedNode->pszValue, "directedNode" ) )
    1491               0 :                 psdirectedNode = psdirectedNode->psNext;
    1492               0 :             if( psdirectedNode == NULL ) goto nonode;
    1493                 : 
    1494               0 :             if( GetElementOrientation( psdirectedNode ) == bNodeOrientation )
    1495               0 :                 goto nonode;
    1496                 : 
    1497               0 :             psNodeElement = FindBareXMLChild(psEdge,"Node");
    1498               0 :             if( psNodeElement == NULL ) goto nonode;
    1499                 : 
    1500               0 :             pspointProperty = FindBareXMLChild(psNodeElement,"pointProperty");
    1501               0 :             if( pspointProperty == NULL )
    1502               0 :                 pspointProperty = FindBareXMLChild(psNodeElement,"connectionPointProperty");
    1503               0 :             if( pspointProperty == NULL ) goto nonode;
    1504                 : 
    1505               0 :             psPoint = FindBareXMLChild(pspointProperty,"Point");
    1506               0 :             if( psPoint == NULL )
    1507               0 :                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
    1508               0 :             if( psPoint == NULL ) goto nonode;
    1509                 : 
    1510                 :             poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
    1511               0 :                                               nRecLevel + 1, TRUE );
    1512               0 :             if( poGeom == NULL
    1513               0 :                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
    1514                 :             {
    1515                 : /*                CPLError( CE_Failure, CPLE_AppDefined, 
    1516                 :                       "Got %.500s geometry as Member instead of POINT.",
    1517                 :                       poGeom ? poGeom->getGeometryName() : "NULL" );*/
    1518               0 :                 if( poGeom != NULL) delete poGeom;
    1519               0 :                 goto nonode;
    1520                 :             }
    1521                 : 
    1522               0 :             if( ( bNodeOrientation == bEdgeOrientation ) != bOrientation )
    1523               0 :                 poNegativeNode = (OGRPoint *)poGeom;
    1524                 :             else
    1525               0 :                 poPositiveNode = (OGRPoint *)poGeom;
    1526                 : 
    1527               0 :             poMP = new OGRMultiPoint();
    1528               0 :             poMP->addGeometryDirectly( poNegativeNode );
    1529               0 :             poMP->addGeometryDirectly( poPositiveNode );
    1530                 :             
    1531               0 :             return poMP;
    1532                 : 
    1533                 :             nonode:;
    1534                 :         }
    1535                 : 
    1536                 :         // collect curveproperty
    1537            1384 :         psCurveProperty = FindBareXMLChild(psEdge,"curveProperty");
    1538            1384 :         if( psCurveProperty == NULL )
    1539                 :         {
    1540                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1541               0 :                         "directedEdge: Failed to get curveProperty in Edge" );
    1542               0 :             return NULL;
    1543                 :         }
    1544                 : 
    1545            1384 :         psCurve = FindBareXMLChild(psCurveProperty,"LineString");
    1546            1384 :         if( psCurve == NULL )
    1547             640 :             psCurve = FindBareXMLChild(psCurveProperty,"Curve");
    1548            1384 :         if( psCurve == NULL )
    1549                 :         {
    1550                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1551               0 :                       "directedEdge: Failed to get LineString or Curve tag in curveProperty" );
    1552               0 :             return NULL;
    1553                 :         }
    1554                 : 
    1555                 :         poLineString = (OGRLineString *)GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
    1556            1384 :                                                                  nRecLevel + 1, TRUE );
    1557            2768 :         if( poLineString == NULL 
    1558            1384 :             || wkbFlatten(poLineString->getGeometryType()) != wkbLineString )
    1559                 :         {
    1560                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1561                 :                       "Got %.500s geometry as Member instead of LINESTRING.",
    1562               0 :                       poLineString ? poLineString->getGeometryName() : "NULL" );
    1563               0 :             if( poLineString != NULL )
    1564               0 :                 delete poLineString;
    1565               0 :             return NULL;
    1566                 :         }
    1567                 : 
    1568            1384 :         if( bGetSecondaryGeometry )
    1569                 :         {
    1570                 :             // choose a point based on the orientation
    1571               0 :             poNegativeNode = new OGRPoint();
    1572               0 :             poPositiveNode = new OGRPoint();
    1573               0 :             if( bEdgeOrientation == bOrientation )
    1574                 :             {
    1575               0 :                 poLineString->StartPoint( poNegativeNode );
    1576               0 :                 poLineString->EndPoint( poPositiveNode );
    1577                 :             }
    1578                 :             else
    1579                 :             {
    1580               0 :                 poLineString->StartPoint( poPositiveNode );
    1581               0 :                 poLineString->EndPoint( poNegativeNode );
    1582                 :             }
    1583               0 :             delete poLineString;
    1584                 : 
    1585               0 :             poMP = new OGRMultiPoint();
    1586               0 :             poMP->addGeometryDirectly( poNegativeNode );
    1587               0 :             poMP->addGeometryDirectly( poPositiveNode );
    1588                 : 
    1589               0 :             return poMP;
    1590                 :         }
    1591                 : 
    1592                 :         // correct orientation of the line string
    1593            1384 :         if( bEdgeOrientation != bOrientation )
    1594                 :         {
    1595             438 :             int nCoordDimensions = poLineString->getCoordinateDimension();
    1596             438 :             int iStartCoord = 0, iEndCoord = poLineString->getNumPoints() - 1;
    1597             438 :             OGRPoint *poTempStartPoint = new OGRPoint();
    1598             876 :             OGRPoint *poTempEndPoint = new OGRPoint();
    1599            1438 :             while( iStartCoord < iEndCoord )
    1600                 :             {
    1601             562 :                 poLineString->getPoint( iStartCoord, poTempStartPoint );
    1602             562 :                 poLineString->getPoint( iEndCoord, poTempEndPoint );
    1603             562 :                 poLineString->setPoint( iStartCoord, poTempEndPoint );
    1604             562 :                 poLineString->setPoint( iEndCoord, poTempStartPoint );
    1605             562 :                 iStartCoord++;
    1606             562 :                 iEndCoord--;
    1607                 :             }
    1608             438 :             delete poTempStartPoint;
    1609             438 :             delete poTempEndPoint;
    1610                 :             /* Restore coordinate dimension ass setPoint will force to 3D */
    1611             438 :             poLineString->setCoordinateDimension(nCoordDimensions);
    1612                 :         }
    1613            1384 :         return poLineString;
    1614                 :     }
    1615                 : 
    1616                 : /* -------------------------------------------------------------------- */
    1617                 : /*      TopoCurve                                                       */
    1618                 : /* -------------------------------------------------------------------- */
    1619            1294 :     if( EQUAL(pszBaseGeometry,"TopoCurve") )
    1620                 :     {
    1621                 :         const CPLXMLNode *psChild;
    1622             452 :         OGRMultiLineString *poMLS = NULL;
    1623             452 :         OGRMultiPoint *poMP = NULL;
    1624                 : 
    1625             452 :         if( bGetSecondaryGeometry )
    1626               0 :             poMP = new OGRMultiPoint();
    1627                 :         else
    1628             452 :             poMLS = new OGRMultiLineString();
    1629                 : 
    1630                 :         // collect directedEdges
    1631             944 :         for( psChild = psNode->psChild; 
    1632                 :              psChild != NULL;
    1633                 :              psChild = psChild->psNext ) 
    1634                 :         {
    1635             492 :             if( psChild->eType == CXT_Element
    1636                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"directedEdge"))
    1637                 :             {
    1638                 :                 OGRGeometry *poGeom;
    1639                 : 
    1640                 :                 poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1641             492 :                                                   nRecLevel + 1 );
    1642             492 :                 if( poGeom == NULL )
    1643                 :                 {
    1644                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1645               0 :                               "Failed to get geometry in directedEdge" );
    1646               0 :                     delete poGeom;
    1647               0 :                     if( bGetSecondaryGeometry )
    1648               0 :                         delete poMP;
    1649                 :                     else
    1650               0 :                         delete poMLS;
    1651               0 :                     return NULL;
    1652                 :                 }
    1653                 : 
    1654                 :                 //Add the two points corresponding to the two nodes to poMP
    1655             492 :                 if( bGetSecondaryGeometry &&
    1656               0 :                      wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint )
    1657                 :                 {
    1658                 :                     //TODO: TopoCurve geometries with more than one
    1659                 :                     //      directedEdge elements were not tested.
    1660               0 :                     if( poMP->getNumGeometries() <= 0 ||
    1661               0 :                         !(poMP->getGeometryRef( poMP->getNumGeometries() - 1 )->Equals(((OGRMultiPoint *)poGeom)->getGeometryRef( 0 ) ) ))
    1662                 :                     {
    1663                 :                         poMP->addGeometry(
    1664               0 :                             ( (OGRMultiPoint *)poGeom )->getGeometryRef( 0 ) );
    1665                 :                     }
    1666                 :                     poMP->addGeometry(
    1667               0 :                             ( (OGRMultiPoint *)poGeom )->getGeometryRef( 1 ) );
    1668               0 :                     delete poGeom;
    1669                 :                 }
    1670             984 :                 else if( !bGetSecondaryGeometry &&
    1671             492 :                      wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
    1672                 :                 {
    1673             492 :                     poMLS->addGeometryDirectly( poGeom );
    1674                 :                 }
    1675                 :                 else
    1676                 :                 {
    1677                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1678                 :                               "Got %.500s geometry as Member instead of %s.",
    1679               0 :                               poGeom ? poGeom->getGeometryName() : "NULL",
    1680               0 :                               bGetSecondaryGeometry?"MULTIPOINT":"LINESTRING");
    1681               0 :                     delete poGeom;
    1682               0 :                     if( bGetSecondaryGeometry )
    1683               0 :                         delete poMP;
    1684                 :                     else
    1685               0 :                         delete poMLS;
    1686               0 :                     return NULL;
    1687                 :                 }
    1688                 :             }
    1689                 :         }
    1690                 : 
    1691             452 :         if( bGetSecondaryGeometry )
    1692               0 :             return poMP;
    1693                 :         else
    1694             452 :             return poMLS;
    1695                 :     }
    1696                 : 
    1697                 : /* -------------------------------------------------------------------- */
    1698                 : /*      TopoSurface                                                     */
    1699                 : /* -------------------------------------------------------------------- */
    1700             842 :     if( EQUAL(pszBaseGeometry,"TopoSurface") )
    1701                 :     {
    1702                 :         /****************************************************************/
    1703                 :         /* applying the FaceHoleNegative = FALSE rules                  */
    1704                 :         /*                                                              */
    1705                 :         /* - each <TopoSurface> is expected to represent a MultiPolygon */
    1706                 :         /* - each <Face> is expected to represent a distinct Polygon,   */
    1707                 :         /*   this including any possible Interior Ring (holes);         */
    1708                 :         /*   orientation="+/-" plays no role at all to identify "holes" */
    1709                 :         /* - each <Edge> within a <Face> may indifferently represent    */
    1710                 :         /*   an element of the Exterior or Interior Boundary; relative  */
    1711                 :         /*   order of <Egdes> is absolutely irrelevant.                 */
    1712                 :         /****************************************************************/
    1713                 :         /* Contributor: Alessandro Furieri, a.furieri@lqt.it            */
    1714                 :         /* Developed for Faunalia (http://www.faunalia.it)              */
    1715                 :         /* with funding from Regione Toscana -                          */
    1716                 :         /* Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE       */
    1717                 :         /****************************************************************/
    1718              90 :         if(bFaceHoleNegative != TRUE)
    1719                 :         {
    1720              68 :             if( bGetSecondaryGeometry )
    1721               0 :                 return NULL;
    1722                 : 
    1723                 : #ifndef HAVE_GEOS
    1724                 :             static int bWarningAlreadyEmitted = FALSE;
    1725                 :             if (!bWarningAlreadyEmitted)
    1726                 :             {
    1727                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1728                 :                         "Interpreating that GML TopoSurface geometry requires GDAL to be built with GEOS support.\n"
    1729                 :                         "As a workaround, you can try defining the GML_FACE_HOLE_NEGATIVE configuration option\n"
    1730                 :                         "to YES, so that the 'old' interpretation algorithm is used. But be warned that\n"
    1731                 :                         "the result might be incorrect.\n");
    1732                 :                 bWarningAlreadyEmitted = TRUE;
    1733                 :             }
    1734                 :             return NULL;
    1735                 : #else
    1736                 :             const CPLXMLNode *psChild, *psFaceChild, *psDirectedEdgeChild;
    1737              68 :             OGRMultiPolygon *poTS = new OGRMultiPolygon();
    1738                 : 
    1739                 :             // collect directed faces
    1740             200 :             for( psChild = psNode->psChild; 
    1741                 :                 psChild != NULL;
    1742                 :             psChild = psChild->psNext ) 
    1743                 :             {
    1744             132 :               if( psChild->eType == CXT_Element
    1745                 :               && EQUAL(BareGMLElement(psChild->pszValue),"directedFace") )
    1746                 :               {
    1747                 :                 // collect next face (psChild->psChild)
    1748             132 :                 psFaceChild = psChild->psChild;
    1749                 :   
    1750             288 :                 while( psFaceChild != NULL &&
    1751                 :                        !(psFaceChild->eType == CXT_Element &&
    1752                 :                          EQUAL(BareGMLElement(psFaceChild->pszValue),"Face")) )
    1753              24 :                         psFaceChild = psFaceChild->psNext;
    1754                 : 
    1755             132 :                 if( psFaceChild == NULL )
    1756               0 :                   continue;
    1757                 : 
    1758             132 :                 OGRMultiLineString *poCollectedGeom = new OGRMultiLineString();
    1759                 : 
    1760                 :                 // collect directed edges of the face
    1761             972 :                 for( psDirectedEdgeChild = psFaceChild->psChild;
    1762                 :                      psDirectedEdgeChild != NULL;
    1763                 :                      psDirectedEdgeChild = psDirectedEdgeChild->psNext )
    1764                 :                 {
    1765             840 :                   if( psDirectedEdgeChild->eType == CXT_Element &&
    1766                 :                       EQUAL(BareGMLElement(psDirectedEdgeChild->pszValue),"directedEdge") )
    1767                 :                   {
    1768                 :                     OGRGeometry *poEdgeGeom;
    1769                 : 
    1770                 :                     poEdgeGeom = GML2OGRGeometry_XMLNode( psDirectedEdgeChild,
    1771                 :                                                           bGetSecondaryGeometryOption,
    1772             708 :                                                           TRUE );
    1773                 : 
    1774            1416 :                     if( poEdgeGeom == NULL ||
    1775             708 :                         wkbFlatten(poEdgeGeom->getGeometryType()) != wkbLineString )
    1776                 :                     {
    1777                 :                       CPLError( CE_Failure, CPLE_AppDefined, 
    1778               0 :                                 "Failed to get geometry in directedEdge" );
    1779               0 :                       delete poEdgeGeom;
    1780               0 :                       delete poCollectedGeom;
    1781               0 :                       delete poTS;
    1782               0 :                       return NULL;
    1783                 :                     }
    1784                 : 
    1785             708 :                     poCollectedGeom->addGeometryDirectly( poEdgeGeom );
    1786                 :                   }
    1787                 :                 }
    1788                 : 
    1789             132 :                 OGRGeometry *poFaceCollectionGeom = NULL;
    1790             132 :                 OGRPolygon *poFaceGeom = NULL;
    1791                 : 
    1792                 : //#ifdef HAVE_GEOS
    1793             132 :                 poFaceCollectionGeom = poCollectedGeom->Polygonize();
    1794             132 :                 if( poFaceCollectionGeom == NULL )
    1795                 :                 {
    1796                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1797               0 :                               "Failed to assemble Edges in Face" );
    1798               0 :                     delete poCollectedGeom;
    1799               0 :                     delete poTS;
    1800               0 :                     return NULL;
    1801                 :                 }
    1802                 : 
    1803             132 :                 poFaceGeom = GML2FaceExtRing( poFaceCollectionGeom );
    1804                 : //#else
    1805                 : //                poFaceGeom = (OGRPolygon*) OGRBuildPolygonFromEdges(
    1806                 : //                    (OGRGeometryH) poCollectedGeom,
    1807                 : //                    FALSE, TRUE, 0, NULL);
    1808                 : //#endif
    1809                 : 
    1810             132 :                 if( poFaceGeom == NULL )
    1811                 :                 {
    1812                 :                     CPLError( CE_Failure, CPLE_AppDefined,
    1813               0 :                                 "Failed to build Polygon for Face" );
    1814               0 :                     delete poCollectedGeom;
    1815               0 :                     delete poTS;
    1816               0 :                     return NULL;
    1817                 :                 }
    1818                 :                 else
    1819                 :                 {
    1820             132 :                     int iCount = poTS->getNumGeometries();
    1821             132 :                     if( iCount == 0)
    1822                 :                     {
    1823                 :                         /* inserting the first Polygon */
    1824              68 :                         poTS->addGeometryDirectly( poFaceGeom );
    1825                 :                     }
    1826                 :                     else
    1827                 :                     {
    1828                 :                         /* using Union to add the current Polygon */
    1829              64 :                         OGRGeometry *poUnion = poTS->Union( poFaceGeom );
    1830              64 :                         delete poFaceGeom;
    1831              64 :                         delete poTS;
    1832              64 :                         if( poUnion == NULL )
    1833                 :                         {
    1834                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1835               0 :                                         "Failed Union for TopoSurface" );
    1836               0 :                             return NULL;
    1837                 :                         }
    1838              64 :                         poTS = (OGRMultiPolygon *)poUnion;
    1839                 :                     }
    1840                 :                 }
    1841             132 :                 delete poFaceCollectionGeom;
    1842             132 :                 delete poCollectedGeom;
    1843                 :               }
    1844                 :             }
    1845                 : 
    1846              68 :             if( wkbFlatten( poTS->getGeometryType()) == wkbPolygon )
    1847                 :             {
    1848                 :                 /* forcing to be a MultiPolygon */
    1849              16 :                 OGRGeometry *poOldTS = poTS;
    1850              16 :                 poTS = new OGRMultiPolygon();
    1851              16 :                 poTS->addGeometryDirectly(poOldTS);
    1852                 :             }
    1853                 : 
    1854              68 :             return poTS;
    1855                 : #endif // HAVE_GEOS
    1856                 :         }
    1857                 : 
    1858                 :         /****************************************************************/
    1859                 :         /* applying the FaceHoleNegative = TRUE rules                   */
    1860                 :         /*                                                              */
    1861                 :         /* - each <TopoSurface> is expected to represent a MultiPolygon */
    1862                 :         /* - any <Face> declaring orientation="+" is expected to        */
    1863                 :         /*   represent an Exterior Ring (no holes are allowed)          */
    1864                 :         /* - any <Face> declaring orientation="-" is expected to        */
    1865                 :         /*   represent an Interior Ring (hole) belonging to the latest  */
    1866                 :         /*   Exterior Ring.                                             */
    1867                 :         /* - <Egdes> within the same <Face> are expected to be          */
    1868                 :         /*   arranged in geometrically adjacent and consecutive         */
    1869                 :         /*   sequence.                                                  */
    1870                 :         /****************************************************************/
    1871              22 :         if( bGetSecondaryGeometry )
    1872               0 :             return NULL;
    1873                 :         const CPLXMLNode *psChild, *psFaceChild, *psDirectedEdgeChild;
    1874              22 :         int bFaceOrientation = TRUE;
    1875              22 :         OGRPolygon *poTS = new OGRPolygon();
    1876                 : 
    1877                 :         // collect directed faces
    1878              66 :         for( psChild = psNode->psChild; 
    1879                 :              psChild != NULL;
    1880                 :              psChild = psChild->psNext ) 
    1881                 :         {
    1882              44 :           if( psChild->eType == CXT_Element
    1883                 :               && EQUAL(BareGMLElement(psChild->pszValue),"directedFace") )
    1884                 :           {
    1885              40 :             bFaceOrientation = GetElementOrientation(psChild);
    1886                 : 
    1887                 :             // collect next face (psChild->psChild)
    1888              40 :             psFaceChild = psChild->psChild;
    1889              92 :             while( psFaceChild != NULL &&
    1890                 :                    !EQUAL(BareGMLElement(psFaceChild->pszValue),"Face") )
    1891              12 :                     psFaceChild = psFaceChild->psNext;
    1892                 : 
    1893              40 :             if( psFaceChild == NULL )
    1894               0 :               continue;
    1895                 : 
    1896              40 :             OGRLinearRing *poFaceGeom = new OGRLinearRing();
    1897                 : 
    1898                 :             // collect directed edges of the face
    1899             260 :             for( psDirectedEdgeChild = psFaceChild->psChild;
    1900                 :                  psDirectedEdgeChild != NULL;
    1901                 :                  psDirectedEdgeChild = psDirectedEdgeChild->psNext )
    1902                 :             {
    1903             220 :               if( psDirectedEdgeChild->eType == CXT_Element &&
    1904                 :                   EQUAL(BareGMLElement(psDirectedEdgeChild->pszValue),"directedEdge") )
    1905                 :               {
    1906                 :                 OGRGeometry *poEdgeGeom;
    1907                 : 
    1908                 :                 poEdgeGeom = GML2OGRGeometry_XMLNode( psDirectedEdgeChild,
    1909                 :                                                       bGetSecondaryGeometryOption,
    1910                 :                                                       nRecLevel + 1,
    1911                 :                                                       TRUE,
    1912             184 :                                                       bFaceOrientation );
    1913                 : 
    1914             368 :                 if( poEdgeGeom == NULL ||
    1915             184 :                     wkbFlatten(poEdgeGeom->getGeometryType()) != wkbLineString )
    1916                 :                 {
    1917                 :                   CPLError( CE_Failure, CPLE_AppDefined, 
    1918               0 :                             "Failed to get geometry in directedEdge" );
    1919               0 :                   delete poEdgeGeom;
    1920               0 :                   delete poFaceGeom;
    1921               0 :                   delete poTS;
    1922               0 :                   return NULL;
    1923                 :                 }
    1924                 : 
    1925             184 :                 if( !bFaceOrientation )
    1926                 :                 {
    1927              30 :                   if( poFaceGeom->getNumPoints() > 0 )
    1928              18 :                     ((OGRLinearRing *)poEdgeGeom)->addSubLineString( (OGRLineString *)poFaceGeom );
    1929              30 :                   poFaceGeom->empty();
    1930                 :                 }
    1931             184 :                 poFaceGeom->addSubLineString( (OGRLinearRing *)poEdgeGeom );
    1932             184 :                 delete poEdgeGeom;
    1933                 :               }
    1934                 :             }
    1935                 : 
    1936                 : /*            if( poFaceGeom == NULL )
    1937                 :             {
    1938                 :               CPLError( CE_Failure, CPLE_AppDefined, 
    1939                 :                         "Failed to get Face geometry in directedFace" );
    1940                 :               delete poFaceGeom;
    1941                 :               return NULL;
    1942                 :             }*/
    1943                 : 
    1944              40 :             poTS->addRingDirectly( poFaceGeom );
    1945                 :           }
    1946                 :         }
    1947                 : 
    1948                 : /*        if( poTS == NULL )
    1949                 :         {
    1950                 :           CPLError( CE_Failure, CPLE_AppDefined, 
    1951                 :                     "Failed to get TopoSurface geometry" );
    1952                 :           delete poTS;
    1953                 :           return NULL;
    1954                 :         }*/
    1955                 : 
    1956              22 :         return poTS;
    1957                 :     }
    1958                 : 
    1959                 : /* -------------------------------------------------------------------- */
    1960                 : /*      Surface                                                         */
    1961                 : /* -------------------------------------------------------------------- */
    1962             752 :     if( EQUAL(pszBaseGeometry,"Surface") )
    1963                 :     {
    1964                 :         const CPLXMLNode *psChild;
    1965             714 :         OGRGeometry *poResult = NULL;
    1966                 : 
    1967                 :         // Find outer ring.
    1968             714 :         psChild = FindBareXMLChild( psNode, "patches" );
    1969             714 :         if( psChild == NULL )
    1970             670 :             psChild = FindBareXMLChild( psNode, "polygonPatches" );
    1971             714 :         if( psChild == NULL )
    1972               4 :             psChild = FindBareXMLChild( psNode, "trianglePatches" );
    1973                 : 
    1974             714 :         if( psChild == NULL || psChild->psChild == NULL )
    1975                 :         {
    1976                 :             /* <gml:Surface/> and <gml:Surface><gml:patches/></gml:Surface> are valid GML */
    1977               6 :             return new OGRPolygon();
    1978                 :         }
    1979                 : 
    1980            1418 :         for( psChild = psChild->psChild; 
    1981                 :              psChild != NULL; psChild = psChild->psNext )
    1982                 :         {
    1983             710 :             if( psChild->eType == CXT_Element
    1984                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"PolygonPatch") ||
    1985                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Triangle") ||
    1986                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Rectangle")))
    1987                 :             {
    1988                 :                 OGRPolygon *poPolygon = (OGRPolygon *) 
    1989                 :                     GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1990             708 :                                              nRecLevel + 1 );
    1991             708 :                 if( poPolygon == NULL )
    1992               0 :                     return NULL;
    1993                 :                 
    1994             708 :                 if( poResult == NULL )
    1995             706 :                     poResult = poPolygon;
    1996               2 :                 else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
    1997                 :                 {
    1998               2 :                     OGRMultiPolygon *poMP = new OGRMultiPolygon();
    1999               2 :                     poMP->addGeometryDirectly( poResult );
    2000               2 :                     poMP->addGeometryDirectly( poPolygon );
    2001               2 :                     poResult = poMP;
    2002                 :                 }
    2003                 :                 else
    2004                 :                 {
    2005               0 :                     ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
    2006                 :                 }
    2007                 :             }
    2008                 :         }
    2009                 :         
    2010             708 :         return poResult;
    2011                 :     }
    2012                 : 
    2013                 : /* -------------------------------------------------------------------- */
    2014                 : /*      TriangulatedSurface                                             */
    2015                 : /* -------------------------------------------------------------------- */
    2016              38 :     if( EQUAL(pszBaseGeometry,"TriangulatedSurface") ||
    2017                 :         EQUAL(pszBaseGeometry,"Tin") )
    2018                 :     {
    2019                 :         const CPLXMLNode *psChild;
    2020               2 :         OGRGeometry *poResult = NULL;
    2021                 : 
    2022                 :         // Find trianglePatches
    2023               2 :         psChild = FindBareXMLChild( psNode, "trianglePatches" );
    2024               2 :         if (psChild == NULL)
    2025               2 :             psChild = FindBareXMLChild( psNode, "patches" );
    2026                 : 
    2027               2 :         if( psChild == NULL || psChild->psChild == NULL )
    2028                 :         {
    2029                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2030               0 :                       "Missing <trianglePatches> for %s.", pszBaseGeometry );
    2031               0 :             return NULL;
    2032                 :         }
    2033                 : 
    2034               4 :         for( psChild = psChild->psChild;
    2035                 :              psChild != NULL; psChild = psChild->psNext )
    2036                 :         {
    2037               2 :             if( psChild->eType == CXT_Element
    2038                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"Triangle") )
    2039                 :             {
    2040                 :                 OGRPolygon *poPolygon = (OGRPolygon *)
    2041                 :                     GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    2042               2 :                                              nRecLevel + 1 );
    2043               2 :                 if( poPolygon == NULL )
    2044               0 :                     return NULL;
    2045                 : 
    2046               2 :                 if( poResult == NULL )
    2047               2 :                     poResult = poPolygon;
    2048               0 :                 else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
    2049                 :                 {
    2050               0 :                     OGRMultiPolygon *poMP = new OGRMultiPolygon();
    2051               0 :                     poMP->addGeometryDirectly( poResult );
    2052               0 :                     poMP->addGeometryDirectly( poPolygon );
    2053               0 :                     poResult = poMP;
    2054                 :                 }
    2055                 :                 else
    2056                 :                 {
    2057               0 :                     ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
    2058                 :                 }
    2059                 :             }
    2060                 :         }
    2061                 : 
    2062               2 :         return poResult;
    2063                 :     }
    2064                 : 
    2065                 : /* -------------------------------------------------------------------- */
    2066                 : /*      Solid                                                           */
    2067                 : /* -------------------------------------------------------------------- */
    2068              36 :     if( EQUAL(pszBaseGeometry,"Solid") )
    2069                 :     {
    2070                 :         const CPLXMLNode *psChild;
    2071                 :         OGRGeometry* poGeom;
    2072                 : 
    2073                 :         // Find exterior element
    2074              12 :         psChild = FindBareXMLChild( psNode, "exterior");
    2075                 : 
    2076              12 :         if( psChild == NULL || psChild->psChild == NULL )
    2077                 :         {
    2078                 :             /* <gml:Solid/> and <gml:Solid><gml:exterior/></gml:Solid> are valid GML */
    2079               6 :             return new OGRPolygon();
    2080                 :         }
    2081                 : 
    2082                 :         // Get the geometry inside <exterior>
    2083                 :         poGeom = GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
    2084               6 :                                           nRecLevel + 1 );
    2085               6 :         if( poGeom == NULL )
    2086                 :         {
    2087               2 :             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior element");
    2088               2 :             delete poGeom;
    2089               2 :             return NULL;
    2090                 :         }
    2091                 : 
    2092               4 :         psChild = FindBareXMLChild( psNode, "interior");
    2093               4 :         if( psChild != NULL )
    2094                 :         {
    2095                 :             static int bWarnedOnce = FALSE;
    2096               2 :             if (!bWarnedOnce)
    2097                 :             {
    2098                 :                 CPLError( CE_Warning, CPLE_AppDefined,
    2099               2 :                           "<interior> elements of <Solid> are ignored");
    2100               2 :                 bWarnedOnce = TRUE;
    2101                 :             }
    2102                 :         }
    2103                 : 
    2104               4 :         return poGeom;
    2105                 :     }
    2106                 : 
    2107                 : /* -------------------------------------------------------------------- */
    2108                 : /*      OrientableSurface                                               */
    2109                 : /* -------------------------------------------------------------------- */
    2110              24 :     if( EQUAL(pszBaseGeometry,"OrientableSurface") )
    2111                 :     {
    2112                 :         const CPLXMLNode *psChild;
    2113                 : 
    2114                 :         // Find baseSurface.
    2115              10 :         psChild = FindBareXMLChild( psNode, "baseSurface" );
    2116                 : 
    2117              10 :         if( psChild == NULL || psChild->psChild == NULL )
    2118                 :         {
    2119                 :             CPLError( CE_Failure, CPLE_AppDefined,
    2120               6 :                       "Missing <baseSurface> for OrientableSurface." );
    2121               6 :             return NULL;
    2122                 :         }
    2123                 : 
    2124                 :         return GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
    2125               4 :                                         nRecLevel + 1 );
    2126                 :     }
    2127                 : 
    2128                 :     CPLError( CE_Failure, CPLE_AppDefined, 
    2129                 :               "Unrecognised geometry type <%.500s>.", 
    2130              14 :               pszBaseGeometry );
    2131                 : 
    2132              14 :     return NULL;
    2133                 : }
    2134                 : 
    2135                 : /************************************************************************/
    2136                 : /*                      OGR_G_CreateFromGMLTree()                       */
    2137                 : /************************************************************************/
    2138                 : 
    2139             680 : OGRGeometryH OGR_G_CreateFromGMLTree( const CPLXMLNode *psTree )
    2140                 : 
    2141                 : {
    2142             680 :     return (OGRGeometryH) GML2OGRGeometry_XMLNode( psTree, -1 );
    2143                 : }
    2144                 : 
    2145                 : /************************************************************************/
    2146                 : /*                        OGR_G_CreateFromGML()                         */
    2147                 : /************************************************************************/
    2148                 : 
    2149                 : /**
    2150                 :  * \brief Create geometry from GML.
    2151                 :  *
    2152                 :  * This method translates a fragment of GML containing only the geometry
    2153                 :  * portion into a corresponding OGRGeometry.  There are many limitations
    2154                 :  * on the forms of GML geometries supported by this parser, but they are
    2155                 :  * too numerous to list here.
    2156                 :  *
    2157                 :  * The following GML2 elements are parsed : Point, LineString, Polygon,
    2158                 :  * MultiPoint, MultiLineString, MultiPolygon, MultiGeometry.
    2159                 :  *
    2160                 :  * (OGR >= 1.8.0) The following GML3 elements are parsed : Surface, MultiSurface,
    2161                 :  * PolygonPatch, Triangle, Rectangle, Curve, MultiCurve, LineStringSegment, Arc,
    2162                 :  * Circle, CompositeSurface, OrientableSurface, Solid, Tin, TriangulatedSurface.
    2163                 :  *
    2164                 :  * Arc and Circle elements are stroked to linestring, by using a
    2165                 :  * 4 degrees step, unless the user has overridden the value with the
    2166                 :  * OGR_ARC_STEPSIZE configuration variable.
    2167                 :  *
    2168                 :  * The C++ method OGRGeometryFactory::createFromGML() is the same as this function.
    2169                 :  *
    2170                 :  * @param pszGML The GML fragment for the geometry.
    2171                 :  *
    2172                 :  * @return a geometry on succes, or NULL on error.
    2173                 :  */
    2174                 : 
    2175             326 : OGRGeometryH OGR_G_CreateFromGML( const char *pszGML )
    2176                 : 
    2177                 : {
    2178             326 :     if( pszGML == NULL || strlen(pszGML) == 0 )
    2179                 :     {
    2180                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2181               0 :                   "GML Geometry is empty in OGR_G_CreateFromGML()." );
    2182               0 :         return NULL;
    2183                 :     }
    2184                 : 
    2185                 : /* ------------------------------------------------------------ -------- */
    2186                 : /*      Try to parse the XML snippet using the MiniXML API.  If this    */
    2187                 : /*      fails, we assume the minixml api has already posted a CPL       */
    2188                 : /*      error, and just return NULL.                                    */
    2189                 : /* -------------------------------------------------------------------- */
    2190             326 :     CPLXMLNode *psGML = CPLParseXMLString( pszGML );
    2191                 : 
    2192             326 :     if( psGML == NULL )
    2193               0 :         return NULL;
    2194                 : 
    2195                 : /* -------------------------------------------------------------------- */
    2196                 : /*      Convert geometry recursively.                                   */
    2197                 : /* -------------------------------------------------------------------- */
    2198                 :     OGRGeometry *poGeometry;
    2199                 : 
    2200                 :     /* Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer() and GMLReader::GMLReader() */
    2201             326 :     int bFaceHoleNegative = CSLTestBoolean(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO"));
    2202             326 :     poGeometry = GML2OGRGeometry_XMLNode( psGML, -1, 0, FALSE, TRUE, bFaceHoleNegative );
    2203                 : 
    2204             326 :     CPLDestroyXMLNode( psGML );
    2205                 :     
    2206             326 :     return (OGRGeometryH) poGeometry;
    2207                 : }
    2208                 : 
    2209                 : 

Generated by: LCOV version 1.7