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 mines-paris dot org>
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 "ogr_libkml.h"
31 //#include "cpl_conv.h"
32 //#include "cpl_string.h"
33 #include "cpl_error.h"
34
35 #include <kml/dom.h>
36
37 using kmldom::KmlFactory;
38 using kmldom::PlacemarkPtr;
39 using kmldom::Placemark;
40 using kmldom::DocumentPtr;
41 using kmldom::ContainerPtr;
42 using kmldom::FeaturePtr;
43 using kmldom::GroundOverlayPtr;
44 using kmldom::KmlPtr;
45 using kmldom::Kml;
46 using kmlengine::KmzFile;
47 using kmlengine::KmlFile;
48 using kmlengine::Bbox;
49 using kmldom::ExtendedDataPtr;
50 using kmldom::SchemaDataPtr;
51 using kmldom::DataPtr;
52 using kmldom::CameraPtr;
53 using kmldom::LookAtPtr;
54 using kmldom::RegionPtr;
55 using kmldom::LatLonAltBoxPtr;
56 using kmldom::LodPtr;
57 using kmldom::ScreenOverlayPtr;
58 using kmldom::IconPtr;
59 using kmldom::CreatePtr;
60 using kmldom::ChangePtr;
61 using kmldom::DeletePtr;
62
63 #include "ogrlibkmlfeature.h"
64 #include "ogrlibkmlfield.h"
65 #include "ogrlibkmlstyle.h"
66
67 /************************************************************************/
68 /* OGRLIBKMLGetSanitizedNCName() */
69 /************************************************************************/
70
OGRLIBKMLGetSanitizedNCName(const char * pszName)71 CPLString OGRLIBKMLGetSanitizedNCName(const char* pszName)
72 {
73 CPLString osName(pszName);
74 /* (Approximate) validation rules for a valic NCName */
75 for(size_t i = 0; i < osName.size(); i++)
76 {
77 char ch = osName[i];
78 if( (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= 'a' && ch <= 'z') )
79 {
80 /* ok */
81 }
82 else if ( i > 0 && (ch == '-' || ch == '.' || (ch >= '0' && ch <= '9')) )
83 {
84 /* ok */
85 }
86 #if 0
87 /* Always false. */
88 else if ( ch > 127 )
89 {
90 /* ok : this is an approximation */
91 }
92 #endif
93 else
94 osName[i] = '_';
95 }
96 return osName;
97 }
98
99 /******************************************************************************
100 OGRLIBKMLLayer constructor
101
102 Args: pszLayerName the name of the layer
103 poSpatialRef the spacial Refrance for the layer
104 eGType the layers geometry type
105 poOgrDS pointer to the datasource the layer is in
106 poKmlRoot pointer to the root kml element of the layer
107 poKmlContainer pointer to the kml container of the layer
108 pszFileName the filename of the layer
109 bNew true if its a new layer
110 bUpdate true if the layer is writeable
111
112 Returns: nothing
113
114 ******************************************************************************/
115
OGRLIBKMLLayer(const char * pszLayerName,OGRSpatialReference * poSpatialRef,OGRwkbGeometryType eGType,OGRLIBKMLDataSource * poOgrDS,ElementPtr poKmlRoot,ContainerPtr poKmlContainer,UpdatePtr poKmlUpdate,const char * pszFileName,int bNew,int bUpdate)116 OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
117 OGRSpatialReference * poSpatialRef,
118 OGRwkbGeometryType eGType,
119 OGRLIBKMLDataSource * poOgrDS,
120 ElementPtr poKmlRoot,
121 ContainerPtr poKmlContainer,
122 UpdatePtr poKmlUpdate,
123 const char *pszFileName,
124 int bNew,
125 int bUpdate )
126 {
127
128 m_poStyleTable = NULL;
129 iFeature = 0;
130 nFeatures = 0;
131 nFID = 1;
132
133 this->bUpdate = bUpdate;
134 bUpdated = FALSE;
135 m_pszName = CPLStrdup ( pszLayerName );
136 m_pszFileName = CPLStrdup ( pszFileName );
137 m_poOgrDS = poOgrDS;
138
139 m_poOgrSRS = new OGRSpatialReference ( NULL );
140 m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );
141
142 m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
143 SetDescription( m_poOgrFeatureDefn->GetName() );
144 m_poOgrFeatureDefn->Reference ( );
145 m_poOgrFeatureDefn->SetGeomType ( eGType );
146 if( m_poOgrFeatureDefn->GetGeomFieldCount() != 0 )
147 m_poOgrFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poOgrSRS);
148
149 /***** store the root element pointer *****/
150
151 m_poKmlLayerRoot = poKmlRoot;
152
153 /***** store the layers container *****/
154
155 m_poKmlLayer = poKmlContainer;
156
157 /* update container */
158 m_poKmlUpdate = poKmlUpdate;
159
160 m_poKmlSchema = NULL;
161
162 /***** related to Region *****/
163
164 m_bWriteRegion = FALSE;
165 m_bRegionBoundsAuto = FALSE;
166 m_dfRegionMinLodPixels = 0;
167 m_dfRegionMaxLodPixels = -1;
168 m_dfRegionMinFadeExtent = 0;
169 m_dfRegionMaxFadeExtent = 0;
170 m_dfRegionMinX = 200;
171 m_dfRegionMinY = 200;
172 m_dfRegionMaxX = -200;
173 m_dfRegionMaxY = -200;
174
175
176 m_bReadGroundOverlay = CSLTestBoolean(CPLGetConfigOption("LIBKML_READ_GROUND_OVERLAY", "YES"));
177 m_bUseSimpleField = CSLTestBoolean(CPLGetConfigOption("LIBKML_USE_SIMPLEFIELD", "YES"));
178
179 m_bUpdateIsFolder = FALSE;
180
181 /***** was the layer created from a DS::Open *****/
182
183 if ( !bNew ) {
184
185 /***** get the number of features on the layer *****/
186
187 nFeatures = m_poKmlLayer->get_feature_array_size ( );
188
189 /***** get the field config *****/
190
191 struct fieldconfig oFC;
192 get_fieldconfig( &oFC );
193
194 /***** name field *****/
195
196 OGRFieldDefn oOgrFieldName ( oFC.namefield,OFTString );
197 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
198
199 /***** descripton field *****/
200
201 OGRFieldDefn oOgrFieldDesc ( oFC.descfield, OFTString );
202 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDesc );
203
204 /***** timestamp field *****/
205
206 OGRFieldDefn oOgrFieldTs ( oFC.tsfield, OFTDateTime );
207 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTs );
208
209 /***** timespan begin field *****/
210
211 OGRFieldDefn oOgrFieldBegin ( oFC.beginfield, OFTDateTime );
212 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldBegin );
213
214 /***** timespan end field *****/
215
216 OGRFieldDefn oOgrFieldEnd ( oFC.endfield, OFTDateTime );
217 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldEnd );
218
219 /***** altitudeMode field *****/
220
221 OGRFieldDefn oOgrFieldAltitudeMode ( oFC.altitudeModefield, OFTString );
222 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldAltitudeMode );
223
224 /***** tessellate field *****/
225
226 OGRFieldDefn oOgrFieldTessellate ( oFC.tessellatefield, OFTInteger );
227 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTessellate );
228
229 /***** extrude field *****/
230
231 OGRFieldDefn oOgrFieldExtrude ( oFC.extrudefield, OFTInteger );
232 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldExtrude );
233
234 /***** visibility field *****/
235
236 OGRFieldDefn oOgrFieldVisibility ( oFC.visibilityfield, OFTInteger );
237 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldVisibility );
238
239 /***** draw order field *****/
240
241 OGRFieldDefn oOgrFieldDrawOrder ( oFC.drawOrderfield, OFTInteger );
242 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDrawOrder );
243
244 /***** icon field *****/
245
246 OGRFieldDefn oOgrFieldIcon ( oFC.iconfield, OFTString );
247 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldIcon );
248
249 /***** get the styles *****/
250
251 if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) )
252 ParseStyles ( AsDocument ( m_poKmlLayer ), &m_poStyleTable );
253
254 /***** get the schema if the layer is a Document *****/
255
256 if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
257 DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
258
259 if ( poKmlDocument->get_schema_array_size ( ) ) {
260 m_poKmlSchema = poKmlDocument->get_schema_array_at ( 0 );
261 kml2FeatureDef ( m_poKmlSchema, m_poOgrFeatureDefn );
262 }
263 }
264
265 /***** the schema is somewhere else *****/
266
267 if (m_poKmlSchema == NULL) {
268
269 /***** try to find the correct schema *****/
270
271 int bHasHeading = FALSE, bHasTilt = FALSE, bHasRoll = FALSE;
272 int bHasSnippet = FALSE;
273 FeaturePtr poKmlFeature;
274
275 /***** find the first placemark *****/
276
277 do {
278 if ( iFeature >= nFeatures )
279 break;
280
281 poKmlFeature =
282 m_poKmlLayer->get_feature_array_at ( iFeature++ );
283
284 if( poKmlFeature->Type() == kmldom::Type_Placemark )
285 {
286 PlacemarkPtr poKmlPlacemark = AsPlacemark ( poKmlFeature );
287 if( !poKmlPlacemark->has_geometry ( ) &&
288 poKmlPlacemark->has_abstractview ( ) &&
289 poKmlPlacemark->get_abstractview()->IsA( kmldom::Type_Camera) )
290 {
291 const CameraPtr& camera = AsCamera(poKmlPlacemark->get_abstractview());
292 if( camera->has_heading() && !bHasHeading )
293 {
294 bHasHeading = TRUE;
295 OGRFieldDefn oOgrField ( oFC.headingfield, OFTReal );
296 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
297 }
298 if( camera->has_tilt() && !bHasTilt )
299 {
300 bHasTilt = TRUE;
301 OGRFieldDefn oOgrField ( oFC.tiltfield, OFTReal );
302 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
303 }
304 if( camera->has_roll() && !bHasRoll )
305 {
306 bHasRoll = TRUE;
307 OGRFieldDefn oOgrField ( oFC.rollfield, OFTReal );
308 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
309 }
310 }
311 }
312 if( !bHasSnippet && poKmlFeature->has_snippet() )
313 {
314 bHasSnippet = TRUE;
315 OGRFieldDefn oOgrField ( oFC.snippetfield, OFTString );
316 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
317 }
318 } while ( poKmlFeature->Type ( ) != kmldom::Type_Placemark );
319
320 if ( iFeature <= nFeatures && poKmlFeature &&
321 poKmlFeature->Type ( ) == kmldom::Type_Placemark &&
322 poKmlFeature->has_extendeddata ( ) ) {
323
324 ExtendedDataPtr poKmlExtendedData = poKmlFeature->
325 get_extendeddata ( );
326
327 if ( poKmlExtendedData->get_schemadata_array_size ( ) > 0 ) {
328 SchemaDataPtr poKmlSchemaData = poKmlExtendedData->
329 get_schemadata_array_at ( 0 );
330
331 if ( poKmlSchemaData->has_schemaurl ( ) ) {
332
333 std::string oKmlSchemaUrl = poKmlSchemaData->
334 get_schemaurl ( );
335 if ( ( m_poKmlSchema =
336 m_poOgrDS->FindSchema ( oKmlSchemaUrl.
337 c_str ( ) ) ) ) {
338 kml2FeatureDef ( m_poKmlSchema,
339 m_poOgrFeatureDefn );
340 }
341 }
342 }
343 else if ( poKmlExtendedData->get_data_array_size() > 0 )
344 {
345 /* Use the <Data> of the first placemark to build the feature definition */
346 /* If others have different fields, too bad... */
347 int bLaunderFieldNames =
348 CSLTestBoolean(CPLGetConfigOption("LIBKML_LAUNDER_FIELD_NAMES", "YES"));
349 size_t nDataArraySize = poKmlExtendedData->get_data_array_size();
350 for(size_t i=0; i < nDataArraySize; i++)
351 {
352 const DataPtr& data = poKmlExtendedData->get_data_array_at(i);
353 if (data->has_name())
354 {
355 CPLString osName = data->get_name();
356 if (bLaunderFieldNames)
357 osName = LaunderFieldNames(osName);
358 OGRFieldDefn oOgrField ( osName,
359 OFTString );
360 m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
361 }
362 }
363 }
364 }
365
366 iFeature = 0;
367
368 }
369
370
371
372 /***** check if any features are another layer *****/
373
374 m_poOgrDS->ParseLayers ( m_poKmlLayer, poSpatialRef );
375
376 }
377
378 /***** it was from a DS::CreateLayer *****/
379
380 else {
381
382 /***** mark the layer as updated *****/
383
384 bUpdated = TRUE;
385 }
386
387 }
388
389 /******************************************************************************
390 OGRLIBKMLLayer Destructor
391
392 Args: none
393
394 Returns: nothing
395
396 ******************************************************************************/
397
~OGRLIBKMLLayer()398 OGRLIBKMLLayer::~OGRLIBKMLLayer ( )
399 {
400
401 CPLFree ( ( void * )m_pszName );
402 CPLFree ( ( void * )m_pszFileName );
403 m_poOgrSRS->Release();
404
405 m_poOgrFeatureDefn->Release ( );
406
407
408 }
409
410
411 /******************************************************************************
412 Method to get the next feature on the layer
413
414 Args: none
415
416 Returns: The next feature, or NULL if there is no more
417
418 this function copyed from the sqlite driver
419 ******************************************************************************/
420
GetNextFeature()421 OGRFeature *OGRLIBKMLLayer::GetNextFeature()
422
423 {
424 for( ; TRUE; )
425 {
426 OGRFeature *poFeature;
427
428 poFeature = GetNextRawFeature();
429 if( poFeature == NULL )
430 return NULL;
431
432 if( (m_poFilterGeom == NULL
433 || FilterGeometry( poFeature->GetGeometryRef() ) )
434 && (m_poAttrQuery == NULL
435 || m_poAttrQuery->Evaluate( poFeature )) )
436 return poFeature;
437
438 delete poFeature;
439 }
440 }
441
442 /******************************************************************************
443 Method to get the next feature on the layer
444
445 Args: none
446
447 Returns: The next feature, or NULL if there is no more
448
449 ******************************************************************************/
450
GetNextRawFeature()451 OGRFeature *OGRLIBKMLLayer::GetNextRawFeature (
452 )
453 {
454 FeaturePtr poKmlFeature;
455 OGRFeature *poOgrFeature = NULL;
456
457 if( m_poKmlLayer == NULL )
458 return NULL;
459
460 /***** loop over the kml features to find the next placemark *****/
461
462 do {
463 if ( iFeature >= nFeatures )
464 break;
465
466 /***** get the next kml feature in the container *****/
467
468 poKmlFeature = m_poKmlLayer->get_feature_array_at ( iFeature++ );
469
470 /***** what type of kml feature in the container? *****/
471
472 switch (poKmlFeature->Type ( )) {
473
474 case kmldom::Type_Placemark:
475 poOgrFeature = kml2feat ( AsPlacemark ( poKmlFeature ),
476 m_poOgrDS, this,
477 m_poOgrFeatureDefn, m_poOgrSRS );
478 break;
479
480 case kmldom::Type_GroundOverlay:
481 if (m_bReadGroundOverlay) {
482 poOgrFeature =
483 kmlgroundoverlay2feat ( AsGroundOverlay ( poKmlFeature ),
484 m_poOgrDS, this,
485 m_poOgrFeatureDefn,
486 m_poOgrSRS );
487 }
488 break;
489
490 default:
491 break;
492
493 }
494
495 } while ( !poOgrFeature );
496
497 /***** set the FID on the ogr feature *****/
498
499 if (poOgrFeature)
500 poOgrFeature->SetFID(nFID ++);
501
502 return poOgrFeature;
503 }
504
505 /******************************************************************************
506 method to add a feature to a layer
507
508 Args: poOgrFeat pointer to the feature to add
509
510 Returns: OGRERR_NONE, or OGRERR_UNSUPPORTED_OPERATION of the layer is
511 not writeable
512
513 ******************************************************************************/
514
ICreateFeature(OGRFeature * poOgrFeat)515 OGRErr OGRLIBKMLLayer::ICreateFeature (
516 OGRFeature * poOgrFeat )
517 {
518
519 if ( !bUpdate )
520 return OGRERR_UNSUPPORTED_OPERATION;
521
522 if( m_bRegionBoundsAuto && poOgrFeat->GetGeometryRef() != NULL &&
523 !(poOgrFeat->GetGeometryRef()->IsEmpty()) )
524 {
525 OGREnvelope sEnvelope;
526 poOgrFeat->GetGeometryRef()->getEnvelope(&sEnvelope);
527 m_dfRegionMinX = MIN(m_dfRegionMinX, sEnvelope.MinX);
528 m_dfRegionMinY = MIN(m_dfRegionMinY, sEnvelope.MinY);
529 m_dfRegionMaxX = MAX(m_dfRegionMaxX, sEnvelope.MaxX);
530 m_dfRegionMaxY = MAX(m_dfRegionMaxY, sEnvelope.MaxY);
531 }
532
533 FeaturePtr poKmlFeature =
534 feat2kml ( m_poOgrDS, this, poOgrFeat, m_poOgrDS->GetKmlFactory ( ),
535 m_bUseSimpleField );
536
537 if( m_poKmlLayer != NULL )
538 m_poKmlLayer->add_feature ( poKmlFeature );
539 else
540 {
541 CPLAssert( m_poKmlUpdate != NULL );
542 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
543 CreatePtr poCreate = poKmlFactory->CreateCreate();
544 ContainerPtr poContainer;
545 if( m_bUpdateIsFolder )
546 poContainer = poKmlFactory->CreateFolder();
547 else
548 poContainer = poKmlFactory->CreateDocument();
549 poContainer->set_targetid(OGRLIBKMLGetSanitizedNCName(GetName()));
550 poContainer->add_feature ( poKmlFeature );
551 poCreate->add_container(poContainer);
552 m_poKmlUpdate->add_updateoperation(poCreate);
553 }
554
555 /***** update the layer class count of features *****/
556
557 if( m_poKmlLayer != NULL )
558 {
559 nFeatures++;
560
561 const char* pszId = CPLSPrintf("%s.%d",
562 OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), nFeatures);
563 poOgrFeat->SetFID(nFeatures);
564 poKmlFeature->set_id(pszId);
565 }
566 else
567 {
568 if( poOgrFeat->GetFID() < 0 )
569 {
570 static int bAlreadyWarned = FALSE;
571 if( !bAlreadyWarned )
572 {
573 bAlreadyWarned = TRUE;
574 CPLError(CE_Warning, CPLE_AppDefined,
575 "It is recommended to define a FID when calling CreateFeature() in a update document");
576 }
577 }
578 else
579 {
580 const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
581 OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), poOgrFeat->GetFID());
582 poOgrFeat->SetFID(nFeatures);
583 poKmlFeature->set_id(pszId);
584 }
585 }
586
587 /***** mark the layer as updated *****/
588
589 bUpdated = TRUE;
590 m_poOgrDS->Updated ( );
591
592 return OGRERR_NONE;
593 }
594
595
596 /******************************************************************************
597 method to update a feature to a layer. Only work on a NetworkLinkControl/Update
598
599 Args: poOgrFeat pointer to the feature to update
600
601 Returns: OGRERR_NONE, or OGRERR_UNSUPPORTED_OPERATION of the layer is
602 not writeable
603
604 ******************************************************************************/
605
ISetFeature(OGRFeature * poOgrFeat)606 OGRErr OGRLIBKMLLayer::ISetFeature ( OGRFeature * poOgrFeat )
607 {
608 if( !bUpdate || m_poKmlUpdate == NULL )
609 return OGRERR_UNSUPPORTED_OPERATION;
610 if( poOgrFeat->GetFID() == OGRNullFID )
611 return OGRERR_FAILURE;
612
613 FeaturePtr poKmlFeature =
614 feat2kml ( m_poOgrDS, this, poOgrFeat, m_poOgrDS->GetKmlFactory ( ),
615 m_bUseSimpleField );
616
617 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
618 ChangePtr poChange = poKmlFactory->CreateChange();
619 poChange->add_object(poKmlFeature);
620 m_poKmlUpdate->add_updateoperation(poChange);
621
622 const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
623 OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), poOgrFeat->GetFID());
624 poKmlFeature->set_targetid(pszId);
625
626 /***** mark the layer as updated *****/
627
628 bUpdated = TRUE;
629 m_poOgrDS->Updated ( );
630
631 return OGRERR_NONE;
632 }
633
634 /******************************************************************************
635 method to delete a feature to a layer. Only work on a NetworkLinkControl/Update
636
637 Args: nFID id of the feature to delete
638
639 Returns: OGRERR_NONE, or OGRERR_UNSUPPORTED_OPERATION of the layer is
640 not writeable
641
642 ******************************************************************************/
643
DeleteFeature(GIntBig nFID)644 OGRErr OGRLIBKMLLayer::DeleteFeature( GIntBig nFID )
645 {
646 if( !bUpdate || m_poKmlUpdate == NULL )
647 return OGRERR_UNSUPPORTED_OPERATION;
648
649 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
650 DeletePtr poDelete = poKmlFactory->CreateDelete();
651 m_poKmlUpdate->add_updateoperation(poDelete);
652 PlacemarkPtr poKmlPlacemark = poKmlFactory->CreatePlacemark();
653 poDelete->add_feature(poKmlPlacemark);
654
655 const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
656 OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), nFID);
657 poKmlPlacemark->set_targetid(pszId);
658
659 /***** mark the layer as updated *****/
660
661 bUpdated = TRUE;
662 m_poOgrDS->Updated ( );
663
664 return OGRERR_NONE;
665 }
666
667 /******************************************************************************
668 method to get the number of features on the layer
669
670 Args: bForce no effect as of now
671
672 Returns: the number of features on the layer
673
674 Note: the result can include links, folders and other items that are
675 not supported by OGR
676
677 ******************************************************************************/
678
GetFeatureCount(int bForce)679 GIntBig OGRLIBKMLLayer::GetFeatureCount (
680 int bForce )
681 {
682
683
684 int i = 0;
685 if (m_poFilterGeom != NULL || m_poAttrQuery != NULL ) {
686 i = OGRLayer::GetFeatureCount( bForce );
687 }
688
689 else if( m_poKmlLayer != NULL ) {
690 size_t iKmlFeature;
691 size_t nKmlFeatures = m_poKmlLayer->get_feature_array_size ( );
692 FeaturePtr poKmlFeature;
693
694 /***** loop over the kml features in the container *****/
695
696 for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
697 poKmlFeature = m_poKmlLayer->get_feature_array_at ( iKmlFeature );
698
699 /***** what type of kml feature? *****/
700
701 switch (poKmlFeature->Type ( )) {
702
703 case kmldom::Type_Placemark:
704 i++;
705 break;
706
707 case kmldom::Type_GroundOverlay:
708 if (m_bReadGroundOverlay)
709 i++;
710 break;
711
712 default:
713 break;
714
715 }
716 }
717 }
718
719 return i;
720 }
721
722 /******************************************************************************
723 GetExtent()
724
725 Args: psExtent pointer to the Envelope to store the result in
726 bForce no effect as of now
727
728 Returns: nothing
729
730 ******************************************************************************/
731
GetExtent(OGREnvelope * psExtent,int bForce)732 OGRErr OGRLIBKMLLayer::GetExtent (
733 OGREnvelope * psExtent,
734 int bForce )
735 {
736 Bbox oKmlBbox;
737
738 if ( m_poKmlLayer != NULL &&
739 kmlengine::
740 GetFeatureBounds ( AsFeature ( m_poKmlLayer ), &oKmlBbox ) ) {
741 psExtent->MinX = oKmlBbox.get_west ( );
742 psExtent->MinY = oKmlBbox.get_south ( );
743 psExtent->MaxX = oKmlBbox.get_east ( );
744 psExtent->MaxY = oKmlBbox.get_north ( );
745
746 return OGRERR_NONE;
747 }
748 else
749 return OGRLayer::GetExtent(psExtent, bForce);
750 }
751
752
753
754
755 /******************************************************************************
756 Method to create a field on a layer
757
758 Args: poField pointer to the Field Definition to add
759 bApproxOK no effect as of now
760
761 Returns: OGRERR_NONE on success or OGRERR_UNSUPPORTED_OPERATION if the
762 layer is not writeable
763
764 ******************************************************************************/
765
CreateField(OGRFieldDefn * poField,CPL_UNUSED int bApproxOK)766 OGRErr OGRLIBKMLLayer::CreateField (
767 OGRFieldDefn * poField,
768 CPL_UNUSED int bApproxOK )
769 {
770 if ( !bUpdate )
771 return OGRERR_UNSUPPORTED_OPERATION;
772
773 if( m_bUseSimpleField )
774 {
775 SimpleFieldPtr poKmlSimpleField = NULL;
776
777 if ( (poKmlSimpleField =
778 FieldDef2kml ( poField, m_poOgrDS->GetKmlFactory ( ) )) != NULL )
779 {
780 if( m_poKmlSchema == NULL )
781 {
782 /***** create a new schema *****/
783
784 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
785
786 m_poKmlSchema = poKmlFactory->CreateSchema ( );
787
788 /***** set the id on the new schema *****/
789
790 std::string oKmlSchemaID = OGRLIBKMLGetSanitizedNCName(m_pszName);
791 oKmlSchemaID.append ( ".schema" );
792 m_poKmlSchema->set_id ( oKmlSchemaID );
793 }
794
795 m_poKmlSchema->add_simplefield ( poKmlSimpleField );
796 }
797 }
798
799 m_poOgrFeatureDefn->AddFieldDefn ( poField );
800
801 /***** mark the layer as updated *****/
802
803 bUpdated = TRUE;
804 m_poOgrDS->Updated ( );
805
806 return OGRERR_NONE;
807 }
808
809
810 /******************************************************************************
811 method to write the datasource to disk
812
813 Args: none
814
815 Returns nothing
816
817 ******************************************************************************/
818
SyncToDisk()819 OGRErr OGRLIBKMLLayer::SyncToDisk (
820 )
821 {
822
823 return OGRERR_NONE;
824 }
825
826 /******************************************************************************
827 method to get a layers style table
828
829 Args: none
830
831 Returns: pointer to the layers style table, or NULL if it does
832 not have one
833
834 ******************************************************************************/
835
GetStyleTable()836 OGRStyleTable *OGRLIBKMLLayer::GetStyleTable (
837 )
838 {
839
840 return m_poStyleTable;
841 }
842
843 /******************************************************************************
844 method to write a style table to a layer
845
846 Args: poStyleTable pointer to the style table to add
847
848 Returns: nothing
849
850 note: this method assumes ownership of the style table
851 ******************************************************************************/
852
SetStyleTableDirectly(OGRStyleTable * poStyleTable)853 void OGRLIBKMLLayer::SetStyleTableDirectly (
854 OGRStyleTable * poStyleTable )
855 {
856
857 if ( !bUpdate || m_poKmlLayer == NULL )
858 return;
859
860 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
861
862 if ( m_poStyleTable )
863 delete m_poStyleTable;
864
865 m_poStyleTable = poStyleTable;
866
867 if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
868
869 /***** delete all the styles *****/
870
871 DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
872 size_t nKmlStyles = poKmlDocument->get_schema_array_size ( );
873 int iKmlStyle;
874
875 for ( iKmlStyle = nKmlStyles - 1; iKmlStyle >= 0; iKmlStyle-- ) {
876 poKmlDocument->DeleteStyleSelectorAt ( iKmlStyle );
877 }
878
879 /***** add the new style table to the document *****/
880
881 styletable2kml ( poStyleTable, poKmlFactory,
882 AsContainer ( poKmlDocument ) );
883
884 }
885
886 /***** mark the layer as updated *****/
887
888 bUpdated = TRUE;
889 m_poOgrDS->Updated ( );
890
891 return;
892 }
893
894 /******************************************************************************
895 method to write a style table to a layer
896
897 Args: poStyleTable pointer to the style table to add
898
899 Returns: nothing
900
901 note: this method copys the style table, and the user will still be
902 responsible for its destruction
903 ******************************************************************************/
904
SetStyleTable(OGRStyleTable * poStyleTable)905 void OGRLIBKMLLayer::SetStyleTable (
906 OGRStyleTable * poStyleTable )
907 {
908
909 if ( !bUpdate || m_poKmlLayer == NULL )
910 return;
911
912 if ( poStyleTable )
913 SetStyleTableDirectly ( poStyleTable->Clone ( ) );
914 else
915 SetStyleTableDirectly ( NULL );
916 return;
917 }
918
919 /******************************************************************************
920 Test if capability is available.
921
922 Args: pszCap layer capability name to test
923
924 Returns: True if the layer supports the capability, otherwise false
925
926 ******************************************************************************/
927
TestCapability(const char * pszCap)928 int OGRLIBKMLLayer::TestCapability (
929 const char *pszCap )
930 {
931 int result = FALSE;
932
933 if ( EQUAL ( pszCap, OLCRandomRead ) )
934 result = FALSE;
935 else if ( EQUAL ( pszCap, OLCSequentialWrite ) )
936 result = bUpdate;
937 else if ( EQUAL ( pszCap, OLCRandomWrite ) )
938 result = FALSE;
939 else if ( EQUAL ( pszCap, OLCFastFeatureCount ) )
940 result = FALSE;
941 else if ( EQUAL ( pszCap, OLCFastSetNextByIndex ) )
942 result = FALSE;
943 else if ( EQUAL ( pszCap, OLCCreateField ) )
944 result = bUpdate;
945 else if ( EQUAL ( pszCap, OLCDeleteFeature ) )
946 result = FALSE;
947 else if ( EQUAL(pszCap, OLCStringsAsUTF8) )
948 result = TRUE;
949
950 return result;
951 }
952
953 /************************************************************************/
954 /* LaunderFieldNames() */
955 /************************************************************************/
956
LaunderFieldNames(CPLString osName)957 CPLString OGRLIBKMLLayer::LaunderFieldNames(CPLString osName)
958 {
959 CPLString osLaunderedName;
960 for(int i=0;i<(int)osName.size();i++)
961 {
962 char ch = osName[i];
963 if ((ch >= '0' && ch <= '9') ||
964 (ch >= 'a' && ch <= 'z') ||
965 (ch >= 'A' && ch <= 'Z') ||
966 (ch == '_'))
967 osLaunderedName += ch;
968 else
969 osLaunderedName += "_";
970 }
971 return osLaunderedName;
972 }
973
974 /************************************************************************/
975 /* SetLookAt() */
976 /************************************************************************/
977
SetLookAt(const char * pszLookatLongitude,const char * pszLookatLatitude,const char * pszLookatAltitude,const char * pszLookatHeading,const char * pszLookatTilt,const char * pszLookatRange,const char * pszLookatAltitudeMode)978 void OGRLIBKMLLayer::SetLookAt( const char* pszLookatLongitude,
979 const char* pszLookatLatitude,
980 const char* pszLookatAltitude,
981 const char* pszLookatHeading,
982 const char* pszLookatTilt,
983 const char* pszLookatRange,
984 const char* pszLookatAltitudeMode )
985 {
986 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
987 LookAtPtr lookAt = poKmlFactory->CreateLookAt();
988 lookAt->set_latitude(CPLAtof(pszLookatLatitude));
989 lookAt->set_longitude(CPLAtof(pszLookatLongitude));
990 if( pszLookatAltitude != NULL )
991 lookAt->set_altitude(CPLAtof(pszLookatAltitude));
992 if( pszLookatHeading != NULL )
993 lookAt->set_heading(CPLAtof(pszLookatHeading));
994 if( pszLookatTilt != NULL )
995 {
996 double dfTilt = CPLAtof(pszLookatTilt);
997 if( dfTilt >= 0 && dfTilt <= 90 )
998 lookAt->set_tilt(dfTilt);
999 else
1000 CPLError(CE_Warning, CPLE_AppDefined, "Invalid value for tilt: %s",
1001 pszLookatTilt);
1002 }
1003 lookAt->set_range(CPLAtof(pszLookatRange));
1004 if( pszLookatAltitudeMode != NULL )
1005 {
1006 int isGX = FALSE;
1007 int iAltitudeMode = kmlAltitudeModeFromString(pszLookatAltitudeMode, isGX);
1008 if( iAltitudeMode != kmldom::ALTITUDEMODE_CLAMPTOGROUND &&
1009 pszLookatAltitude == NULL )
1010 {
1011 CPLError(CE_Warning, CPLE_AppDefined, "Lookat altitude should be present for altitudeMode = %s",
1012 pszLookatAltitudeMode);
1013 }
1014 else if( isGX )
1015 lookAt->set_gx_altitudemode(iAltitudeMode);
1016 else
1017 lookAt->set_altitudemode(iAltitudeMode);
1018 }
1019
1020 m_poKmlLayer->set_abstractview(lookAt);
1021 }
1022
1023 /************************************************************************/
1024 /* SetCamera() */
1025 /************************************************************************/
1026
SetCamera(const char * pszCameraLongitude,const char * pszCameraLatitude,const char * pszCameraAltitude,const char * pszCameraHeading,const char * pszCameraTilt,const char * pszCameraRoll,const char * pszCameraAltitudeMode)1027 void OGRLIBKMLLayer::SetCamera( const char* pszCameraLongitude,
1028 const char* pszCameraLatitude,
1029 const char* pszCameraAltitude,
1030 const char* pszCameraHeading,
1031 const char* pszCameraTilt,
1032 const char* pszCameraRoll,
1033 const char* pszCameraAltitudeMode )
1034 {
1035 int isGX = FALSE;
1036 int iAltitudeMode = kmlAltitudeModeFromString(pszCameraAltitudeMode, isGX);
1037 if( isGX == FALSE && iAltitudeMode == kmldom::ALTITUDEMODE_CLAMPTOGROUND )
1038 {
1039 CPLError(CE_Warning, CPLE_AppDefined, "Camera altitudeMode should be different from %s",
1040 pszCameraAltitudeMode);
1041 return;
1042 }
1043 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
1044 CameraPtr camera = poKmlFactory->CreateCamera();
1045 camera->set_latitude(CPLAtof(pszCameraLatitude));
1046 camera->set_longitude(CPLAtof(pszCameraLongitude));
1047 camera->set_altitude(CPLAtof(pszCameraAltitude));
1048 if( pszCameraHeading != NULL )
1049 camera->set_heading(CPLAtof(pszCameraHeading));
1050 if( pszCameraTilt != NULL )
1051 {
1052 double dfTilt = CPLAtof(pszCameraTilt);
1053 if( dfTilt >= 0 && dfTilt <= 90 )
1054 camera->set_tilt(dfTilt);
1055 else
1056 CPLError(CE_Warning, CPLE_AppDefined, "Invalid value for tilt: %s",
1057 pszCameraTilt);
1058 }
1059 if( pszCameraRoll != NULL )
1060 camera->set_roll(CPLAtof(pszCameraRoll));
1061 if( isGX )
1062 camera->set_gx_altitudemode(iAltitudeMode);
1063 else
1064 camera->set_altitudemode(iAltitudeMode);
1065
1066 m_poKmlLayer->set_abstractview(camera);
1067 }
1068
1069 /************************************************************************/
1070 /* SetWriteRegion() */
1071 /************************************************************************/
1072
SetWriteRegion(double dfMinLodPixels,double dfMaxLodPixels,double dfMinFadeExtent,double dfMaxFadeExtent)1073 void OGRLIBKMLLayer::SetWriteRegion(double dfMinLodPixels,
1074 double dfMaxLodPixels,
1075 double dfMinFadeExtent,
1076 double dfMaxFadeExtent)
1077 {
1078 m_bWriteRegion = TRUE;
1079 m_bRegionBoundsAuto = TRUE;
1080 m_dfRegionMinLodPixels = dfMinLodPixels;
1081 m_dfRegionMaxLodPixels = dfMaxLodPixels;
1082 m_dfRegionMinFadeExtent = dfMinFadeExtent;
1083 m_dfRegionMaxFadeExtent = dfMaxFadeExtent;
1084 }
1085
1086 /************************************************************************/
1087 /* SetRegionBounds() */
1088 /************************************************************************/
1089
SetRegionBounds(double dfMinX,double dfMinY,double dfMaxX,double dfMaxY)1090 void OGRLIBKMLLayer::SetRegionBounds(double dfMinX, double dfMinY,
1091 double dfMaxX, double dfMaxY)
1092 {
1093 m_bRegionBoundsAuto = FALSE;
1094 m_dfRegionMinX = dfMinX;
1095 m_dfRegionMinY = dfMinY;
1096 m_dfRegionMaxX = dfMaxX;
1097 m_dfRegionMaxY = dfMaxY;
1098 }
1099
1100 /************************************************************************/
1101 /* Finalize() */
1102 /************************************************************************/
1103
Finalize(DocumentPtr poKmlDocument)1104 void OGRLIBKMLLayer::Finalize(DocumentPtr poKmlDocument)
1105 {
1106 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
1107
1108 if( m_bWriteRegion && m_dfRegionMinX < m_dfRegionMaxX )
1109 {
1110 RegionPtr region = poKmlFactory->CreateRegion();
1111
1112 LatLonAltBoxPtr box = poKmlFactory->CreateLatLonAltBox();
1113 box->set_west(m_dfRegionMinX);
1114 box->set_east(m_dfRegionMaxX);
1115 box->set_south(m_dfRegionMinY);
1116 box->set_north(m_dfRegionMaxY);
1117 region->set_latlonaltbox(box);
1118
1119 LodPtr lod = poKmlFactory->CreateLod();
1120 lod->set_minlodpixels(m_dfRegionMinLodPixels);
1121 lod->set_maxlodpixels(m_dfRegionMaxLodPixels);
1122 if( (m_dfRegionMinFadeExtent != 0 || m_dfRegionMaxFadeExtent != 0) &&
1123 m_dfRegionMinFadeExtent + m_dfRegionMaxFadeExtent <
1124 m_dfRegionMaxLodPixels - m_dfRegionMinLodPixels )
1125 {
1126 lod->set_minfadeextent(m_dfRegionMinFadeExtent);
1127 lod->set_maxfadeextent(m_dfRegionMaxFadeExtent);
1128 }
1129
1130 region->set_lod(lod);
1131 m_poKmlLayer->set_region(region);
1132 }
1133
1134 createkmlliststyle (poKmlFactory,
1135 GetName(),
1136 m_poKmlLayer,
1137 poKmlDocument,
1138 osListStyleType,
1139 osListStyleIconHref);
1140 }
1141
1142 /************************************************************************/
1143 /* LIBKMLGetUnits() */
1144 /************************************************************************/
1145
LIBKMLGetUnits(const char * pszUnits)1146 static int LIBKMLGetUnits(const char* pszUnits)
1147 {
1148 if( EQUAL(pszUnits, "fraction") )
1149 return kmldom::UNITS_FRACTION;
1150 if( EQUAL(pszUnits, "pixels") )
1151 return kmldom::UNITS_PIXELS;
1152 if( EQUAL(pszUnits, "insetPixels") )
1153 return kmldom::UNITS_INSETPIXELS;
1154 return kmldom::UNITS_FRACTION;
1155 }
1156
1157 /************************************************************************/
1158 /* LIBKMLSetVec2() */
1159 /************************************************************************/
1160
LIBKMLSetVec2(kmldom::Vec2Ptr vec2,const char * pszX,const char * pszY,const char * pszXUnits,const char * pszYUnits)1161 static void LIBKMLSetVec2(kmldom::Vec2Ptr vec2, const char* pszX, const char* pszY,
1162 const char* pszXUnits, const char* pszYUnits)
1163 {
1164 double dfX = CPLAtof(pszX);
1165 double dfY = CPLAtof(pszY);
1166 vec2->set_x(dfX);
1167 vec2->set_y(dfY);
1168 if( dfX <= 1 && dfY <= 1 )
1169 {
1170 if( pszXUnits == NULL ) pszXUnits = "fraction";
1171 if( pszYUnits == NULL ) pszYUnits = "fraction";
1172 }
1173 else
1174 {
1175 if( pszXUnits == NULL ) pszXUnits = "pixels";
1176 if( pszYUnits == NULL ) pszYUnits = "pixels";
1177 }
1178 vec2->set_xunits(LIBKMLGetUnits(pszXUnits));
1179 vec2->set_yunits(LIBKMLGetUnits(pszYUnits));
1180 }
1181
1182 /************************************************************************/
1183 /* SetScreenOverlay() */
1184 /************************************************************************/
1185
SetScreenOverlay(const char * pszSOHref,const char * pszSOName,const char * pszSODescription,const char * pszSOOverlayX,const char * pszSOOverlayY,const char * pszSOOverlayXUnits,const char * pszSOOverlayYUnits,const char * pszSOScreenX,const char * pszSOScreenY,const char * pszSOScreenXUnits,const char * pszSOScreenYUnits,const char * pszSOSizeX,const char * pszSOSizeY,const char * pszSOSizeXUnits,const char * pszSOSizeYUnits)1186 void OGRLIBKMLLayer::SetScreenOverlay(const char* pszSOHref,
1187 const char* pszSOName,
1188 const char* pszSODescription,
1189 const char* pszSOOverlayX,
1190 const char* pszSOOverlayY,
1191 const char* pszSOOverlayXUnits,
1192 const char* pszSOOverlayYUnits,
1193 const char* pszSOScreenX,
1194 const char* pszSOScreenY,
1195 const char* pszSOScreenXUnits,
1196 const char* pszSOScreenYUnits,
1197 const char* pszSOSizeX,
1198 const char* pszSOSizeY,
1199 const char* pszSOSizeXUnits,
1200 const char* pszSOSizeYUnits)
1201 {
1202 KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
1203 ScreenOverlayPtr so = poKmlFactory->CreateScreenOverlay();
1204
1205 if( pszSOName != NULL )
1206 so->set_name(pszSOName);
1207 if( pszSODescription != NULL )
1208 so->set_description(pszSODescription);
1209
1210 IconPtr icon = poKmlFactory->CreateIcon();
1211 icon->set_href(pszSOHref);
1212 so->set_icon(icon);
1213
1214 if( pszSOOverlayX != NULL && pszSOOverlayY != NULL )
1215 {
1216 kmldom::OverlayXYPtr overlayxy = poKmlFactory->CreateOverlayXY();
1217 LIBKMLSetVec2(overlayxy, pszSOOverlayX, pszSOOverlayY,
1218 pszSOOverlayXUnits, pszSOOverlayYUnits);
1219 so->set_overlayxy(overlayxy);
1220 }
1221
1222 if( pszSOScreenX != NULL && pszSOScreenY != NULL )
1223 {
1224 kmldom::ScreenXYPtr screenxy = poKmlFactory->CreateScreenXY();
1225 LIBKMLSetVec2(screenxy, pszSOScreenX, pszSOScreenY,
1226 pszSOScreenXUnits, pszSOScreenYUnits);
1227 so->set_screenxy(screenxy);
1228 }
1229 else
1230 {
1231 kmldom::ScreenXYPtr screenxy = poKmlFactory->CreateScreenXY();
1232 LIBKMLSetVec2(screenxy, "0.05", "0.05", NULL, NULL);
1233 so->set_screenxy(screenxy);
1234 }
1235
1236 if( pszSOSizeX != NULL && pszSOSizeY != NULL )
1237 {
1238 kmldom::SizePtr sizexy = poKmlFactory->CreateSize();
1239 LIBKMLSetVec2(sizexy, pszSOSizeX, pszSOSizeY,
1240 pszSOSizeXUnits, pszSOSizeYUnits);
1241 so->set_size(sizexy);
1242 }
1243
1244 m_poKmlLayer->add_feature(so);
1245 }
1246
1247 /************************************************************************/
1248 /* SetListStyle() */
1249 /************************************************************************/
1250
SetListStyle(const char * pszListStyleType,const char * pszListStyleIconHref)1251 void OGRLIBKMLLayer::SetListStyle(const char* pszListStyleType,
1252 const char* pszListStyleIconHref)
1253 {
1254 osListStyleType = (pszListStyleType) ? pszListStyleType : "";
1255 osListStyleIconHref = (pszListStyleIconHref) ? pszListStyleIconHref : "";
1256 }
1257