1 : /******************************************************************************
2 : * $Id: gml2ogrgeometry.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: NAS Reader
5 : * Purpose: Code to translate GML3 (NAS) geometries into OGR format.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2008, 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 : #include "cpl_minixml.h"
31 : #include "ogr_geometry.h"
32 : #include "ogr_api.h"
33 : #include "cpl_error.h"
34 : #include "cpl_string.h"
35 : #include <ctype.h>
36 :
37 : CPL_C_START
38 : OGRGeometryH OGR_G_CreateFromGML3( const char *pszGML );
39 : CPL_C_END
40 :
41 : /************************************************************************/
42 : /* BareGMLElement() */
43 : /* */
44 : /* Returns the passed string with any namespace prefix */
45 : /* stripped off. */
46 : /************************************************************************/
47 :
48 7 : static const char *BareGMLElement( const char *pszInput )
49 :
50 : {
51 : const char *pszReturn;
52 :
53 7 : pszReturn = strchr( pszInput, ':' );
54 7 : if( pszReturn == NULL )
55 7 : pszReturn = pszInput;
56 : else
57 0 : pszReturn++;
58 :
59 7 : return pszReturn;
60 : }
61 :
62 : /************************************************************************/
63 : /* FindBareXMLChild() */
64 : /* */
65 : /* Find a child node with the indicated "bare" name, that is */
66 : /* after any namespace qualifiers have been stripped off. */
67 : /************************************************************************/
68 :
69 : static CPLXMLNode *FindBareXMLChild( CPLXMLNode *psParent,
70 3 : const char *pszBareName )
71 :
72 : {
73 3 : CPLXMLNode *psCandidate = psParent->psChild;
74 :
75 : // Is the passed in parent the target element?
76 3 : if( psParent != NULL
77 : && psParent->eType == CXT_Element
78 : && EQUAL(BareGMLElement(psParent->pszValue), pszBareName) )
79 0 : return psParent;
80 :
81 : // Otherwise search direct children (but not siblings)
82 8 : while( psCandidate != NULL )
83 : {
84 3 : if( psCandidate->eType == CXT_Element
85 : && EQUAL(BareGMLElement(psCandidate->pszValue), pszBareName) )
86 1 : return psCandidate;
87 :
88 2 : psCandidate = psCandidate->psNext;
89 : }
90 :
91 2 : return NULL;
92 : }
93 :
94 : /************************************************************************/
95 : /* GetElementText() */
96 : /************************************************************************/
97 :
98 1 : static const char *GetElementText( CPLXMLNode *psElement )
99 :
100 : {
101 1 : if( psElement == NULL )
102 0 : return NULL;
103 :
104 1 : CPLXMLNode *psChild = psElement->psChild;
105 :
106 2 : while( psChild != NULL )
107 : {
108 1 : if( psChild->eType == CXT_Text )
109 1 : return psChild->pszValue;
110 :
111 0 : psChild = psChild->psNext;
112 : }
113 :
114 0 : return NULL;
115 : }
116 :
117 : /************************************************************************/
118 : /* AddPoint() */
119 : /* */
120 : /* Add a point to the passed geometry. */
121 : /************************************************************************/
122 :
123 : static int AddPoint( OGRGeometry *poGeometry,
124 1 : double dfX, double dfY, double dfZ, int nDimension )
125 :
126 : {
127 1 : if( poGeometry->getGeometryType() == wkbPoint
128 : || poGeometry->getGeometryType() == wkbPoint25D )
129 : {
130 1 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
131 :
132 1 : if( poPoint->getX() != 0.0 || poPoint->getY() != 0.0 )
133 : {
134 : CPLError( CE_Failure, CPLE_AppDefined,
135 0 : "More than one coordinate for <Point> element.");
136 0 : return FALSE;
137 : }
138 :
139 1 : poPoint->setX( dfX );
140 1 : poPoint->setY( dfY );
141 1 : if( nDimension == 3 )
142 0 : poPoint->setZ( dfZ );
143 :
144 1 : return TRUE;
145 : }
146 :
147 0 : else if( poGeometry->getGeometryType() == wkbLineString
148 : || poGeometry->getGeometryType() == wkbLineString25D )
149 : {
150 0 : if( nDimension == 3 )
151 0 : ((OGRLineString *) poGeometry)->addPoint( dfX, dfY, dfZ );
152 : else
153 0 : ((OGRLineString *) poGeometry)->addPoint( dfX, dfY );
154 :
155 0 : return TRUE;
156 : }
157 :
158 : else
159 : {
160 0 : CPLAssert( FALSE );
161 0 : return FALSE;
162 : }
163 : }
164 :
165 : /************************************************************************/
166 : /* ParseGML3Coordinates() */
167 : /************************************************************************/
168 :
169 : static int
170 1 : ParseGML3Coordinates( CPLXMLNode *psGeomNode, OGRGeometry *poGeometry )
171 :
172 : {
173 1 : CPLXMLNode *psCoordinates = FindBareXMLChild( psGeomNode, "coordinates" );
174 1 : int iCoord = 0;
175 :
176 : /* -------------------------------------------------------------------- */
177 : /* Handle <coordinates> case. */
178 : /* -------------------------------------------------------------------- */
179 1 : if( psCoordinates != NULL )
180 : {
181 0 : const char *pszCoordString = GetElementText( psCoordinates );
182 :
183 0 : if( pszCoordString == NULL )
184 : {
185 : CPLError( CE_Failure, CPLE_AppDefined,
186 0 : "<coordinates> element missing value." );
187 0 : return FALSE;
188 : }
189 :
190 0 : while( *pszCoordString != '\0' )
191 : {
192 0 : double dfX, dfY, dfZ = 0.0;
193 0 : int nDimension = 2;
194 :
195 : // parse out 2 or 3 tuple.
196 0 : dfX = atof( pszCoordString );
197 0 : while( *pszCoordString != '\0'
198 : && *pszCoordString != ','
199 : && !isspace(*pszCoordString) )
200 0 : pszCoordString++;
201 :
202 0 : if( *pszCoordString == '\0' || isspace(*pszCoordString) )
203 : {
204 : CPLError( CE_Failure, CPLE_AppDefined,
205 0 : "Corrupt <coordinates> value." );
206 0 : return FALSE;
207 : }
208 :
209 0 : pszCoordString++;
210 0 : dfY = atof( pszCoordString );
211 0 : while( *pszCoordString != '\0'
212 : && *pszCoordString != ','
213 : && !isspace(*pszCoordString) )
214 0 : pszCoordString++;
215 :
216 0 : if( *pszCoordString == ',' )
217 : {
218 0 : pszCoordString++;
219 0 : dfZ = atof( pszCoordString );
220 0 : nDimension = 3;
221 0 : while( *pszCoordString != '\0'
222 : && *pszCoordString != ','
223 : && !isspace(*pszCoordString) )
224 0 : pszCoordString++;
225 : }
226 :
227 0 : while( isspace(*pszCoordString) )
228 0 : pszCoordString++;
229 :
230 0 : if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
231 0 : return FALSE;
232 :
233 0 : iCoord++;
234 : }
235 :
236 0 : return iCoord > 0;
237 : }
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Handle <posList> case. Similar to <coordinates> but it appears */
241 : /* There is no way to distinguish tuples so we have to assume 2D. */
242 : /* -------------------------------------------------------------------- */
243 :
244 : /* example:
245 : <gml:posList>353251.030 5531121.109 353241.105 5531103.952 353279.145 5531077.967 353289.798 5531095.563 353251.030 5531121.109</gml:posList> if( psCoordinates != NULL )
246 : */
247 :
248 1 : psCoordinates = FindBareXMLChild( psGeomNode, "posList" );
249 1 : if( psCoordinates != NULL )
250 : {
251 0 : const char *pszCoordString = GetElementText( psCoordinates );
252 :
253 0 : if( pszCoordString == NULL )
254 : {
255 : CPLError( CE_Failure, CPLE_AppDefined,
256 0 : "<posList> element missing value." );
257 0 : return FALSE;
258 : }
259 :
260 0 : while( *pszCoordString != '\0' )
261 : {
262 : double dfX, dfY;
263 :
264 : // parse out pair of values.
265 0 : dfX = atof( pszCoordString );
266 0 : while( *pszCoordString != '\0'
267 : && *pszCoordString != ','
268 : && !isspace(*pszCoordString) )
269 0 : pszCoordString++;
270 :
271 0 : if( *pszCoordString == '\0' )
272 : {
273 : CPLError( CE_Failure, CPLE_AppDefined,
274 0 : "Corrupt <posList> value." );
275 0 : return FALSE;
276 : }
277 :
278 0 : pszCoordString++;
279 0 : dfY = atof( pszCoordString );
280 0 : while( *pszCoordString != '\0'
281 : && *pszCoordString != ','
282 : && !isspace(*pszCoordString) )
283 0 : pszCoordString++;
284 :
285 0 : while( isspace(*pszCoordString) )
286 0 : pszCoordString++;
287 :
288 0 : if( !AddPoint( poGeometry, dfX, dfY, 0.0, 2 ) )
289 0 : return FALSE;
290 :
291 0 : iCoord++;
292 : }
293 :
294 0 : return iCoord > 0;
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Is this a "pos"? I think this is a GML 3 construct. */
299 : /* -------------------------------------------------------------------- */
300 1 : CPLXMLNode *psPos = FindBareXMLChild( psGeomNode, "pos" );
301 :
302 1 : if( psPos != NULL )
303 : {
304 : char **papszTokens = CSLTokenizeStringComplex(
305 1 : GetElementText( psPos ), " ,", FALSE, FALSE );
306 1 : int bSuccess = FALSE;
307 :
308 1 : if( CSLCount( papszTokens ) > 2 )
309 : {
310 : bSuccess = AddPoint( poGeometry,
311 : atof(papszTokens[0]),
312 : atof(papszTokens[1]),
313 0 : atof(papszTokens[2]), 3 );
314 : }
315 1 : else if( CSLCount( papszTokens ) > 1 )
316 : {
317 : bSuccess = AddPoint( poGeometry,
318 : atof(papszTokens[0]),
319 : atof(papszTokens[1]),
320 1 : 0.0, 2 );
321 : }
322 : else
323 : {
324 : CPLError( CE_Failure, CPLE_AppDefined,
325 : "Did not get 2+ values in <gml:pos>%s</gml:pos> tuple.",
326 0 : GetElementText( psPos ) );
327 : }
328 :
329 1 : CSLDestroy( papszTokens );
330 :
331 1 : return bSuccess;
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Handle form with a list of <coord> items each with an <X>, */
336 : /* and <Y> element. */
337 : /* -------------------------------------------------------------------- */
338 : CPLXMLNode *psCoordNode;
339 :
340 0 : for( psCoordNode = psGeomNode->psChild;
341 : psCoordNode != NULL;
342 : psCoordNode = psCoordNode->psNext )
343 : {
344 0 : if( psCoordNode->eType != CXT_Element
345 : || !EQUAL(BareGMLElement(psCoordNode->pszValue),"coord") )
346 0 : continue;
347 :
348 : CPLXMLNode *psXNode, *psYNode, *psZNode;
349 0 : double dfX, dfY, dfZ = 0.0;
350 0 : int nDimension = 2;
351 :
352 0 : psXNode = FindBareXMLChild( psCoordNode, "X" );
353 0 : psYNode = FindBareXMLChild( psCoordNode, "Y" );
354 0 : psZNode = FindBareXMLChild( psCoordNode, "Z" );
355 :
356 0 : if( psXNode == NULL || psYNode == NULL
357 : || GetElementText(psXNode) == NULL
358 : || GetElementText(psYNode) == NULL
359 : || (psZNode != NULL && GetElementText(psZNode) == NULL) )
360 : {
361 : CPLError( CE_Failure, CPLE_AppDefined,
362 0 : "Corrupt <coord> element, missing <X> or <Y> element?" );
363 0 : return FALSE;
364 : }
365 :
366 0 : dfX = atof( GetElementText(psXNode) );
367 0 : dfY = atof( GetElementText(psYNode) );
368 :
369 0 : if( psZNode != NULL && GetElementText(psZNode) != NULL )
370 : {
371 0 : dfZ = atof( GetElementText(psZNode) );
372 0 : nDimension = 3;
373 : }
374 :
375 0 : if( !AddPoint( poGeometry, dfX, dfY, dfZ, nDimension ) )
376 0 : return FALSE;
377 :
378 0 : iCoord++;
379 : }
380 :
381 0 : return iCoord > 0.0;
382 : }
383 :
384 : /************************************************************************/
385 : /* GML2OGRGeometry_XMLNode() */
386 : /* */
387 : /* Translates the passed XMLnode and it's children into an */
388 : /* OGRGeometry. This is used recursively for geometry */
389 : /* collections. */
390 : /************************************************************************/
391 :
392 1 : static OGRGeometry *GML3OGRGeometry_XMLNode( CPLXMLNode *psNode )
393 :
394 : {
395 1 : const char *pszBaseGeometry = BareGMLElement( psNode->pszValue );
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* PointType */
399 : /* -------------------------------------------------------------------- */
400 1 : if( EQUAL(pszBaseGeometry,"PointType")
401 : || EQUAL(pszBaseGeometry,"Point") )
402 : {
403 1 : OGRPoint *poPoint = new OGRPoint();
404 :
405 1 : if( !ParseGML3Coordinates( psNode, poPoint ) )
406 : {
407 0 : delete poPoint;
408 0 : return NULL;
409 : }
410 :
411 1 : return poPoint;
412 : }
413 :
414 : /* -------------------------------------------------------------------- */
415 : /* LineStringSegment type Curve. */
416 : /* -------------------------------------------------------------------- */
417 0 : if( EQUAL(pszBaseGeometry,"Curve") )
418 : {
419 0 : CPLXMLNode *psSegments = FindBareXMLChild( psNode, "segments" );
420 : CPLXMLNode *psLSS;
421 :
422 0 : if( psSegments == NULL )
423 : {
424 : CPLError( CE_Failure, CPLE_AppDefined,
425 0 : "GML3 Curve geometry lacks segments element." );
426 0 : return NULL;
427 : }
428 :
429 : OGRLineString *poLS;
430 0 : poLS = new OGRLineString();
431 :
432 0 : for( psLSS = psSegments->psChild; psLSS != NULL; psLSS = psLSS->psNext )
433 : {
434 0 : if( psLSS->eType != CXT_Element
435 : || (!EQUAL(psLSS->pszValue,"LineStringSegment")
436 : && !EQUAL(psLSS->pszValue,"Arc")) ) // we should stroke arcs!
437 0 : continue;
438 :
439 : CPLXMLNode *psPos;
440 :
441 0 : for( psPos = psLSS->psChild; psPos != NULL; psPos = psPos->psNext )
442 : {
443 0 : if( psPos->eType != CXT_Element
444 : || (!EQUAL(psPos->pszValue,"pos")
445 : && !EQUAL(psPos->pszValue,"posList") ) )
446 0 : continue;
447 :
448 0 : if( !ParseGML3Coordinates( psPos, poLS ) )
449 : {
450 0 : delete poLS;
451 0 : return NULL;
452 : }
453 : }
454 : }
455 :
456 0 : return poLS;
457 : }
458 :
459 : /* -------------------------------------------------------------------- */
460 : /* Surface */
461 : /* -------------------------------------------------------------------- */
462 0 : if( EQUAL(pszBaseGeometry,"Surface") )
463 : {
464 : CPLXMLNode *psChild;
465 0 : OGRGeometry *poResult = NULL;
466 :
467 : // Find outer ring.
468 0 : psChild = FindBareXMLChild( psNode, "patches" );
469 0 : if( psChild == NULL )
470 0 : psChild = FindBareXMLChild( psNode, "polygonPatches" );
471 :
472 0 : if( psChild == NULL || psChild->psChild == NULL )
473 : {
474 : CPLError( CE_Failure, CPLE_AppDefined,
475 0 : "Missing <patches> for Surface." );
476 0 : return NULL;
477 : }
478 :
479 0 : for( psChild = psChild->psChild;
480 : psChild != NULL; psChild = psChild->psNext )
481 : {
482 0 : if( psChild->eType == CXT_Element
483 : && EQUAL(BareGMLElement(psChild->pszValue),"PolygonPatch") )
484 : {
485 : OGRPolygon *poPolygon = (OGRPolygon *)
486 0 : GML3OGRGeometry_XMLNode( psChild );
487 0 : if( poPolygon == NULL )
488 0 : return NULL;
489 :
490 0 : if( poResult == NULL )
491 0 : poResult = poPolygon;
492 0 : else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
493 : {
494 0 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
495 0 : poMP->addGeometryDirectly( poResult );
496 0 : poMP->addGeometryDirectly( poPolygon );
497 0 : poResult = poMP;
498 : }
499 : else
500 : {
501 0 : ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
502 : }
503 : }
504 : }
505 :
506 0 : return poResult;
507 : }
508 :
509 : /* -------------------------------------------------------------------- */
510 : /* Polygon */
511 : /* -------------------------------------------------------------------- */
512 0 : if( EQUAL(pszBaseGeometry,"PolygonPatch") )
513 : {
514 : CPLXMLNode *psChild;
515 0 : OGRPolygon *poPolygon = new OGRPolygon();
516 : OGRLinearRing *poRing;
517 :
518 : // Find outer ring.
519 0 : psChild = FindBareXMLChild( psNode, "exterior" );
520 0 : if( psChild == NULL || psChild->psChild == NULL )
521 : {
522 : CPLError( CE_Failure, CPLE_AppDefined,
523 0 : "Missing outerBoundaryIs property on Polygon." );
524 0 : delete poPolygon;
525 0 : return NULL;
526 : }
527 :
528 : // Translate outer ring and add to polygon.
529 : poRing = (OGRLinearRing *)
530 0 : GML3OGRGeometry_XMLNode( psChild->psChild );
531 0 : if( poRing == NULL )
532 : {
533 0 : delete poPolygon;
534 0 : return NULL;
535 : }
536 :
537 0 : if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
538 : {
539 : CPLError( CE_Failure, CPLE_AppDefined,
540 : "Got %.500s geometry as outerBoundaryIs instead of LINEARRING.",
541 0 : poRing->getGeometryName() );
542 0 : delete poPolygon;
543 0 : delete poRing;
544 0 : return NULL;
545 : }
546 :
547 0 : poPolygon->addRingDirectly( poRing );
548 :
549 : // Find all inner rings
550 0 : for( psChild = psNode->psChild;
551 : psChild != NULL;
552 : psChild = psChild->psNext )
553 : {
554 0 : if( psChild->eType == CXT_Element
555 : && EQUAL(BareGMLElement(psChild->pszValue),"interior") )
556 : {
557 0 : if (psChild->psChild)
558 : poRing = (OGRLinearRing *)
559 0 : GML3OGRGeometry_XMLNode( psChild->psChild );
560 : else
561 0 : poRing = NULL;
562 0 : if (poRing == NULL)
563 : {
564 0 : CPLError( CE_Failure, CPLE_AppDefined, "Invalid interior ring");
565 0 : delete poPolygon;
566 0 : return NULL;
567 : }
568 0 : if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
569 : {
570 : CPLError( CE_Failure, CPLE_AppDefined,
571 : "Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
572 0 : poRing->getGeometryName() );
573 0 : delete poPolygon;
574 0 : delete poRing;
575 0 : return NULL;
576 : }
577 :
578 0 : poPolygon->addRingDirectly( poRing );
579 : }
580 : }
581 :
582 0 : return poPolygon;
583 : }
584 :
585 : /* -------------------------------------------------------------------- */
586 : /* LinearRing */
587 : /* -------------------------------------------------------------------- */
588 0 : if( EQUAL(pszBaseGeometry,"Ring") )
589 : {
590 0 : OGRLinearRing *poLinearRing = new OGRLinearRing();
591 : CPLXMLNode *psChild;
592 :
593 0 : for( psChild = psNode->psChild;
594 : psChild != NULL; psChild = psChild->psNext )
595 : {
596 0 : if( psChild->eType == CXT_Element
597 : && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
598 : {
599 : OGRLineString *poLS;
600 0 : if (psChild->psChild)
601 : poLS = (OGRLineString *)
602 0 : GML3OGRGeometry_XMLNode( psChild->psChild );
603 : else
604 0 : poLS = NULL;
605 :
606 0 : if( poLS == NULL
607 : || wkbFlatten(poLS->getGeometryType()) != wkbLineString )
608 : {
609 0 : delete poLS;
610 0 : delete poLinearRing;
611 0 : return NULL;
612 : }
613 :
614 : // we might need to take steps to avoid duplicate points...
615 0 : poLinearRing->addSubLineString( poLS );
616 0 : delete poLS;
617 : }
618 : }
619 :
620 0 : return poLinearRing;
621 : }
622 :
623 : /* -------------------------------------------------------------------- */
624 : /* MultiPoint */
625 : /* -------------------------------------------------------------------- */
626 0 : if( EQUAL(pszBaseGeometry,"MultiPoint") )
627 : {
628 : CPLXMLNode *psChild;
629 0 : OGRMultiPoint *poMP = new OGRMultiPoint();
630 :
631 : // collect points.
632 0 : for( psChild = psNode->psChild;
633 : psChild != NULL;
634 : psChild = psChild->psNext )
635 : {
636 0 : if( psChild->eType == CXT_Element
637 : && EQUAL(BareGMLElement(psChild->pszValue),"pointMember") )
638 : {
639 : OGRPoint *poPoint;
640 :
641 0 : if (psChild->psChild != NULL)
642 : poPoint = (OGRPoint *)
643 0 : GML3OGRGeometry_XMLNode( psChild->psChild );
644 : else
645 0 : poPoint = NULL;
646 0 : if( poPoint == NULL
647 : || wkbFlatten(poPoint->getGeometryType()) != wkbPoint )
648 : {
649 : CPLError( CE_Failure, CPLE_AppDefined,
650 : "Got %.500s geometry as pointMember instead of MULTIPOINT",
651 0 : poPoint ? poPoint->getGeometryName() : "NULL" );
652 0 : delete poPoint;
653 0 : delete poMP;
654 0 : return NULL;
655 : }
656 :
657 0 : poMP->addGeometryDirectly( poPoint );
658 : }
659 : }
660 :
661 0 : return poMP;
662 : }
663 :
664 : /* -------------------------------------------------------------------- */
665 : /* MultiSurface */
666 : /* -------------------------------------------------------------------- */
667 0 : if( EQUAL(pszBaseGeometry,"MultiSurface") )
668 : {
669 : CPLXMLNode *psChild;
670 0 : OGRMultiPolygon *poMP = new OGRMultiPolygon();
671 :
672 : // collect surfaces
673 0 : for( psChild = psNode->psChild;
674 : psChild != NULL;
675 : psChild = psChild->psNext )
676 : {
677 0 : if( psChild->eType == CXT_Element
678 : && EQUAL(BareGMLElement(psChild->pszValue),"surfaceMember") )
679 : {
680 : OGRPolygon *poPolygon;
681 :
682 0 : if (psChild->psChild)
683 : poPolygon = (OGRPolygon *)
684 0 : GML3OGRGeometry_XMLNode( psChild->psChild );
685 : else
686 0 : poPolygon = NULL;
687 :
688 : // We likely ought to support getting back a multipolygon
689 : // and merging it's contents into our aggregate multipolygon.
690 :
691 0 : if( poPolygon == NULL )
692 : {
693 0 : delete poMP;
694 0 : return NULL;
695 : }
696 :
697 0 : if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") )
698 : {
699 : CPLError( CE_Failure, CPLE_AppDefined,
700 : "Got %.500s geometry as surfaceMember instead of POLYGON.",
701 0 : poPolygon->getGeometryName() );
702 0 : delete poPolygon;
703 0 : delete poMP;
704 0 : return NULL;
705 : }
706 :
707 0 : poMP->addGeometryDirectly( poPolygon );
708 : }
709 : }
710 :
711 0 : return poMP;
712 : }
713 :
714 : CPLError( CE_Failure, CPLE_AppDefined,
715 : "Unrecognised geometry type <%.500s>.",
716 0 : pszBaseGeometry );
717 :
718 0 : return NULL;
719 : }
720 :
721 : /************************************************************************/
722 : /* OGR_G_CreateFromGML() */
723 : /************************************************************************/
724 :
725 1 : OGRGeometryH OGR_G_CreateFromGML3( const char *pszGML )
726 :
727 : {
728 1 : if( pszGML == NULL || strlen(pszGML) == 0 )
729 : {
730 : CPLError( CE_Failure, CPLE_AppDefined,
731 0 : "GML Geometry is empty in GML2OGRGeometry()." );
732 0 : return NULL;
733 : }
734 :
735 : /* -------------------------------------------------------------------- */
736 : /* Try to parse the XML snippet using the MiniXML API. If this */
737 : /* fails, we assume the minixml api has already posted a CPL */
738 : /* error, and just return NULL. */
739 : /* -------------------------------------------------------------------- */
740 1 : CPLXMLNode *psGML = CPLParseXMLString( pszGML );
741 :
742 1 : if( psGML == NULL )
743 0 : return NULL;
744 :
745 : /* -------------------------------------------------------------------- */
746 : /* Convert geometry recursively. */
747 : /* -------------------------------------------------------------------- */
748 : OGRGeometry *poGeometry;
749 :
750 1 : poGeometry = GML3OGRGeometry_XMLNode( psGML );
751 :
752 1 : CPLDestroyXMLNode( psGML );
753 :
754 1 : return (OGRGeometryH) poGeometry;
755 : }
|