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