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 :
|