LCOV - code coverage report
Current view: directory - ogr - gml2ogrgeometry.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 890 715 80.3 %
Date: 2012-12-26 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.7