LCOV - code coverage report
Current view: directory - ogr - gml2ogrgeometry.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 772 625 81.0 %
Date: 2011-12-18 Functions: 11 11 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gml2ogrgeometry.cpp 23589 2011-12-17 14:21:01Z 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           48672 : static const char* GMLGetCoordTokenPos(const char* pszStr,
      59                 :                                        const char** ppszNextToken)
      60                 : {
      61                 :     char ch;
      62           22593 :     while(TRUE)
      63                 :     {
      64           48672 :         ch = *pszStr;
      65           48672 :         if (ch == '\0')
      66                 :         {
      67              75 :             *ppszNextToken = NULL;
      68              75 :             return NULL;
      69                 :         }
      70           48597 :         else if (!(ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ' || ch == ','))
      71                 :             break;
      72           22593 :         pszStr ++;
      73                 :     }
      74                 : 
      75           26004 :     const char* pszToken = pszStr;
      76          312351 :     while((ch = *pszStr) != '\0')
      77                 :     {
      78          282755 :         if (ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ' || ch == ',')
      79                 :         {
      80           22412 :             *ppszNextToken = pszStr;
      81           22412 :             return pszToken;
      82                 :         }
      83          260343 :         pszStr ++;
      84                 :     }
      85            3592 :     *ppszNextToken = NULL;
      86            3592 :     return pszToken;
      87                 : }
      88                 : 
      89                 : /************************************************************************/
      90                 : /*                           BareGMLElement()                           */
      91                 : /*                                                                      */
      92                 : /*      Returns the passed string with any namespace prefix             */
      93                 : /*      stripped off.                                                   */
      94                 : /************************************************************************/
      95                 : 
      96           35319 : static const char *BareGMLElement( const char *pszInput )
      97                 : 
      98                 : {
      99                 :     const char *pszReturn;
     100                 : 
     101           35319 :     pszReturn = strchr( pszInput, ':' );
     102           35319 :     if( pszReturn == NULL )
     103           34295 :         pszReturn = pszInput;
     104                 :     else
     105            1024 :         pszReturn++;
     106                 : 
     107           35319 :     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           12245 : static const CPLXMLNode *FindBareXMLChild( const CPLXMLNode *psParent, 
     118                 :                                            const char *pszBareName )
     119                 : 
     120                 : {
     121           12245 :     const CPLXMLNode *psCandidate = psParent->psChild;
     122                 : 
     123           34828 :     while( psCandidate != NULL )
     124                 :     {
     125           18225 :         if( psCandidate->eType == CXT_Element
     126                 :             && EQUAL(BareGMLElement(psCandidate->pszValue), pszBareName) )
     127            7887 :             return psCandidate;
     128                 : 
     129           10338 :         psCandidate = psCandidate->psNext;
     130                 :     }
     131                 : 
     132            4358 :     return NULL;
     133                 : }
     134                 : 
     135                 : /************************************************************************/
     136                 : /*                           GetElementText()                           */
     137                 : /************************************************************************/
     138                 : 
     139            3855 : static const char *GetElementText( const CPLXMLNode *psElement )
     140                 : 
     141                 : {
     142            3855 :     if( psElement == NULL )
     143               0 :         return NULL;
     144                 : 
     145            3855 :     const CPLXMLNode *psChild = psElement->psChild;
     146                 : 
     147            8107 :     while( psChild != NULL )
     148                 :     {
     149            4248 :         if( psChild->eType == CXT_Text )
     150            3851 :             return psChild->pszValue;
     151                 : 
     152             397 :         psChild = psChild->psNext;
     153                 :     }
     154                 :     
     155               4 :     return NULL;
     156                 : }
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                           GetChildElement()                          */
     160                 : /************************************************************************/
     161                 : 
     162            3010 : static const CPLXMLNode *GetChildElement( const CPLXMLNode *psElement )
     163                 : 
     164                 : {
     165            3010 :     if( psElement == NULL )
     166               0 :         return NULL;
     167                 : 
     168            3010 :     const CPLXMLNode *psChild = psElement->psChild;
     169                 : 
     170            6021 :     while( psChild != NULL )
     171                 :     {
     172            3006 :         if( psChild->eType == CXT_Element )
     173            3005 :             return psChild;
     174                 : 
     175               1 :         psChild = psChild->psNext;
     176                 :     }
     177                 : 
     178               5 :     return NULL;
     179                 : }
     180                 : 
     181                 : /************************************************************************/
     182                 : /*                    GetElementOrientation()                           */
     183                 : /*     Returns true for positive orientation.                           */
     184                 : /************************************************************************/
     185                 : 
     186             276 : int GetElementOrientation( const CPLXMLNode *psElement )
     187                 : {
     188             276 :     if( psElement == NULL )
     189               0 :         return TRUE;
     190                 : 
     191             276 :     const CPLXMLNode *psChild = psElement->psChild;
     192                 : 
     193             730 :     while( psChild != NULL )
     194                 :     {
     195             276 :         if( psChild->eType == CXT_Attribute &&
     196                 :             EQUAL(psChild->pszValue,"orientation") )
     197              98 :                 return EQUAL(psChild->psChild->pszValue,"+");
     198                 : 
     199             178 :         psChild = psChild->psNext;
     200                 :     }
     201                 :     
     202             178 :     return TRUE;
     203                 : }
     204                 : 
     205                 : /************************************************************************/
     206                 : /*                              AddPoint()                              */
     207                 : /*                                                                      */
     208                 : /*      Add a point to the passed geometry.                             */
     209                 : /************************************************************************/
     210                 : 
     211           13378 : static int AddPoint( OGRGeometry *poGeometry, 
     212                 :                      double dfX, double dfY, double dfZ, int nDimension )
     213                 : 
     214                 : {
     215           13378 :     OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
     216           13378 :     if( eType == wkbPoint )
     217                 :     {
     218             387 :         OGRPoint *poPoint = (OGRPoint *) poGeometry;
     219                 : 
     220             387 :         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             385 :         poPoint->setX( dfX );
     228             385 :         poPoint->setY( dfY );
     229             385 :         if( nDimension == 3 )
     230              12 :             poPoint->setZ( dfZ );
     231                 : 
     232             385 :         return TRUE;
     233                 :     }
     234                 :                 
     235           12991 :     else if( eType == wkbLineString )
     236                 :     {
     237           12991 :         if( nDimension == 3 )
     238              54 :             ((OGRLineString *) poGeometry)->addPoint( dfX, dfY, dfZ );
     239                 :         else
     240           12937 :             ((OGRLineString *) poGeometry)->addPoint( dfX, dfY );
     241                 : 
     242           12991 :         return TRUE;
     243                 :     }
     244                 : 
     245                 :     else
     246                 :     {
     247               0 :         CPLAssert( FALSE );
     248               0 :         return FALSE;                                                   
     249                 :     }
     250                 : }
     251                 : 
     252                 : /************************************************************************/
     253                 : /*                        ParseGMLCoordinates()                         */
     254                 : /************************************************************************/
     255                 : 
     256            3712 : static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeometry )
     257                 : 
     258                 : {
     259            3712 :     const CPLXMLNode *psCoordinates = FindBareXMLChild( psGeomNode, "coordinates" );
     260            3712 :     int iCoord = 0;
     261                 : 
     262                 : /* -------------------------------------------------------------------- */
     263                 : /*      Handle <coordinates> case.                                      */
     264                 : /* -------------------------------------------------------------------- */
     265            3712 :     if( psCoordinates != NULL )
     266                 :     {
     267             177 :         const char *pszCoordString = GetElementText( psCoordinates );
     268             177 :         char chCS = ',';
     269                 : 
     270             177 :         if( pszCoordString == NULL )
     271                 :         {
     272                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     273               1 :                       "<coordinates> element missing value." );
     274               1 :             return FALSE;
     275                 :         }
     276                 : 
     277             747 :         while( *pszCoordString != '\0' )
     278                 :         {
     279             397 :             double dfX, dfY, dfZ = 0.0;
     280             397 :             int nDimension = 2;
     281                 : 
     282                 :             // parse out 2 or 3 tuple. 
     283             397 :             dfX = OGRFastAtof( pszCoordString );
     284            4859 :             while( *pszCoordString != '\0'
     285                 :                    && *pszCoordString != ','
     286                 :                    && !isspace((unsigned char)*pszCoordString) )
     287            4065 :                 pszCoordString++;
     288                 : 
     289             397 :             if( *pszCoordString == '\0' )
     290                 :             {
     291                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     292               1 :                         "Corrupt <coordinates> value." );
     293               1 :                 return FALSE;
     294                 :             }
     295             396 :             else if( chCS == ',' && isspace((unsigned char)*pszCoordString) )
     296                 :             {
     297                 :                 /* In theory, the coordinates inside a coordinate tuple should be */
     298                 :                 /* separated by a comma. However it has been found in the wild */
     299                 :                 /* that the coordinates are in rare cases separated by a space, and the tuples by a comma */
     300                 :                 /* See https://52north.org/twiki/bin/view/Processing/WPS-IDWExtension-ObservationCollectionExample */
     301                 :                 /* or http://agisdemo.faa.gov/aixmServices/getAllFeaturesByLocatorId?locatorId=DFW */
     302               2 :                 chCS = ' ';
     303                 :             }
     304                 : 
     305             396 :             pszCoordString++;
     306             396 :             dfY = OGRFastAtof( pszCoordString );
     307            4857 :             while( *pszCoordString != '\0' 
     308                 :                    && *pszCoordString != ','
     309                 :                    && !isspace((unsigned char)*pszCoordString) )
     310            4065 :                 pszCoordString++;
     311                 : 
     312             396 :             if( *pszCoordString == chCS )
     313                 :             {
     314              25 :                 pszCoordString++;
     315              25 :                 dfZ = OGRFastAtof( pszCoordString );
     316              25 :                 nDimension = 3;
     317              75 :                 while( *pszCoordString != '\0' 
     318                 :                        && *pszCoordString != ','
     319                 :                        && !isspace((unsigned char)*pszCoordString) )
     320              25 :                 pszCoordString++;
     321                 :             }
     322                 : 
     323             396 :             if ( chCS == ' ' && *pszCoordString == ',' )
     324                 :             {
     325               0 :                 pszCoordString++;
     326                 :             }
     327                 : 
     328            1042 :             while( isspace((unsigned char)*pszCoordString) )
     329             250 :                 pszCoordString++;
     330                 : 
     331             396 :             if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
     332               1 :                 return FALSE;
     333                 : 
     334             395 :             iCoord++;
     335                 :         }
     336                 : 
     337             174 :         return iCoord > 0;
     338                 :     }
     339                 : 
     340                 : /* -------------------------------------------------------------------- */
     341                 : /*      Is this a "pos"?  GML 3 construct.                              */
     342                 : /*      Parse if it exist a series of pos elements (this would allow    */
     343                 : /*      the correct parsing of gml3.1.1 geomtries such as linestring    */
     344                 : /*      defined with pos elements.                                      */
     345                 : /* -------------------------------------------------------------------- */
     346                 :     const CPLXMLNode *psPos;
     347                 :     
     348            3535 :     int bHasFoundPosElement = FALSE;
     349            7696 :     for( psPos = psGeomNode->psChild;
     350                 :          psPos != NULL;
     351                 :          psPos = psPos->psNext )
     352                 :     {
     353            4164 :         if( psPos->eType != CXT_Element  )
     354             484 :             continue;
     355                 : 
     356            3680 :         const char* pszSubElement = BareGMLElement(psPos->pszValue);
     357                 : 
     358            3680 :         if( EQUAL(pszSubElement, "pointProperty") )
     359                 :         {
     360                 :             const CPLXMLNode *psPointPropertyIter;
     361               2 :             for( psPointPropertyIter = psPos->psChild;
     362                 :                  psPointPropertyIter != NULL;
     363                 :                  psPointPropertyIter = psPointPropertyIter->psNext )
     364                 :             {
     365               1 :                 if( psPointPropertyIter->eType != CXT_Element  )
     366               0 :                     continue;
     367                 : 
     368               1 :                 if (EQUAL(BareGMLElement(psPointPropertyIter->pszValue),"Point") )
     369                 :                 {
     370               1 :                     OGRPoint oPoint;
     371               1 :                     if( ParseGMLCoordinates( psPointPropertyIter, &oPoint ) )
     372                 :                     {
     373                 :                         int bSuccess = AddPoint( poGeometry, oPoint.getX(),
     374                 :                                                  oPoint.getY(), oPoint.getZ(),
     375               1 :                                                  oPoint.getCoordinateDimension() );
     376               1 :                         if (bSuccess)
     377               1 :                             bHasFoundPosElement = TRUE;
     378                 :                         else
     379               0 :                             return FALSE;
     380               0 :                     }
     381                 :                 }
     382                 :             }
     383               1 :             continue;
     384                 :         }
     385                 : 
     386            3679 :         if( !EQUAL(pszSubElement,"pos") )
     387            3275 :             continue;
     388                 : 
     389             404 :         const char* pszPos = GetElementText( psPos );
     390             404 :         const char* pszCur = pszPos;
     391                 :         const char* pszX = (pszCur != NULL) ?
     392             404 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     393                 :         const char* pszY = (pszCur != NULL) ?
     394             404 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     395                 :         const char* pszZ = (pszCur != NULL) ?
     396             404 :                             GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     397                 : 
     398             404 :         if (pszY == NULL)
     399                 :         {
     400                 :             CPLError( CE_Failure, CPLE_AppDefined,
     401                 :                       "Did not get 2+ values in <gml:pos>%s</gml:pos> tuple.",
     402               2 :                       pszPos ? pszPos : "" );
     403               2 :             return FALSE;
     404                 :         }
     405                 : 
     406             402 :         double dfX = OGRFastAtof(pszX);
     407             402 :         double dfY = OGRFastAtof(pszY);
     408             402 :         double dfZ = (pszZ != NULL) ? OGRFastAtof(pszZ) : 0.0;
     409             402 :         int bSuccess = AddPoint( poGeometry, dfX, dfY, dfZ, (pszZ != NULL) ? 3 : 2 );
     410                 : 
     411             402 :         if (bSuccess)
     412             401 :             bHasFoundPosElement = TRUE;
     413                 :         else
     414               1 :             return FALSE;
     415                 :     }
     416                 : 
     417            3532 :     if (bHasFoundPosElement)
     418             250 :         return TRUE;
     419                 : 
     420                 : /* -------------------------------------------------------------------- */
     421                 : /*      Is this a "posList"?  GML 3 construct (SF profile).             */
     422                 : /* -------------------------------------------------------------------- */
     423            3282 :     const CPLXMLNode *psPosList = FindBareXMLChild( psGeomNode, "posList" );
     424                 :     
     425            3282 :     if( psPosList != NULL )
     426                 :     {
     427            3266 :         int bSuccess = FALSE;
     428                 :         const CPLXMLNode* psChild;
     429            3266 :         int nDimension = 2;
     430                 : 
     431                 :         /* Try to detect the presence of an srsDimension attribute */
     432                 :         /* This attribute is only availabe for gml3.1.1 but not */
     433                 :         /* available for gml3.1 SF*/
     434            3266 :         psChild = psPosList->psChild;
     435            6532 :         while (psChild != NULL)
     436                 :         {
     437            3265 :             if (psChild->eType == CXT_Attribute &&
     438                 :                 EQUAL(psChild->pszValue, "srsDimension"))
     439                 :             {
     440             304 :                 nDimension = atoi(psChild->psChild->pszValue);
     441             304 :                 break;
     442                 :             }
     443            2961 :             else if (psChild->eType != CXT_Attribute)
     444                 :             {
     445            2961 :                 break;
     446                 :             }
     447               0 :             psChild = psChild->psNext;
     448                 :         }
     449                 : 
     450            3266 :         if (nDimension != 2 && nDimension != 3)
     451                 :         {
     452                 :             CPLError( CE_Failure, CPLE_AppDefined,
     453               1 :                       "srsDimension = %d not supported", nDimension);
     454               1 :             return FALSE;
     455                 :         }
     456                 : 
     457            3265 :         const char* pszPosList = GetElementText( psPosList );
     458            3265 :         if (pszPosList == NULL)
     459                 :         {
     460                 :             CPLError( CE_Failure, CPLE_AppDefined,
     461                 :                       "Did not get at least %d values or invalid number of \n"
     462                 :                       "set of coordinates <gml:posList>%s</gml:posList>",
     463               1 :                       nDimension, pszPosList ? pszPosList : "");
     464               1 :             return FALSE;
     465                 :         }
     466                 : 
     467            3264 :         const char* pszCur = pszPosList;
     468            9391 :         while (TRUE)
     469                 :         {
     470           12655 :             const char* pszX = GMLGetCoordTokenPos(pszCur, &pszCur);
     471           12655 :             if (pszX == NULL && bSuccess)
     472              75 :                 break;
     473                 :             const char* pszY = (pszCur != NULL) ?
     474           12580 :                     GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     475                 :             const char* pszZ = (nDimension == 3 && pszCur != NULL) ?
     476           12580 :                     GMLGetCoordTokenPos(pszCur, &pszCur) : NULL;
     477                 : 
     478           12580 :             if (pszY == NULL || (nDimension == 3 && pszZ == NULL))
     479                 :             {
     480                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     481                 :                         "Did not get at least %d values or invalid number of \n"
     482                 :                         "set of coordinates <gml:posList>%s</gml:posList>",
     483               3 :                         nDimension, pszPosList ? pszPosList : "");
     484               3 :                 return FALSE;
     485                 :             }
     486                 : 
     487           12577 :             double dfX = OGRFastAtof(pszX);
     488           12577 :             double dfY = OGRFastAtof(pszY);
     489           12577 :             double dfZ = (pszZ != NULL) ? OGRFastAtof(pszZ) : 0.0;
     490           12577 :             bSuccess = AddPoint( poGeometry, dfX, dfY, dfZ, nDimension );
     491                 : 
     492           12577 :             if (bSuccess == FALSE || pszCur == NULL)
     493            3186 :                 break;
     494                 :         }
     495                 : 
     496            3261 :         return bSuccess;
     497                 :     }
     498                 :     
     499                 : 
     500                 : /* -------------------------------------------------------------------- */
     501                 : /*      Handle form with a list of <coord> items each with an <X>,      */
     502                 : /*      and <Y> element.                                                */
     503                 : /* -------------------------------------------------------------------- */
     504                 :     const CPLXMLNode *psCoordNode;
     505                 : 
     506              24 :     for( psCoordNode = psGeomNode->psChild; 
     507                 :          psCoordNode != NULL;
     508                 :          psCoordNode = psCoordNode->psNext )
     509                 :     {
     510              11 :         if( psCoordNode->eType != CXT_Element 
     511                 :             || !EQUAL(BareGMLElement(psCoordNode->pszValue),"coord") )
     512               6 :             continue;
     513                 : 
     514                 :         const CPLXMLNode *psXNode, *psYNode, *psZNode;
     515               5 :         double dfX, dfY, dfZ = 0.0;
     516               5 :         int nDimension = 2;
     517                 : 
     518               5 :         psXNode = FindBareXMLChild( psCoordNode, "X" );
     519               5 :         psYNode = FindBareXMLChild( psCoordNode, "Y" );
     520               5 :         psZNode = FindBareXMLChild( psCoordNode, "Z" );
     521                 : 
     522               5 :         if( psXNode == NULL || psYNode == NULL 
     523                 :             || GetElementText(psXNode) == NULL
     524                 :             || GetElementText(psYNode) == NULL
     525                 :             || (psZNode != NULL && GetElementText(psZNode) == NULL) )
     526                 :         {
     527                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     528               3 :                       "Corrupt <coord> element, missing <X> or <Y> element?" );
     529               3 :             return FALSE;
     530                 :         }
     531                 : 
     532               2 :         dfX = OGRFastAtof( GetElementText(psXNode) );
     533               2 :         dfY = OGRFastAtof( GetElementText(psYNode) );
     534                 : 
     535               2 :         if( psZNode != NULL && GetElementText(psZNode) != NULL )
     536                 :         {
     537               0 :             dfZ = OGRFastAtof( GetElementText(psZNode) );
     538               0 :             nDimension = 3;
     539                 :         }
     540                 : 
     541               2 :         if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
     542               0 :             return FALSE;
     543                 : 
     544               2 :         iCoord++;
     545                 :     }
     546                 : 
     547              13 :     return iCoord > 0.0;
     548                 : }
     549                 : 
     550                 : /************************************************************************/
     551                 : /*                      GML2OGRGeometry_XMLNode()                       */
     552                 : /*                                                                      */
     553                 : /*      Translates the passed XMLnode and it's children into an         */
     554                 : /*      OGRGeometry.  This is used recursively for geometry             */
     555                 : /*      collections.                                                    */
     556                 : /************************************************************************/
     557                 : 
     558           11154 : OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     559                 :                                       int bGetSecondaryGeometryOption,
     560                 :                                       int nRecLevel,
     561                 :                                       int bIgnoreGSG,
     562                 :                                       int bOrientation )
     563                 : 
     564                 : {
     565           11154 :     const char *pszBaseGeometry = BareGMLElement( psNode->pszValue );
     566           11154 :     if (bGetSecondaryGeometryOption < 0)
     567             504 :         bGetSecondaryGeometryOption = CSLTestBoolean(CPLGetConfigOption("GML_GET_SECONDARY_GEOM", "NO"));
     568           11154 :     int bGetSecondaryGeometry = bIgnoreGSG ? FALSE : bGetSecondaryGeometryOption;
     569                 : 
     570                 :     /* Arbitrary value, but certainly large enough for reasonable usages ! */
     571           11154 :     if( nRecLevel == 32 )
     572                 :     {
     573                 :         CPLError( CE_Failure, CPLE_AppDefined,
     574                 :                     "Too many recursiong level (%d) while parsing GML geometry.",
     575               1 :                     nRecLevel );
     576               1 :         return NULL;
     577                 :     }
     578                 : 
     579           11153 :     if( bGetSecondaryGeometry )
     580               0 :         if( !( EQUAL(pszBaseGeometry,"directedEdge") ||
     581                 :                EQUAL(pszBaseGeometry,"TopoCurve") ) )
     582               0 :             return NULL;
     583                 : 
     584                 : /* -------------------------------------------------------------------- */
     585                 : /*      Polygon / PolygonPatch / Triangle / Rectangle                   */
     586                 : /* -------------------------------------------------------------------- */
     587           11153 :     if( EQUAL(pszBaseGeometry,"Polygon") ||
     588                 :         EQUAL(pszBaseGeometry,"PolygonPatch") ||
     589                 :         EQUAL(pszBaseGeometry,"Triangle") ||
     590                 :         EQUAL(pszBaseGeometry,"Rectangle"))
     591                 :     {
     592                 :         const CPLXMLNode *psChild;
     593             438 :         OGRPolygon *poPolygon = new OGRPolygon();
     594                 :         OGRLinearRing *poRing;
     595                 : 
     596                 :         // Find outer ring.
     597             438 :         psChild = FindBareXMLChild( psNode, "outerBoundaryIs" );
     598             438 :         if (psChild == NULL)
     599             422 :            psChild = FindBareXMLChild( psNode, "exterior");
     600                 : 
     601             438 :         if( psChild == NULL || psChild->psChild == NULL )
     602                 :         {
     603                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     604               4 :                       "Missing outerBoundaryIs property on %s.", pszBaseGeometry );
     605               4 :             delete poPolygon;
     606               4 :             return NULL;
     607                 :         }
     608                 : 
     609                 :         // Translate outer ring and add to polygon.
     610                 :         poRing = (OGRLinearRing *) 
     611                 :             GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
     612             434 :                                      nRecLevel + 1 );
     613             434 :         if( poRing == NULL )
     614                 :         {
     615               2 :             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior ring");
     616               2 :             delete poPolygon;
     617               2 :             return NULL;
     618                 :         }
     619                 : 
     620             432 :         if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
     621                 :         {
     622                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     623                 :                       "%s: Got %.500s geometry as outerBoundaryIs instead of LINEARRING.",
     624               1 :                       pszBaseGeometry, poRing->getGeometryName() );
     625               1 :             delete poPolygon;
     626               1 :             delete poRing;
     627               1 :             return NULL;
     628                 :         }
     629                 : 
     630             431 :         poPolygon->addRingDirectly( poRing );
     631                 : 
     632                 :         // Find all inner rings 
     633             935 :         for( psChild = psNode->psChild; 
     634                 :              psChild != NULL;
     635                 :              psChild = psChild->psNext ) 
     636                 :         {
     637             506 :             if( psChild->eType == CXT_Element
     638                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"innerBoundaryIs") ||
     639                 :                     EQUAL(BareGMLElement(psChild->pszValue),"interior")))
     640                 :             {
     641              18 :                 if (psChild->psChild != NULL)
     642                 :                     poRing = (OGRLinearRing *) 
     643                 :                         GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
     644              17 :                                                  nRecLevel + 1);
     645                 :                 else
     646               1 :                     poRing = NULL;
     647              18 :                 if (poRing == NULL)
     648                 :                 {
     649               1 :                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid interior ring");
     650               1 :                     delete poPolygon;
     651               1 :                     return NULL;
     652                 :                 }
     653              17 :                 if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
     654                 :                 {
     655                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     656                 :                               "%s: Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
     657               1 :                               pszBaseGeometry, poRing->getGeometryName() );
     658               1 :                     delete poPolygon;
     659               1 :                     delete poRing;
     660               1 :                     return NULL;
     661                 :                 }
     662                 : 
     663              16 :                 poPolygon->addRingDirectly( poRing );
     664                 :             }
     665                 :         }
     666                 : 
     667             429 :         return poPolygon;
     668                 :     }
     669                 : 
     670                 : /* -------------------------------------------------------------------- */
     671                 : /*      LinearRing                                                      */
     672                 : /* -------------------------------------------------------------------- */
     673           10715 :     if( EQUAL(pszBaseGeometry,"LinearRing") )
     674                 :     {
     675             110 :         OGRLinearRing   *poLinearRing = new OGRLinearRing();
     676                 :         
     677             110 :         if( !ParseGMLCoordinates( psNode, poLinearRing ) )
     678                 :         {
     679               1 :             delete poLinearRing;
     680               1 :             return NULL;
     681                 :         }
     682                 : 
     683             109 :         return poLinearRing;
     684                 :     }
     685                 : 
     686                 : /* -------------------------------------------------------------------- */
     687                 : /*      Ring GML3                                                       */
     688                 : /* -------------------------------------------------------------------- */
     689           10605 :     if( EQUAL(pszBaseGeometry,"Ring") )
     690                 :     {
     691             343 :         OGRLinearRing   *poLinearRing = new OGRLinearRing();
     692                 :         const CPLXMLNode *psChild;
     693                 : 
     694            3235 :         for( psChild = psNode->psChild; 
     695                 :              psChild != NULL; psChild = psChild->psNext )
     696                 :         {
     697            2895 :             if( psChild->eType == CXT_Element
     698                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
     699                 :             {
     700            2894 :                 const CPLXMLNode* psCurveChild = GetChildElement(psChild);
     701                 :                 OGRLineString *poLS;
     702            2894 :                 if (psCurveChild != NULL)
     703                 :                     poLS = (OGRLineString *) 
     704                 :                         GML2OGRGeometry_XMLNode( psCurveChild, bGetSecondaryGeometryOption,
     705            2893 :                                                  nRecLevel + 1);
     706                 :                 else
     707               1 :                     poLS = NULL;
     708                 : 
     709            5786 :                 if( poLS == NULL 
     710            2892 :                     || wkbFlatten(poLS->getGeometryType()) != wkbLineString )
     711                 :                 {
     712               3 :                     delete poLS;
     713               3 :                     delete poLinearRing;
     714               3 :                     return NULL;
     715                 :                 }
     716                 : 
     717                 :                 // we might need to take steps to avoid duplicate points...
     718            2891 :                 poLinearRing->addSubLineString( poLS );
     719            2891 :                 delete poLS;
     720                 :             }
     721                 :         }
     722                 : 
     723             340 :         return poLinearRing;
     724                 :     }
     725                 : 
     726                 : /* -------------------------------------------------------------------- */
     727                 : /*      LineString                                                      */
     728                 : /* -------------------------------------------------------------------- */
     729           10262 :     if( EQUAL(pszBaseGeometry,"LineString")
     730                 :         || EQUAL(pszBaseGeometry,"LineStringSegment") )
     731                 :     {
     732            3189 :         OGRLineString   *poLine = new OGRLineString();
     733                 :         
     734            3189 :         if( !ParseGMLCoordinates( psNode, poLine ) )
     735                 :         {
     736              11 :             delete poLine;
     737              11 :             return NULL;
     738                 :         }
     739                 : 
     740            3178 :         return poLine;
     741                 :     }
     742                 : 
     743                 : /* -------------------------------------------------------------------- */
     744                 : /*      Arc/Circle : we approximate them by linear segments             */
     745                 : /* -------------------------------------------------------------------- */
     746            7073 :     if( EQUAL(pszBaseGeometry,"Arc") ||
     747                 :         EQUAL(pszBaseGeometry,"Circle") )
     748                 :     {
     749              15 :         OGRLineString   *poLine = new OGRLineString();
     750                 : 
     751              29 :         if( !ParseGMLCoordinates( psNode, poLine ) ||
     752                 :             poLine->getNumPoints() != 3 )
     753                 :         {
     754               2 :             delete poLine;
     755               2 :             return NULL;
     756                 :         }
     757                 : 
     758              13 :         double x0 = poLine->getX(0);
     759              13 :         double y0 = poLine->getY(0);
     760              13 :         double x1 = poLine->getX(1);
     761              13 :         double y1 = poLine->getY(1);
     762              13 :         double x2 = poLine->getX(2);
     763              13 :         double y2 = poLine->getY(2);
     764              13 :         double dx01 = x1 - x0;
     765              13 :         double dy01 = y1 - y0;
     766              13 :         double dx12 = x2 - x1;
     767              13 :         double dy12 = y2 - y1;
     768              13 :         double c01 = dx01 * (x0 + x1) / 2 + dy01 * (y0 + y1) / 2;
     769              13 :         double c12 = dx12 * (x1 + x2) / 2 + dy12 * (y1 + y2) / 2;
     770              13 :         double det = dx01 * dy12 - dx12 * dy01;
     771              13 :         if (det == 0)
     772                 :         {
     773               1 :             return poLine;
     774                 :         }
     775              12 :         double cx =  (c01 * dy12 - c12 * dy01) / det;
     776              12 :         double cy =  (- c01 * dx12 + c12 * dx01) / det;
     777                 : 
     778              12 :         double alpha0 = atan2(y0 - cy, x0 - cx);
     779              12 :         double alpha1 = atan2(y1 - cy, x1 - cx);
     780              12 :         double alpha2 = atan2(y2 - cy, x2 - cx);
     781                 :         double alpha3;
     782              12 :         double R = sqrt((x0 - cx) * (x0 - cx) + (y0 - cy) * (y0 - cy));
     783                 : 
     784                 :         /* if det is negative, the orientation if clockwise */
     785              12 :         if (det < 0)
     786                 :         {
     787               6 :             if (alpha1 > alpha0)
     788               1 :                 alpha1 -= 2 * PI;
     789               6 :             if (alpha2 > alpha1)
     790               2 :                 alpha2 -= 2 * PI;
     791               6 :             alpha3 = alpha0 - 2 * PI;
     792                 :         }
     793                 :         else
     794                 :         {
     795               6 :             if (alpha1 < alpha0)
     796               0 :                 alpha1 += 2 * PI;
     797               6 :             if (alpha2 < alpha1)
     798               2 :                 alpha2 += 2 * PI;
     799               6 :             alpha3 = alpha0 + 2 * PI;
     800                 :         }
     801                 : 
     802                 :         CPLAssert((alpha0 <= alpha1 && alpha1 <= alpha2 && alpha2 <= alpha3) ||
     803              12 :                   (alpha0 >= alpha1 && alpha1 >= alpha2 && alpha2 >= alpha3));
     804                 : 
     805              12 :         int nSign = (det >= 0) ? 1 : -1;
     806                 : 
     807                 :         double alpha;
     808                 :         double dfStep =
     809              12 :             atof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4")) / 180 * PI;
     810              12 :         if (dfStep <= 0.1)
     811               3 :             dfStep = 4. / 180 * PI;
     812                 : 
     813              12 :         poLine->setNumPoints(0);
     814                 : 
     815              12 :         dfStep *= nSign;
     816                 : 
     817              37 :         for(alpha = alpha0; (alpha - alpha1) * nSign < 0; alpha += dfStep)
     818                 :         {
     819              25 :             poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     820                 :         }
     821              39 :         for(alpha = alpha1; (alpha - alpha2) * nSign < 0; alpha += dfStep)
     822                 :         {
     823              27 :             poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     824                 :         }
     825                 : 
     826              12 :         if (EQUAL(pszBaseGeometry,"Circle"))
     827                 :         {
     828               3 :             for(alpha = alpha2; (alpha - alpha3) * nSign < 0; alpha += dfStep)
     829                 :             {
     830               2 :                 poLine->addPoint(cx + R * cos(alpha), cy + R * sin(alpha));
     831                 :             }
     832               1 :             poLine->addPoint(cx + R * cos(alpha3), cy + R * sin(alpha3));
     833                 :         }
     834                 :         else
     835                 :         {
     836              11 :             poLine->addPoint(cx + R * cos(alpha2), cy + R * sin(alpha2));
     837                 :         }
     838                 : 
     839              12 :         return poLine;
     840                 :     }
     841                 : 
     842                 : /* -------------------------------------------------------------------- */
     843                 : /*      PointType                                                       */
     844                 : /* -------------------------------------------------------------------- */
     845            7058 :     if( EQUAL(pszBaseGeometry,"PointType") 
     846                 :         || EQUAL(pszBaseGeometry,"Point")
     847                 :         || EQUAL(pszBaseGeometry,"ConnectionPoint") )
     848                 :     {
     849             394 :         OGRPoint *poPoint = new OGRPoint();
     850                 :         
     851             394 :         if( !ParseGMLCoordinates( psNode, poPoint ) )
     852                 :         {
     853              12 :             delete poPoint;
     854              12 :             return NULL;
     855                 :         }
     856                 : 
     857             382 :         return poPoint;
     858                 :     }
     859                 : 
     860                 : /* -------------------------------------------------------------------- */
     861                 : /*      Box                                                             */
     862                 : /* -------------------------------------------------------------------- */
     863            6664 :     if( EQUAL(pszBaseGeometry,"BoxType") || EQUAL(pszBaseGeometry,"Box") )
     864                 :     {
     865               3 :         OGRLineString  oPoints;
     866                 : 
     867               3 :         if( !ParseGMLCoordinates( psNode, &oPoints ) )
     868               1 :             return NULL;
     869                 : 
     870               2 :         if( oPoints.getNumPoints() < 2 )
     871               1 :             return NULL;
     872                 : 
     873               1 :         OGRLinearRing *poBoxRing = new OGRLinearRing();
     874               2 :         OGRPolygon *poBoxPoly = new OGRPolygon();
     875                 : 
     876               1 :         poBoxRing->setNumPoints( 5 );
     877                 :         poBoxRing->setPoint( 
     878               1 :             0, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
     879                 :         poBoxRing->setPoint( 
     880               1 :             1, oPoints.getX(1), oPoints.getY(0), oPoints.getZ(0) );
     881                 :         poBoxRing->setPoint( 
     882               1 :             2, oPoints.getX(1), oPoints.getY(1), oPoints.getZ(1) );
     883                 :         poBoxRing->setPoint( 
     884               1 :             3, oPoints.getX(0), oPoints.getY(1), oPoints.getZ(0) );
     885                 :         poBoxRing->setPoint( 
     886               1 :             4, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) );
     887                 : 
     888               1 :         poBoxPoly->addRingDirectly( poBoxRing );
     889                 : 
     890               1 :         return poBoxPoly;
     891                 :     }
     892                 : 
     893                 : /* ------------------------const CPLXMLNode *psChild;-------------------------------------------- */
     894                 : /*      MultiPolygon / MultiSurface / CompositeSurface                  */
     895                 : /*                                                                      */
     896                 : /* For CompositeSurface, this is a very rough approximation to deal with*/
     897                 : /* it as a MultiPolygon, because it can several faces of a 3D volume... */
     898                 : /* -------------------------------------------------------------------- */
     899            6661 :     if( EQUAL(pszBaseGeometry,"MultiPolygon") ||
     900                 :         EQUAL(pszBaseGeometry,"MultiSurface") ||
     901                 :         EQUAL(pszBaseGeometry,"CompositeSurface") )
     902                 :     {
     903                 :         const CPLXMLNode *psChild;
     904              26 :         OGRMultiPolygon *poMPoly = new OGRMultiPolygon();
     905                 : 
     906                 :         // Iterate over children
     907              72 :         for( psChild = psNode->psChild; 
     908                 :              psChild != NULL;
     909                 :              psChild = psChild->psNext ) 
     910                 :         {
     911              50 :             if( psChild->eType == CXT_Element
     912                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"polygonMember") ||
     913                 :                     EQUAL(BareGMLElement(psChild->pszValue),"surfaceMember")) )
     914                 :             {
     915              20 :                 const CPLXMLNode* psSurfaceChild = GetChildElement(psChild);
     916                 :                 OGRPolygon *poPolygon;
     917                 : 
     918              20 :                 if (psSurfaceChild != NULL)
     919                 :                     poPolygon = (OGRPolygon *) 
     920                 :                         GML2OGRGeometry_XMLNode( psSurfaceChild, bGetSecondaryGeometryOption,
     921              19 :                                                  nRecLevel + 1);
     922                 :                 else
     923               1 :                     poPolygon = NULL;
     924                 : 
     925              20 :                 if( poPolygon == NULL )
     926                 :                 {
     927                 :                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
     928               2 :                               BareGMLElement(psChild->pszValue));
     929               2 :                     delete poMPoly;
     930               2 :                     return NULL;
     931                 :                 }
     932                 : 
     933              18 :                 if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") )
     934                 :                 {
     935                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     936                 :                               "Got %.500s geometry as polygonMember instead of MULTIPOLYGON.",
     937               1 :                               poPolygon->getGeometryName() );
     938               1 :                     delete poPolygon;
     939               1 :                     delete poMPoly;
     940               1 :                     return NULL;
     941                 :                 }
     942                 : 
     943              17 :                 poMPoly->addGeometryDirectly( poPolygon );
     944                 :             }
     945              30 :             else if (psChild->eType == CXT_Element
     946                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"surfaceMembers") )
     947                 :             {
     948                 :                 const CPLXMLNode *psChild2;
     949              11 :                 for( psChild2 = psChild->psChild;
     950                 :                      psChild2 != NULL;
     951                 :                      psChild2 = psChild2->psNext )
     952                 :                 {
     953               6 :                     if( psChild2->eType == CXT_Element
     954                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"Surface") ||
     955                 :                             EQUAL(BareGMLElement(psChild2->pszValue),"Polygon") ||
     956                 :                             EQUAL(BareGMLElement(psChild2->pszValue),"PolygonPatch")) )
     957                 :                     {
     958                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
     959               5 :                                                                        nRecLevel + 1);
     960               5 :                         if (poGeom == NULL)
     961                 :                         {
     962                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
     963               1 :                                     BareGMLElement(psChild2->pszValue));
     964               1 :                             delete poMPoly;
     965               1 :                             return NULL;
     966                 :                         }
     967                 : 
     968               4 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
     969                 :                         {
     970               3 :                             poMPoly->addGeometryDirectly( (OGRPolygon*) poGeom );
     971                 :                         }
     972               1 :                         else if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
     973                 :                         {
     974               1 :                             OGRMultiPolygon* poMPoly2 = (OGRMultiPolygon*) poGeom;
     975                 :                             int i;
     976               3 :                             for(i=0;i<poMPoly2->getNumGeometries();i++)
     977                 :                             {
     978               2 :                                 poMPoly->addGeometry(poMPoly2->getGeometryRef(i));
     979                 :                             }
     980               1 :                             delete poGeom;
     981                 :                         }
     982                 :                         else
     983                 :                         {
     984                 :                             CPLError( CE_Failure, CPLE_AppDefined,
     985                 :                                     "Got %.500s geometry as polygonMember instead of POLYGON/MULTIPOLYGON.",
     986               0 :                                     poGeom->getGeometryName() );
     987               0 :                             delete poGeom;
     988               0 :                             delete poMPoly;
     989               0 :                             return NULL;
     990                 :                         }
     991                 :                     }
     992                 :                 }
     993                 :             }
     994                 :         }
     995                 : 
     996              22 :         return poMPoly;
     997                 :     }
     998                 : 
     999                 : /* -------------------------------------------------------------------- */
    1000                 : /*      MultiPoint                                                      */
    1001                 : /* -------------------------------------------------------------------- */
    1002            6635 :     if( EQUAL(pszBaseGeometry,"MultiPoint") )
    1003                 :     {
    1004                 :         const CPLXMLNode *psChild;
    1005              16 :         OGRMultiPoint *poMP = new OGRMultiPoint();
    1006                 : 
    1007                 :         // collect points.
    1008              43 :         for( psChild = psNode->psChild; 
    1009                 :              psChild != NULL;
    1010                 :              psChild = psChild->psNext ) 
    1011                 :         {
    1012              30 :             if( psChild->eType == CXT_Element
    1013                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"pointMember") )
    1014                 :             {
    1015              15 :                 const CPLXMLNode* psPointChild = GetChildElement(psChild);
    1016                 :                 OGRPoint *poPoint;
    1017                 : 
    1018              15 :                 if (psPointChild != NULL)
    1019                 :                     poPoint = (OGRPoint *) 
    1020                 :                         GML2OGRGeometry_XMLNode( psPointChild, bGetSecondaryGeometryOption,
    1021              14 :                                                  nRecLevel + 1);
    1022                 :                 else
    1023               1 :                     poPoint = NULL;
    1024              29 :                 if( poPoint == NULL 
    1025              14 :                     || wkbFlatten(poPoint->getGeometryType()) != wkbPoint )
    1026                 :                 {
    1027                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1028                 :                               "MultiPoint: Got %.500s geometry as pointMember instead of POINT",
    1029               2 :                               poPoint ? poPoint->getGeometryName() : "NULL" );
    1030               2 :                     delete poPoint;
    1031               2 :                     delete poMP;
    1032               2 :                     return NULL;
    1033                 :                 }
    1034                 : 
    1035              13 :                 poMP->addGeometryDirectly( poPoint );
    1036                 :             }
    1037              15 :             else if (psChild->eType == CXT_Element
    1038                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"pointMembers") )
    1039                 :             {
    1040                 :                 const CPLXMLNode *psChild2;
    1041               7 :                 for( psChild2 = psChild->psChild;
    1042                 :                      psChild2 != NULL;
    1043                 :                      psChild2 = psChild2->psNext )
    1044                 :                 {
    1045               4 :                     if( psChild2->eType == CXT_Element
    1046                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"Point")) )
    1047                 :                     {
    1048                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
    1049               3 :                                                                        nRecLevel + 1);
    1050               3 :                         if (poGeom == NULL)
    1051                 :                         {
    1052                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1053               1 :                                     BareGMLElement(psChild2->pszValue));
    1054               1 :                             delete poMP;
    1055               1 :                             return NULL;
    1056                 :                         }
    1057                 : 
    1058               2 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1059                 :                         {
    1060               2 :                             poMP->addGeometryDirectly( (OGRPoint *)poGeom );
    1061                 :                         }
    1062                 :                         else
    1063                 :                         {
    1064                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1065                 :                                     "Got %.500s geometry as pointMember instead of POINT.",
    1066               0 :                                     poGeom->getGeometryName() );
    1067               0 :                             delete poGeom;
    1068               0 :                             delete poMP;
    1069               0 :                             return NULL;
    1070                 :                         }
    1071                 :                     }
    1072                 :                 }
    1073                 :             }
    1074                 :         }
    1075                 : 
    1076              13 :         return poMP;
    1077                 :     }
    1078                 : 
    1079                 : /* -------------------------------------------------------------------- */
    1080                 : /*      MultiLineString                                                 */
    1081                 : /* -------------------------------------------------------------------- */
    1082            6619 :     if( EQUAL(pszBaseGeometry,"MultiLineString") )
    1083                 :     {
    1084                 :         const CPLXMLNode *psChild;
    1085               5 :         OGRMultiLineString *poMLS = new OGRMultiLineString();
    1086                 : 
    1087                 :         // collect lines
    1088              10 :         for( psChild = psNode->psChild; 
    1089                 :              psChild != NULL;
    1090                 :              psChild = psChild->psNext ) 
    1091                 :         {
    1092               7 :             if( psChild->eType == CXT_Element
    1093                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"lineStringMember") )
    1094                 :             {
    1095               6 :                 const CPLXMLNode* psLineStringChild = GetChildElement(psChild);
    1096                 :                 OGRGeometry *poGeom;
    1097                 : 
    1098               6 :                 if (psLineStringChild != NULL)
    1099                 :                     poGeom = GML2OGRGeometry_XMLNode( psLineStringChild, bGetSecondaryGeometryOption,
    1100               5 :                                                       nRecLevel + 1);
    1101                 :                 else
    1102               1 :                     poGeom = NULL;
    1103              11 :                 if( poGeom == NULL 
    1104               5 :                     || wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1105                 :                 {
    1106                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1107                 :                               "MultiLineString: Got %.500s geometry as Member instead of LINESTRING.",
    1108               2 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1109               2 :                     delete poGeom;
    1110               2 :                     delete poMLS;
    1111               2 :                     return NULL;
    1112                 :                 }
    1113                 : 
    1114               4 :                 poMLS->addGeometryDirectly( poGeom );
    1115                 :             }
    1116                 :         }
    1117                 : 
    1118               3 :         return poMLS;
    1119                 :     }
    1120                 : 
    1121                 : 
    1122                 : /* -------------------------------------------------------------------- */
    1123                 : /*      MultiCurve                                                      */
    1124                 : /* -------------------------------------------------------------------- */
    1125            6614 :     if( EQUAL(pszBaseGeometry,"MultiCurve") )
    1126                 :     {
    1127                 :         const CPLXMLNode *psChild, *psCurve;
    1128              19 :         OGRMultiLineString *poMLS = new OGRMultiLineString();
    1129                 : 
    1130                 :         // collect curveMembers
    1131              45 :         for( psChild = psNode->psChild; 
    1132                 :              psChild != NULL;
    1133                 :              psChild = psChild->psNext ) 
    1134                 :         {
    1135              32 :             if( psChild->eType == CXT_Element
    1136                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
    1137                 :             {
    1138                 :                 OGRGeometry *poGeom;
    1139                 : 
    1140                 :                 // There can be only one curve under a curveMember.
    1141                 :                 // Currently "Curve" and "LineString" are handled.
    1142              15 :                 psCurve = FindBareXMLChild( psChild, "Curve" );
    1143              15 :                 if( psCurve == NULL )
    1144              10 :                     psCurve = FindBareXMLChild( psChild, "LineString" );
    1145              15 :                 if( psCurve == NULL )
    1146                 :                 {
    1147                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1148               2 :                               "Failed to get curve element in curveMember" );
    1149               2 :                     delete poMLS;
    1150               2 :                     return NULL;
    1151                 :                 }
    1152                 :                 poGeom = GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
    1153              13 :                                                   nRecLevel + 1);
    1154              23 :                 if( poGeom == NULL ||
    1155              10 :                     ( wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) )
    1156                 :                 {
    1157                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1158                 :                               "MultiCurve: Got %.500s geometry as Member instead of LINESTRING.",
    1159               3 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1160               3 :                     if( poGeom != NULL ) delete poGeom;
    1161               3 :                     delete poMLS;
    1162               3 :                     return NULL;
    1163                 :                 }
    1164                 : 
    1165              10 :                 poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
    1166                 :             }
    1167              17 :             else if (psChild->eType == CXT_Element
    1168                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMembers") )
    1169                 :             {
    1170                 :                 const CPLXMLNode *psChild2;
    1171               8 :                 for( psChild2 = psChild->psChild;
    1172                 :                      psChild2 != NULL;
    1173                 :                      psChild2 = psChild2->psNext )
    1174                 :                 {
    1175               4 :                     if( psChild2->eType == CXT_Element
    1176                 :                         && (EQUAL(BareGMLElement(psChild2->pszValue),"LineString")) )
    1177                 :                     {
    1178                 :                         OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
    1179               3 :                                                                        nRecLevel + 1);
    1180               3 :                         if (poGeom == NULL)
    1181                 :                         {
    1182                 :                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
    1183               1 :                                     BareGMLElement(psChild2->pszValue));
    1184               1 :                             delete poMLS;
    1185               1 :                             return NULL;
    1186                 :                         }
    1187                 : 
    1188               2 :                         if (wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1189                 :                         {
    1190               2 :                             poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
    1191                 :                         }
    1192                 :                         else
    1193                 :                         {
    1194                 :                             CPLError( CE_Failure, CPLE_AppDefined,
    1195                 :                                     "Got %.500s geometry as curveMember instead of LINESTRING.",
    1196               0 :                                     poGeom->getGeometryName() );
    1197               0 :                             delete poGeom;
    1198               0 :                             delete poMLS;
    1199               0 :                             return NULL;
    1200                 :                         }
    1201                 :                     }
    1202                 :                 }
    1203                 :             }
    1204                 :         }
    1205              13 :         return poMLS;
    1206                 :     }
    1207                 : 
    1208                 : /* -------------------------------------------------------------------- */
    1209                 : /*      Curve                                                      */
    1210                 : /* -------------------------------------------------------------------- */
    1211            6595 :     if( EQUAL(pszBaseGeometry,"Curve") )
    1212                 :     {
    1213                 :         const CPLXMLNode *psChild;
    1214                 : 
    1215            2917 :         psChild = FindBareXMLChild( psNode, "segments");
    1216            2917 :         if( psChild == NULL )
    1217                 :         {
    1218                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1219               5 :                       "GML3 Curve geometry lacks segments element." );
    1220               5 :             return NULL;
    1221                 :         }
    1222                 : 
    1223                 :         OGRGeometry *poGeom;
    1224                 : 
    1225                 :         poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1226            2912 :                                           nRecLevel + 1);
    1227            5824 :         if( poGeom == NULL ||
    1228            2912 :             wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1229                 :         {
    1230                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1231                 :                 "Curve: Got %.500s geometry as Member instead of segments.",
    1232               0 :                 poGeom ? poGeom->getGeometryName() : "NULL" );
    1233               0 :             if( poGeom != NULL ) delete poGeom;
    1234               0 :             return NULL;
    1235                 :         }
    1236                 : 
    1237            2912 :         return poGeom;
    1238                 :     }
    1239                 : 
    1240                 : /* -------------------------------------------------------------------- */
    1241                 : /*      segments                                                        */
    1242                 : /* -------------------------------------------------------------------- */
    1243            3678 :     if( EQUAL(pszBaseGeometry,"segments") )
    1244                 :     {
    1245                 :         const CPLXMLNode *psChild;
    1246            2917 :         OGRLineString *poLS = new OGRLineString();
    1247                 : 
    1248            5832 :         for( psChild = psNode->psChild; 
    1249                 :              psChild != NULL;
    1250                 :              psChild = psChild->psNext ) 
    1251                 : 
    1252                 :         {
    1253            2915 :             if( psChild->eType == CXT_Element
    1254                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"LineStringSegment") ||
    1255                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Arc") ||
    1256                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Circle")) )
    1257                 :             {
    1258                 :                 OGRGeometry *poGeom;
    1259                 : 
    1260                 :                 poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1261            2912 :                                                   nRecLevel + 1);
    1262            5821 :                 if( poGeom != NULL &&
    1263            2909 :                     wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
    1264                 :                 {
    1265                 :                     CPLError( CE_Failure, CPLE_AppDefined,
    1266                 :                               "segments: Got %.500s geometry as Member instead of LINESTRING.",
    1267               0 :                               poGeom ? poGeom->getGeometryName() : "NULL" );
    1268               0 :                     delete poGeom;
    1269               0 :                     delete poLS;
    1270               0 :                     return NULL;
    1271                 :                 }
    1272            2912 :                 if( poGeom != NULL )
    1273                 :                 {
    1274            2909 :                     poLS->addSubLineString( (OGRLineString *)poGeom );
    1275            2909 :                     delete poGeom;
    1276                 :                 }
    1277                 :             }
    1278                 :         }
    1279                 : 
    1280            2917 :         return poLS;
    1281                 :     }
    1282                 : 
    1283                 : /* -------------------------------------------------------------------- */
    1284                 : /*      MultiGeometry                                                   */
    1285                 : /* CAUTION: OGR < 1.8.0 produced GML with GeometryCollection, which is  */
    1286                 : /* not a valid GML 2 keyword! The right name is MultiGeometry. Let's be */
    1287                 : /* tolerant with the non compliant files we produced...                 */
    1288                 : /* -------------------------------------------------------------------- */
    1289             761 :     if( EQUAL(pszBaseGeometry,"MultiGeometry") ||
    1290                 :         EQUAL(pszBaseGeometry,"GeometryCollection") )
    1291                 :     {
    1292                 :         const CPLXMLNode *psChild;
    1293              70 :         OGRGeometryCollection *poGC = new OGRGeometryCollection();
    1294                 : 
    1295                 :         // collect geoms
    1296             112 :         for( psChild = psNode->psChild; 
    1297                 :              psChild != NULL;
    1298                 :              psChild = psChild->psNext ) 
    1299                 :         {
    1300              76 :             if( psChild->eType == CXT_Element
    1301                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"geometryMember") )
    1302                 :             {
    1303              75 :                 const CPLXMLNode* psGeometryChild = GetChildElement(psChild);
    1304                 :                 OGRGeometry *poGeom;
    1305                 : 
    1306              75 :                 if (psGeometryChild != NULL)
    1307                 :                     poGeom = GML2OGRGeometry_XMLNode( psGeometryChild, bGetSecondaryGeometryOption,
    1308              74 :                                                       nRecLevel + 1 );
    1309                 :                 else
    1310               1 :                     poGeom = NULL;
    1311              75 :                 if( poGeom == NULL )
    1312                 :                 {
    1313                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1314              34 :                               "GeometryCollection: Failed to get geometry in geometryMember" );
    1315              34 :                     delete poGeom;
    1316              34 :                     delete poGC;
    1317              34 :                     return NULL;
    1318                 :                 }
    1319                 : 
    1320              41 :                 poGC->addGeometryDirectly( poGeom );
    1321                 :             }
    1322                 :         }
    1323                 : 
    1324              36 :         return poGC;
    1325                 :     }
    1326                 : 
    1327                 : /* -------------------------------------------------------------------- */
    1328                 : /*      Directed Edge                                              */
    1329                 : /* -------------------------------------------------------------------- */
    1330             691 :     if( EQUAL(pszBaseGeometry,"directedEdge") )
    1331                 :     {
    1332                 :         const CPLXMLNode *psEdge,
    1333                 :                          *psdirectedNode,
    1334                 :                          *psNodeElement,
    1335                 :                          *pspointProperty,
    1336                 :                          *psPoint,
    1337                 :                          *psCurveProperty,
    1338                 :                          *psCurve;
    1339             238 :         int               bEdgeOrientation = TRUE,
    1340             238 :                           bNodeOrientation = TRUE;
    1341                 :         OGRGeometry      *poGeom;
    1342                 :         OGRLineString    *poLineString;
    1343             238 :         OGRPoint         *poPositiveNode = NULL, *poNegativeNode = NULL;
    1344                 :         OGRMultiPoint    *poMP;
    1345                 :     
    1346             238 :         bEdgeOrientation = GetElementOrientation(psNode);
    1347                 : 
    1348                 :         //collect edge
    1349             238 :         psEdge = FindBareXMLChild(psNode,"Edge");
    1350             238 :         if( psEdge == NULL )
    1351                 :         {
    1352                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1353               0 :                       "Failed to get Edge element in directedEdge" );
    1354               0 :             return NULL;
    1355                 :         }
    1356                 : 
    1357             238 :         if( bGetSecondaryGeometry )
    1358                 :         {
    1359               0 :             psdirectedNode = FindBareXMLChild(psEdge,"directedNode");
    1360               0 :             if( psdirectedNode == NULL ) goto nonode;
    1361                 : 
    1362               0 :             bNodeOrientation = GetElementOrientation( psdirectedNode );
    1363                 : 
    1364               0 :             psNodeElement = FindBareXMLChild(psdirectedNode,"Node");
    1365               0 :             if( psNodeElement == NULL ) goto nonode;
    1366                 : 
    1367               0 :             pspointProperty = FindBareXMLChild(psNodeElement,"pointProperty");
    1368               0 :             if( pspointProperty == NULL )
    1369               0 :                 pspointProperty = FindBareXMLChild(psNodeElement,"connectionPointProperty");
    1370               0 :             if( pspointProperty == NULL ) goto nonode;
    1371                 : 
    1372               0 :             psPoint = FindBareXMLChild(pspointProperty,"Point");
    1373               0 :             if( psPoint == NULL )
    1374               0 :                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
    1375               0 :             if( psPoint == NULL ) goto nonode;
    1376                 : 
    1377                 :             poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
    1378               0 :                                               nRecLevel + 1, TRUE );
    1379               0 :             if( poGeom == NULL
    1380               0 :                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
    1381                 :             {
    1382                 : /*                CPLError( CE_Failure, CPLE_AppDefined, 
    1383                 :                       "Got %.500s geometry as Member instead of POINT.",
    1384                 :                       poGeom ? poGeom->getGeometryName() : "NULL" );*/
    1385               0 :                 if( poGeom != NULL) delete poGeom;
    1386               0 :                 goto nonode;
    1387                 :             }
    1388                 : 
    1389               0 :             if( ( bNodeOrientation == bEdgeOrientation ) != bOrientation )
    1390               0 :                 poPositiveNode = (OGRPoint *)poGeom;
    1391                 :             else
    1392               0 :                 poNegativeNode = (OGRPoint *)poGeom;
    1393                 : 
    1394                 :             // look for the other node
    1395               0 :             psdirectedNode = psdirectedNode->psNext;
    1396               0 :             while( psdirectedNode != NULL &&
    1397                 :                    !EQUAL( psdirectedNode->pszValue, "directedNode" ) )
    1398               0 :                 psdirectedNode = psdirectedNode->psNext;
    1399               0 :             if( psdirectedNode == NULL ) goto nonode;
    1400                 : 
    1401               0 :             if( GetElementOrientation( psdirectedNode ) == bNodeOrientation )
    1402               0 :                 goto nonode;
    1403                 : 
    1404               0 :             psNodeElement = FindBareXMLChild(psEdge,"Node");
    1405               0 :             if( psNodeElement == NULL ) goto nonode;
    1406                 : 
    1407               0 :             pspointProperty = FindBareXMLChild(psNodeElement,"pointProperty");
    1408               0 :             if( pspointProperty == NULL )
    1409               0 :                 pspointProperty = FindBareXMLChild(psNodeElement,"connectionPointProperty");
    1410               0 :             if( pspointProperty == NULL ) goto nonode;
    1411                 : 
    1412               0 :             psPoint = FindBareXMLChild(pspointProperty,"Point");
    1413               0 :             if( psPoint == NULL )
    1414               0 :                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
    1415               0 :             if( psPoint == NULL ) goto nonode;
    1416                 : 
    1417                 :             poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
    1418               0 :                                               nRecLevel + 1, TRUE );
    1419               0 :             if( poGeom == NULL
    1420               0 :                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
    1421                 :             {
    1422                 : /*                CPLError( CE_Failure, CPLE_AppDefined, 
    1423                 :                       "Got %.500s geometry as Member instead of POINT.",
    1424                 :                       poGeom ? poGeom->getGeometryName() : "NULL" );*/
    1425               0 :                 if( poGeom != NULL) delete poGeom;
    1426               0 :                 goto nonode;
    1427                 :             }
    1428                 : 
    1429               0 :             if( ( bNodeOrientation == bEdgeOrientation ) != bOrientation )
    1430               0 :                 poNegativeNode = (OGRPoint *)poGeom;
    1431                 :             else
    1432               0 :                 poPositiveNode = (OGRPoint *)poGeom;
    1433                 : 
    1434               0 :             poMP = new OGRMultiPoint();
    1435               0 :             poMP->addGeometryDirectly( poNegativeNode );
    1436               0 :             poMP->addGeometryDirectly( poPositiveNode );
    1437                 :             
    1438               0 :             return poMP;
    1439                 : 
    1440                 :             nonode:;
    1441                 :         }
    1442                 : 
    1443                 :         // collect curveproperty
    1444             238 :         psCurveProperty = FindBareXMLChild(psEdge,"curveProperty");
    1445             238 :         if( psCurveProperty == NULL )
    1446                 :         {
    1447                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1448               0 :                         "directedEdge: Failed to get curveProperty in Edge" );
    1449               0 :             return NULL;
    1450                 :         }
    1451                 : 
    1452             238 :         psCurve = FindBareXMLChild(psCurveProperty,"LineString");
    1453             238 :         if( psCurve == NULL )
    1454              12 :             psCurve = FindBareXMLChild(psCurveProperty,"Curve");
    1455             238 :         if( psCurve == NULL )
    1456                 :         {
    1457                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1458               0 :                       "directedEdge: Failed to get LineString or Curve tag in curveProperty" );
    1459               0 :             return NULL;
    1460                 :         }
    1461                 : 
    1462                 :         poLineString = (OGRLineString *)GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
    1463             238 :                                                                  nRecLevel + 1, TRUE );
    1464             476 :         if( poLineString == NULL 
    1465             238 :             || wkbFlatten(poLineString->getGeometryType()) != wkbLineString )
    1466                 :         {
    1467                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1468                 :                       "Got %.500s geometry as Member instead of LINESTRING.",
    1469               0 :                       poLineString ? poLineString->getGeometryName() : "NULL" );
    1470               0 :             if( poLineString != NULL )
    1471               0 :                 delete poLineString;
    1472               0 :             return NULL;
    1473                 :         }
    1474                 : 
    1475             238 :         if( bGetSecondaryGeometry )
    1476                 :         {
    1477                 :             // choose a point based on the orientation
    1478               0 :             poNegativeNode = new OGRPoint();
    1479               0 :             poPositiveNode = new OGRPoint();
    1480               0 :             if( bEdgeOrientation == bOrientation )
    1481                 :             {
    1482               0 :                 poLineString->StartPoint( poNegativeNode );
    1483               0 :                 poLineString->EndPoint( poPositiveNode );
    1484                 :             }
    1485                 :             else
    1486                 :             {
    1487               0 :                 poLineString->StartPoint( poPositiveNode );
    1488               0 :                 poLineString->EndPoint( poNegativeNode );
    1489                 :             }
    1490               0 :             delete poLineString;
    1491                 : 
    1492               0 :             poMP = new OGRMultiPoint();
    1493               0 :             poMP->addGeometryDirectly( poNegativeNode );
    1494               0 :             poMP->addGeometryDirectly( poPositiveNode );
    1495                 : 
    1496               0 :             return poMP;
    1497                 :         }
    1498                 : 
    1499                 :         // correct orientation of the line string
    1500             238 :         if( bEdgeOrientation != bOrientation )
    1501                 :         {
    1502              80 :             int nCoordDimensions = poLineString->getCoordinateDimension();
    1503              80 :             int iStartCoord = 0, iEndCoord = poLineString->getNumPoints() - 1;
    1504              80 :             OGRPoint *poTempStartPoint = new OGRPoint();
    1505             160 :             OGRPoint *poTempEndPoint = new OGRPoint();
    1506             268 :             while( iStartCoord < iEndCoord )
    1507                 :             {
    1508             108 :                 poLineString->getPoint( iStartCoord, poTempStartPoint );
    1509             108 :                 poLineString->getPoint( iEndCoord, poTempEndPoint );
    1510             108 :                 poLineString->setPoint( iStartCoord, poTempEndPoint );
    1511             108 :                 poLineString->setPoint( iEndCoord, poTempStartPoint );
    1512             108 :                 iStartCoord++;
    1513             108 :                 iEndCoord--;
    1514                 :             }
    1515              80 :             delete poTempStartPoint;
    1516              80 :             delete poTempEndPoint;
    1517                 :             /* Restore coordinate dimension ass setPoint will force to 3D */
    1518              80 :             poLineString->setCoordinateDimension(nCoordDimensions);
    1519                 :         }
    1520             238 :         return poLineString;
    1521                 :     }
    1522                 : 
    1523                 : /* -------------------------------------------------------------------- */
    1524                 : /*      TopoCurve                                                       */
    1525                 : /* -------------------------------------------------------------------- */
    1526             453 :     if( EQUAL(pszBaseGeometry,"TopoCurve") )
    1527                 :     {
    1528                 :         const CPLXMLNode *psChild;
    1529              58 :         OGRMultiLineString *poMLS = NULL;
    1530              58 :         OGRMultiPoint *poMP = NULL;
    1531                 : 
    1532              58 :         if( bGetSecondaryGeometry )
    1533               0 :             poMP = new OGRMultiPoint();
    1534                 :         else
    1535              58 :             poMLS = new OGRMultiLineString();
    1536                 : 
    1537                 :         // collect directedEdges
    1538             124 :         for( psChild = psNode->psChild; 
    1539                 :              psChild != NULL;
    1540                 :              psChild = psChild->psNext ) 
    1541                 :         {
    1542              66 :             if( psChild->eType == CXT_Element
    1543                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"directedEdge"))
    1544                 :             {
    1545                 :                 OGRGeometry *poGeom;
    1546                 : 
    1547                 :                 poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1548              66 :                                                   nRecLevel + 1 );
    1549              66 :                 if( poGeom == NULL )
    1550                 :                 {
    1551                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1552               0 :                               "Failed to get geometry in directedEdge" );
    1553               0 :                     delete poGeom;
    1554               0 :                     if( bGetSecondaryGeometry )
    1555               0 :                         delete poMP;
    1556                 :                     else
    1557               0 :                         delete poMLS;
    1558               0 :                     return NULL;
    1559                 :                 }
    1560                 : 
    1561                 :                 //Add the two points corresponding to the two nodes to poMP
    1562              66 :                 if( bGetSecondaryGeometry &&
    1563               0 :                      wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint )
    1564                 :                 {
    1565                 :                     //TODO: TopoCurve geometries with more than one
    1566                 :                     //      directedEdge elements were not tested.
    1567               0 :                     if( poMP->getNumGeometries() <= 0 ||
    1568               0 :                         !(poMP->getGeometryRef( poMP->getNumGeometries() - 1 )->Equals(((OGRMultiPoint *)poGeom)->getGeometryRef( 0 ) ) ))
    1569                 :                     {
    1570                 :                         poMP->addGeometry(
    1571               0 :                             ( (OGRMultiPoint *)poGeom )->getGeometryRef( 0 ) );
    1572                 :                     }
    1573                 :                     poMP->addGeometry(
    1574               0 :                             ( (OGRMultiPoint *)poGeom )->getGeometryRef( 1 ) );
    1575               0 :                     delete poGeom;
    1576                 :                 }
    1577             132 :                 else if( !bGetSecondaryGeometry &&
    1578              66 :                      wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
    1579                 :                 {
    1580              66 :                     poMLS->addGeometryDirectly( poGeom );
    1581                 :                 }
    1582                 :                 else
    1583                 :                 {
    1584                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
    1585                 :                               "Got %.500s geometry as Member instead of %s.",
    1586               0 :                               poGeom ? poGeom->getGeometryName() : "NULL",
    1587               0 :                               bGetSecondaryGeometry?"MULTIPOINT":"LINESTRING");
    1588               0 :                     delete poGeom;
    1589               0 :                     if( bGetSecondaryGeometry )
    1590               0 :                         delete poMP;
    1591                 :                     else
    1592               0 :                         delete poMLS;
    1593               0 :                     return NULL;
    1594                 :                 }
    1595                 :             }
    1596                 :         }
    1597                 : 
    1598              58 :         if( bGetSecondaryGeometry )
    1599               0 :             return poMP;
    1600                 :         else
    1601              58 :             return poMLS;
    1602                 :     }
    1603                 : 
    1604                 : /* -------------------------------------------------------------------- */
    1605                 : /*      TopoSurface                                                     */
    1606                 : /* -------------------------------------------------------------------- */
    1607             395 :     if( EQUAL(pszBaseGeometry,"TopoSurface") )
    1608                 :     {
    1609              20 :         if( bGetSecondaryGeometry )
    1610               0 :             return NULL;
    1611                 :         const CPLXMLNode *psChild, *psFaceChild, *psDirectedEdgeChild;
    1612              20 :         int bFaceOrientation = TRUE;
    1613              20 :         OGRPolygon *poTS = new OGRPolygon();
    1614                 : 
    1615                 :         // collect directed faces
    1616              60 :         for( psChild = psNode->psChild; 
    1617                 :              psChild != NULL;
    1618                 :              psChild = psChild->psNext ) 
    1619                 :         {
    1620              40 :           if( psChild->eType == CXT_Element
    1621                 :               && EQUAL(BareGMLElement(psChild->pszValue),"directedFace") )
    1622                 :           {
    1623              38 :             bFaceOrientation = GetElementOrientation(psChild);
    1624                 : 
    1625                 :             // collect next face (psChild->psChild)
    1626              38 :             psFaceChild = psChild->psChild;
    1627              88 :             while( psFaceChild != NULL &&
    1628                 :                    !EQUAL(BareGMLElement(psFaceChild->pszValue),"Face") )
    1629              12 :                     psFaceChild = psFaceChild->psNext;
    1630                 : 
    1631              38 :             if( psFaceChild == NULL )
    1632               0 :               continue;
    1633                 : 
    1634              38 :             OGRLinearRing *poFaceGeom = new OGRLinearRing();
    1635                 : 
    1636                 :             // collect directed edges of the face
    1637             246 :             for( psDirectedEdgeChild = psFaceChild->psChild;
    1638                 :                  psDirectedEdgeChild != NULL;
    1639                 :                  psDirectedEdgeChild = psDirectedEdgeChild->psNext )
    1640                 :             {
    1641             208 :               if( psDirectedEdgeChild->eType == CXT_Element &&
    1642                 :                   EQUAL(BareGMLElement(psDirectedEdgeChild->pszValue),"directedEdge") )
    1643                 :               {
    1644                 :                 OGRGeometry *poEdgeGeom;
    1645                 : 
    1646                 :                 poEdgeGeom = GML2OGRGeometry_XMLNode( psDirectedEdgeChild,
    1647                 :                                                       bGetSecondaryGeometryOption,
    1648                 :                                                       nRecLevel + 1,
    1649                 :                                                       TRUE,
    1650             172 :                                                       bFaceOrientation );
    1651                 : 
    1652             344 :                 if( poEdgeGeom == NULL ||
    1653             172 :                     wkbFlatten(poEdgeGeom->getGeometryType()) != wkbLineString )
    1654                 :                 {
    1655                 :                   CPLError( CE_Failure, CPLE_AppDefined, 
    1656               0 :                             "Failed to get geometry in directedEdge" );
    1657               0 :                   delete poEdgeGeom;
    1658               0 :                   delete poFaceGeom;
    1659               0 :                   delete poTS;
    1660               0 :                   return NULL;
    1661                 :                 }
    1662                 : 
    1663             172 :                 if( !bFaceOrientation )
    1664                 :                 {
    1665              30 :                   if( poFaceGeom->getNumPoints() > 0 )
    1666              18 :                     ((OGRLinearRing *)poEdgeGeom)->addSubLineString( (OGRLineString *)poFaceGeom );
    1667              30 :                   poFaceGeom->empty();
    1668                 :                 }
    1669             172 :                 poFaceGeom->addSubLineString( (OGRLinearRing *)poEdgeGeom );
    1670             172 :                 delete poEdgeGeom;
    1671                 :               }
    1672                 :             }
    1673                 : 
    1674                 : /*            if( poFaceGeom == NULL )
    1675                 :             {
    1676                 :               CPLError( CE_Failure, CPLE_AppDefined, 
    1677                 :                         "Failed to get Face geometry in directedFace" );
    1678                 :               delete poFaceGeom;
    1679                 :               return NULL;
    1680                 :             }*/
    1681                 : 
    1682              38 :             poTS->addRingDirectly( poFaceGeom );
    1683                 :           }
    1684                 :         }
    1685                 : 
    1686                 : /*        if( poTS == NULL )
    1687                 :         {
    1688                 :           CPLError( CE_Failure, CPLE_AppDefined, 
    1689                 :                     "Failed to get TopoSurface geometry" );
    1690                 :           delete poTS;
    1691                 :           return NULL;
    1692                 :         }*/
    1693                 : 
    1694              20 :         return poTS;
    1695                 :     }
    1696                 : 
    1697                 : /* -------------------------------------------------------------------- */
    1698                 : /*      Surface                                                         */
    1699                 : /* -------------------------------------------------------------------- */
    1700             375 :     if( EQUAL(pszBaseGeometry,"Surface") )
    1701                 :     {
    1702                 :         const CPLXMLNode *psChild;
    1703             356 :         OGRGeometry *poResult = NULL;
    1704                 : 
    1705                 :         // Find outer ring.
    1706             356 :         psChild = FindBareXMLChild( psNode, "patches" );
    1707             356 :         if( psChild == NULL )
    1708             335 :             psChild = FindBareXMLChild( psNode, "polygonPatches" );
    1709             356 :         if( psChild == NULL )
    1710               2 :             psChild = FindBareXMLChild( psNode, "trianglePatches" );
    1711                 : 
    1712             356 :         if( psChild == NULL || psChild->psChild == NULL )
    1713                 :         {
    1714                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1715               3 :                       "Missing <patches> for Surface." );
    1716               3 :             return NULL;
    1717                 :         }
    1718                 : 
    1719             706 :         for( psChild = psChild->psChild; 
    1720                 :              psChild != NULL; psChild = psChild->psNext )
    1721                 :         {
    1722             354 :             if( psChild->eType == CXT_Element
    1723                 :                 && (EQUAL(BareGMLElement(psChild->pszValue),"PolygonPatch") ||
    1724                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Triangle") ||
    1725                 :                     EQUAL(BareGMLElement(psChild->pszValue),"Rectangle")))
    1726                 :             {
    1727                 :                 OGRPolygon *poPolygon = (OGRPolygon *) 
    1728                 :                     GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1729             353 :                                              nRecLevel + 1 );
    1730             353 :                 if( poPolygon == NULL )
    1731               1 :                     return NULL;
    1732                 :                 
    1733             352 :                 if( poResult == NULL )
    1734             351 :                     poResult = poPolygon;
    1735               1 :                 else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
    1736                 :                 {
    1737               1 :                     OGRMultiPolygon *poMP = new OGRMultiPolygon();
    1738               1 :                     poMP->addGeometryDirectly( poResult );
    1739               1 :                     poMP->addGeometryDirectly( poPolygon );
    1740               1 :                     poResult = poMP;
    1741                 :                 }
    1742                 :                 else
    1743                 :                 {
    1744               0 :                     ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
    1745                 :                 }
    1746                 :             }
    1747                 :         }
    1748                 :         
    1749             352 :         return poResult;
    1750                 :     }
    1751                 : 
    1752                 : /* -------------------------------------------------------------------- */
    1753                 : /*      TriangulatedSurface                                             */
    1754                 : /* -------------------------------------------------------------------- */
    1755              19 :     if( EQUAL(pszBaseGeometry,"TriangulatedSurface") ||
    1756                 :         EQUAL(pszBaseGeometry,"Tin") )
    1757                 :     {
    1758                 :         const CPLXMLNode *psChild;
    1759               1 :         OGRGeometry *poResult = NULL;
    1760                 : 
    1761                 :         // Find trianglePatches
    1762               1 :         psChild = FindBareXMLChild( psNode, "trianglePatches" );
    1763               1 :         if (psChild == NULL)
    1764               1 :             psChild = FindBareXMLChild( psNode, "patches" );
    1765                 : 
    1766               1 :         if( psChild == NULL || psChild->psChild == NULL )
    1767                 :         {
    1768                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1769               0 :                       "Missing <trianglePatches> for %s.", pszBaseGeometry );
    1770               0 :             return NULL;
    1771                 :         }
    1772                 : 
    1773               2 :         for( psChild = psChild->psChild;
    1774                 :              psChild != NULL; psChild = psChild->psNext )
    1775                 :         {
    1776               1 :             if( psChild->eType == CXT_Element
    1777                 :                 && EQUAL(BareGMLElement(psChild->pszValue),"Triangle") )
    1778                 :             {
    1779                 :                 OGRPolygon *poPolygon = (OGRPolygon *)
    1780                 :                     GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
    1781               1 :                                              nRecLevel + 1 );
    1782               1 :                 if( poPolygon == NULL )
    1783               0 :                     return NULL;
    1784                 : 
    1785               1 :                 if( poResult == NULL )
    1786               1 :                     poResult = poPolygon;
    1787               0 :                 else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
    1788                 :                 {
    1789               0 :                     OGRMultiPolygon *poMP = new OGRMultiPolygon();
    1790               0 :                     poMP->addGeometryDirectly( poResult );
    1791               0 :                     poMP->addGeometryDirectly( poPolygon );
    1792               0 :                     poResult = poMP;
    1793                 :                 }
    1794                 :                 else
    1795                 :                 {
    1796               0 :                     ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
    1797                 :                 }
    1798                 :             }
    1799                 :         }
    1800                 : 
    1801               1 :         return poResult;
    1802                 :     }
    1803                 : 
    1804                 : /* -------------------------------------------------------------------- */
    1805                 : /*      Solid                                                           */
    1806                 : /* -------------------------------------------------------------------- */
    1807              18 :     if( EQUAL(pszBaseGeometry,"Solid") )
    1808                 :     {
    1809                 :         const CPLXMLNode *psChild;
    1810                 :         OGRGeometry* poGeom;
    1811                 : 
    1812                 :         // Find exterior element
    1813               6 :         psChild = FindBareXMLChild( psNode, "exterior");
    1814                 : 
    1815               6 :         if( psChild == NULL || psChild->psChild == NULL )
    1816                 :         {
    1817                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1818               3 :                       "Missing exterior property on Solid." );
    1819               3 :             return NULL;
    1820                 :         }
    1821                 : 
    1822                 :         // Get the geometry inside <exterior>
    1823                 :         poGeom = GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
    1824               3 :                                           nRecLevel + 1 );
    1825               3 :         if( poGeom == NULL )
    1826                 :         {
    1827               1 :             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior element");
    1828               1 :             delete poGeom;
    1829               1 :             return NULL;
    1830                 :         }
    1831                 : 
    1832               2 :         psChild = FindBareXMLChild( psNode, "interior");
    1833               2 :         if( psChild != NULL )
    1834                 :         {
    1835                 :             static int bWarnedOnce = FALSE;
    1836               1 :             if (!bWarnedOnce)
    1837                 :             {
    1838                 :                 CPLError( CE_Warning, CPLE_AppDefined,
    1839               1 :                           "<interior> elements of <Solid> are ignored");
    1840               1 :                 bWarnedOnce = TRUE;
    1841                 :             }
    1842                 :         }
    1843                 : 
    1844               2 :         return poGeom;
    1845                 :     }
    1846                 : 
    1847                 : /* -------------------------------------------------------------------- */
    1848                 : /*      OrientableSurface                                               */
    1849                 : /* -------------------------------------------------------------------- */
    1850              12 :     if( EQUAL(pszBaseGeometry,"OrientableSurface") )
    1851                 :     {
    1852                 :         const CPLXMLNode *psChild;
    1853                 : 
    1854                 :         // Find baseSurface.
    1855               5 :         psChild = FindBareXMLChild( psNode, "baseSurface" );
    1856                 : 
    1857               5 :         if( psChild == NULL || psChild->psChild == NULL )
    1858                 :         {
    1859                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1860               3 :                       "Missing <baseSurface> for OrientableSurface." );
    1861               3 :             return NULL;
    1862                 :         }
    1863                 : 
    1864                 :         return GML2OGRGeometry_XMLNode( psChild->psChild, bGetSecondaryGeometryOption,
    1865               2 :                                         nRecLevel + 1 );
    1866                 :     }
    1867                 : 
    1868                 :     CPLError( CE_Failure, CPLE_AppDefined, 
    1869                 :               "Unrecognised geometry type <%.500s>.", 
    1870               7 :               pszBaseGeometry );
    1871                 : 
    1872               7 :     return NULL;
    1873                 : }
    1874                 : 
    1875                 : /************************************************************************/
    1876                 : /*                      OGR_G_CreateFromGMLTree()                       */
    1877                 : /************************************************************************/
    1878                 : 
    1879             342 : OGRGeometryH OGR_G_CreateFromGMLTree( const CPLXMLNode *psTree )
    1880                 : 
    1881                 : {
    1882             342 :     return (OGRGeometryH) GML2OGRGeometry_XMLNode( psTree, -1 );
    1883                 : }
    1884                 : 
    1885                 : /************************************************************************/
    1886                 : /*                        OGR_G_CreateFromGML()                         */
    1887                 : /************************************************************************/
    1888                 : 
    1889                 : /**
    1890                 :  * \brief Create geometry from GML.
    1891                 :  *
    1892                 :  * This method translates a fragment of GML containing only the geometry
    1893                 :  * portion into a corresponding OGRGeometry.  There are many limitations
    1894                 :  * on the forms of GML geometries supported by this parser, but they are
    1895                 :  * too numerous to list here.
    1896                 :  *
    1897                 :  * The following GML2 elements are parsed : Point, LineString, Polygon,
    1898                 :  * MultiPoint, MultiLineString, MultiPolygon, MultiGeometry.
    1899                 :  *
    1900                 :  * (OGR >= 1.8.0) The following GML3 elements are parsed : Surface, MultiSurface,
    1901                 :  * PolygonPatch, Triangle, Rectangle, Curve, MultiCurve, LineStringSegment, Arc,
    1902                 :  * Circle, CompositeSurface, OrientableSurface, Solid, Tin, TriangulatedSurface.
    1903                 :  *
    1904                 :  * Arc and Circle elements are stroked to linestring, by using a
    1905                 :  * 4 degrees step, unless the user has overridden the value with the
    1906                 :  * OGR_ARC_STEPSIZE configuration variable.
    1907                 :  *
    1908                 :  * The C++ method OGRGeometryFactory::createFromGML() is the same as this function.
    1909                 :  *
    1910                 :  * @param pszGML The GML fragment for the geometry.
    1911                 :  *
    1912                 :  * @return a geometry on succes, or NULL on error.
    1913                 :  */
    1914                 : 
    1915             162 : OGRGeometryH OGR_G_CreateFromGML( const char *pszGML )
    1916                 : 
    1917                 : {
    1918             162 :     if( pszGML == NULL || strlen(pszGML) == 0 )
    1919                 :     {
    1920                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1921               0 :                   "GML Geometry is empty in OGR_G_CreateFromGML()." );
    1922               0 :         return NULL;
    1923                 :     }
    1924                 : 
    1925                 : /* ------------------------------------------------------------ -------- */
    1926                 : /*      Try to parse the XML snippet using the MiniXML API.  If this    */
    1927                 : /*      fails, we assume the minixml api has already posted a CPL       */
    1928                 : /*      error, and just return NULL.                                    */
    1929                 : /* -------------------------------------------------------------------- */
    1930             162 :     CPLXMLNode *psGML = CPLParseXMLString( pszGML );
    1931                 : 
    1932             162 :     if( psGML == NULL )
    1933               0 :         return NULL;
    1934                 : 
    1935                 : /* -------------------------------------------------------------------- */
    1936                 : /*      Convert geometry recursively.                                   */
    1937                 : /* -------------------------------------------------------------------- */
    1938                 :     OGRGeometry *poGeometry;
    1939                 : 
    1940             162 :     poGeometry = GML2OGRGeometry_XMLNode( psGML, -1 );
    1941                 : 
    1942             162 :     CPLDestroyXMLNode( psGML );
    1943                 :     
    1944             162 :     return (OGRGeometryH) poGeometry;
    1945                 : }
    1946                 : 
    1947                 : 

Generated by: LCOV version 1.7