1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 :
29 : #include <ogrsf_frmts.h>
30 : #include <ogr_feature.h>
31 : #include "ogr_p.h"
32 :
33 : #include <kml/dom.h>
34 : #include <iostream>
35 :
36 : using kmldom::ExtendedDataPtr;
37 : using kmldom::SchemaPtr;
38 : using kmldom::SchemaDataPtr;
39 : using kmldom::SimpleDataPtr;
40 : using kmldom::DataPtr;
41 :
42 : using kmldom::TimeStampPtr;
43 : using kmldom::TimeSpanPtr;
44 : using kmldom::TimePrimitivePtr;
45 :
46 : using kmldom::PointPtr;
47 : using kmldom::LineStringPtr;
48 : using kmldom::PolygonPtr;
49 : using kmldom::MultiGeometryPtr;
50 : using kmldom::GeometryPtr;
51 :
52 : using kmldom::FeaturePtr;
53 : using kmldom::GroundOverlayPtr;
54 : using kmldom::IconPtr;
55 :
56 : #include "ogr_libkml.h"
57 :
58 : #include "ogrlibkmlfield.h"
59 :
60 0 : void ogr2altitudemode_rec (
61 : GeometryPtr poKmlGeometry,
62 : int iAltitudeMode,
63 : int isGX )
64 : {
65 :
66 0 : PointPtr poKmlPoint;
67 0 : LineStringPtr poKmlLineString;
68 0 : PolygonPtr poKmlPolygon;
69 0 : MultiGeometryPtr poKmlMultiGeometry;
70 :
71 : size_t nGeom;
72 : size_t i;
73 :
74 0 : switch ( poKmlGeometry->Type ( ) ) {
75 :
76 : case kmldom::Type_Point:
77 0 : poKmlPoint = AsPoint ( poKmlGeometry );
78 :
79 0 : if ( !isGX )
80 0 : poKmlPoint->set_altitudemode ( iAltitudeMode );
81 : else
82 0 : poKmlPoint->set_gx_altitudemode ( iAltitudeMode );
83 :
84 0 : break;
85 :
86 : case kmldom::Type_LineString:
87 0 : poKmlLineString = AsLineString ( poKmlGeometry );
88 :
89 0 : if ( !isGX )
90 0 : poKmlLineString->set_altitudemode ( iAltitudeMode );
91 : else
92 0 : poKmlLineString->set_gx_altitudemode ( iAltitudeMode );
93 :
94 0 : break;
95 :
96 : case kmldom::Type_LinearRing:
97 0 : break;
98 :
99 : case kmldom::Type_Polygon:
100 0 : poKmlPolygon = AsPolygon ( poKmlGeometry );
101 :
102 0 : if ( !isGX )
103 0 : poKmlPolygon->set_altitudemode ( iAltitudeMode );
104 : else
105 0 : poKmlPolygon->set_gx_altitudemode ( iAltitudeMode );
106 :
107 0 : break;
108 :
109 : case kmldom::Type_MultiGeometry:
110 0 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
111 :
112 0 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
113 0 : for ( i = 0; i < nGeom; i++ ) {
114 : ogr2altitudemode_rec ( poKmlMultiGeometry->
115 : get_geometry_array_at ( i ), iAltitudeMode,
116 0 : isGX );
117 : }
118 :
119 : break;
120 :
121 : default:
122 : break;
123 :
124 0 : }
125 :
126 0 : }
127 :
128 0 : void ogr2extrude_rec (
129 : int nExtrude,
130 : GeometryPtr poKmlGeometry )
131 : {
132 :
133 0 : PointPtr poKmlPoint;
134 0 : LineStringPtr poKmlLineString;
135 0 : PolygonPtr poKmlPolygon;
136 0 : MultiGeometryPtr poKmlMultiGeometry;
137 :
138 : size_t nGeom;
139 : size_t i;
140 :
141 0 : switch ( poKmlGeometry->Type ( ) ) {
142 : case kmldom::Type_Point:
143 0 : poKmlPoint = AsPoint ( poKmlGeometry );
144 0 : poKmlPoint->set_extrude ( nExtrude );
145 0 : break;
146 :
147 : case kmldom::Type_LineString:
148 0 : poKmlLineString = AsLineString ( poKmlGeometry );
149 0 : poKmlLineString->set_extrude ( nExtrude );
150 0 : break;
151 :
152 : case kmldom::Type_LinearRing:
153 0 : break;
154 :
155 : case kmldom::Type_Polygon:
156 0 : poKmlPolygon = AsPolygon ( poKmlGeometry );
157 0 : poKmlPolygon->set_extrude ( nExtrude );
158 0 : break;
159 :
160 : case kmldom::Type_MultiGeometry:
161 0 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
162 :
163 0 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
164 0 : for ( i = 0; i < nGeom; i++ ) {
165 : ogr2extrude_rec ( nExtrude,
166 : poKmlMultiGeometry->
167 0 : get_geometry_array_at ( i ) );
168 : }
169 : break;
170 :
171 : default:
172 : break;
173 :
174 0 : }
175 0 : }
176 :
177 0 : void ogr2tessellate_rec (
178 : int nTessellate,
179 : GeometryPtr poKmlGeometry )
180 : {
181 :
182 0 : LineStringPtr poKmlLineString;
183 0 : PolygonPtr poKmlPolygon;
184 0 : MultiGeometryPtr poKmlMultiGeometry;
185 :
186 : size_t nGeom;
187 : size_t i;
188 :
189 0 : switch ( poKmlGeometry->Type ( ) ) {
190 :
191 : case kmldom::Type_Point:
192 0 : break;
193 :
194 : case kmldom::Type_LineString:
195 0 : poKmlLineString = AsLineString ( poKmlGeometry );
196 0 : poKmlLineString->set_tessellate ( nTessellate );
197 0 : break;
198 :
199 : case kmldom::Type_LinearRing:
200 0 : break;
201 :
202 : case kmldom::Type_Polygon:
203 0 : poKmlPolygon = AsPolygon ( poKmlGeometry );
204 :
205 0 : poKmlPolygon->set_tessellate ( nTessellate );
206 0 : break;
207 :
208 : case kmldom::Type_MultiGeometry:
209 0 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
210 :
211 0 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
212 0 : for ( i = 0; i < nGeom; i++ ) {
213 : ogr2tessellate_rec ( nTessellate,
214 : poKmlMultiGeometry->
215 0 : get_geometry_array_at ( i ) );
216 : }
217 :
218 : break;
219 :
220 : default:
221 : break;
222 :
223 0 : }
224 0 : }
225 :
226 :
227 : /************************************************************************/
228 : /* OGRLIBKMLSanitizeUTF8String() */
229 : /************************************************************************/
230 :
231 9 : static char* OGRLIBKMLSanitizeUTF8String(const char* pszString)
232 : {
233 9 : if (!CPLIsUTF8(pszString, -1) &&
234 : CSLTestBoolean(CPLGetConfigOption("OGR_FORCE_ASCII", "YES")))
235 : {
236 : static int bFirstTime = TRUE;
237 0 : if (bFirstTime)
238 : {
239 0 : bFirstTime = FALSE;
240 : CPLError(CE_Warning, CPLE_AppDefined,
241 : "%s is not a valid UTF-8 string. Forcing it to ASCII.\n"
242 : "If you still want the original string and change the XML file encoding\n"
243 : "afterwards, you can define OGR_FORCE_ASCII=NO as configuration option.\n"
244 0 : "This warning won't be issued anymore", pszString);
245 : }
246 : else
247 : {
248 : CPLDebug("OGR", "%s is not a valid UTF-8 string. Forcing it to ASCII",
249 0 : pszString);
250 : }
251 0 : return CPLForceToASCII(pszString, -1, '?');
252 : }
253 : else
254 9 : return CPLStrdup(pszString);
255 : }
256 :
257 : /******************************************************************************
258 : function to output ogr fields in kml
259 :
260 : args:
261 : poOgrFeat pointer to the feature the field is in
262 : poOgrLayer pointer to the layer the feature is in
263 : poKmlFactory pointer to the libkml dom factory
264 : poKmlPlacemark pointer to the placemark to add to
265 :
266 : returns:
267 : nothing
268 :
269 : env vars:
270 : LIBKML_TIMESTAMP_FIELD default: OFTDate or OFTDateTime named timestamp
271 : LIBKML_TIMESPAN_BEGIN_FIELD default: OFTDate or OFTDateTime named begin
272 : LIBKML_TIMESPAN_END_FIELD default: OFTDate or OFTDateTime named end
273 : LIBKML_DESCRIPTION_FIELD default: none
274 : LIBKML_NAME_FIELD default: OFTString field named name
275 :
276 :
277 : ******************************************************************************/
278 :
279 :
280 :
281 27 : void field2kml (
282 : OGRFeature * poOgrFeat,
283 : OGRLIBKMLLayer * poOgrLayer,
284 : KmlFactory * poKmlFactory,
285 : PlacemarkPtr poKmlPlacemark )
286 : {
287 : int i;
288 :
289 27 : SchemaDataPtr poKmlSchemaData = poKmlFactory->CreateSchemaData ( );
290 27 : SchemaPtr poKmlSchema = poOgrLayer->GetKmlSchema ( );
291 :
292 : /***** set the url to the schema *****/
293 :
294 27 : if ( poKmlSchema && poKmlSchema->has_id ( ) ) {
295 27 : std::string oKmlSchemaID = poKmlSchema->get_id ( );
296 :
297 :
298 27 : std::string oKmlSchemaURL = "#";
299 27 : oKmlSchemaURL.append ( oKmlSchemaID );
300 :
301 27 : poKmlSchemaData->set_schemaurl ( oKmlSchemaURL );
302 : }
303 :
304 27 : const char *namefield = CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
305 : const char *descfield =
306 27 : CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
307 : const char *tsfield =
308 27 : CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
309 : const char *beginfield =
310 27 : CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
311 27 : const char *endfield = CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
312 : const char *altitudeModefield =
313 27 : CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
314 : const char *tessellatefield =
315 27 : CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
316 : const char *extrudefield =
317 27 : CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
318 : const char *visibilityfield =
319 27 : CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );
320 :
321 27 : TimeSpanPtr poKmlTimeSpan = NULL;
322 :
323 27 : int nFields = poOgrFeat->GetFieldCount ( );
324 27 : int iSkip1 = -1;
325 27 : int iSkip2 = -1;
326 :
327 27 : for ( i = 0; i < nFields; i++ ) {
328 :
329 : /***** if the field is set to skip, do so *****/
330 :
331 72 : if ( i == iSkip1 || i == iSkip2 )
332 0 : continue;
333 :
334 : /***** if the field isn't set just bail now *****/
335 :
336 72 : if ( !poOgrFeat->IsFieldSet ( i ) )
337 63 : continue;
338 :
339 9 : OGRFieldDefn *poOgrFieldDef = poOgrFeat->GetFieldDefnRef ( i );
340 9 : OGRFieldType type = poOgrFieldDef->GetType ( );
341 9 : const char *name = poOgrFieldDef->GetNameRef ( );
342 :
343 9 : SimpleDataPtr poKmlSimpleData = NULL;
344 : int year,
345 : month,
346 : day,
347 : hour,
348 : min,
349 : sec,
350 : tz;
351 :
352 9 : switch ( type ) {
353 :
354 : case OFTString: // String of ASCII chars
355 : {
356 : char* pszUTF8String = OGRLIBKMLSanitizeUTF8String(
357 9 : poOgrFeat->GetFieldAsString ( i ));
358 : /***** name *****/
359 :
360 9 : if ( EQUAL ( name, namefield ) ) {
361 3 : poKmlPlacemark->set_name ( pszUTF8String );
362 3 : CPLFree( pszUTF8String );
363 3 : continue;
364 : }
365 :
366 : /***** description *****/
367 :
368 6 : else if ( EQUAL ( name, descfield ) ) {
369 3 : poKmlPlacemark->set_description ( pszUTF8String );
370 3 : CPLFree( pszUTF8String );
371 3 : continue;
372 : }
373 :
374 : /***** altitudemode *****/
375 :
376 3 : else if ( EQUAL ( name, altitudeModefield ) ) {
377 0 : const char *pszAltitudeMode = pszUTF8String ;
378 :
379 0 : int isGX = FALSE;
380 0 : int iAltitudeMode = kmldom::ALTITUDEMODE_CLAMPTOGROUND;
381 :
382 0 : if ( EQUAL ( pszAltitudeMode, "clampToGround" ) )
383 0 : iAltitudeMode = kmldom::ALTITUDEMODE_CLAMPTOGROUND;
384 :
385 0 : else if ( EQUAL ( pszAltitudeMode, "relativeToGround" ) )
386 0 : iAltitudeMode = kmldom::ALTITUDEMODE_RELATIVETOGROUND;
387 :
388 0 : else if ( EQUAL ( pszAltitudeMode, "absolute" ) )
389 0 : iAltitudeMode = kmldom::ALTITUDEMODE_ABSOLUTE;
390 :
391 0 : else if ( EQUAL ( pszAltitudeMode, "relativeToSeaFloor" ) ) {
392 : iAltitudeMode =
393 0 : kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR;
394 0 : isGX = TRUE;
395 : }
396 :
397 0 : else if ( EQUAL ( pszAltitudeMode, "clampToSeaFloor" ) ) {
398 : iAltitudeMode =
399 0 : kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR;
400 0 : isGX = TRUE;
401 : }
402 :
403 :
404 0 : if ( poKmlPlacemark->has_geometry ( ) ) {
405 : GeometryPtr poKmlGeometry =
406 0 : poKmlPlacemark->get_geometry ( );
407 :
408 : ogr2altitudemode_rec ( poKmlGeometry, iAltitudeMode,
409 0 : isGX );
410 :
411 : }
412 :
413 0 : CPLFree( pszUTF8String );
414 :
415 0 : continue;
416 : }
417 :
418 : /***** timestamp *****/
419 :
420 3 : else if ( EQUAL ( name, tsfield ) ) {
421 :
422 : TimeStampPtr poKmlTimeStamp =
423 0 : poKmlFactory->CreateTimeStamp ( );
424 0 : poKmlTimeStamp->set_when ( pszUTF8String );
425 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeStamp );
426 :
427 0 : CPLFree( pszUTF8String );
428 :
429 0 : continue;
430 : }
431 :
432 : /***** begin *****/
433 :
434 3 : if ( EQUAL ( name, beginfield ) ) {
435 :
436 0 : if ( !poKmlTimeSpan ) {
437 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan ( );
438 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
439 : }
440 :
441 0 : poKmlTimeSpan->set_begin ( pszUTF8String );
442 :
443 0 : CPLFree( pszUTF8String );
444 :
445 0 : continue;
446 :
447 : }
448 :
449 : /***** end *****/
450 :
451 3 : else if ( EQUAL ( name, endfield ) ) {
452 :
453 0 : if ( !poKmlTimeSpan ) {
454 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan ( );
455 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
456 : }
457 :
458 0 : poKmlTimeSpan->set_end ( pszUTF8String );
459 :
460 0 : CPLFree( pszUTF8String );
461 :
462 0 : continue;
463 : }
464 :
465 : /***** other *****/
466 :
467 3 : poKmlSimpleData = poKmlFactory->CreateSimpleData ( );
468 3 : poKmlSimpleData->set_name ( name );
469 6 : poKmlSimpleData->set_text ( pszUTF8String );
470 :
471 3 : CPLFree( pszUTF8String );
472 :
473 3 : break;
474 : }
475 :
476 : case OFTDate: // Date
477 : {
478 : poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
479 0 : &hour, &min, &sec, &tz );
480 :
481 : int iTimeField;
482 :
483 0 : for ( iTimeField = i + 1; iTimeField < nFields; iTimeField++ ) {
484 0 : if ( iTimeField == iSkip1 || iTimeField == iSkip2 )
485 0 : continue;
486 :
487 : OGRFieldDefn *poOgrFieldDef2 =
488 0 : poOgrFeat->GetFieldDefnRef ( i );
489 0 : OGRFieldType type2 = poOgrFieldDef2->GetType ( );
490 0 : const char *name2 = poOgrFieldDef2->GetNameRef ( );
491 :
492 0 : if ( EQUAL ( name2, name ) && type2 == OFTTime &&
493 : ( EQUAL ( name, tsfield ) ||
494 : EQUAL ( name, beginfield ) ||
495 : EQUAL ( name, endfield ) ) ) {
496 :
497 : int year2,
498 : month2,
499 : day2,
500 : hour2,
501 : min2,
502 : sec2,
503 : tz2;
504 :
505 : poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
506 : &month2, &day2, &hour2,
507 0 : &min2, &sec2, &tz2 );
508 :
509 0 : hour = hour2;
510 0 : min = min2;
511 0 : sec = sec2;
512 0 : tz = tz2;
513 :
514 0 : if ( 0 > iSkip1 )
515 0 : iSkip1 = iTimeField;
516 : else
517 0 : iSkip2 = iTimeField;
518 : }
519 : }
520 :
521 0 : goto Do_DateTime;
522 :
523 : }
524 :
525 :
526 : case OFTTime: // Time
527 : {
528 : poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
529 0 : &hour, &min, &sec, &tz );
530 :
531 : int iTimeField;
532 :
533 0 : for ( iTimeField = i + 1; iTimeField < nFields; iTimeField++ ) {
534 0 : if ( iTimeField == iSkip1 || iTimeField == iSkip2 )
535 0 : continue;
536 :
537 : OGRFieldDefn *poOgrFieldDef2 =
538 0 : poOgrFeat->GetFieldDefnRef ( i );
539 0 : OGRFieldType type2 = poOgrFieldDef2->GetType ( );
540 0 : const char *name2 = poOgrFieldDef2->GetNameRef ( );
541 :
542 0 : if ( EQUAL ( name2, name ) && type2 == OFTTime &&
543 : ( EQUAL ( name, tsfield ) ||
544 : EQUAL ( name, beginfield ) ||
545 : EQUAL ( name, endfield ) ) ) {
546 :
547 : int year2,
548 : month2,
549 : day2,
550 : hour2,
551 : min2,
552 : sec2,
553 : tz2;
554 :
555 : poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
556 : &month2, &day2, &hour2,
557 0 : &min2, &sec2, &tz2 );
558 :
559 0 : year = year2;
560 0 : month = month2;
561 0 : day = day2;
562 :
563 0 : if ( 0 > iSkip1 )
564 0 : iSkip1 = iTimeField;
565 : else
566 0 : iSkip2 = iTimeField;
567 : }
568 : }
569 :
570 0 : goto Do_DateTime;
571 :
572 : }
573 :
574 : case OFTDateTime: // Date and Time
575 : {
576 : poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
577 0 : &hour, &min, &sec, &tz );
578 :
579 : Do_DateTime:
580 : /***** timestamp *****/
581 :
582 0 : if ( EQUAL ( name, tsfield ) ) {
583 :
584 : char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
585 0 : min, sec, tz );
586 :
587 : TimeStampPtr poKmlTimeStamp =
588 0 : poKmlFactory->CreateTimeStamp ( );
589 0 : poKmlTimeStamp->set_when ( timebuf );
590 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeStamp );
591 0 : CPLFree( timebuf );
592 :
593 0 : continue;
594 : }
595 :
596 : /***** begin *****/
597 :
598 0 : if ( EQUAL ( name, beginfield ) ) {
599 :
600 : char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
601 0 : min, sec, tz );
602 :
603 0 : if ( !poKmlTimeSpan ) {
604 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan ( );
605 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
606 : }
607 :
608 0 : poKmlTimeSpan->set_begin ( timebuf );
609 0 : CPLFree( timebuf );
610 :
611 0 : continue;
612 :
613 : }
614 :
615 : /***** end *****/
616 :
617 0 : else if ( EQUAL ( name, endfield ) ) {
618 :
619 : char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
620 0 : min, sec, tz );
621 :
622 :
623 0 : if ( !poKmlTimeSpan ) {
624 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan ( );
625 0 : poKmlPlacemark->set_timeprimitive ( poKmlTimeSpan );
626 : }
627 :
628 0 : poKmlTimeSpan->set_end ( timebuf );
629 0 : CPLFree( timebuf );
630 :
631 0 : continue;
632 : }
633 :
634 : /***** other *****/
635 :
636 0 : poKmlSimpleData = poKmlFactory->CreateSimpleData ( );
637 0 : poKmlSimpleData->set_name ( name );
638 : poKmlSimpleData->set_text ( poOgrFeat->
639 0 : GetFieldAsString ( i ) );
640 :
641 0 : break;
642 : }
643 :
644 : case OFTInteger: // Simple 32bit integer
645 :
646 : /***** extrude *****/
647 :
648 0 : if ( EQUAL ( name, extrudefield ) ) {
649 :
650 0 : if ( poKmlPlacemark->has_geometry ( )
651 : && -1 < poOgrFeat->GetFieldAsInteger ( i ) ) {
652 : GeometryPtr poKmlGeometry =
653 0 : poKmlPlacemark->get_geometry ( );
654 : ogr2extrude_rec ( poOgrFeat->GetFieldAsInteger ( i ),
655 0 : poKmlGeometry );
656 : }
657 0 : continue;
658 : }
659 :
660 : /***** tessellate *****/
661 :
662 :
663 0 : if ( EQUAL ( name, tessellatefield ) ) {
664 :
665 0 : if ( poKmlPlacemark->has_geometry ( )
666 : && -1 < poOgrFeat->GetFieldAsInteger ( i ) ) {
667 : GeometryPtr poKmlGeometry =
668 0 : poKmlPlacemark->get_geometry ( );
669 : ogr2tessellate_rec ( poOgrFeat->GetFieldAsInteger ( i ),
670 0 : poKmlGeometry );
671 : }
672 :
673 0 : continue;
674 : }
675 :
676 :
677 : /***** visibility *****/
678 :
679 0 : if ( EQUAL ( name, visibilityfield ) ) {
680 0 : if ( -1 < poOgrFeat->GetFieldAsInteger ( i ) )
681 : poKmlPlacemark->set_visibility ( poOgrFeat->
682 0 : GetFieldAsInteger ( i ) );
683 :
684 0 : continue;
685 : }
686 :
687 : /***** other *****/
688 :
689 0 : poKmlSimpleData = poKmlFactory->CreateSimpleData ( );
690 0 : poKmlSimpleData->set_name ( name );
691 0 : poKmlSimpleData->set_text ( poOgrFeat->GetFieldAsString ( i ) );
692 :
693 0 : break;
694 :
695 : case OFTReal: // Double Precision floating point
696 : {
697 0 : poKmlSimpleData = poKmlFactory->CreateSimpleData ( );
698 0 : poKmlSimpleData->set_name ( name );
699 :
700 0 : char* pszStr = CPLStrdup( poOgrFeat->GetFieldAsString ( i ) );
701 : /* Use point as decimal separator */
702 0 : char* pszComma = strchr(pszStr, ',');
703 0 : if (pszComma)
704 0 : *pszComma = '.';
705 0 : poKmlSimpleData->set_text ( pszStr );
706 0 : CPLFree(pszStr);
707 :
708 0 : break;
709 : }
710 :
711 : case OFTStringList: // Array of strings
712 : case OFTIntegerList: // List of 32bit integers
713 : case OFTRealList: // List of doubles
714 : case OFTBinary: // Raw Binary data
715 : case OFTWideStringList: // deprecated
716 : default:
717 :
718 : /***** other *****/
719 :
720 0 : poKmlSimpleData = poKmlFactory->CreateSimpleData ( );
721 0 : poKmlSimpleData->set_name ( name );
722 0 : poKmlSimpleData->set_text ( poOgrFeat->GetFieldAsString ( i ) );
723 :
724 : break;
725 : }
726 3 : poKmlSchemaData->add_simpledata ( poKmlSimpleData );
727 : }
728 :
729 : /***** dont add it to the placemark unless there is data *****/
730 :
731 27 : if ( poKmlSchemaData->get_simpledata_array_size ( ) > 0 ) {
732 : ExtendedDataPtr poKmlExtendedData =
733 3 : poKmlFactory->CreateExtendedData ( );
734 3 : poKmlExtendedData->add_schemadata ( poKmlSchemaData );
735 3 : poKmlPlacemark->set_extendeddata ( poKmlExtendedData );
736 : }
737 :
738 27 : return;
739 : }
740 :
741 : /******************************************************************************
742 : recursive function to read altitude mode from the geometry
743 : ******************************************************************************/
744 :
745 374 : int kml2altitudemode_rec (
746 : GeometryPtr poKmlGeometry,
747 : int *pnAltitudeMode,
748 : int *pbIsGX )
749 : {
750 :
751 374 : PointPtr poKmlPoint;
752 374 : LineStringPtr poKmlLineString;
753 374 : PolygonPtr poKmlPolygon;
754 374 : MultiGeometryPtr poKmlMultiGeometry;
755 :
756 : size_t nGeom;
757 : size_t i;
758 :
759 374 : switch ( poKmlGeometry->Type ( ) ) {
760 :
761 : case kmldom::Type_Point:
762 91 : poKmlPoint = AsPoint ( poKmlGeometry );
763 :
764 91 : if ( poKmlPoint->has_altitudemode ( ) ) {
765 30 : *pnAltitudeMode = poKmlPoint->get_altitudemode ( );
766 30 : return TRUE;
767 : }
768 61 : else if ( poKmlPoint->has_gx_altitudemode ( ) ) {
769 0 : *pnAltitudeMode = poKmlPoint->get_gx_altitudemode ( );
770 0 : *pbIsGX = TRUE;
771 0 : return TRUE;
772 : }
773 :
774 61 : break;
775 :
776 : case kmldom::Type_LineString:
777 105 : poKmlLineString = AsLineString ( poKmlGeometry );
778 :
779 105 : if ( poKmlLineString->has_altitudemode ( ) ) {
780 54 : *pnAltitudeMode = poKmlLineString->get_altitudemode ( );
781 54 : return TRUE;
782 : }
783 51 : else if ( poKmlLineString->has_gx_altitudemode ( ) ) {
784 0 : *pnAltitudeMode = poKmlLineString->get_gx_altitudemode ( );
785 0 : *pbIsGX = TRUE;
786 0 : return TRUE;
787 : }
788 51 : break;
789 :
790 : case kmldom::Type_LinearRing:
791 3 : break;
792 :
793 : case kmldom::Type_Polygon:
794 156 : poKmlPolygon = AsPolygon ( poKmlGeometry );
795 :
796 156 : if ( poKmlPolygon->has_altitudemode ( ) ) {
797 137 : *pnAltitudeMode = poKmlPolygon->get_altitudemode ( );
798 137 : return TRUE;
799 : }
800 19 : else if ( poKmlPolygon->has_gx_altitudemode ( ) ) {
801 0 : *pnAltitudeMode = poKmlPolygon->get_gx_altitudemode ( );
802 0 : *pbIsGX = TRUE;
803 0 : return TRUE;
804 : }
805 :
806 19 : break;
807 :
808 : case kmldom::Type_MultiGeometry:
809 19 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
810 :
811 19 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
812 50 : for ( i = 0; i < nGeom; i++ ) {
813 31 : if ( kml2altitudemode_rec ( poKmlMultiGeometry->
814 : get_geometry_array_at ( i ),
815 : pnAltitudeMode, pbIsGX ) )
816 0 : return TRUE;
817 : }
818 :
819 : break;
820 :
821 : default:
822 : break;
823 :
824 : }
825 :
826 153 : return FALSE;
827 : }
828 :
829 : /******************************************************************************
830 : recursive function to read extrude from the geometry
831 : ******************************************************************************/
832 :
833 374 : int kml2extrude_rec (
834 : GeometryPtr poKmlGeometry,
835 : int *pnExtrude )
836 : {
837 :
838 374 : PointPtr poKmlPoint;
839 374 : LineStringPtr poKmlLineString;
840 374 : PolygonPtr poKmlPolygon;
841 374 : MultiGeometryPtr poKmlMultiGeometry;
842 :
843 : size_t nGeom;
844 : size_t i;
845 :
846 374 : switch ( poKmlGeometry->Type ( ) ) {
847 :
848 : case kmldom::Type_Point:
849 91 : poKmlPoint = AsPoint ( poKmlGeometry );
850 :
851 91 : if ( poKmlPoint->has_extrude ( ) ) {
852 15 : *pnExtrude = poKmlPoint->get_extrude ( );
853 15 : return TRUE;
854 : }
855 :
856 76 : break;
857 :
858 : case kmldom::Type_LineString:
859 105 : poKmlLineString = AsLineString ( poKmlGeometry );
860 :
861 105 : if ( poKmlLineString->has_extrude ( ) ) {
862 26 : *pnExtrude = poKmlLineString->get_extrude ( );
863 26 : return TRUE;
864 : }
865 :
866 79 : break;
867 :
868 : case kmldom::Type_LinearRing:
869 3 : break;
870 :
871 : case kmldom::Type_Polygon:
872 156 : poKmlPolygon = AsPolygon ( poKmlGeometry );
873 :
874 156 : if ( poKmlPolygon->has_extrude ( ) ) {
875 107 : *pnExtrude = poKmlPolygon->get_extrude ( );
876 107 : return TRUE;
877 : }
878 :
879 49 : break;
880 :
881 : case kmldom::Type_MultiGeometry:
882 19 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
883 :
884 19 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
885 50 : for ( i = 0; i < nGeom; i++ ) {
886 31 : if ( kml2extrude_rec ( poKmlMultiGeometry->
887 : get_geometry_array_at ( i ), pnExtrude ) )
888 0 : return TRUE;
889 : }
890 :
891 : break;
892 :
893 : default:
894 : break;
895 :
896 : }
897 :
898 226 : return FALSE;
899 : }
900 :
901 : /******************************************************************************
902 : recursive function to read tessellate from the geometry
903 : ******************************************************************************/
904 :
905 374 : int kml2tessellate_rec (
906 : GeometryPtr poKmlGeometry,
907 : int *pnTessellate )
908 : {
909 :
910 374 : LineStringPtr poKmlLineString;
911 374 : PolygonPtr poKmlPolygon;
912 374 : MultiGeometryPtr poKmlMultiGeometry;
913 :
914 : size_t nGeom;
915 : size_t i;
916 :
917 374 : switch ( poKmlGeometry->Type ( ) ) {
918 :
919 : case kmldom::Type_Point:
920 91 : break;
921 :
922 : case kmldom::Type_LineString:
923 105 : poKmlLineString = AsLineString ( poKmlGeometry );
924 :
925 105 : if ( poKmlLineString->has_tessellate ( ) ) {
926 88 : *pnTessellate = poKmlLineString->get_tessellate ( );
927 88 : return TRUE;
928 : }
929 :
930 17 : break;
931 :
932 : case kmldom::Type_LinearRing:
933 3 : break;
934 :
935 : case kmldom::Type_Polygon:
936 156 : poKmlPolygon = AsPolygon ( poKmlGeometry );
937 :
938 156 : if ( poKmlPolygon->has_tessellate ( ) ) {
939 56 : *pnTessellate = poKmlPolygon->get_tessellate ( );
940 56 : return TRUE;
941 : }
942 :
943 100 : break;
944 :
945 : case kmldom::Type_MultiGeometry:
946 19 : poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry );
947 :
948 19 : nGeom = poKmlMultiGeometry->get_geometry_array_size ( );
949 50 : for ( i = 0; i < nGeom; i++ ) {
950 31 : if ( kml2tessellate_rec ( poKmlMultiGeometry->
951 : get_geometry_array_at ( i ),
952 : pnTessellate ) )
953 0 : return TRUE;
954 : }
955 :
956 : break;
957 :
958 : default:
959 : break;
960 :
961 : }
962 :
963 230 : return FALSE;
964 : }
965 :
966 : /******************************************************************************
967 : function to read kml into ogr fields
968 : ******************************************************************************/
969 :
970 376 : void kml2field (
971 : OGRFeature * poOgrFeat,
972 : FeaturePtr poKmlFeature )
973 : {
974 :
975 376 : const char *namefield = CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
976 : const char *descfield =
977 376 : CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
978 : const char *tsfield =
979 376 : CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
980 : const char *beginfield =
981 376 : CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
982 376 : const char *endfield = CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
983 : const char *altitudeModefield =
984 376 : CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
985 : const char *tessellatefield =
986 376 : CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
987 : const char *extrudefield =
988 376 : CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
989 : const char *visibilityfield =
990 376 : CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );
991 : const char *drawOrderfield =
992 376 : CPLGetConfigOption ( "LIBKML_DRAWORDER_FIELD", "drawOrder" );
993 : const char *iconfield =
994 376 : CPLGetConfigOption ( "LIBKML_ICON_FIELD", "icon" );
995 :
996 : /***** name *****/
997 :
998 376 : if ( poKmlFeature->has_name ( ) ) {
999 328 : const std::string oKmlName = poKmlFeature->get_name ( );
1000 328 : int iField = poOgrFeat->GetFieldIndex ( namefield );
1001 :
1002 328 : if ( iField > -1 )
1003 328 : poOgrFeat->SetField ( iField, oKmlName.c_str ( ) );
1004 : }
1005 :
1006 : /***** description *****/
1007 :
1008 376 : if ( poKmlFeature->has_description ( ) ) {
1009 173 : const std::string oKmlDesc = poKmlFeature->get_description ( );
1010 173 : int iField = poOgrFeat->GetFieldIndex ( descfield );
1011 :
1012 173 : if ( iField > -1 )
1013 173 : poOgrFeat->SetField ( iField, oKmlDesc.c_str ( ) );
1014 : }
1015 :
1016 376 : if ( poKmlFeature->has_timeprimitive ( ) ) {
1017 : TimePrimitivePtr poKmlTimePrimitive =
1018 0 : poKmlFeature->get_timeprimitive ( );
1019 :
1020 : /***** timestamp *****/
1021 :
1022 0 : if ( poKmlTimePrimitive->IsA ( kmldom::Type_TimeStamp ) ) {
1023 0 : TimeStampPtr poKmlTimeStamp = AsTimeStamp ( poKmlTimePrimitive );
1024 :
1025 0 : if ( poKmlTimeStamp->has_when ( ) ) {
1026 0 : const std::string oKmlWhen = poKmlTimeStamp->get_when ( );
1027 :
1028 :
1029 0 : int iField = poOgrFeat->GetFieldIndex ( tsfield );
1030 :
1031 0 : if ( iField > -1 ) {
1032 : int nYear,
1033 : nMonth,
1034 : nDay,
1035 : nHour,
1036 : nMinute,
1037 : nTZ;
1038 : float fSecond;
1039 :
1040 0 : if ( OGRParseXMLDateTime
1041 : ( oKmlWhen.c_str ( ), &nYear, &nMonth, &nDay, &nHour,
1042 : &nMinute, &fSecond, &nTZ ) )
1043 : poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
1044 : nHour, nMinute, ( int )fSecond,
1045 0 : nTZ );
1046 0 : }
1047 0 : }
1048 : }
1049 :
1050 : /***** timespan *****/
1051 :
1052 0 : if ( poKmlTimePrimitive->IsA ( kmldom::Type_TimeSpan ) ) {
1053 0 : TimeSpanPtr poKmlTimeSpan = AsTimeSpan ( poKmlTimePrimitive );
1054 :
1055 : /***** begin *****/
1056 :
1057 0 : if ( poKmlTimeSpan->has_begin ( ) ) {
1058 0 : const std::string oKmlWhen = poKmlTimeSpan->get_begin ( );
1059 :
1060 :
1061 0 : int iField = poOgrFeat->GetFieldIndex ( beginfield );
1062 :
1063 0 : if ( iField > -1 ) {
1064 : int nYear,
1065 : nMonth,
1066 : nDay,
1067 : nHour,
1068 : nMinute,
1069 : nTZ;
1070 : float fSecond;
1071 :
1072 0 : if ( OGRParseXMLDateTime
1073 : ( oKmlWhen.c_str ( ), &nYear, &nMonth, &nDay, &nHour,
1074 : &nMinute, &fSecond, &nTZ ) )
1075 : poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
1076 : nHour, nMinute, ( int )fSecond,
1077 0 : nTZ );
1078 0 : }
1079 : }
1080 :
1081 : /***** end *****/
1082 :
1083 0 : if ( poKmlTimeSpan->has_end ( ) ) {
1084 0 : const std::string oKmlWhen = poKmlTimeSpan->get_end ( );
1085 :
1086 :
1087 0 : int iField = poOgrFeat->GetFieldIndex ( endfield );
1088 :
1089 0 : if ( iField > -1 ) {
1090 : int nYear,
1091 : nMonth,
1092 : nDay,
1093 : nHour,
1094 : nMinute,
1095 : nTZ;
1096 : float fSecond;
1097 :
1098 0 : if ( OGRParseXMLDateTime
1099 : ( oKmlWhen.c_str ( ), &nYear, &nMonth, &nDay, &nHour,
1100 : &nMinute, &fSecond, &nTZ ) )
1101 : poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
1102 : nHour, nMinute, ( int )fSecond,
1103 0 : nTZ );
1104 0 : }
1105 0 : }
1106 0 : }
1107 : }
1108 :
1109 :
1110 : /***** placemark *****/
1111 376 : PlacemarkPtr poKmlPlacemark = AsPlacemark ( poKmlFeature );
1112 376 : GroundOverlayPtr poKmlGroundOverlay = AsGroundOverlay ( poKmlFeature );
1113 376 : if ( poKmlPlacemark && poKmlPlacemark->has_geometry ( ) ) {
1114 343 : GeometryPtr poKmlGeometry = poKmlPlacemark->get_geometry ( );
1115 :
1116 : /***** altitudeMode *****/
1117 :
1118 :
1119 343 : int bIsGX = FALSE;
1120 343 : int nAltitudeMode = -1;
1121 :
1122 343 : int iField = poOgrFeat->GetFieldIndex ( altitudeModefield );
1123 :
1124 343 : if ( iField > -1 ) {
1125 :
1126 343 : if ( kml2altitudemode_rec ( poKmlGeometry,
1127 : &nAltitudeMode, &bIsGX ) ) {
1128 :
1129 221 : if ( !bIsGX ) {
1130 :
1131 221 : switch ( nAltitudeMode ) {
1132 : case kmldom::ALTITUDEMODE_CLAMPTOGROUND:
1133 0 : poOgrFeat->SetField ( iField, "clampToGround" );
1134 0 : break;
1135 :
1136 : case kmldom::ALTITUDEMODE_RELATIVETOGROUND:
1137 163 : poOgrFeat->SetField ( iField, "relativeToGround" );
1138 163 : break;
1139 :
1140 : case kmldom::ALTITUDEMODE_ABSOLUTE:
1141 58 : poOgrFeat->SetField ( iField, "absolute" );
1142 : break;
1143 :
1144 : }
1145 : }
1146 :
1147 : else {
1148 0 : switch ( nAltitudeMode ) {
1149 : case kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR:
1150 0 : poOgrFeat->SetField ( iField, "relativeToSeaFloor" );
1151 0 : break;
1152 :
1153 : case kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR:
1154 0 : poOgrFeat->SetField ( iField, "clampToSeaFloor" );
1155 : break;
1156 : }
1157 :
1158 : }
1159 : }
1160 :
1161 : }
1162 :
1163 : /***** tessellate *****/
1164 :
1165 343 : int nTessellate = -1;
1166 :
1167 343 : kml2tessellate_rec ( poKmlGeometry, &nTessellate );
1168 :
1169 343 : iField = poOgrFeat->GetFieldIndex ( tessellatefield );
1170 343 : if ( iField > -1 )
1171 343 : poOgrFeat->SetField ( iField, nTessellate );
1172 :
1173 : /***** extrude *****/
1174 :
1175 343 : int nExtrude = -1;
1176 :
1177 343 : kml2extrude_rec ( poKmlGeometry, &nExtrude );
1178 :
1179 343 : iField = poOgrFeat->GetFieldIndex ( extrudefield );
1180 343 : if ( iField > -1 )
1181 343 : poOgrFeat->SetField ( iField, nExtrude );
1182 :
1183 : }
1184 :
1185 : /***** ground overlay *****/
1186 :
1187 33 : else if ( poKmlGroundOverlay ) {
1188 :
1189 : /***** icon *****/
1190 :
1191 18 : int iField = poOgrFeat->GetFieldIndex ( iconfield );
1192 18 : if ( iField > -1 ) {
1193 :
1194 18 : if ( poKmlGroundOverlay->has_icon ( ) ) {
1195 18 : IconPtr icon = poKmlGroundOverlay->get_icon ( );
1196 18 : if ( icon->has_href ( ) ) {
1197 18 : poOgrFeat->SetField ( iField, icon->get_href ( ).c_str ( ) );
1198 18 : }
1199 : }
1200 : }
1201 :
1202 : /***** drawOrder *****/
1203 :
1204 :
1205 18 : iField = poOgrFeat->GetFieldIndex ( drawOrderfield );
1206 18 : if ( iField > -1 ) {
1207 :
1208 18 : if ( poKmlGroundOverlay->has_draworder ( ) ) {
1209 0 : poOgrFeat->SetField ( iField, poKmlGroundOverlay->get_draworder ( ) );
1210 : }
1211 : }
1212 :
1213 : /***** altitudeMode *****/
1214 :
1215 18 : iField = poOgrFeat->GetFieldIndex ( altitudeModefield );
1216 :
1217 18 : if ( iField > -1 ) {
1218 :
1219 18 : if ( poKmlGroundOverlay->has_altitudemode ( ) ) {
1220 0 : switch ( poKmlGroundOverlay->get_altitudemode ( ) ) {
1221 : case kmldom::ALTITUDEMODE_CLAMPTOGROUND:
1222 0 : poOgrFeat->SetField ( iField, "clampToGround" );
1223 0 : break;
1224 :
1225 : case kmldom::ALTITUDEMODE_RELATIVETOGROUND:
1226 0 : poOgrFeat->SetField ( iField, "relativeToGround" );
1227 0 : break;
1228 :
1229 : case kmldom::ALTITUDEMODE_ABSOLUTE:
1230 0 : poOgrFeat->SetField ( iField, "absolute" );
1231 : break;
1232 :
1233 : }
1234 18 : } else if ( poKmlGroundOverlay->has_gx_altitudemode ( ) ) {
1235 0 : switch ( poKmlGroundOverlay->get_gx_altitudemode ( ) ) {
1236 : case kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR:
1237 0 : poOgrFeat->SetField ( iField, "relativeToSeaFloor" );
1238 0 : break;
1239 :
1240 : case kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR:
1241 0 : poOgrFeat->SetField ( iField, "clampToSeaFloor" );
1242 : break;
1243 : }
1244 : }
1245 :
1246 : }
1247 : }
1248 :
1249 : /***** visibility *****/
1250 :
1251 376 : int nVisibility = -1;
1252 :
1253 376 : if ( poKmlFeature->has_visibility ( ) )
1254 287 : nVisibility = poKmlFeature->get_visibility ( );
1255 :
1256 376 : int iField = poOgrFeat->GetFieldIndex ( visibilityfield );
1257 :
1258 376 : if ( iField > -1 )
1259 376 : poOgrFeat->SetField ( iField, nVisibility );
1260 :
1261 376 : ExtendedDataPtr poKmlExtendedData = NULL;
1262 :
1263 376 : if ( poKmlFeature->has_extendeddata ( ) ) {
1264 5 : poKmlExtendedData = poKmlFeature->get_extendeddata ( );
1265 :
1266 : /***** loop over the schemadata_arrays *****/
1267 :
1268 5 : size_t nSchemaData = poKmlExtendedData->get_schemadata_array_size ( );
1269 :
1270 : size_t iSchemaData;
1271 :
1272 10 : for ( iSchemaData = 0; iSchemaData < nSchemaData; iSchemaData++ ) {
1273 : SchemaDataPtr poKmlSchemaData =
1274 5 : poKmlExtendedData->get_schemadata_array_at ( iSchemaData );
1275 :
1276 : /***** loop over the simpledata array *****/
1277 :
1278 : size_t nSimpleData =
1279 5 : poKmlSchemaData->get_simpledata_array_size ( );
1280 :
1281 : size_t iSimpleData;
1282 :
1283 10 : for ( iSimpleData = 0; iSimpleData < nSimpleData; iSimpleData++ ) {
1284 : SimpleDataPtr poKmlSimpleData =
1285 5 : poKmlSchemaData->get_simpledata_array_at ( iSimpleData );
1286 :
1287 : /***** find the field index *****/
1288 :
1289 5 : int iField = -1;
1290 :
1291 5 : if ( poKmlSimpleData->has_name ( ) ) {
1292 5 : const string oName = poKmlSimpleData->get_name ( );
1293 5 : const char *pszName = oName.c_str ( );
1294 :
1295 5 : iField = poOgrFeat->GetFieldIndex ( pszName );
1296 : }
1297 :
1298 : /***** if it has trxt set the field *****/
1299 :
1300 5 : if ( iField > -1 && poKmlSimpleData->has_text ( ) ) {
1301 5 : string oText = poKmlSimpleData->get_text ( );
1302 :
1303 : /* SerializePretty() adds a new line before the data */
1304 : /* ands trailing spaces. I believe this is wrong */
1305 : /* as it breaks round-tripping */
1306 :
1307 : /* Trim trailing spaces */
1308 42 : while (oText.size() != 0 && oText[oText.size()-1] == ' ')
1309 32 : oText.resize(oText.size()-1);
1310 :
1311 : /* Skip leading newline and spaces */
1312 5 : const char* pszText = oText.c_str ( );
1313 5 : if (pszText[0] == '\n')
1314 3 : pszText ++;
1315 10 : while (pszText[0] == ' ')
1316 0 : pszText ++;
1317 :
1318 5 : poOgrFeat->SetField ( iField, pszText );
1319 : }
1320 : }
1321 : }
1322 :
1323 5 : if (nSchemaData == 0 && poKmlExtendedData->get_data_array_size() > 0 )
1324 : {
1325 : int bLaunderFieldNames =
1326 0 : CSLTestBoolean(CPLGetConfigOption("LIBKML_LAUNDER_FIELD_NAMES", "YES"));
1327 0 : size_t nDataArraySize = poKmlExtendedData->get_data_array_size();
1328 0 : for(size_t i=0; i < nDataArraySize; i++)
1329 : {
1330 0 : const DataPtr& data = poKmlExtendedData->get_data_array_at(i);
1331 0 : if (data->has_name() && data->has_value())
1332 : {
1333 0 : CPLString osName = data->get_name();
1334 0 : if (bLaunderFieldNames)
1335 0 : osName = OGRLIBKMLLayer::LaunderFieldNames(osName);
1336 0 : int iField = poOgrFeat->GetFieldIndex ( osName );
1337 0 : if (iField >= 0)
1338 : {
1339 0 : poOgrFeat->SetField ( iField, data->get_value().c_str() );
1340 0 : }
1341 : }
1342 : }
1343 : }
1344 376 : }
1345 :
1346 376 : }
1347 :
1348 : /******************************************************************************
1349 : function create a simplefield from a FieldDefn
1350 : ******************************************************************************/
1351 :
1352 9 : SimpleFieldPtr FieldDef2kml (
1353 : OGRFieldDefn * poOgrFieldDef,
1354 : KmlFactory * poKmlFactory )
1355 : {
1356 :
1357 9 : SimpleFieldPtr poKmlSimpleField = poKmlFactory->CreateSimpleField ( );
1358 9 : const char *pszFieldName = poOgrFieldDef->GetNameRef ( );
1359 :
1360 9 : poKmlSimpleField->set_name ( pszFieldName );
1361 :
1362 18 : const char *namefield = CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
1363 : const char *descfield =
1364 9 : CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
1365 : const char *tsfield =
1366 9 : CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
1367 : const char *beginfield =
1368 9 : CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
1369 9 : const char *endfield = CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
1370 : const char *altitudeModefield =
1371 9 : CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
1372 : const char *tessellatefield =
1373 9 : CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
1374 : const char *extrudefield =
1375 9 : CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
1376 : const char *visibilityfield =
1377 9 : CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );
1378 :
1379 :
1380 9 : SimpleDataPtr poKmlSimpleData = NULL;
1381 :
1382 9 : switch ( poOgrFieldDef->GetType ( ) ) {
1383 :
1384 : case OFTInteger:
1385 : case OFTIntegerList:
1386 0 : if ( EQUAL ( pszFieldName, tessellatefield ) ||
1387 : EQUAL ( pszFieldName, extrudefield ) ||
1388 : EQUAL ( pszFieldName, visibilityfield ) )
1389 0 : break;
1390 0 : poKmlSimpleField->set_type ( "int" );
1391 0 : return poKmlSimpleField;
1392 : case OFTReal:
1393 : case OFTRealList:
1394 0 : poKmlSimpleField->set_type ( "float" );
1395 0 : return poKmlSimpleField;
1396 : case OFTBinary:
1397 0 : poKmlSimpleField->set_type ( "bool" );
1398 0 : return poKmlSimpleField;
1399 : case OFTString:
1400 : case OFTStringList:
1401 9 : if ( EQUAL ( pszFieldName, namefield ) ||
1402 : EQUAL ( pszFieldName, descfield ) ||
1403 : EQUAL ( pszFieldName, altitudeModefield ) )
1404 6 : break;
1405 3 : poKmlSimpleField->set_type ( "string" );
1406 3 : return poKmlSimpleField;
1407 :
1408 : /***** kml has these types but as timestamp/timespan *****/
1409 :
1410 : case OFTDate:
1411 : case OFTTime:
1412 : case OFTDateTime:
1413 0 : if ( EQUAL ( pszFieldName, tsfield )
1414 : || EQUAL ( pszFieldName, beginfield )
1415 : || EQUAL ( pszFieldName, endfield ) )
1416 0 : break;
1417 : default:
1418 0 : poKmlSimpleField->set_type ( "string" );
1419 0 : return poKmlSimpleField;
1420 : }
1421 :
1422 6 : return NULL;
1423 : }
1424 :
1425 : /******************************************************************************
1426 : function to add the simpleFields in a schema to a featuredefn
1427 : ******************************************************************************/
1428 :
1429 5 : void kml2FeatureDef (
1430 : SchemaPtr poKmlSchema,
1431 : OGRFeatureDefn * poOgrFeatureDefn )
1432 : {
1433 :
1434 5 : size_t nSimpleFields = poKmlSchema->get_simplefield_array_size ( );
1435 : size_t iSimpleField;
1436 :
1437 10 : for ( iSimpleField = 0; iSimpleField < nSimpleFields; iSimpleField++ ) {
1438 : SimpleFieldPtr poKmlSimpleField =
1439 5 : poKmlSchema->get_simplefield_array_at ( iSimpleField );
1440 :
1441 5 : const char *pszType = "string";
1442 5 : string osName = "Unknown";
1443 :
1444 10 : if ( poKmlSimpleField->has_type ( ) ) {
1445 5 : const string oType = poKmlSimpleField->get_type ( );
1446 :
1447 5 : pszType = oType.c_str ( );
1448 : }
1449 :
1450 : /* FIXME? We cannot set displayname as the field name because in kml2field() we make the */
1451 : /* lookup on fields based on their name. We would need some map if we really */
1452 : /* want to use displayname, but that might not be a good idea because displayname */
1453 : /* may have HTML formatting, which makes it impractical when converting to other */
1454 : /* drivers or to make requests */
1455 : /* Example: http://www.jasonbirch.com/files/newt_combined.kml */
1456 : /*if ( poKmlSimpleField->has_displayname ( ) ) {
1457 : osName = poKmlSimpleField->get_displayname ( );
1458 : }
1459 :
1460 5 : else*/ if ( poKmlSimpleField->has_name ( ) ) {
1461 5 : osName = poKmlSimpleField->get_name ( );
1462 : }
1463 :
1464 5 : if ( EQUAL ( pszType, "bool" ) ||
1465 : EQUAL ( pszType, "int" ) ||
1466 : EQUAL ( pszType, "short" ) ||
1467 : EQUAL ( pszType, "ushort" ) ) {
1468 0 : OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTInteger );
1469 0 : poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
1470 : }
1471 5 : else if ( EQUAL ( pszType, "float" ) ||
1472 : EQUAL ( pszType, "double" ) ||
1473 :
1474 : /* a too big uint wouldn't fit in a int, so we map it to OFTReal for now ... */
1475 : EQUAL ( pszType, "uint" ) ) {
1476 0 : OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTReal );
1477 0 : poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
1478 : }
1479 : else /* string, or any other unrecognized type */
1480 : {
1481 5 : OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTString );
1482 5 : poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
1483 : }
1484 : }
1485 :
1486 : return;
1487 2139 : }
|