1 : /******************************************************************************
2 : * $Id: ogr2gmlgeometry.cpp 23502 2011-12-09 18:49:24Z rouault $
3 : *
4 : * Project: GML Translator
5 : * Purpose: Code to translate OGRGeometry to GML string representation.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
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 if caller could be trusted.
33 : *
34 : * Security Audit 2003/03/28 warmerda:
35 : * Completed security audit. I believe that this module may be safely used
36 : * to generate GML from arbitrary but well formed OGRGeomety objects that
37 : * come from a potentially hostile source, but through a trusted OGR importer
38 : * without compromising the system.
39 : *
40 : */
41 :
42 : #include "cpl_minixml.h"
43 : #include "ogr_geometry.h"
44 : #include "ogr_api.h"
45 : #include "ogr_p.h"
46 : #include "cpl_error.h"
47 : #include "cpl_conv.h"
48 :
49 : /************************************************************************/
50 : /* MakeGMLCoordinate() */
51 : /************************************************************************/
52 :
53 804 : static void MakeGMLCoordinate( char *pszTarget,
54 : double x, double y, double z, int b3D )
55 :
56 : {
57 804 : OGRMakeWktCoordinate( pszTarget, x, y, z, b3D ? 3 : 2 );
58 21394 : while( *pszTarget != '\0' )
59 : {
60 19786 : if( *pszTarget == ' ' )
61 1340 : *pszTarget = ',';
62 19786 : pszTarget++;
63 : }
64 :
65 : #ifdef notdef
66 : if( !b3D )
67 : {
68 : if( x == (int) x && y == (int) y )
69 : sprintf( pszTarget, "%d,%d", (int) x, (int) y );
70 : else if( fabs(x) < 370 && fabs(y) < 370 )
71 : sprintf( pszTarget, "%.16g,%.16g", x, y );
72 : else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 )
73 : sprintf( pszTarget, "%.16g,%.16g", x, y );
74 : else
75 : sprintf( pszTarget, "%.3f,%.3f", x, y );
76 : }
77 : else
78 : {
79 : if( x == (int) x && y == (int) y && z == (int) z )
80 : sprintf( pszTarget, "%d,%d,%d", (int) x, (int) y, (int) z );
81 : else if( fabs(x) < 370 && fabs(y) < 370 )
82 : sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
83 : else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0
84 : || fabs(z) > 100000000.0 )
85 : sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
86 : else
87 : sprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
88 : }
89 : #endif
90 804 : }
91 :
92 : /************************************************************************/
93 : /* _GrowBuffer() */
94 : /************************************************************************/
95 :
96 2680 : static void _GrowBuffer( int nNeeded, char **ppszText, int *pnMaxLength )
97 :
98 : {
99 2680 : if( nNeeded+1 >= *pnMaxLength )
100 : {
101 650 : *pnMaxLength = MAX(*pnMaxLength * 2,nNeeded+1);
102 650 : *ppszText = (char *) CPLRealloc(*ppszText, *pnMaxLength);
103 : }
104 2680 : }
105 :
106 : /************************************************************************/
107 : /* AppendString() */
108 : /************************************************************************/
109 :
110 1020 : static void AppendString( char **ppszText, int *pnLength, int *pnMaxLength,
111 : const char *pszTextToAppend )
112 :
113 : {
114 : _GrowBuffer( *pnLength + strlen(pszTextToAppend) + 1,
115 1020 : ppszText, pnMaxLength );
116 :
117 1020 : strcat( *ppszText + *pnLength, pszTextToAppend );
118 1020 : *pnLength += strlen( *ppszText + *pnLength );
119 1020 : }
120 :
121 :
122 : /************************************************************************/
123 : /* AppendCoordinateList() */
124 : /************************************************************************/
125 :
126 76 : static void AppendCoordinateList( OGRLineString *poLine,
127 : char **ppszText, int *pnLength,
128 : int *pnMaxLength )
129 :
130 : {
131 : char szCoordinate[256];
132 76 : int b3D = (poLine->getGeometryType() & wkb25DBit);
133 :
134 76 : *pnLength += strlen(*ppszText + *pnLength);
135 76 : _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
136 :
137 76 : strcat( *ppszText + *pnLength, "<gml:coordinates>" );
138 76 : *pnLength += strlen(*ppszText + *pnLength);
139 :
140 :
141 838 : for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
142 : {
143 : MakeGMLCoordinate( szCoordinate,
144 : poLine->getX(iPoint),
145 : poLine->getY(iPoint),
146 : poLine->getZ(iPoint),
147 762 : b3D );
148 : _GrowBuffer( *pnLength + strlen(szCoordinate)+1,
149 762 : ppszText, pnMaxLength );
150 :
151 762 : if( iPoint != 0 )
152 686 : strcat( *ppszText + *pnLength, " " );
153 :
154 762 : strcat( *ppszText + *pnLength, szCoordinate );
155 762 : *pnLength += strlen(*ppszText + *pnLength);
156 : }
157 :
158 76 : _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
159 76 : strcat( *ppszText + *pnLength, "</gml:coordinates>" );
160 76 : *pnLength += strlen(*ppszText + *pnLength);
161 76 : }
162 :
163 : /************************************************************************/
164 : /* OGR2GMLGeometryAppend() */
165 : /************************************************************************/
166 :
167 180 : static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
168 : char **ppszText, int *pnLength,
169 : int *pnMaxLength,
170 : int bIsSubGeometry )
171 :
172 : {
173 :
174 : /* -------------------------------------------------------------------- */
175 : /* Check for Spatial Reference System attached to given geometry */
176 : /* -------------------------------------------------------------------- */
177 :
178 : // Buffer for srsName attribute (srsName="...")
179 180 : char szAttributes[30] = { 0 };
180 180 : int nAttrsLength = 0;
181 :
182 180 : const OGRSpatialReference* poSRS = NULL;
183 180 : poSRS = poGeometry->getSpatialReference();
184 :
185 180 : if( NULL != poSRS && !bIsSubGeometry )
186 : {
187 36 : const char* pszAuthName = NULL;
188 36 : const char* pszAuthCode = NULL;
189 36 : const char* pszTarget = NULL;
190 :
191 36 : if (poSRS->IsProjected())
192 20 : pszTarget = "PROJCS";
193 : else
194 16 : pszTarget = "GEOGCS";
195 :
196 36 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
197 36 : if( NULL != pszAuthName )
198 : {
199 16 : if( EQUAL( pszAuthName, "EPSG" ) )
200 : {
201 16 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
202 16 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
203 : {
204 : sprintf( szAttributes, " srsName=\"%s:%s\"",
205 16 : pszAuthName, pszAuthCode );
206 :
207 16 : nAttrsLength = strlen(szAttributes);
208 : }
209 : }
210 : }
211 : }
212 :
213 : /* -------------------------------------------------------------------- */
214 : /* 2D Point */
215 : /* -------------------------------------------------------------------- */
216 180 : if( poGeometry->getGeometryType() == wkbPoint )
217 : {
218 : char szCoordinate[256];
219 34 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
220 :
221 : MakeGMLCoordinate( szCoordinate,
222 34 : poPoint->getX(), poPoint->getY(), 0.0, FALSE );
223 :
224 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nAttrsLength,
225 34 : ppszText, pnMaxLength );
226 :
227 : sprintf( *ppszText + *pnLength,
228 : "<gml:Point%s><gml:coordinates>%s</gml:coordinates></gml:Point>",
229 34 : szAttributes, szCoordinate );
230 :
231 34 : *pnLength += strlen( *ppszText + *pnLength );
232 : }
233 : /* -------------------------------------------------------------------- */
234 : /* 3D Point */
235 : /* -------------------------------------------------------------------- */
236 146 : else if( poGeometry->getGeometryType() == wkbPoint25D )
237 : {
238 : char szCoordinate[256];
239 8 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
240 :
241 : MakeGMLCoordinate( szCoordinate,
242 : poPoint->getX(), poPoint->getY(), poPoint->getZ(),
243 8 : TRUE );
244 :
245 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nAttrsLength,
246 8 : ppszText, pnMaxLength );
247 :
248 : sprintf( *ppszText + *pnLength,
249 : "<gml:Point%s><gml:coordinates>%s</gml:coordinates></gml:Point>",
250 8 : szAttributes, szCoordinate );
251 :
252 8 : *pnLength += strlen( *ppszText + *pnLength );
253 : }
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* LineString and LinearRing */
257 : /* -------------------------------------------------------------------- */
258 230 : else if( poGeometry->getGeometryType() == wkbLineString
259 92 : || poGeometry->getGeometryType() == wkbLineString25D )
260 : {
261 76 : int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
262 :
263 : // Buffer for tag name + srsName attribute if set
264 76 : const size_t nLineTagLength = 16;
265 76 : char* pszLineTagName = NULL;
266 76 : pszLineTagName = (char *) CPLMalloc( nLineTagLength + nAttrsLength + 1 );
267 :
268 76 : if( bRing )
269 : {
270 46 : sprintf( pszLineTagName, "<gml:LinearRing%s>", szAttributes );
271 :
272 : AppendString( ppszText, pnLength, pnMaxLength,
273 46 : pszLineTagName );
274 : }
275 : else
276 : {
277 30 : sprintf( pszLineTagName, "<gml:LineString%s>", szAttributes );
278 :
279 : AppendString( ppszText, pnLength, pnMaxLength,
280 30 : pszLineTagName );
281 : }
282 :
283 : // FREE TAG BUFFER
284 76 : CPLFree( pszLineTagName );
285 :
286 : AppendCoordinateList( (OGRLineString *) poGeometry,
287 76 : ppszText, pnLength, pnMaxLength );
288 :
289 76 : if( bRing )
290 : AppendString( ppszText, pnLength, pnMaxLength,
291 46 : "</gml:LinearRing>" );
292 : else
293 : AppendString( ppszText, pnLength, pnMaxLength,
294 30 : "</gml:LineString>" );
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Polygon */
299 : /* -------------------------------------------------------------------- */
300 106 : else if( poGeometry->getGeometryType() == wkbPolygon
301 44 : || poGeometry->getGeometryType() == wkbPolygon25D )
302 : {
303 42 : OGRPolygon *poPolygon = (OGRPolygon *) poGeometry;
304 :
305 : // Buffer for polygon tag name + srsName attribute if set
306 42 : const size_t nPolyTagLength = 13;
307 42 : char* pszPolyTagName = NULL;
308 42 : pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nAttrsLength + 1 );
309 :
310 : // Compose Polygon tag with or without srsName attribute
311 42 : sprintf( pszPolyTagName, "<gml:Polygon%s>", szAttributes );
312 :
313 : AppendString( ppszText, pnLength, pnMaxLength,
314 42 : pszPolyTagName );
315 :
316 : // FREE TAG BUFFER
317 42 : CPLFree( pszPolyTagName );
318 :
319 : // Don't add srsName to polygon rings
320 :
321 42 : if( poPolygon->getExteriorRing() != NULL )
322 : {
323 : AppendString( ppszText, pnLength, pnMaxLength,
324 42 : "<gml:outerBoundaryIs>" );
325 :
326 42 : if( !OGR2GMLGeometryAppend( poPolygon->getExteriorRing(),
327 : ppszText, pnLength, pnMaxLength,
328 : TRUE ) )
329 : {
330 0 : return FALSE;
331 : }
332 :
333 : AppendString( ppszText, pnLength, pnMaxLength,
334 42 : "</gml:outerBoundaryIs>" );
335 : }
336 :
337 46 : for( int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++ )
338 : {
339 4 : OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);
340 :
341 : AppendString( ppszText, pnLength, pnMaxLength,
342 4 : "<gml:innerBoundaryIs>" );
343 :
344 4 : if( !OGR2GMLGeometryAppend( poRing, ppszText, pnLength,
345 : pnMaxLength, TRUE ) )
346 0 : return FALSE;
347 :
348 : AppendString( ppszText, pnLength, pnMaxLength,
349 4 : "</gml:innerBoundaryIs>" );
350 : }
351 :
352 : AppendString( ppszText, pnLength, pnMaxLength,
353 42 : "</gml:Polygon>" );
354 : }
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* MultiPolygon, MultiLineString, MultiPoint, MultiGeometry */
358 : /* -------------------------------------------------------------------- */
359 54 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
360 16 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
361 12 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
362 6 : || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
363 : {
364 20 : OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
365 : int iMember;
366 20 : const char *pszElemClose = NULL;
367 20 : const char *pszMemberElem = NULL;
368 :
369 : // Buffer for opening tag + srsName attribute
370 20 : char* pszElemOpen = NULL;
371 :
372 20 : if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
373 : {
374 4 : pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
375 4 : sprintf( pszElemOpen, "MultiPolygon%s>", szAttributes );
376 :
377 4 : pszElemClose = "MultiPolygon>";
378 4 : pszMemberElem = "polygonMember>";
379 : }
380 16 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
381 : {
382 4 : pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
383 4 : sprintf( pszElemOpen, "MultiLineString%s>", szAttributes );
384 :
385 4 : pszElemClose = "MultiLineString>";
386 4 : pszMemberElem = "lineStringMember>";
387 : }
388 12 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
389 : {
390 6 : pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
391 6 : sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );
392 :
393 6 : pszElemClose = "MultiPoint>";
394 6 : pszMemberElem = "pointMember>";
395 : }
396 : else
397 : {
398 6 : pszElemOpen = (char *) CPLMalloc( 19 + nAttrsLength + 1 );
399 6 : sprintf( pszElemOpen, "MultiGeometry%s>", szAttributes );
400 :
401 6 : pszElemClose = "MultiGeometry>";
402 6 : pszMemberElem = "geometryMember>";
403 : }
404 :
405 20 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
406 20 : AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen );
407 :
408 86 : for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
409 : {
410 66 : OGRGeometry *poMember = poGC->getGeometryRef( iMember );
411 :
412 66 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
413 66 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
414 :
415 66 : if( !OGR2GMLGeometryAppend( poMember,
416 : ppszText, pnLength, pnMaxLength,
417 : TRUE ) )
418 : {
419 0 : return FALSE;
420 : }
421 :
422 66 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
423 66 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
424 : }
425 :
426 20 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
427 20 : AppendString( ppszText, pnLength, pnMaxLength, pszElemClose );
428 :
429 : // FREE TAG BUFFER
430 20 : CPLFree( pszElemOpen );
431 : }
432 : else
433 : {
434 0 : return FALSE;
435 : }
436 :
437 180 : return TRUE;
438 : }
439 :
440 : /************************************************************************/
441 : /* OGR_G_ExportEnvelopeToGMLTree() */
442 : /* */
443 : /* Export the envelope of a geometry as a gml:Box. */
444 : /************************************************************************/
445 :
446 0 : CPLXMLNode *OGR_G_ExportEnvelopeToGMLTree( OGRGeometryH hGeometry )
447 :
448 : {
449 : CPLXMLNode *psBox, *psCoord;
450 0 : OGREnvelope sEnvelope;
451 : char szCoordinate[256];
452 : char *pszY;
453 :
454 0 : memset( &sEnvelope, 0, sizeof(sEnvelope) );
455 0 : ((OGRGeometry *) hGeometry)->getEnvelope( &sEnvelope );
456 :
457 0 : if( sEnvelope.MinX == 0 && sEnvelope.MaxX == 0
458 : && sEnvelope.MaxX == 0 && sEnvelope.MaxY == 0 )
459 : {
460 : /* there is apparently a special way of representing a null box
461 : geometry ... we should use it here eventually. */
462 :
463 0 : return NULL;
464 : }
465 :
466 0 : psBox = CPLCreateXMLNode( NULL, CXT_Element, "gml:Box" );
467 :
468 : /* -------------------------------------------------------------------- */
469 : /* Add minxy coordinate. */
470 : /* -------------------------------------------------------------------- */
471 0 : psCoord = CPLCreateXMLNode( psBox, CXT_Element, "gml:coord" );
472 :
473 : MakeGMLCoordinate( szCoordinate, sEnvelope.MinX, sEnvelope.MinY, 0.0,
474 0 : FALSE );
475 0 : pszY = strstr(szCoordinate,",") + 1;
476 0 : pszY[-1] = '\0';
477 :
478 0 : CPLCreateXMLElementAndValue( psCoord, "gml:X", szCoordinate );
479 0 : CPLCreateXMLElementAndValue( psCoord, "gml:Y", pszY );
480 :
481 : /* -------------------------------------------------------------------- */
482 : /* Add maxxy coordinate. */
483 : /* -------------------------------------------------------------------- */
484 0 : psCoord = CPLCreateXMLNode( psBox, CXT_Element, "gml:coord" );
485 :
486 : MakeGMLCoordinate( szCoordinate, sEnvelope.MaxX, sEnvelope.MaxY, 0.0,
487 0 : FALSE );
488 0 : pszY = strstr(szCoordinate,",") + 1;
489 0 : pszY[-1] = '\0';
490 :
491 0 : CPLCreateXMLElementAndValue( psCoord, "gml:X", szCoordinate );
492 0 : CPLCreateXMLElementAndValue( psCoord, "gml:Y", pszY );
493 :
494 0 : return psBox;
495 : }
496 :
497 :
498 : /************************************************************************/
499 : /* AppendGML3CoordinateList() */
500 : /************************************************************************/
501 :
502 48 : static void AppendGML3CoordinateList( OGRLineString *poLine, int bCoordSwap,
503 : char **ppszText, int *pnLength,
504 : int *pnMaxLength )
505 :
506 : {
507 : char szCoordinate[256];
508 48 : int b3D = (poLine->getGeometryType() & wkb25DBit);
509 :
510 48 : *pnLength += strlen(*ppszText + *pnLength);
511 48 : _GrowBuffer( *pnLength + 40, ppszText, pnMaxLength );
512 :
513 48 : if (b3D)
514 24 : strcat( *ppszText + *pnLength, "<gml:posList srsDimension=\"3\">" );
515 : else
516 24 : strcat( *ppszText + *pnLength, "<gml:posList>" );
517 48 : *pnLength += strlen(*ppszText + *pnLength);
518 :
519 :
520 626 : for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
521 : {
522 578 : if (bCoordSwap)
523 : OGRMakeWktCoordinate( szCoordinate,
524 : poLine->getY(iPoint),
525 : poLine->getX(iPoint),
526 : poLine->getZ(iPoint),
527 0 : b3D ? 3 : 2 );
528 : else
529 : OGRMakeWktCoordinate( szCoordinate,
530 : poLine->getX(iPoint),
531 : poLine->getY(iPoint),
532 : poLine->getZ(iPoint),
533 578 : b3D ? 3 : 2 );
534 : _GrowBuffer( *pnLength + strlen(szCoordinate)+1,
535 578 : ppszText, pnMaxLength );
536 :
537 578 : if( iPoint != 0 )
538 530 : strcat( *ppszText + *pnLength, " " );
539 :
540 578 : strcat( *ppszText + *pnLength, szCoordinate );
541 578 : *pnLength += strlen(*ppszText + *pnLength);
542 : }
543 :
544 48 : _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
545 48 : strcat( *ppszText + *pnLength, "</gml:posList>" );
546 48 : *pnLength += strlen(*ppszText + *pnLength);
547 48 : }
548 :
549 : /************************************************************************/
550 : /* OGR2GML3GeometryAppend() */
551 : /************************************************************************/
552 :
553 116 : static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
554 : const OGRSpatialReference* poParentSRS,
555 : char **ppszText, int *pnLength,
556 : int *pnMaxLength,
557 : int bIsSubGeometry,
558 : int bLongSRS,
559 : int bLineStringAsCurve,
560 : const char* pszGMLId = NULL)
561 :
562 : {
563 :
564 : /* -------------------------------------------------------------------- */
565 : /* Check for Spatial Reference System attached to given geometry */
566 : /* -------------------------------------------------------------------- */
567 :
568 : // Buffer for srsName and gml:id attributes (srsName="..." gml:id="...")
569 : char szAttributes[256];
570 116 : int nAttrsLength = 0;
571 :
572 116 : szAttributes[0] = 0;
573 :
574 116 : const OGRSpatialReference* poSRS = NULL;
575 116 : if (poParentSRS)
576 20 : poSRS = poParentSRS;
577 : else
578 96 : poParentSRS = poSRS = poGeometry->getSpatialReference();
579 :
580 116 : int bCoordSwap = FALSE;
581 :
582 116 : if( NULL != poSRS )
583 : {
584 60 : const char* pszAuthName = NULL;
585 60 : const char* pszAuthCode = NULL;
586 60 : const char* pszTarget = NULL;
587 :
588 60 : if (poSRS->IsProjected())
589 42 : pszTarget = "PROJCS";
590 : else
591 18 : pszTarget = "GEOGCS";
592 :
593 60 : pszAuthName = poSRS->GetAuthorityName( pszTarget );
594 60 : if( NULL != pszAuthName )
595 : {
596 20 : if( EQUAL( pszAuthName, "EPSG" ) )
597 : {
598 20 : pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
599 20 : if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
600 : {
601 20 : if (bLongSRS && !((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong())
602 : {
603 16 : OGRSpatialReference oSRS;
604 16 : if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
605 : {
606 16 : if (oSRS.EPSGTreatsAsLatLong())
607 14 : bCoordSwap = TRUE;
608 16 : }
609 : }
610 :
611 20 : if (!bIsSubGeometry)
612 : {
613 20 : if (bLongSRS)
614 : {
615 : snprintf( szAttributes, sizeof(szAttributes),
616 : " srsName=\"urn:ogc:def:crs:%s::%s\"",
617 18 : pszAuthName, pszAuthCode );
618 : }
619 : else
620 : {
621 : snprintf( szAttributes, sizeof(szAttributes),
622 : " srsName=\"%s:%s\"",
623 2 : pszAuthName, pszAuthCode );
624 : }
625 :
626 20 : nAttrsLength = strlen(szAttributes);
627 : }
628 : }
629 : }
630 : }
631 : }
632 :
633 116 : if (pszGMLId != NULL && nAttrsLength + 9 + strlen(pszGMLId) + 1 < sizeof(szAttributes))
634 : {
635 4 : strcat(szAttributes, " gml:id=\"");
636 4 : strcat(szAttributes, pszGMLId);
637 4 : strcat(szAttributes, "\"");
638 4 : nAttrsLength = strlen(szAttributes);
639 : }
640 :
641 : /* -------------------------------------------------------------------- */
642 : /* 2D Point */
643 : /* -------------------------------------------------------------------- */
644 116 : if( poGeometry->getGeometryType() == wkbPoint )
645 : {
646 : char szCoordinate[256];
647 28 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
648 :
649 28 : if (bCoordSwap)
650 : OGRMakeWktCoordinate( szCoordinate,
651 14 : poPoint->getY(), poPoint->getX(), 0.0, 2 );
652 : else
653 : OGRMakeWktCoordinate( szCoordinate,
654 14 : poPoint->getX(), poPoint->getY(), 0.0, 2 );
655 :
656 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nAttrsLength,
657 28 : ppszText, pnMaxLength );
658 :
659 : sprintf( *ppszText + *pnLength,
660 : "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
661 28 : szAttributes, szCoordinate );
662 :
663 28 : *pnLength += strlen( *ppszText + *pnLength );
664 : }
665 : /* -------------------------------------------------------------------- */
666 : /* 3D Point */
667 : /* -------------------------------------------------------------------- */
668 88 : else if( poGeometry->getGeometryType() == wkbPoint25D )
669 : {
670 : char szCoordinate[256];
671 2 : OGRPoint *poPoint = (OGRPoint *) poGeometry;
672 :
673 2 : if (bCoordSwap)
674 : OGRMakeWktCoordinate( szCoordinate,
675 0 : poPoint->getY(), poPoint->getX(), poPoint->getZ(), 3 );
676 : else
677 : OGRMakeWktCoordinate( szCoordinate,
678 2 : poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3 );
679 :
680 : _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nAttrsLength,
681 2 : ppszText, pnMaxLength );
682 :
683 : sprintf( *ppszText + *pnLength,
684 : "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
685 2 : szAttributes, szCoordinate );
686 :
687 2 : *pnLength += strlen( *ppszText + *pnLength );
688 : }
689 :
690 : /* -------------------------------------------------------------------- */
691 : /* LineString and LinearRing */
692 : /* -------------------------------------------------------------------- */
693 148 : else if( poGeometry->getGeometryType() == wkbLineString
694 62 : || poGeometry->getGeometryType() == wkbLineString25D )
695 : {
696 48 : int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
697 56 : if (!bRing && bLineStringAsCurve)
698 : {
699 : AppendString( ppszText, pnLength, pnMaxLength,
700 8 : "<gml:Curve" );
701 : AppendString( ppszText, pnLength, pnMaxLength,
702 8 : szAttributes );
703 : AppendString( ppszText, pnLength, pnMaxLength,
704 8 : "><gml:segments><gml:LineStringSegment>" );
705 : AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
706 8 : ppszText, pnLength, pnMaxLength );
707 : AppendString( ppszText, pnLength, pnMaxLength,
708 8 : "</gml:LineStringSegment></gml:segments></gml:Curve>" );
709 : }
710 : else
711 : {
712 : // Buffer for tag name + srsName attribute if set
713 40 : const size_t nLineTagLength = 16;
714 40 : char* pszLineTagName = NULL;
715 40 : pszLineTagName = (char *) CPLMalloc( nLineTagLength + nAttrsLength + 1 );
716 :
717 40 : if( bRing )
718 : {
719 : /* LinearRing isn't supposed to have srsName attribute according to GML3 SF-0 */
720 : AppendString( ppszText, pnLength, pnMaxLength,
721 30 : "<gml:LinearRing>" );
722 : }
723 : else
724 : {
725 10 : sprintf( pszLineTagName, "<gml:LineString%s>", szAttributes );
726 :
727 : AppendString( ppszText, pnLength, pnMaxLength,
728 10 : pszLineTagName );
729 : }
730 :
731 : // FREE TAG BUFFER
732 40 : CPLFree( pszLineTagName );
733 :
734 : AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
735 40 : ppszText, pnLength, pnMaxLength );
736 :
737 40 : if( bRing )
738 : AppendString( ppszText, pnLength, pnMaxLength,
739 30 : "</gml:LinearRing>" );
740 : else
741 : AppendString( ppszText, pnLength, pnMaxLength,
742 10 : "</gml:LineString>" );
743 : }
744 : }
745 :
746 : /* -------------------------------------------------------------------- */
747 : /* Polygon */
748 : /* -------------------------------------------------------------------- */
749 68 : else if( poGeometry->getGeometryType() == wkbPolygon
750 30 : || poGeometry->getGeometryType() == wkbPolygon25D )
751 : {
752 28 : OGRPolygon *poPolygon = (OGRPolygon *) poGeometry;
753 :
754 : // Buffer for polygon tag name + srsName attribute if set
755 28 : const size_t nPolyTagLength = 13;
756 28 : char* pszPolyTagName = NULL;
757 28 : pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nAttrsLength + 1 );
758 :
759 : // Compose Polygon tag with or without srsName attribute
760 28 : sprintf( pszPolyTagName, "<gml:Polygon%s>", szAttributes );
761 :
762 : AppendString( ppszText, pnLength, pnMaxLength,
763 28 : pszPolyTagName );
764 :
765 : // FREE TAG BUFFER
766 28 : CPLFree( pszPolyTagName );
767 :
768 : // Don't add srsName to polygon rings
769 :
770 28 : if( poPolygon->getExteriorRing() != NULL )
771 : {
772 : AppendString( ppszText, pnLength, pnMaxLength,
773 28 : "<gml:exterior>" );
774 :
775 28 : if( !OGR2GML3GeometryAppend( poPolygon->getExteriorRing(), poSRS,
776 : ppszText, pnLength, pnMaxLength,
777 : TRUE, bLongSRS, bLineStringAsCurve ) )
778 : {
779 0 : return FALSE;
780 : }
781 :
782 : AppendString( ppszText, pnLength, pnMaxLength,
783 28 : "</gml:exterior>" );
784 : }
785 :
786 30 : for( int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++ )
787 : {
788 2 : OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);
789 :
790 : AppendString( ppszText, pnLength, pnMaxLength,
791 2 : "<gml:interior>" );
792 :
793 2 : if( !OGR2GML3GeometryAppend( poRing, poSRS, ppszText, pnLength,
794 : pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve ) )
795 0 : return FALSE;
796 :
797 : AppendString( ppszText, pnLength, pnMaxLength,
798 2 : "</gml:interior>" );
799 : }
800 :
801 : AppendString( ppszText, pnLength, pnMaxLength,
802 28 : "</gml:Polygon>" );
803 : }
804 :
805 : /* -------------------------------------------------------------------- */
806 : /* MultiPolygon, MultiLineString, MultiPoint, MultiGeometry */
807 : /* -------------------------------------------------------------------- */
808 24 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
809 8 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
810 4 : || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
811 2 : || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
812 : {
813 10 : OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
814 : int iMember;
815 10 : const char *pszElemClose = NULL;
816 10 : const char *pszMemberElem = NULL;
817 :
818 : // Buffer for opening tag + srsName attribute
819 10 : char* pszElemOpen = NULL;
820 :
821 10 : if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
822 : {
823 2 : pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
824 2 : sprintf( pszElemOpen, "MultiSurface%s>", szAttributes );
825 :
826 2 : pszElemClose = "MultiSurface>";
827 2 : pszMemberElem = "surfaceMember>";
828 : }
829 8 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
830 : {
831 4 : pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
832 4 : sprintf( pszElemOpen, "MultiCurve%s>", szAttributes );
833 :
834 4 : pszElemClose = "MultiCurve>";
835 4 : pszMemberElem = "curveMember>";
836 : }
837 4 : else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
838 : {
839 2 : pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
840 2 : sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );
841 :
842 2 : pszElemClose = "MultiPoint>";
843 2 : pszMemberElem = "pointMember>";
844 : }
845 : else
846 : {
847 2 : pszElemOpen = (char *) CPLMalloc( 19 + nAttrsLength + 1 );
848 2 : sprintf( pszElemOpen, "MultiGeometry%s>", szAttributes );
849 :
850 2 : pszElemClose = "MultiGeometry>";
851 2 : pszMemberElem = "geometryMember>";
852 : }
853 :
854 10 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
855 10 : AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen );
856 :
857 30 : for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
858 : {
859 20 : OGRGeometry *poMember = poGC->getGeometryRef( iMember );
860 :
861 20 : AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
862 20 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
863 :
864 20 : char* pszGMLIdSub = NULL;
865 20 : if (pszGMLId != NULL)
866 0 : pszGMLIdSub = CPLStrdup(CPLSPrintf("%s.%d", pszGMLId, iMember));
867 :
868 20 : if( !OGR2GML3GeometryAppend( poMember, poSRS,
869 : ppszText, pnLength, pnMaxLength,
870 : TRUE, bLongSRS, bLineStringAsCurve,
871 : pszGMLIdSub) )
872 : {
873 0 : CPLFree(pszGMLIdSub);
874 0 : return FALSE;
875 : }
876 :
877 20 : CPLFree(pszGMLIdSub);
878 :
879 20 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
880 20 : AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
881 : }
882 :
883 10 : AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
884 10 : AppendString( ppszText, pnLength, pnMaxLength, pszElemClose );
885 :
886 : // FREE TAG BUFFER
887 10 : CPLFree( pszElemOpen );
888 : }
889 : else
890 : {
891 0 : return FALSE;
892 : }
893 :
894 116 : return TRUE;
895 : }
896 :
897 : /************************************************************************/
898 : /* OGR_G_ExportToGMLTree() */
899 : /************************************************************************/
900 :
901 0 : CPLXMLNode *OGR_G_ExportToGMLTree( OGRGeometryH hGeometry )
902 :
903 : {
904 : char *pszText;
905 : CPLXMLNode *psTree;
906 :
907 0 : pszText = OGR_G_ExportToGML( hGeometry );
908 0 : if( pszText == NULL )
909 0 : return NULL;
910 :
911 0 : psTree = CPLParseXMLString( pszText );
912 :
913 0 : CPLFree( pszText );
914 :
915 0 : return psTree;
916 : }
917 :
918 : /************************************************************************/
919 : /* OGR_G_ExportToGML() */
920 : /************************************************************************/
921 :
922 : /**
923 : * \brief Convert a geometry into GML format.
924 : *
925 : * The GML geometry is expressed directly in terms of GML basic data
926 : * types assuming the this is available in the gml namespace. The returned
927 : * string should be freed with CPLFree() when no longer required.
928 : *
929 : * This method is the same as the C++ method OGRGeometry::exportToGML().
930 : *
931 : * @param hGeometry handle to the geometry.
932 : * @return A GML fragment or NULL in case of error.
933 : */
934 :
935 0 : char *OGR_G_ExportToGML( OGRGeometryH hGeometry )
936 :
937 : {
938 0 : return OGR_G_ExportToGMLEx(hGeometry, NULL);
939 : }
940 :
941 : /************************************************************************/
942 : /* OGR_G_ExportToGMLEx() */
943 : /************************************************************************/
944 :
945 : /**
946 : * \brief Convert a geometry into GML format.
947 : *
948 : * The GML geometry is expressed directly in terms of GML basic data
949 : * types assuming the this is available in the gml namespace. The returned
950 : * string should be freed with CPLFree() when no longer required.
951 : *
952 : * The supported options in OGR 1.8.0 are :
953 : * <ul>
954 : * <li> FORMAT=GML3. Otherwise it will default to GML 2.1.2 output.
955 : * <li> GML3_LINESTRING_ELEMENT=curve. (Only valid for FORMAT=GML3) To use gml:Curve element for linestrings.
956 : * Otherwise gml:LineString will be used .
957 : * <li> GML3_LONGSRS=YES/NO. (Only valid for FORMAT=GML3) Default to YES. If YES, SRS with EPSG authority will
958 : * be written with the "urn:ogc:def:crs:EPSG::" prefix.
959 : * In the case, if the SRS is a geographic SRS without explicit AXIS order, but that the same SRS authority code
960 : * imported with ImportFromEPSGA() should be treated as lat/long, then the function will take care of coordinate order swapping.
961 : * If set to NO, SRS with EPSG authority will be written with the "EPSG:" prefix, even if they are in lat/long order.
962 : * <li> GMLID=astring. If specified, a gml:id attribute will be written in the top-level geometry element with the provided value.
963 : * Required for GML 3.2 compatibility.
964 : * </ul>
965 : *
966 : * This method is the same as the C++ method OGRGeometry::exportToGML().
967 : *
968 : * @param hGeometry handle to the geometry.
969 : * @param papszOptions NULL-terminated list of options.
970 : * @return A GML fragment or NULL in case of error.
971 : *
972 : * @since OGR 1.8.0
973 : */
974 :
975 134 : char *OGR_G_ExportToGMLEx( OGRGeometryH hGeometry, char** papszOptions )
976 :
977 : {
978 : char *pszText;
979 134 : int nLength = 0, nMaxLength = 1;
980 :
981 134 : if( hGeometry == NULL )
982 0 : return CPLStrdup( "" );
983 :
984 134 : pszText = (char *) CPLMalloc(nMaxLength);
985 134 : pszText[0] = '\0';
986 :
987 134 : const char* pszFormat = CSLFetchNameValue(papszOptions, "FORMAT");
988 134 : if (pszFormat && EQUAL(pszFormat, "GML3"))
989 : {
990 66 : const char* pszLineStringElement = CSLFetchNameValue(papszOptions, "GML3_LINESTRING_ELEMENT");
991 66 : int bLineStringAsCurve = (pszLineStringElement && EQUAL(pszLineStringElement, "curve"));
992 66 : int bLongSRS = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "GML3_LONGSRS", "YES"));
993 66 : const char* pszGMLId = CSLFetchNameValue(papszOptions, "GMLID");
994 66 : if( !OGR2GML3GeometryAppend( (OGRGeometry *) hGeometry, NULL, &pszText,
995 : &nLength, &nMaxLength, FALSE, bLongSRS, bLineStringAsCurve, pszGMLId ))
996 : {
997 0 : CPLFree( pszText );
998 0 : return NULL;
999 : }
1000 : else
1001 66 : return pszText;
1002 : }
1003 :
1004 68 : if( !OGR2GMLGeometryAppend( (OGRGeometry *) hGeometry, &pszText,
1005 : &nLength, &nMaxLength, FALSE ))
1006 : {
1007 0 : CPLFree( pszText );
1008 0 : return NULL;
1009 : }
1010 : else
1011 68 : return pszText;
1012 : }
|