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