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