Line data Source code
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 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.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
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : *****************************************************************************/
29 :
30 : #include "libkml_headers.h"
31 : #include "ogrlibkmlfield.h"
32 :
33 : #include <string>
34 :
35 : #include "ogr_feature.h"
36 : #include "ogr_p.h"
37 : #include "ogrsf_frmts.h"
38 :
39 : using kmldom::CameraPtr;
40 : using kmldom::DataPtr;
41 : using kmldom::ExtendedDataPtr;
42 : using kmldom::FeaturePtr;
43 : using kmldom::GeometryPtr;
44 : using kmldom::GroundOverlayPtr;
45 : using kmldom::GxMultiTrackPtr;
46 : using kmldom::GxTrackPtr;
47 : using kmldom::IconPtr;
48 : using kmldom::KmlFactory;
49 : using kmldom::LineStringPtr;
50 : using kmldom::MultiGeometryPtr;
51 : using kmldom::PlacemarkPtr;
52 : using kmldom::PointPtr;
53 : using kmldom::PolygonPtr;
54 : using kmldom::SchemaDataPtr;
55 : using kmldom::SchemaPtr;
56 : using kmldom::SimpleDataPtr;
57 : using kmldom::SimpleFieldPtr;
58 : using kmldom::SnippetPtr;
59 : using kmldom::TimePrimitivePtr;
60 : using kmldom::TimeSpanPtr;
61 : using kmldom::TimeStampPtr;
62 :
63 1 : static void ogr2altitudemode_rec(const GeometryPtr &poKmlGeometry,
64 : int iAltitudeMode, int isGX)
65 : {
66 1 : switch (poKmlGeometry->Type())
67 : {
68 0 : case kmldom::Type_Point:
69 : {
70 0 : PointPtr poKmlPoint = AsPoint(poKmlGeometry);
71 :
72 0 : if (!isGX)
73 0 : poKmlPoint->set_altitudemode(iAltitudeMode);
74 : else
75 0 : poKmlPoint->set_gx_altitudemode(iAltitudeMode);
76 :
77 0 : break;
78 : }
79 0 : case kmldom::Type_LineString:
80 : {
81 0 : LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
82 :
83 0 : if (!isGX)
84 0 : poKmlLineString->set_altitudemode(iAltitudeMode);
85 : else
86 0 : poKmlLineString->set_gx_altitudemode(iAltitudeMode);
87 :
88 0 : break;
89 : }
90 0 : case kmldom::Type_LinearRing:
91 : {
92 0 : break;
93 : }
94 0 : case kmldom::Type_Polygon:
95 : {
96 0 : PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
97 :
98 0 : if (!isGX)
99 0 : poKmlPolygon->set_altitudemode(iAltitudeMode);
100 : else
101 0 : poKmlPolygon->set_gx_altitudemode(iAltitudeMode);
102 :
103 0 : break;
104 : }
105 0 : case kmldom::Type_MultiGeometry:
106 : {
107 : MultiGeometryPtr poKmlMultiGeometry =
108 0 : AsMultiGeometry(poKmlGeometry);
109 :
110 0 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
111 0 : for (size_t i = 0; i < nGeom; i++)
112 : {
113 0 : ogr2altitudemode_rec(
114 : poKmlMultiGeometry->get_geometry_array_at(i), iAltitudeMode,
115 : isGX);
116 : }
117 :
118 0 : break;
119 : }
120 1 : default:
121 : {
122 1 : break;
123 : }
124 : }
125 1 : }
126 :
127 0 : static void ogr2extrude_rec(bool bExtrude, const GeometryPtr &poKmlGeometry)
128 : {
129 0 : switch (poKmlGeometry->Type())
130 : {
131 0 : case kmldom::Type_Point:
132 : {
133 0 : PointPtr const poKmlPoint = AsPoint(poKmlGeometry);
134 0 : poKmlPoint->set_extrude(bExtrude);
135 0 : break;
136 : }
137 0 : case kmldom::Type_LineString:
138 : {
139 0 : LineStringPtr const poKmlLineString = AsLineString(poKmlGeometry);
140 0 : poKmlLineString->set_extrude(bExtrude);
141 0 : break;
142 : }
143 0 : case kmldom::Type_LinearRing:
144 : {
145 0 : break;
146 : }
147 0 : case kmldom::Type_Polygon:
148 : {
149 0 : PolygonPtr const poKmlPolygon = AsPolygon(poKmlGeometry);
150 0 : poKmlPolygon->set_extrude(bExtrude);
151 0 : break;
152 : }
153 0 : case kmldom::Type_MultiGeometry:
154 : {
155 : MultiGeometryPtr const poKmlMultiGeometry =
156 0 : AsMultiGeometry(poKmlGeometry);
157 :
158 0 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
159 0 : for (size_t i = 0; i < nGeom; i++)
160 : {
161 0 : ogr2extrude_rec(bExtrude,
162 : poKmlMultiGeometry->get_geometry_array_at(i));
163 : }
164 0 : break;
165 : }
166 0 : default:
167 : {
168 0 : break;
169 : }
170 : }
171 0 : }
172 :
173 0 : static void ogr2tessellate_rec(bool bTessellate,
174 : const GeometryPtr &poKmlGeometry)
175 : {
176 0 : switch (poKmlGeometry->Type())
177 : {
178 0 : case kmldom::Type_Point:
179 : {
180 0 : break;
181 : }
182 0 : case kmldom::Type_LineString:
183 : {
184 0 : LineStringPtr const poKmlLineString = AsLineString(poKmlGeometry);
185 0 : poKmlLineString->set_tessellate(bTessellate);
186 0 : break;
187 : }
188 0 : case kmldom::Type_LinearRing:
189 : {
190 0 : break;
191 : }
192 0 : case kmldom::Type_Polygon:
193 : {
194 0 : PolygonPtr const poKmlPolygon = AsPolygon(poKmlGeometry);
195 :
196 0 : poKmlPolygon->set_tessellate(bTessellate);
197 0 : break;
198 : }
199 0 : case kmldom::Type_MultiGeometry:
200 : {
201 : MultiGeometryPtr const poKmlMultiGeometry =
202 0 : AsMultiGeometry(poKmlGeometry);
203 :
204 0 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
205 0 : for (size_t i = 0; i < nGeom; i++)
206 : {
207 0 : ogr2tessellate_rec(
208 : bTessellate, poKmlMultiGeometry->get_geometry_array_at(i));
209 : }
210 :
211 0 : break;
212 : }
213 0 : default:
214 : {
215 0 : break;
216 : }
217 : }
218 0 : }
219 :
220 : /************************************************************************/
221 : /* OGRLIBKMLSanitizeUTF8String() */
222 : /************************************************************************/
223 :
224 83 : static char *OGRLIBKMLSanitizeUTF8String(const char *pszString)
225 : {
226 83 : if (!CPLIsUTF8(pszString, -1) &&
227 0 : CPLTestBool(CPLGetConfigOption("OGR_FORCE_ASCII", "YES")))
228 : {
229 : static bool bFirstTime = true;
230 0 : if (bFirstTime)
231 : {
232 0 : bFirstTime = false;
233 0 : CPLError(
234 : CE_Warning, CPLE_AppDefined,
235 : "%s is not a valid UTF-8 string. Forcing it to ASCII. "
236 : "If you still want the original string and change the XML file "
237 : "encoding afterwards, you can define OGR_FORCE_ASCII=NO as "
238 : " configuration option. This warning won't be issued anymore",
239 : pszString);
240 : }
241 : else
242 : {
243 0 : CPLDebug("OGR",
244 : "%s is not a valid UTF-8 string. Forcing it to ASCII",
245 : pszString);
246 : }
247 0 : return CPLForceToASCII(pszString, -1, '?');
248 : }
249 :
250 83 : return CPLStrdup(pszString);
251 : }
252 :
253 : /******************************************************************************
254 : Function to output ogr fields in kml.
255 :
256 : Args:
257 : poOgrFeat pointer to the feature the field is in
258 : poOgrLayer pointer to the layer the feature is in
259 : poKmlFactory pointer to the libkml dom factory
260 : poKmlPlacemark pointer to the placemark to add to
261 :
262 : Returns:
263 : nothing
264 :
265 : env vars:
266 : LIBKML_TIMESTAMP_FIELD default: OFTDate or OFTDateTime named timestamp
267 : LIBKML_TIMESPAN_BEGIN_FIELD default: OFTDate or OFTDateTime named begin
268 : LIBKML_TIMESPAN_END_FIELD default: OFTDate or OFTDateTime named end
269 : LIBKML_DESCRIPTION_FIELD default: none
270 : LIBKML_NAME_FIELD default: OFTString field named name
271 :
272 : ******************************************************************************/
273 :
274 143 : void field2kml(OGRFeature *poOgrFeat, OGRLIBKMLLayer *poOgrLayer,
275 : KmlFactory *poKmlFactory, FeaturePtr poKmlFeature,
276 : int bUseSimpleFieldIn)
277 : {
278 143 : const bool bUseSimpleField = CPL_TO_BOOL(bUseSimpleFieldIn);
279 286 : SchemaDataPtr poKmlSchemaData = nullptr;
280 143 : if (bUseSimpleField)
281 : {
282 142 : poKmlSchemaData = poKmlFactory->CreateSchemaData();
283 284 : SchemaPtr poKmlSchema = poOgrLayer->GetKmlSchema();
284 :
285 : /***** set the url to the schema *****/
286 142 : if (poKmlSchema && poKmlSchema->has_id())
287 : {
288 226 : std::string oKmlSchemaID = poKmlSchema->get_id();
289 226 : std::string oKmlSchemaURL = "#";
290 113 : oKmlSchemaURL.append(oKmlSchemaID);
291 :
292 113 : poKmlSchemaData->set_schemaurl(oKmlSchemaURL);
293 : }
294 : }
295 :
296 : /***** Get the field config *****/
297 : struct fieldconfig oFC;
298 143 : get_fieldconfig(&oFC);
299 :
300 286 : TimeSpanPtr poKmlTimeSpan = nullptr;
301 :
302 143 : const int nFields = poOgrFeat->GetFieldCount();
303 143 : int iSkip1 = -1;
304 143 : int iSkip2 = -1;
305 143 : int iAltitudeMode = kmldom::ALTITUDEMODE_CLAMPTOGROUND;
306 143 : int isGX = false;
307 :
308 286 : ExtendedDataPtr poKmlExtendedData = nullptr;
309 :
310 749 : for (int i = 0; i < nFields; i++)
311 : {
312 : /***** If the field is set to skip, do so *****/
313 606 : if (i == iSkip1 || i == iSkip2)
314 352 : continue;
315 :
316 : /***** If the field isn't set just bail now *****/
317 606 : if (!poOgrFeat->IsFieldSetAndNotNull(i))
318 283 : continue;
319 :
320 323 : OGRFieldDefn *poOgrFieldDef = poOgrFeat->GetFieldDefnRef(i);
321 323 : const OGRFieldType type = poOgrFieldDef->GetType();
322 323 : const char *name = poOgrFieldDef->GetNameRef();
323 :
324 323 : SimpleDataPtr poKmlSimpleData = nullptr;
325 323 : DataPtr poKmlData = nullptr;
326 : OGRField sFieldDT;
327 :
328 : // TODO(schwehr): Refactor to get rid of gotos.
329 323 : switch (type)
330 : {
331 83 : case OFTString: // String of ASCII chars
332 : {
333 : char *const pszUTF8String =
334 83 : OGRLIBKMLSanitizeUTF8String(poOgrFeat->GetFieldAsString(i));
335 83 : if (pszUTF8String[0] == '\0')
336 : {
337 0 : CPLFree(pszUTF8String);
338 0 : continue;
339 : }
340 :
341 : /***** name *****/
342 83 : if (EQUAL(name, oFC.namefield))
343 : {
344 7 : poKmlFeature->set_name(pszUTF8String);
345 7 : CPLFree(pszUTF8String);
346 7 : continue;
347 : }
348 : /***** description *****/
349 76 : else if (EQUAL(name, oFC.descfield))
350 : {
351 4 : poKmlFeature->set_description(pszUTF8String);
352 4 : CPLFree(pszUTF8String);
353 4 : continue;
354 : }
355 : /***** altitudemode *****/
356 72 : else if (EQUAL(name, oFC.altitudeModefield))
357 : {
358 2 : const char *pszAltitudeMode = pszUTF8String;
359 :
360 : iAltitudeMode =
361 2 : kmlAltitudeModeFromString(pszAltitudeMode, isGX);
362 :
363 2 : if (poKmlFeature->IsA(kmldom::Type_Placemark))
364 : {
365 : PlacemarkPtr const poKmlPlacemark =
366 4 : AsPlacemark(poKmlFeature);
367 2 : if (poKmlPlacemark->has_geometry())
368 : {
369 : GeometryPtr poKmlGeometry =
370 2 : poKmlPlacemark->get_geometry();
371 :
372 1 : ogr2altitudemode_rec(poKmlGeometry, iAltitudeMode,
373 : isGX);
374 : }
375 : }
376 :
377 2 : CPLFree(pszUTF8String);
378 :
379 2 : continue;
380 : }
381 : /***** timestamp *****/
382 70 : else if (EQUAL(name, oFC.tsfield))
383 : {
384 : TimeStampPtr poKmlTimeStamp =
385 0 : poKmlFactory->CreateTimeStamp();
386 0 : poKmlTimeStamp->set_when(pszUTF8String);
387 0 : poKmlFeature->set_timeprimitive(poKmlTimeStamp);
388 :
389 0 : CPLFree(pszUTF8String);
390 :
391 0 : continue;
392 : }
393 : /***** begin *****/
394 70 : if (EQUAL(name, oFC.beginfield))
395 : {
396 0 : if (!poKmlTimeSpan)
397 : {
398 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan();
399 0 : poKmlFeature->set_timeprimitive(poKmlTimeSpan);
400 : }
401 :
402 0 : poKmlTimeSpan->set_begin(pszUTF8String);
403 :
404 0 : CPLFree(pszUTF8String);
405 :
406 0 : continue;
407 : }
408 : /***** end *****/
409 70 : else if (EQUAL(name, oFC.endfield))
410 : {
411 0 : if (!poKmlTimeSpan)
412 : {
413 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan();
414 0 : poKmlFeature->set_timeprimitive(poKmlTimeSpan);
415 : }
416 :
417 0 : poKmlTimeSpan->set_end(pszUTF8String);
418 :
419 0 : CPLFree(pszUTF8String);
420 :
421 0 : continue;
422 : }
423 : /***** snippet *****/
424 70 : else if (EQUAL(name, oFC.snippetfield))
425 : {
426 2 : SnippetPtr snippet = poKmlFactory->CreateSnippet();
427 1 : snippet->set_text(pszUTF8String);
428 1 : poKmlFeature->set_snippet(snippet);
429 :
430 1 : CPLFree(pszUTF8String);
431 :
432 1 : continue;
433 : }
434 : /***** other special fields *****/
435 69 : else if (EQUAL(name, oFC.iconfield) ||
436 69 : EQUAL(name, oFC.modelfield) ||
437 67 : EQUAL(name, oFC.networklinkfield) ||
438 64 : EQUAL(name, oFC.networklink_refreshMode_field) ||
439 63 : EQUAL(name, oFC.networklink_viewRefreshMode_field) ||
440 62 : EQUAL(name, oFC.networklink_viewFormat_field) ||
441 61 : EQUAL(name, oFC.networklink_httpQuery_field) ||
442 60 : EQUAL(name, oFC.camera_altitudemode_field) ||
443 58 : EQUAL(name, oFC.photooverlayfield) ||
444 56 : EQUAL(name, oFC.photooverlay_shape_field) ||
445 54 : EQUAL(name, oFC.imagepyramid_gridorigin_field))
446 : {
447 15 : CPLFree(pszUTF8String);
448 :
449 15 : continue;
450 : }
451 :
452 : /***** other *****/
453 :
454 54 : if (bUseSimpleField)
455 : {
456 53 : poKmlSimpleData = poKmlFactory->CreateSimpleData();
457 53 : poKmlSimpleData->set_name(name);
458 53 : poKmlSimpleData->set_text(pszUTF8String);
459 : }
460 : else
461 : {
462 1 : poKmlData = poKmlFactory->CreateData();
463 1 : poKmlData->set_name(name);
464 1 : poKmlData->set_value(pszUTF8String);
465 : }
466 :
467 54 : CPLFree(pszUTF8String);
468 :
469 54 : break;
470 : }
471 :
472 : // This code checks if there's a OFTTime field with the same name
473 : // that could be used to compose a DateTime. Not sure this is really
474 : // supported in OGR data model to have 2 fields with same name.
475 48 : case OFTDate: // Date
476 : {
477 48 : memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i),
478 : sizeof(OGRField));
479 :
480 96 : for (int iTimeField = i + 1; iTimeField < nFields; iTimeField++)
481 : {
482 48 : if (iTimeField == iSkip1 || iTimeField == iSkip2)
483 0 : continue;
484 :
485 : OGRFieldDefn *poOgrFieldDef2 =
486 48 : poOgrFeat->GetFieldDefnRef(i);
487 48 : OGRFieldType type2 = poOgrFieldDef2->GetType();
488 48 : const char *name2 = poOgrFieldDef2->GetNameRef();
489 :
490 48 : if (EQUAL(name2, name) && type2 == OFTTime &&
491 0 : (EQUAL(name, oFC.tsfield) ||
492 0 : EQUAL(name, oFC.beginfield) ||
493 0 : EQUAL(name, oFC.endfield)))
494 : {
495 : const OGRField *const psField2 =
496 0 : poOgrFeat->GetRawFieldRef(iTimeField);
497 0 : sFieldDT.Date.Hour = psField2->Date.Hour;
498 0 : sFieldDT.Date.Minute = psField2->Date.Minute;
499 0 : sFieldDT.Date.Second = psField2->Date.Second;
500 0 : sFieldDT.Date.TZFlag = psField2->Date.TZFlag;
501 :
502 0 : if (0 > iSkip1)
503 0 : iSkip1 = iTimeField;
504 : else
505 0 : iSkip2 = iTimeField;
506 : }
507 : }
508 :
509 48 : goto Do_DateTime;
510 : }
511 :
512 : // This code checks if there's a OFTTime field with the same name
513 : // that could be used to compose a DateTime. Not sure this is really
514 : // supported in OGR data model to have 2 fields with same name.
515 4 : case OFTTime: // Time
516 : {
517 4 : memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i),
518 : sizeof(OGRField));
519 :
520 8 : for (int iTimeField = i + 1; iTimeField < nFields; iTimeField++)
521 : {
522 4 : if (iTimeField == iSkip1 || iTimeField == iSkip2)
523 0 : continue;
524 :
525 : OGRFieldDefn *const poOgrFieldDef2 =
526 4 : poOgrFeat->GetFieldDefnRef(i);
527 4 : OGRFieldType type2 = poOgrFieldDef2->GetType();
528 4 : const char *const name2 = poOgrFieldDef2->GetNameRef();
529 :
530 4 : if (EQUAL(name2, name) && type2 == OFTDate &&
531 0 : (EQUAL(name, oFC.tsfield) ||
532 0 : EQUAL(name, oFC.beginfield) ||
533 0 : EQUAL(name, oFC.endfield)))
534 : {
535 : const OGRField *psField2 =
536 0 : poOgrFeat->GetRawFieldRef(iTimeField);
537 0 : sFieldDT.Date.Year = psField2->Date.Year;
538 0 : sFieldDT.Date.Month = psField2->Date.Month;
539 0 : sFieldDT.Date.Day = psField2->Date.Day;
540 :
541 0 : if (0 > iSkip1)
542 0 : iSkip1 = iTimeField;
543 : else
544 0 : iSkip2 = iTimeField;
545 : }
546 : }
547 :
548 4 : goto Do_DateTime;
549 : }
550 :
551 52 : case OFTDateTime: // Date and Time
552 : {
553 52 : memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i),
554 : sizeof(OGRField));
555 :
556 104 : Do_DateTime:
557 : /***** timestamp *****/
558 104 : if (EQUAL(name, oFC.tsfield))
559 : {
560 0 : char *const timebuf = OGRGetXMLDateTime(&sFieldDT);
561 :
562 : TimeStampPtr poKmlTimeStamp =
563 0 : poKmlFactory->CreateTimeStamp();
564 0 : poKmlTimeStamp->set_when(timebuf);
565 0 : poKmlFeature->set_timeprimitive(poKmlTimeStamp);
566 0 : CPLFree(timebuf);
567 :
568 0 : continue;
569 : }
570 :
571 : /***** begin *****/
572 104 : if (EQUAL(name, oFC.beginfield))
573 : {
574 0 : char *const timebuf = OGRGetXMLDateTime(&sFieldDT);
575 :
576 0 : if (!poKmlTimeSpan)
577 : {
578 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan();
579 0 : poKmlFeature->set_timeprimitive(poKmlTimeSpan);
580 : }
581 :
582 0 : poKmlTimeSpan->set_begin(timebuf);
583 0 : CPLFree(timebuf);
584 :
585 0 : continue;
586 : }
587 :
588 : /***** end *****/
589 104 : else if (EQUAL(name, oFC.endfield))
590 : {
591 0 : char *const timebuf = OGRGetXMLDateTime(&sFieldDT);
592 :
593 0 : if (!poKmlTimeSpan)
594 : {
595 0 : poKmlTimeSpan = poKmlFactory->CreateTimeSpan();
596 0 : poKmlFeature->set_timeprimitive(poKmlTimeSpan);
597 : }
598 :
599 0 : poKmlTimeSpan->set_end(timebuf);
600 0 : CPLFree(timebuf);
601 :
602 0 : continue;
603 : }
604 :
605 : /***** other *****/
606 : const char *pszVal =
607 : type == OFTDateTime
608 104 : ? poOgrFeat->GetFieldAsISO8601DateTime(i, nullptr)
609 52 : : poOgrFeat->GetFieldAsString(i);
610 104 : if (bUseSimpleField)
611 : {
612 104 : poKmlSimpleData = poKmlFactory->CreateSimpleData();
613 104 : poKmlSimpleData->set_name(name);
614 104 : poKmlSimpleData->set_text(pszVal);
615 : }
616 : else
617 : {
618 0 : poKmlData = poKmlFactory->CreateData();
619 0 : poKmlData->set_name(name);
620 0 : poKmlData->set_value(pszVal);
621 : }
622 :
623 104 : break;
624 : }
625 :
626 53 : case OFTInteger: // Simple 32bit integer
627 :
628 : /***** extrude *****/
629 53 : if (EQUAL(name, oFC.extrudefield))
630 : {
631 0 : if (poKmlFeature->IsA(kmldom::Type_Placemark))
632 : {
633 0 : PlacemarkPtr poKmlPlacemark = AsPlacemark(poKmlFeature);
634 0 : if (poKmlPlacemark->has_geometry() &&
635 0 : -1 < poOgrFeat->GetFieldAsInteger(i))
636 : {
637 : const int iExtrude =
638 0 : poOgrFeat->GetFieldAsInteger(i);
639 0 : if (iExtrude && !isGX &&
640 : iAltitudeMode ==
641 0 : kmldom::ALTITUDEMODE_CLAMPTOGROUND &&
642 0 : CPLTestBool(CPLGetConfigOption(
643 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
644 : {
645 0 : CPLError(CE_Warning, CPLE_NotSupported,
646 : "altitudeMode=clampToGround "
647 : "unsupported with "
648 : "extrude=1");
649 : }
650 : else
651 : {
652 : GeometryPtr poKmlGeometry =
653 0 : poKmlPlacemark->get_geometry();
654 0 : ogr2extrude_rec(CPL_TO_BOOL(iExtrude),
655 : poKmlGeometry);
656 : }
657 : }
658 : }
659 0 : continue;
660 : }
661 :
662 : /***** tessellate *****/
663 53 : if (EQUAL(name, oFC.tessellatefield))
664 : {
665 0 : if (poKmlFeature->IsA(kmldom::Type_Placemark))
666 : {
667 0 : PlacemarkPtr poKmlPlacemark = AsPlacemark(poKmlFeature);
668 0 : if (poKmlPlacemark->has_geometry() &&
669 0 : -1 < poOgrFeat->GetFieldAsInteger(i))
670 : {
671 : const int iTessellate =
672 0 : poOgrFeat->GetFieldAsInteger(i);
673 0 : if (iTessellate &&
674 0 : !(!isGX &&
675 : static_cast<kmldom::AltitudeModeEnum>(
676 : iAltitudeMode) ==
677 0 : kmldom::ALTITUDEMODE_CLAMPTOGROUND) &&
678 0 : !(isGX &&
679 : static_cast<kmldom::GxAltitudeModeEnum>(
680 : iAltitudeMode) ==
681 : kmldom::
682 0 : GX_ALTITUDEMODE_CLAMPTOSEAFLOOR) &&
683 0 : CPLTestBool(CPLGetConfigOption(
684 : "LIBKML_STRICT_COMPLIANCE", "TRUE")))
685 : {
686 0 : CPLError(CE_Warning, CPLE_NotSupported,
687 : "altitudeMode!=clampToGround && "
688 : "altitudeMode!=clampToSeaFloor "
689 : "unsupported with tessellate=1");
690 : }
691 : else
692 : {
693 : GeometryPtr poKmlGeometry =
694 0 : poKmlPlacemark->get_geometry();
695 0 : ogr2tessellate_rec(CPL_TO_BOOL(iTessellate),
696 : poKmlGeometry);
697 0 : if (!isGX &&
698 : iAltitudeMode ==
699 : kmldom::ALTITUDEMODE_CLAMPTOGROUND)
700 0 : ogr2altitudemode_rec(poKmlGeometry,
701 : iAltitudeMode, isGX);
702 : }
703 : }
704 : }
705 :
706 0 : continue;
707 : }
708 :
709 : /***** visibility *****/
710 53 : if (EQUAL(name, oFC.visibilityfield))
711 : {
712 0 : if (-1 < poOgrFeat->GetFieldAsInteger(i))
713 0 : poKmlFeature->set_visibility(
714 0 : CPL_TO_BOOL(poOgrFeat->GetFieldAsInteger(i)));
715 :
716 0 : continue;
717 : }
718 : /***** other special fields *****/
719 53 : else if (EQUAL(name, oFC.drawOrderfield) ||
720 53 : EQUAL(name, oFC.networklink_refreshvisibility_field) ||
721 52 : EQUAL(name, oFC.networklink_flytoview_field) ||
722 51 : EQUAL(name, oFC.networklink_refreshInterval_field) ||
723 51 : EQUAL(name, oFC.networklink_viewRefreshMode_field) ||
724 51 : EQUAL(name, oFC.networklink_viewRefreshTime_field) ||
725 51 : EQUAL(name, oFC.imagepyramid_tilesize_field) ||
726 50 : EQUAL(name, oFC.imagepyramid_maxwidth_field) ||
727 49 : EQUAL(name, oFC.imagepyramid_maxheight_field))
728 : {
729 5 : continue;
730 : }
731 :
732 : /***** other *****/
733 48 : if (bUseSimpleField)
734 : {
735 48 : poKmlSimpleData = poKmlFactory->CreateSimpleData();
736 48 : poKmlSimpleData->set_name(name);
737 48 : poKmlSimpleData->set_text(poOgrFeat->GetFieldAsString(i));
738 : }
739 : else
740 : {
741 0 : poKmlData = poKmlFactory->CreateData();
742 0 : poKmlData->set_name(name);
743 0 : poKmlData->set_value(poOgrFeat->GetFieldAsString(i));
744 : }
745 :
746 48 : break;
747 :
748 83 : case OFTReal: // Double Precision floating point
749 : {
750 83 : if (EQUAL(name, oFC.headingfield) ||
751 78 : EQUAL(name, oFC.tiltfield) || EQUAL(name, oFC.rollfield) ||
752 70 : EQUAL(name, oFC.scalexfield) ||
753 69 : EQUAL(name, oFC.scaleyfield) ||
754 68 : EQUAL(name, oFC.scalezfield) ||
755 67 : EQUAL(name, oFC.networklink_refreshInterval_field) ||
756 66 : EQUAL(name, oFC.networklink_viewRefreshMode_field) ||
757 66 : EQUAL(name, oFC.networklink_viewRefreshTime_field) ||
758 65 : EQUAL(name, oFC.networklink_viewBoundScale_field) ||
759 64 : EQUAL(name, oFC.camera_longitude_field) ||
760 62 : EQUAL(name, oFC.camera_latitude_field) ||
761 60 : EQUAL(name, oFC.camera_altitude_field) ||
762 58 : EQUAL(name, oFC.leftfovfield) ||
763 56 : EQUAL(name, oFC.rightfovfield) ||
764 54 : EQUAL(name, oFC.bottomfovfield) ||
765 52 : EQUAL(name, oFC.topfovfield) ||
766 50 : EQUAL(name, oFC.nearfield) ||
767 48 : EQUAL(name, oFC.camera_altitude_field))
768 : {
769 35 : continue;
770 : }
771 :
772 48 : char *pszStr = CPLStrdup(poOgrFeat->GetFieldAsString(i));
773 :
774 48 : if (bUseSimpleField)
775 : {
776 48 : poKmlSimpleData = poKmlFactory->CreateSimpleData();
777 48 : poKmlSimpleData->set_name(name);
778 48 : poKmlSimpleData->set_text(pszStr);
779 : }
780 : else
781 : {
782 0 : poKmlData = poKmlFactory->CreateData();
783 0 : poKmlData->set_name(name);
784 0 : poKmlData->set_value(pszStr);
785 : }
786 :
787 48 : CPLFree(pszStr);
788 :
789 48 : break;
790 : }
791 :
792 0 : case OFTStringList: // Array of strings
793 : case OFTIntegerList: // List of 32bit integers
794 : case OFTRealList: // List of doubles
795 : case OFTBinary: // Raw Binary data
796 : case OFTWideStringList: // deprecated
797 : default:
798 :
799 : /***** other *****/
800 :
801 0 : if (bUseSimpleField)
802 : {
803 0 : poKmlSimpleData = poKmlFactory->CreateSimpleData();
804 0 : poKmlSimpleData->set_name(name);
805 0 : poKmlSimpleData->set_text(poOgrFeat->GetFieldAsString(i));
806 : }
807 : else
808 : {
809 0 : poKmlData = poKmlFactory->CreateData();
810 0 : poKmlData->set_name(name);
811 0 : poKmlData->set_value(poOgrFeat->GetFieldAsString(i));
812 : }
813 :
814 0 : break;
815 : }
816 :
817 254 : if (poKmlSimpleData)
818 : {
819 253 : poKmlSchemaData->add_simpledata(poKmlSimpleData);
820 : }
821 1 : else if (poKmlData)
822 : {
823 1 : if (!poKmlExtendedData)
824 1 : poKmlExtendedData = poKmlFactory->CreateExtendedData();
825 1 : poKmlExtendedData->add_data(poKmlData);
826 : }
827 : }
828 :
829 : // Do not add it to the placemark unless there is data.
830 143 : if (bUseSimpleField && poKmlSchemaData->get_simpledata_array_size() > 0)
831 : {
832 53 : poKmlExtendedData = poKmlFactory->CreateExtendedData();
833 53 : poKmlExtendedData->add_schemadata(poKmlSchemaData);
834 : }
835 143 : if (poKmlExtendedData)
836 : {
837 54 : poKmlFeature->set_extendeddata(poKmlExtendedData);
838 : }
839 143 : }
840 :
841 : /******************************************************************************
842 : Recursive function to read altitude mode from the geometry.
843 : ******************************************************************************/
844 :
845 755 : static bool kml2altitudemode_rec(GeometryPtr poKmlGeometry, int *pnAltitudeMode,
846 : int *pbIsGX)
847 : {
848 755 : switch (poKmlGeometry->Type())
849 : {
850 176 : case kmldom::Type_Point:
851 : {
852 176 : PointPtr poKmlPoint = AsPoint(poKmlGeometry);
853 :
854 176 : if (poKmlPoint->has_altitudemode())
855 : {
856 60 : *pnAltitudeMode = poKmlPoint->get_altitudemode();
857 60 : return true;
858 : }
859 116 : else if (poKmlPoint->has_gx_altitudemode())
860 : {
861 0 : *pnAltitudeMode = poKmlPoint->get_gx_altitudemode();
862 0 : *pbIsGX = true;
863 0 : return true;
864 : }
865 :
866 116 : break;
867 : }
868 234 : case kmldom::Type_LineString:
869 : {
870 234 : LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
871 :
872 234 : if (poKmlLineString->has_altitudemode())
873 : {
874 128 : *pnAltitudeMode = poKmlLineString->get_altitudemode();
875 128 : return true;
876 : }
877 106 : else if (poKmlLineString->has_gx_altitudemode())
878 : {
879 0 : *pnAltitudeMode = poKmlLineString->get_gx_altitudemode();
880 0 : *pbIsGX = true;
881 0 : return true;
882 : }
883 106 : break;
884 : }
885 3 : case kmldom::Type_LinearRing:
886 : {
887 3 : break;
888 : }
889 316 : case kmldom::Type_Polygon:
890 : {
891 316 : PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
892 :
893 316 : if (poKmlPolygon->has_altitudemode())
894 : {
895 296 : *pnAltitudeMode = poKmlPolygon->get_altitudemode();
896 296 : return true;
897 : }
898 20 : else if (poKmlPolygon->has_gx_altitudemode())
899 : {
900 0 : *pnAltitudeMode = poKmlPolygon->get_gx_altitudemode();
901 0 : *pbIsGX = true;
902 0 : return true;
903 : }
904 :
905 20 : break;
906 : }
907 23 : case kmldom::Type_MultiGeometry:
908 : {
909 : MultiGeometryPtr poKmlMultiGeometry =
910 23 : AsMultiGeometry(poKmlGeometry);
911 :
912 23 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
913 57 : for (size_t i = 0; i < nGeom; i++)
914 : {
915 34 : if (kml2altitudemode_rec(
916 34 : poKmlMultiGeometry->get_geometry_array_at(i),
917 : pnAltitudeMode, pbIsGX))
918 0 : return true;
919 : }
920 :
921 23 : break;
922 : }
923 3 : default:
924 : {
925 3 : break;
926 : }
927 : }
928 :
929 271 : return false;
930 : }
931 :
932 : /******************************************************************************
933 : Recursive function to read extrude from the geometry.
934 : ******************************************************************************/
935 :
936 755 : static bool kml2extrude_rec(GeometryPtr poKmlGeometry, bool *pbExtrude)
937 : {
938 755 : switch (poKmlGeometry->Type())
939 : {
940 176 : case kmldom::Type_Point:
941 : {
942 176 : PointPtr poKmlPoint = AsPoint(poKmlGeometry);
943 :
944 176 : if (poKmlPoint->has_extrude())
945 : {
946 30 : *pbExtrude = poKmlPoint->get_extrude();
947 30 : return true;
948 : }
949 :
950 146 : break;
951 : }
952 234 : case kmldom::Type_LineString:
953 : {
954 234 : LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
955 :
956 234 : if (poKmlLineString->has_extrude())
957 : {
958 60 : *pbExtrude = poKmlLineString->get_extrude();
959 60 : return true;
960 : }
961 :
962 174 : break;
963 : }
964 3 : case kmldom::Type_LinearRing:
965 : {
966 3 : break;
967 : }
968 316 : case kmldom::Type_Polygon:
969 : {
970 316 : PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
971 :
972 316 : if (poKmlPolygon->has_extrude())
973 : {
974 228 : *pbExtrude = poKmlPolygon->get_extrude();
975 228 : return true;
976 : }
977 :
978 88 : break;
979 : }
980 23 : case kmldom::Type_MultiGeometry:
981 : {
982 : MultiGeometryPtr poKmlMultiGeometry =
983 23 : AsMultiGeometry(poKmlGeometry);
984 :
985 23 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
986 57 : for (size_t i = 0; i < nGeom; i++)
987 : {
988 34 : if (kml2extrude_rec(
989 34 : poKmlMultiGeometry->get_geometry_array_at(i),
990 : pbExtrude))
991 0 : return true;
992 : }
993 :
994 23 : break;
995 : }
996 3 : default:
997 : {
998 3 : break;
999 : }
1000 : }
1001 :
1002 437 : return false;
1003 : }
1004 :
1005 : /******************************************************************************
1006 : Recursive function to read tessellate from the geometry.
1007 : ******************************************************************************/
1008 :
1009 755 : static bool kml2tessellate_rec(GeometryPtr poKmlGeometry, int *pnTessellate)
1010 : {
1011 755 : switch (poKmlGeometry->Type())
1012 : {
1013 176 : case kmldom::Type_Point:
1014 : {
1015 176 : break;
1016 : }
1017 234 : case kmldom::Type_LineString:
1018 : {
1019 234 : LineStringPtr poKmlLineString = AsLineString(poKmlGeometry);
1020 :
1021 234 : if (poKmlLineString->has_tessellate())
1022 : {
1023 214 : *pnTessellate = poKmlLineString->get_tessellate();
1024 214 : return true;
1025 : }
1026 :
1027 20 : break;
1028 : }
1029 3 : case kmldom::Type_LinearRing:
1030 : {
1031 3 : break;
1032 : }
1033 316 : case kmldom::Type_Polygon:
1034 : {
1035 316 : PolygonPtr poKmlPolygon = AsPolygon(poKmlGeometry);
1036 :
1037 316 : if (poKmlPolygon->has_tessellate())
1038 : {
1039 124 : *pnTessellate = poKmlPolygon->get_tessellate();
1040 124 : return true;
1041 : }
1042 :
1043 192 : break;
1044 : }
1045 23 : case kmldom::Type_MultiGeometry:
1046 : {
1047 : MultiGeometryPtr poKmlMultiGeometry =
1048 23 : AsMultiGeometry(poKmlGeometry);
1049 :
1050 23 : const size_t nGeom = poKmlMultiGeometry->get_geometry_array_size();
1051 57 : for (size_t i = 0; i < nGeom; i++)
1052 : {
1053 34 : if (kml2tessellate_rec(
1054 34 : poKmlMultiGeometry->get_geometry_array_at(i),
1055 : pnTessellate))
1056 0 : return true;
1057 : }
1058 :
1059 23 : break;
1060 : }
1061 3 : default:
1062 3 : break;
1063 : }
1064 :
1065 417 : return false;
1066 : }
1067 :
1068 : /************************************************************************/
1069 : /* ogrkmlSetAltitudeMode() */
1070 : /************************************************************************/
1071 :
1072 485 : static void ogrkmlSetAltitudeMode(OGRFeature *poOgrFeat, int iField,
1073 : int nAltitudeMode, bool bIsGX)
1074 : {
1075 485 : if (!bIsGX)
1076 : {
1077 485 : switch (nAltitudeMode)
1078 : {
1079 0 : case kmldom::ALTITUDEMODE_CLAMPTOGROUND:
1080 0 : poOgrFeat->SetField(iField, "clampToGround");
1081 0 : break;
1082 :
1083 349 : case kmldom::ALTITUDEMODE_RELATIVETOGROUND:
1084 349 : poOgrFeat->SetField(iField, "relativeToGround");
1085 349 : break;
1086 :
1087 136 : case kmldom::ALTITUDEMODE_ABSOLUTE:
1088 136 : poOgrFeat->SetField(iField, "absolute");
1089 136 : break;
1090 : }
1091 : }
1092 : else
1093 : {
1094 0 : switch (nAltitudeMode)
1095 : {
1096 0 : case kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR:
1097 0 : poOgrFeat->SetField(iField, "relativeToSeaFloor");
1098 0 : break;
1099 :
1100 0 : case kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR:
1101 0 : poOgrFeat->SetField(iField, "clampToSeaFloor");
1102 0 : break;
1103 : }
1104 : }
1105 485 : }
1106 :
1107 : /************************************************************************/
1108 : /* TrimSpaces() */
1109 : /************************************************************************/
1110 :
1111 21 : static const char *TrimSpaces(CPLString &oText)
1112 : {
1113 : // SerializePretty() adds a new line before the data
1114 : // ands trailing spaces. I believe this is wrong
1115 : // as it breaks round-tripping.
1116 :
1117 : // Trim trailing spaces.
1118 21 : while (!oText.empty() && oText.back() == ' ')
1119 0 : oText.resize(oText.size() - 1);
1120 :
1121 : // Skip leading newline and spaces.
1122 21 : const char *pszText = oText.c_str();
1123 21 : if (pszText[0] == '\n')
1124 0 : pszText++;
1125 21 : while (pszText[0] == ' ')
1126 0 : pszText++;
1127 :
1128 21 : return pszText;
1129 : }
1130 :
1131 : /************************************************************************/
1132 : /* kmldatetime2ogr() */
1133 : /************************************************************************/
1134 :
1135 7 : static void kmldatetime2ogr(OGRFeature *poOgrFeat, const char *pszOGRField,
1136 : const std::string &osKmlDateTime)
1137 : {
1138 7 : const int iField = poOgrFeat->GetFieldIndex(pszOGRField);
1139 :
1140 7 : if (iField > -1)
1141 : {
1142 : OGRField sField;
1143 :
1144 7 : if (OGRParseXMLDateTime(osKmlDateTime.c_str(), &sField))
1145 7 : poOgrFeat->SetField(iField, &sField);
1146 : }
1147 7 : }
1148 :
1149 : /******************************************************************************
1150 : function to read kml into ogr fields
1151 : ******************************************************************************/
1152 :
1153 819 : void kml2field(OGRFeature *poOgrFeat, FeaturePtr poKmlFeature)
1154 : {
1155 : /***** get the field config *****/
1156 :
1157 : struct fieldconfig oFC;
1158 819 : get_fieldconfig(&oFC);
1159 :
1160 : /***** name *****/
1161 :
1162 819 : if (poKmlFeature->has_name())
1163 : {
1164 1478 : const std::string oKmlName = poKmlFeature->get_name();
1165 739 : int iField = poOgrFeat->GetFieldIndex(oFC.namefield);
1166 :
1167 739 : if (iField > -1)
1168 739 : poOgrFeat->SetField(iField, oKmlName.c_str());
1169 : }
1170 :
1171 : /***** description *****/
1172 :
1173 819 : if (poKmlFeature->has_description())
1174 : {
1175 786 : const std::string oKmlDesc = poKmlFeature->get_description();
1176 393 : int iField = poOgrFeat->GetFieldIndex(oFC.descfield);
1177 :
1178 393 : if (iField > -1)
1179 393 : poOgrFeat->SetField(iField, oKmlDesc.c_str());
1180 : }
1181 :
1182 819 : if (poKmlFeature->has_timeprimitive())
1183 : {
1184 4 : TimePrimitivePtr poKmlTimePrimitive = poKmlFeature->get_timeprimitive();
1185 :
1186 : /***** timestamp *****/
1187 :
1188 2 : if (poKmlTimePrimitive->IsA(kmldom::Type_TimeStamp))
1189 : {
1190 : // Probably a libkml bug: AsTimeStamp should really return not NULL
1191 : // on a gx:TimeStamp.
1192 2 : TimeStampPtr poKmlTimeStamp = AsTimeStamp(poKmlTimePrimitive);
1193 1 : if (!poKmlTimeStamp)
1194 1 : poKmlTimeStamp = AsGxTimeStamp(poKmlTimePrimitive);
1195 :
1196 1 : if (poKmlTimeStamp && poKmlTimeStamp->has_when())
1197 : {
1198 2 : const std::string oKmlWhen = poKmlTimeStamp->get_when();
1199 1 : kmldatetime2ogr(poOgrFeat, oFC.tsfield, oKmlWhen);
1200 : }
1201 : }
1202 :
1203 : /***** timespan *****/
1204 :
1205 2 : if (poKmlTimePrimitive->IsA(kmldom::Type_TimeSpan))
1206 : {
1207 : // Probably a libkml bug: AsTimeSpan should really return not NULL
1208 : // on a gx:TimeSpan.
1209 2 : TimeSpanPtr poKmlTimeSpan = AsTimeSpan(poKmlTimePrimitive);
1210 1 : if (!poKmlTimeSpan)
1211 1 : poKmlTimeSpan = AsGxTimeSpan(poKmlTimePrimitive);
1212 :
1213 : /***** begin *****/
1214 :
1215 1 : if (poKmlTimeSpan && poKmlTimeSpan->has_begin())
1216 : {
1217 2 : const std::string oKmlWhen = poKmlTimeSpan->get_begin();
1218 1 : kmldatetime2ogr(poOgrFeat, oFC.beginfield, oKmlWhen);
1219 : }
1220 :
1221 : /***** end *****/
1222 :
1223 1 : if (poKmlTimeSpan && poKmlTimeSpan->has_end())
1224 : {
1225 2 : const std::string oKmlWhen = poKmlTimeSpan->get_end();
1226 1 : kmldatetime2ogr(poOgrFeat, oFC.endfield, oKmlWhen);
1227 : }
1228 : }
1229 : }
1230 :
1231 : /***** placemark *****/
1232 1638 : PlacemarkPtr poKmlPlacemark = AsPlacemark(poKmlFeature);
1233 1638 : GroundOverlayPtr poKmlGroundOverlay = AsGroundOverlay(poKmlFeature);
1234 819 : if (poKmlPlacemark && poKmlPlacemark->has_geometry())
1235 : {
1236 1442 : GeometryPtr poKmlGeometry = poKmlPlacemark->get_geometry();
1237 :
1238 : /***** altitudeMode *****/
1239 721 : int bIsGX = false;
1240 721 : int nAltitudeMode = -1;
1241 :
1242 721 : int iField = poOgrFeat->GetFieldIndex(oFC.altitudeModefield);
1243 :
1244 721 : if (iField > -1)
1245 : {
1246 721 : if (kml2altitudemode_rec(poKmlGeometry, &nAltitudeMode, &bIsGX))
1247 : {
1248 484 : ogrkmlSetAltitudeMode(poOgrFeat, iField, nAltitudeMode,
1249 484 : CPL_TO_BOOL(bIsGX));
1250 : }
1251 : }
1252 :
1253 : /***** tessellate *****/
1254 721 : int nTessellate = -1;
1255 :
1256 721 : kml2tessellate_rec(poKmlGeometry, &nTessellate);
1257 :
1258 721 : iField = poOgrFeat->GetFieldIndex(oFC.tessellatefield);
1259 721 : if (iField > -1)
1260 721 : poOgrFeat->SetField(iField, nTessellate);
1261 :
1262 : /***** extrude *****/
1263 :
1264 721 : bool bExtrude = false;
1265 :
1266 721 : kml2extrude_rec(poKmlGeometry, &bExtrude);
1267 :
1268 721 : iField = poOgrFeat->GetFieldIndex(oFC.extrudefield);
1269 721 : if (iField > -1)
1270 721 : poOgrFeat->SetField(iField, bExtrude ? 1 : 0);
1271 :
1272 : /***** special case for gx:Track ******/
1273 : /* we set the first timestamp as begin and the last one as end */
1274 723 : if (poKmlGeometry->Type() == kmldom::Type_GxTrack &&
1275 2 : !poKmlFeature->has_timeprimitive())
1276 : {
1277 4 : GxTrackPtr poKmlGxTrack = AsGxTrack(poKmlGeometry);
1278 2 : if (poKmlGxTrack)
1279 : {
1280 2 : const size_t nCoords = poKmlGxTrack->get_when_array_size();
1281 2 : if (nCoords > 0)
1282 : {
1283 2 : kmldatetime2ogr(poOgrFeat, oFC.beginfield,
1284 1 : poKmlGxTrack->get_when_array_at(0).c_str());
1285 2 : kmldatetime2ogr(
1286 : poOgrFeat, oFC.endfield,
1287 1 : poKmlGxTrack->get_when_array_at(nCoords - 1).c_str());
1288 : }
1289 : }
1290 : }
1291 :
1292 : /***** special case for gx:MultiTrack ******/
1293 : /* we set the first timestamp as begin and the last one as end */
1294 720 : else if (poKmlGeometry->Type() == kmldom::Type_GxMultiTrack &&
1295 1 : !poKmlFeature->has_timeprimitive())
1296 : {
1297 2 : GxMultiTrackPtr poKmlGxMultiTrack = AsGxMultiTrack(poKmlGeometry);
1298 1 : if (poKmlGxMultiTrack)
1299 : {
1300 : const size_t nGeom =
1301 1 : poKmlGxMultiTrack->get_gx_track_array_size();
1302 1 : if (nGeom >= 1)
1303 : {
1304 : {
1305 : GxTrackPtr poKmlGxTrack =
1306 2 : poKmlGxMultiTrack->get_gx_track_array_at(0);
1307 : const size_t nCoords =
1308 1 : poKmlGxTrack->get_when_array_size();
1309 1 : if (nCoords > 0)
1310 : {
1311 2 : kmldatetime2ogr(
1312 : poOgrFeat, oFC.beginfield,
1313 1 : poKmlGxTrack->get_when_array_at(0).c_str());
1314 : }
1315 : }
1316 :
1317 : {
1318 : GxTrackPtr poKmlGxTrack =
1319 2 : poKmlGxMultiTrack->get_gx_track_array_at(nGeom - 1);
1320 : const size_t nCoords =
1321 1 : poKmlGxTrack->get_when_array_size();
1322 1 : if (nCoords > 0)
1323 : {
1324 2 : kmldatetime2ogr(
1325 : poOgrFeat, oFC.endfield,
1326 1 : poKmlGxTrack->get_when_array_at(nCoords - 1)
1327 : .c_str());
1328 : }
1329 : }
1330 : }
1331 : }
1332 : }
1333 : }
1334 :
1335 : /***** camera *****/
1336 :
1337 100 : else if (poKmlPlacemark && poKmlPlacemark->has_abstractview() &&
1338 2 : poKmlPlacemark->get_abstractview()->IsA(kmldom::Type_Camera))
1339 : {
1340 4 : const CameraPtr &camera = AsCamera(poKmlPlacemark->get_abstractview());
1341 :
1342 2 : if (camera->has_heading())
1343 : {
1344 2 : int iField = poOgrFeat->GetFieldIndex(oFC.headingfield);
1345 2 : if (iField > -1)
1346 2 : poOgrFeat->SetField(iField, camera->get_heading());
1347 : }
1348 :
1349 2 : if (camera->has_tilt())
1350 : {
1351 1 : int iField = poOgrFeat->GetFieldIndex(oFC.tiltfield);
1352 1 : if (iField > -1)
1353 1 : poOgrFeat->SetField(iField, camera->get_tilt());
1354 : }
1355 :
1356 2 : if (camera->has_roll())
1357 : {
1358 1 : int iField = poOgrFeat->GetFieldIndex(oFC.rollfield);
1359 1 : if (iField > -1)
1360 1 : poOgrFeat->SetField(iField, camera->get_roll());
1361 : }
1362 :
1363 2 : int iField = poOgrFeat->GetFieldIndex(oFC.altitudeModefield);
1364 :
1365 2 : if (iField > -1)
1366 : {
1367 2 : if (camera->has_altitudemode())
1368 : {
1369 1 : const int nAltitudeMode = camera->get_altitudemode();
1370 1 : ogrkmlSetAltitudeMode(poOgrFeat, iField, nAltitudeMode, false);
1371 : }
1372 1 : else if (camera->has_gx_altitudemode())
1373 : {
1374 0 : const int nAltitudeMode = camera->get_gx_altitudemode();
1375 0 : ogrkmlSetAltitudeMode(poOgrFeat, iField, nAltitudeMode, true);
1376 : }
1377 : }
1378 : }
1379 : /***** ground overlay *****/
1380 96 : else if (poKmlGroundOverlay)
1381 : {
1382 : /***** icon *****/
1383 42 : int iField = poOgrFeat->GetFieldIndex(oFC.iconfield);
1384 42 : if (iField > -1)
1385 : {
1386 42 : if (poKmlGroundOverlay->has_icon())
1387 : {
1388 84 : IconPtr icon = poKmlGroundOverlay->get_icon();
1389 42 : if (icon->has_href())
1390 : {
1391 42 : poOgrFeat->SetField(iField, icon->get_href().c_str());
1392 : }
1393 : }
1394 : }
1395 :
1396 : /***** drawOrder *****/
1397 42 : iField = poOgrFeat->GetFieldIndex(oFC.drawOrderfield);
1398 42 : if (iField > -1)
1399 : {
1400 42 : if (poKmlGroundOverlay->has_draworder())
1401 : {
1402 0 : poOgrFeat->SetField(iField,
1403 0 : poKmlGroundOverlay->get_draworder());
1404 : }
1405 : }
1406 :
1407 : /***** altitudeMode *****/
1408 :
1409 42 : iField = poOgrFeat->GetFieldIndex(oFC.altitudeModefield);
1410 :
1411 42 : if (iField > -1)
1412 : {
1413 42 : if (poKmlGroundOverlay->has_altitudemode())
1414 : {
1415 0 : switch (poKmlGroundOverlay->get_altitudemode())
1416 : {
1417 0 : case kmldom::ALTITUDEMODE_CLAMPTOGROUND:
1418 0 : poOgrFeat->SetField(iField, "clampToGround");
1419 0 : break;
1420 :
1421 0 : case kmldom::ALTITUDEMODE_RELATIVETOGROUND:
1422 0 : poOgrFeat->SetField(iField, "relativeToGround");
1423 0 : break;
1424 :
1425 0 : case kmldom::ALTITUDEMODE_ABSOLUTE:
1426 0 : poOgrFeat->SetField(iField, "absolute");
1427 0 : break;
1428 : }
1429 : }
1430 42 : else if (poKmlGroundOverlay->has_gx_altitudemode())
1431 : {
1432 0 : switch (poKmlGroundOverlay->get_gx_altitudemode())
1433 : {
1434 0 : case kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR:
1435 0 : poOgrFeat->SetField(iField, "relativeToSeaFloor");
1436 0 : break;
1437 :
1438 0 : case kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR:
1439 0 : poOgrFeat->SetField(iField, "clampToSeaFloor");
1440 0 : break;
1441 : }
1442 : }
1443 : }
1444 : }
1445 :
1446 : /***** visibility *****/
1447 : const int nVisibility =
1448 819 : poKmlFeature->has_visibility() ? poKmlFeature->get_visibility() : -1;
1449 :
1450 819 : int iField = poOgrFeat->GetFieldIndex(oFC.visibilityfield);
1451 :
1452 819 : if (iField > -1)
1453 803 : poOgrFeat->SetField(iField, nVisibility);
1454 :
1455 : /***** snippet *****/
1456 :
1457 819 : if (poKmlFeature->has_snippet())
1458 : {
1459 2 : CPLString oText = poKmlFeature->get_snippet()->get_text();
1460 :
1461 1 : iField = poOgrFeat->GetFieldIndex(oFC.snippetfield);
1462 :
1463 1 : if (iField > -1)
1464 1 : poOgrFeat->SetField(iField, TrimSpaces(oText));
1465 : }
1466 :
1467 : /***** extended schema *****/
1468 1638 : ExtendedDataPtr poKmlExtendedData = nullptr;
1469 :
1470 819 : if (poKmlFeature->has_extendeddata())
1471 : {
1472 13 : poKmlExtendedData = poKmlFeature->get_extendeddata();
1473 :
1474 : /***** loop over the schemadata_arrays *****/
1475 :
1476 : const size_t nSchemaData =
1477 13 : poKmlExtendedData->get_schemadata_array_size();
1478 :
1479 23 : for (size_t iSchemaData = 0; iSchemaData < nSchemaData; iSchemaData++)
1480 : {
1481 : SchemaDataPtr poKmlSchemaData =
1482 20 : poKmlExtendedData->get_schemadata_array_at(iSchemaData);
1483 :
1484 : /***** loop over the simpledata array *****/
1485 :
1486 : const size_t nSimpleData =
1487 10 : poKmlSchemaData->get_simpledata_array_size();
1488 :
1489 30 : for (size_t iSimpleData = 0; iSimpleData < nSimpleData;
1490 : iSimpleData++)
1491 : {
1492 : SimpleDataPtr poKmlSimpleData =
1493 40 : poKmlSchemaData->get_simpledata_array_at(iSimpleData);
1494 :
1495 : /***** find the field index *****/
1496 :
1497 20 : iField = -1;
1498 :
1499 20 : if (poKmlSimpleData->has_name())
1500 : {
1501 20 : const string oName = poKmlSimpleData->get_name();
1502 20 : const char *pszName = oName.c_str();
1503 :
1504 20 : iField = poOgrFeat->GetFieldIndex(pszName);
1505 : }
1506 :
1507 : /***** if it has trxt set the field *****/
1508 :
1509 20 : if (iField > -1 && poKmlSimpleData->has_text())
1510 : {
1511 40 : CPLString oText = poKmlSimpleData->get_text();
1512 :
1513 20 : poOgrFeat->SetField(iField, TrimSpaces(oText));
1514 : }
1515 : }
1516 : }
1517 :
1518 13 : if (nSchemaData == 0 && poKmlExtendedData->get_data_array_size() > 0)
1519 : {
1520 3 : const bool bLaunderFieldNames = CPLTestBool(
1521 : CPLGetConfigOption("LIBKML_LAUNDER_FIELD_NAMES", "YES"));
1522 : const size_t nDataArraySize =
1523 3 : poKmlExtendedData->get_data_array_size();
1524 8 : for (size_t i = 0; i < nDataArraySize; i++)
1525 : {
1526 5 : const DataPtr &data = poKmlExtendedData->get_data_array_at(i);
1527 5 : if (data->has_name() && data->has_value())
1528 : {
1529 10 : CPLString osName = std::string(data->get_name());
1530 5 : if (bLaunderFieldNames)
1531 5 : osName = OGRLIBKMLLayer::LaunderFieldNames(osName);
1532 5 : iField = poOgrFeat->GetFieldIndex(osName);
1533 5 : if (iField >= 0)
1534 : {
1535 5 : poOgrFeat->SetField(iField, data->get_value().c_str());
1536 : }
1537 : }
1538 : }
1539 : }
1540 : }
1541 819 : }
1542 :
1543 : /******************************************************************************
1544 : function create a simplefield from a FieldDefn
1545 : ******************************************************************************/
1546 :
1547 159 : SimpleFieldPtr FieldDef2kml(const OGRFieldDefn *poOgrFieldDef,
1548 : KmlFactory *poKmlFactory, bool bApproxOK)
1549 : {
1550 : /***** Get the field config. *****/
1551 : struct fieldconfig oFC;
1552 159 : get_fieldconfig(&oFC);
1553 :
1554 159 : const char *pszFieldName = poOgrFieldDef->GetNameRef();
1555 :
1556 159 : if (EQUAL(pszFieldName, oFC.namefield) ||
1557 153 : EQUAL(pszFieldName, oFC.descfield) ||
1558 149 : EQUAL(pszFieldName, oFC.tsfield) ||
1559 149 : EQUAL(pszFieldName, oFC.beginfield) ||
1560 149 : EQUAL(pszFieldName, oFC.endfield) ||
1561 149 : EQUAL(pszFieldName, oFC.altitudeModefield) ||
1562 147 : EQUAL(pszFieldName, oFC.tessellatefield) ||
1563 147 : EQUAL(pszFieldName, oFC.extrudefield) ||
1564 147 : EQUAL(pszFieldName, oFC.visibilityfield) ||
1565 147 : EQUAL(pszFieldName, oFC.drawOrderfield) ||
1566 147 : EQUAL(pszFieldName, oFC.iconfield) ||
1567 147 : EQUAL(pszFieldName, oFC.headingfield) ||
1568 144 : EQUAL(pszFieldName, oFC.tiltfield) ||
1569 141 : EQUAL(pszFieldName, oFC.rollfield) ||
1570 138 : EQUAL(pszFieldName, oFC.snippetfield) ||
1571 137 : EQUAL(pszFieldName, oFC.modelfield) ||
1572 136 : EQUAL(pszFieldName, oFC.scalexfield) ||
1573 135 : EQUAL(pszFieldName, oFC.scaleyfield) ||
1574 134 : EQUAL(pszFieldName, oFC.scalezfield) ||
1575 133 : EQUAL(pszFieldName, oFC.networklinkfield) ||
1576 132 : EQUAL(pszFieldName, oFC.networklink_refreshvisibility_field) ||
1577 131 : EQUAL(pszFieldName, oFC.networklink_flytoview_field) ||
1578 130 : EQUAL(pszFieldName, oFC.networklink_refreshMode_field) ||
1579 129 : EQUAL(pszFieldName, oFC.networklink_refreshInterval_field) ||
1580 128 : EQUAL(pszFieldName, oFC.networklink_viewRefreshMode_field) ||
1581 127 : EQUAL(pszFieldName, oFC.networklink_viewRefreshTime_field) ||
1582 126 : EQUAL(pszFieldName, oFC.networklink_viewBoundScale_field) ||
1583 125 : EQUAL(pszFieldName, oFC.networklink_viewFormat_field) ||
1584 124 : EQUAL(pszFieldName, oFC.networklink_httpQuery_field) ||
1585 123 : EQUAL(pszFieldName, oFC.camera_longitude_field) ||
1586 122 : EQUAL(pszFieldName, oFC.camera_latitude_field) ||
1587 121 : EQUAL(pszFieldName, oFC.camera_altitude_field) ||
1588 120 : EQUAL(pszFieldName, oFC.camera_altitudemode_field) ||
1589 119 : EQUAL(pszFieldName, oFC.photooverlayfield) ||
1590 118 : EQUAL(pszFieldName, oFC.leftfovfield) ||
1591 117 : EQUAL(pszFieldName, oFC.rightfovfield) ||
1592 116 : EQUAL(pszFieldName, oFC.bottomfovfield) ||
1593 115 : EQUAL(pszFieldName, oFC.topfovfield) ||
1594 114 : EQUAL(pszFieldName, oFC.nearfield) ||
1595 113 : EQUAL(pszFieldName, oFC.photooverlay_shape_field) ||
1596 112 : EQUAL(pszFieldName, oFC.imagepyramid_tilesize_field) ||
1597 111 : EQUAL(pszFieldName, oFC.imagepyramid_maxwidth_field) ||
1598 110 : EQUAL(pszFieldName, oFC.imagepyramid_maxheight_field) ||
1599 109 : EQUAL(pszFieldName, oFC.imagepyramid_gridorigin_field))
1600 : {
1601 50 : return nullptr;
1602 : }
1603 :
1604 218 : SimpleFieldPtr poKmlSimpleField = poKmlFactory->CreateSimpleField();
1605 109 : poKmlSimpleField->set_name(pszFieldName);
1606 :
1607 109 : switch (poOgrFieldDef->GetType())
1608 : {
1609 16 : case OFTInteger:
1610 : case OFTIntegerList:
1611 16 : poKmlSimpleField->set_type("int");
1612 16 : return poKmlSimpleField;
1613 :
1614 16 : case OFTReal:
1615 : case OFTRealList:
1616 16 : poKmlSimpleField->set_type("float");
1617 16 : return poKmlSimpleField;
1618 :
1619 37 : case OFTString:
1620 : case OFTStringList:
1621 37 : poKmlSimpleField->set_type("string");
1622 37 : return poKmlSimpleField;
1623 :
1624 : /***** kml has these types but as timestamp/timespan *****/
1625 :
1626 40 : case OFTDate:
1627 : case OFTTime:
1628 : case OFTDateTime:
1629 40 : if (bApproxOK)
1630 : {
1631 40 : poKmlSimpleField->set_type("string");
1632 40 : return poKmlSimpleField;
1633 : }
1634 0 : break;
1635 :
1636 0 : default:
1637 0 : poKmlSimpleField->set_type("string");
1638 0 : return poKmlSimpleField;
1639 : }
1640 :
1641 0 : return nullptr;
1642 : }
1643 :
1644 : /******************************************************************************
1645 : function to add the simpleFields in a schema to a featuredefn
1646 : ******************************************************************************/
1647 :
1648 30 : void kml2FeatureDef(SchemaPtr poKmlSchema, OGRFeatureDefn *poOgrFeatureDefn)
1649 : {
1650 30 : const size_t nSimpleFields = poKmlSchema->get_simplefield_array_size();
1651 :
1652 138 : for (size_t iSimpleField = 0; iSimpleField < nSimpleFields; iSimpleField++)
1653 : {
1654 : SimpleFieldPtr poKmlSimpleField =
1655 216 : poKmlSchema->get_simplefield_array_at(iSimpleField);
1656 :
1657 108 : const char *pszType = "string";
1658 216 : string osName = "Unknown";
1659 216 : string osType;
1660 :
1661 108 : if (poKmlSimpleField->has_type())
1662 : {
1663 108 : osType = poKmlSimpleField->get_type();
1664 :
1665 108 : pszType = osType.c_str();
1666 : }
1667 :
1668 : // TODO: We cannot set displayname as the field name because in
1669 : // kml2field() we make the lookup on fields based on their name. We
1670 : // would need some map if we really want to use displayname, but that
1671 : // might not be a good idea because displayname may have HTML
1672 : // formatting, which makes it impractical when converting to other
1673 : // drivers or to make requests.
1674 : // Example: http://www.jasonbirch.com/files/newt_combined.kml
1675 :
1676 : // if( poKmlSimpleField->has_displayname() )
1677 : // {
1678 : // osName = poKmlSimpleField->get_displayname();
1679 : // }
1680 : // else
1681 108 : if (poKmlSimpleField->has_name())
1682 : {
1683 108 : osName = poKmlSimpleField->get_name();
1684 : }
1685 108 : if (poOgrFeatureDefn->GetFieldIndex(osName.c_str()) < 0)
1686 : {
1687 104 : if (EQUAL(pszType, "bool") || EQUAL(pszType, "boolean") ||
1688 104 : EQUAL(pszType, "int") || EQUAL(pszType, "short") ||
1689 88 : EQUAL(pszType, "ushort"))
1690 : {
1691 32 : OGRFieldDefn oOgrFieldName(osName.c_str(), OFTInteger);
1692 32 : poOgrFeatureDefn->AddFieldDefn(&oOgrFieldName);
1693 : }
1694 88 : else if (EQUAL(pszType, "uint"))
1695 : {
1696 0 : OGRFieldDefn oOgrFieldName(osName.c_str(), OFTInteger64);
1697 0 : poOgrFeatureDefn->AddFieldDefn(&oOgrFieldName);
1698 : }
1699 88 : else if (EQUAL(pszType, "float") || EQUAL(pszType, "double"))
1700 : {
1701 32 : OGRFieldDefn oOgrFieldName(osName.c_str(), OFTReal);
1702 32 : poOgrFeatureDefn->AddFieldDefn(&oOgrFieldName);
1703 : }
1704 : else // string, or any other unrecognized type.
1705 : {
1706 144 : OGRFieldDefn oOgrFieldName(osName.c_str(), OFTString);
1707 72 : poOgrFeatureDefn->AddFieldDefn(&oOgrFieldName);
1708 : }
1709 : }
1710 : }
1711 30 : }
1712 :
1713 : /*******************************************************************************
1714 : * function to fetch the field config options
1715 : *
1716 : *******************************************************************************/
1717 :
1718 1451 : void get_fieldconfig(struct fieldconfig *oFC)
1719 : {
1720 1451 : oFC->namefield = CPLGetConfigOption("LIBKML_NAME_FIELD", "Name");
1721 1451 : oFC->descfield =
1722 1451 : CPLGetConfigOption("LIBKML_DESCRIPTION_FIELD", "description");
1723 1451 : oFC->tsfield = CPLGetConfigOption("LIBKML_TIMESTAMP_FIELD", "timestamp");
1724 1451 : oFC->beginfield = CPLGetConfigOption("LIBKML_BEGIN_FIELD", "begin");
1725 1451 : oFC->endfield = CPLGetConfigOption("LIBKML_END_FIELD", "end");
1726 1451 : oFC->altitudeModefield =
1727 1451 : CPLGetConfigOption("LIBKML_ALTITUDEMODE_FIELD", "altitudeMode");
1728 1451 : oFC->tessellatefield =
1729 1451 : CPLGetConfigOption("LIBKML_TESSELLATE_FIELD", "tessellate");
1730 1451 : oFC->extrudefield = CPLGetConfigOption("LIBKML_EXTRUDE_FIELD", "extrude");
1731 1451 : oFC->visibilityfield =
1732 1451 : CPLGetConfigOption("LIBKML_VISIBILITY_FIELD", "visibility");
1733 1451 : oFC->drawOrderfield =
1734 1451 : CPLGetConfigOption("LIBKML_DRAWORDER_FIELD", "drawOrder");
1735 1451 : oFC->iconfield = CPLGetConfigOption("LIBKML_ICON_FIELD", "icon");
1736 1451 : oFC->headingfield = CPLGetConfigOption("LIBKML_HEADING_FIELD", "heading");
1737 1451 : oFC->tiltfield = CPLGetConfigOption("LIBKML_TILT_FIELD", "tilt");
1738 1451 : oFC->rollfield = CPLGetConfigOption("LIBKML_ROLL_FIELD", "roll");
1739 1451 : oFC->snippetfield = CPLGetConfigOption("LIBKML_SNIPPET_FIELD", "snippet");
1740 1451 : oFC->modelfield = CPLGetConfigOption("LIBKML_MODEL_FIELD", "model");
1741 1451 : oFC->scalexfield = CPLGetConfigOption("LIBKML_SCALE_X_FIELD", "scale_x");
1742 1451 : oFC->scaleyfield = CPLGetConfigOption("LIBKML_SCALE_Y_FIELD", "scale_y");
1743 1451 : oFC->scalezfield = CPLGetConfigOption("LIBKML_SCALE_Z_FIELD", "scale_z");
1744 1451 : oFC->networklinkfield =
1745 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_FIELD", "networklink");
1746 1451 : oFC->networklink_refreshvisibility_field =
1747 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_REFRESHVISIBILITY_FIELD",
1748 : "networklink_refreshvisibility");
1749 1451 : oFC->networklink_flytoview_field = CPLGetConfigOption(
1750 : "LIBKML_NETWORKLINK_FLYTOVIEW_FIELD", "networklink_flytoview");
1751 1451 : oFC->networklink_refreshMode_field = CPLGetConfigOption(
1752 : "LIBKML_NETWORKLINK_REFRESHMODE_FIELD", "networklink_refreshmode");
1753 1451 : oFC->networklink_refreshInterval_field =
1754 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_REFRESHINTERVAL_FIELD",
1755 : "networklink_refreshinterval");
1756 1451 : oFC->networklink_viewRefreshMode_field =
1757 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_VIEWREFRESHMODE_FIELD",
1758 : "networklink_viewrefreshmode");
1759 1451 : oFC->networklink_viewRefreshTime_field =
1760 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_VIEWREFRESHTIME_FIELD",
1761 : "networklink_viewrefreshtime");
1762 1451 : oFC->networklink_viewBoundScale_field =
1763 1451 : CPLGetConfigOption("LIBKML_NETWORKLINK_VIEWBOUNDSCALE_FIELD",
1764 : "networklink_viewboundscale");
1765 1451 : oFC->networklink_viewFormat_field = CPLGetConfigOption(
1766 : "LIBKML_NETWORKLINK_VIEWFORMAT_FIELD", "networklink_viewformat");
1767 1451 : oFC->networklink_httpQuery_field = CPLGetConfigOption(
1768 : "LIBKML_NETWORKLINK_HTTPQUERY_FIELD", "networklink_httpquery");
1769 1451 : oFC->camera_longitude_field =
1770 1451 : CPLGetConfigOption("LIBKML_CAMERA_LONGITUDE_FIELD", "camera_longitude");
1771 1451 : oFC->camera_latitude_field =
1772 1451 : CPLGetConfigOption("LIBKML_CAMERA_LATITUDE_FIELD", "camera_latitude");
1773 1451 : oFC->camera_altitude_field =
1774 1451 : CPLGetConfigOption("LIBKML_CAMERA_ALTITUDE_FIELD", "camera_altitude");
1775 1451 : oFC->camera_altitudemode_field = CPLGetConfigOption(
1776 : "LIBKML_CAMERA_ALTITUDEMODE_FIELD", "camera_altitudemode");
1777 1451 : oFC->photooverlayfield =
1778 1451 : CPLGetConfigOption("LIBKML_PHOTOOVERLAY_FIELD", "photooverlay");
1779 1451 : oFC->leftfovfield = CPLGetConfigOption("LIBKML_LEFTFOV_FIELD", "leftfov");
1780 1451 : oFC->rightfovfield =
1781 1451 : CPLGetConfigOption("LIBKML_RIGHTFOV_FIELD", "rightfov");
1782 1451 : oFC->bottomfovfield =
1783 1451 : CPLGetConfigOption("LIBKML_BOTTOMFOV_FIELD", "bottomfov");
1784 1451 : oFC->topfovfield = CPLGetConfigOption("LIBKML_TOPFOV_FIELD", "topfov");
1785 1451 : oFC->nearfield = CPLGetConfigOption("LIBKML_NEARFOV_FIELD", "near");
1786 1451 : oFC->photooverlay_shape_field = CPLGetConfigOption(
1787 : "LIBKML_PHOTOOVERLAY_SHAPE_FIELD", "photooverlay_shape");
1788 1451 : oFC->imagepyramid_tilesize_field = CPLGetConfigOption(
1789 : "LIBKML_IMAGEPYRAMID_TILESIZE", "imagepyramid_tilesize");
1790 1451 : oFC->imagepyramid_maxwidth_field = CPLGetConfigOption(
1791 : "LIBKML_IMAGEPYRAMID_MAXWIDTH", "imagepyramid_maxwidth");
1792 1451 : oFC->imagepyramid_maxheight_field = CPLGetConfigOption(
1793 : "LIBKML_IMAGEPYRAMID_MAXHEIGHT", "imagepyramid_maxheight");
1794 1451 : oFC->imagepyramid_gridorigin_field = CPLGetConfigOption(
1795 : "LIBKML_IMAGEPYRAMID_GRIDORIGIN", "imagepyramid_gridorigin");
1796 1451 : }
1797 :
1798 : /************************************************************************/
1799 : /* kmlAltitudeModeFromString() */
1800 : /************************************************************************/
1801 :
1802 8 : int kmlAltitudeModeFromString(const char *pszAltitudeMode, int &isGX)
1803 : {
1804 8 : isGX = FALSE;
1805 8 : int iAltitudeMode = static_cast<int>(kmldom::ALTITUDEMODE_CLAMPTOGROUND);
1806 :
1807 8 : if (EQUAL(pszAltitudeMode, "clampToGround"))
1808 : {
1809 0 : iAltitudeMode = static_cast<int>(kmldom::ALTITUDEMODE_CLAMPTOGROUND);
1810 : }
1811 8 : else if (EQUAL(pszAltitudeMode, "relativeToGround"))
1812 : {
1813 8 : iAltitudeMode = static_cast<int>(kmldom::ALTITUDEMODE_RELATIVETOGROUND);
1814 : }
1815 0 : else if (EQUAL(pszAltitudeMode, "absolute"))
1816 : {
1817 0 : iAltitudeMode = static_cast<int>(kmldom::ALTITUDEMODE_ABSOLUTE);
1818 : }
1819 0 : else if (EQUAL(pszAltitudeMode, "relativeToSeaFloor"))
1820 : {
1821 0 : iAltitudeMode =
1822 : static_cast<int>(kmldom::GX_ALTITUDEMODE_RELATIVETOSEAFLOOR);
1823 0 : isGX = TRUE;
1824 : }
1825 0 : else if (EQUAL(pszAltitudeMode, "clampToSeaFloor"))
1826 : {
1827 0 : iAltitudeMode =
1828 : static_cast<int>(kmldom::GX_ALTITUDEMODE_CLAMPTOSEAFLOOR);
1829 0 : isGX = TRUE;
1830 : }
1831 : else
1832 : {
1833 0 : CPLError(CE_Warning, CPLE_NotSupported,
1834 : "Unrecognized value for altitudeMode: %s", pszAltitudeMode);
1835 : }
1836 :
1837 8 : return iAltitudeMode;
1838 : }
|