1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 :
29 : #include "ogr_libkml.h"
30 : //#include "cpl_conv.h"
31 : //#include "cpl_string.h"
32 : #include "cpl_error.h"
33 :
34 : #include <kml/dom.h>
35 :
36 : using kmldom::KmlFactory;
37 : using kmldom::PlacemarkPtr;
38 : using kmldom::Placemark;
39 : using kmldom::DocumentPtr;
40 : using kmldom::ContainerPtr;
41 : using kmldom::FeaturePtr;
42 : using kmldom::KmlPtr;
43 : using kmldom::Kml;
44 : using kmlengine::KmzFile;
45 : using kmlengine::KmlFile;
46 : using kmlengine::Bbox;
47 : using kmldom::ExtendedDataPtr;
48 : using kmldom::SchemaDataPtr;
49 :
50 : #include "ogrlibkmlfeature.h"
51 : #include "ogrlibkmlfield.h"
52 : #include "ogrlibkmlstyle.h"
53 :
54 : /******************************************************************************
55 : OGRLIBKMLLayer constructor
56 :
57 : Args: pszLayerName the name of the layer
58 : poSpatialRef the spacial Refrance for the layer
59 : eGType the layers geometry type
60 : poOgrDS pointer to the datasource the layer is in
61 : poKmlRoot pointer to the root kml element of the layer
62 : pszFileName the filename of the layer
63 : bNew true if its a new layer
64 : bUpdate true if the layer is writeable
65 :
66 : Returns: nothing
67 :
68 : ******************************************************************************/
69 :
70 : OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
71 : OGRSpatialReference * poSpatialRef,
72 : OGRwkbGeometryType eGType,
73 : OGRLIBKMLDataSource * poOgrDS,
74 : ElementPtr poKmlRoot,
75 : ContainerPtr poKmlContainer,
76 : const char *pszFileName,
77 : int bNew,
78 15 : int bUpdate )
79 : {
80 :
81 15 : m_poStyleTable = NULL;
82 15 : iFeature = 0;
83 15 : nFeatures = 0;
84 15 : nFID = 1;
85 :
86 15 : this->bUpdate = bUpdate;
87 15 : m_pszName = CPLStrdup ( pszLayerName );
88 15 : m_pszFileName = CPLStrdup ( pszFileName );
89 15 : m_poOgrDS = poOgrDS;
90 :
91 15 : m_poOgrSRS = new OGRSpatialReference ( NULL );
92 15 : m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );
93 :
94 15 : m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
95 15 : m_poOgrFeatureDefn->Reference ( );
96 15 : m_poOgrFeatureDefn->SetGeomType ( eGType );
97 :
98 : /***** store the root element pointer *****/
99 :
100 15 : m_poKmlLayerRoot = poKmlRoot;
101 :
102 : /***** store the layers container *****/
103 :
104 15 : m_poKmlLayer = poKmlContainer;
105 :
106 : /***** was the layer created from a DS::Open *****/
107 :
108 15 : if ( !bNew ) {
109 :
110 : /***** get the number of features on the layer *****/
111 :
112 13 : nFeatures = m_poKmlLayer->get_feature_array_size ( );
113 :
114 : /***** add the name and desc fields *****/
115 :
116 : const char *namefield =
117 13 : CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
118 : const char *descfield =
119 13 : CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
120 : const char *tsfield =
121 13 : CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
122 : const char *beginfield =
123 13 : CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
124 : const char *endfield =
125 13 : CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
126 : const char *altitudeModefield =
127 13 : CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
128 : const char *tessellatefield =
129 13 : CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
130 : const char *extrudefield =
131 13 : CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
132 : const char *visibilityfield =
133 13 : CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );
134 :
135 : OGRFieldDefn oOgrFieldName (
136 : namefield,
137 13 : OFTString );
138 :
139 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
140 :
141 : OGRFieldDefn oOgrFieldDesc (
142 : descfield,
143 13 : OFTString );
144 :
145 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDesc );
146 :
147 : OGRFieldDefn oOgrFieldTs (
148 : tsfield,
149 13 : OFTDateTime );
150 :
151 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTs );
152 :
153 : OGRFieldDefn oOgrFieldBegin (
154 : beginfield,
155 13 : OFTDateTime );
156 :
157 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldBegin );
158 :
159 : OGRFieldDefn oOgrFieldEnd (
160 : endfield,
161 13 : OFTDateTime );
162 :
163 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldEnd );
164 :
165 : OGRFieldDefn oOgrFieldAltitudeMode (
166 : altitudeModefield,
167 13 : OFTString );
168 :
169 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldAltitudeMode );
170 :
171 : OGRFieldDefn oOgrFieldTessellate (
172 : tessellatefield,
173 13 : OFTInteger );
174 :
175 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTessellate );
176 :
177 : OGRFieldDefn oOgrFieldExtrude (
178 : extrudefield,
179 13 : OFTInteger );
180 :
181 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldExtrude );
182 :
183 : OGRFieldDefn oOgrFieldVisibility (
184 : visibilityfield,
185 13 : OFTInteger );
186 :
187 13 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldVisibility );
188 :
189 : /***** get the styles *****/
190 :
191 13 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) )
192 3 : ParseStyles ( AsDocument ( m_poKmlLayer ), &m_poStyleTable );
193 :
194 : /***** get the schema if the layer is a Document *****/
195 :
196 13 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
197 3 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
198 :
199 3 : if ( poKmlDocument->get_schema_array_size ( ) ) {
200 0 : m_poKmlSchema = poKmlDocument->get_schema_array_at ( 0 );
201 0 : kml2FeatureDef ( m_poKmlSchema, m_poOgrFeatureDefn );
202 3 : }
203 : }
204 :
205 : /***** the schema is somewhere else *****/
206 :
207 : else {
208 :
209 : /***** try to find the correct schema *****/
210 :
211 10 : FeaturePtr poKmlFeature;
212 :
213 : /***** find the first placemark *****/
214 :
215 19 : do {
216 22 : if ( iFeature >= nFeatures )
217 3 : break;
218 :
219 : poKmlFeature =
220 19 : m_poKmlLayer->get_feature_array_at ( iFeature++ );
221 :
222 : } while ( poKmlFeature->Type ( ) != kmldom::Type_Placemark );
223 :
224 10 : if ( iFeature <= nFeatures && poKmlFeature &&
225 : poKmlFeature->Type ( ) == kmldom::Type_Placemark &&
226 : poKmlFeature->has_extendeddata ( ) ) {
227 :
228 : ExtendedDataPtr poKmlExtendedData = poKmlFeature->
229 0 : get_extendeddata ( );
230 :
231 0 : if ( poKmlExtendedData->get_schemadata_array_size ( ) > 0 ) {
232 : SchemaDataPtr poKmlSchemaData = poKmlExtendedData->
233 0 : get_schemadata_array_at ( 0 );
234 :
235 0 : if ( poKmlSchemaData->has_schemaurl ( ) ) {
236 :
237 : std::string oKmlSchemaUrl = poKmlSchemaData->
238 0 : get_schemaurl ( );
239 0 : if ( ( m_poKmlSchema =
240 : m_poOgrDS->FindSchema ( oKmlSchemaUrl.
241 : c_str ( ) ) ) ) {
242 : kml2FeatureDef ( m_poKmlSchema,
243 0 : m_poOgrFeatureDefn );
244 0 : }
245 :
246 :
247 :
248 :
249 0 : }
250 0 : }
251 : }
252 :
253 10 : iFeature = 0;
254 :
255 : }
256 :
257 :
258 :
259 : /***** check if any features are another layer *****/
260 :
261 13 : m_poOgrDS->ParseLayers ( m_poKmlLayer, poSpatialRef );
262 :
263 : }
264 :
265 : /***** it was from a DS::CreateLayer *****/
266 :
267 : else {
268 :
269 : /***** mark the layer as updated *****/
270 :
271 2 : bUpdated = TRUE;
272 :
273 : /***** create a new schema *****/
274 :
275 2 : KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
276 :
277 2 : m_poKmlSchema = poKmlFactory->CreateSchema ( );
278 :
279 : /***** set the id on the new schema *****/
280 :
281 2 : std::string oKmlSchemaID = m_pszName;
282 2 : oKmlSchemaID.append ( ".schema" );
283 2 : m_poKmlSchema->set_id ( oKmlSchemaID );
284 : }
285 :
286 :
287 :
288 :
289 15 : }
290 :
291 : /******************************************************************************
292 : OGRLIBKMLLayer Destructor
293 :
294 : Args: none
295 :
296 : Returns: nothing
297 :
298 : ******************************************************************************/
299 :
300 15 : OGRLIBKMLLayer::~OGRLIBKMLLayer ( )
301 : {
302 :
303 15 : CPLFree ( ( void * )m_pszName );
304 15 : CPLFree ( ( void * )m_pszFileName );
305 15 : delete m_poOgrSRS;
306 :
307 15 : m_poOgrFeatureDefn->Release ( );
308 :
309 :
310 15 : }
311 :
312 :
313 : /******************************************************************************
314 : Method to get the next feature on the layer
315 :
316 : Args: none
317 :
318 : Returns: The next feature, or NULL if there is no more
319 :
320 : this function copyed from the sqlite driver
321 : ******************************************************************************/
322 :
323 57 : OGRFeature *OGRLIBKMLLayer::GetNextFeature()
324 :
325 : {
326 0 : for( ; TRUE; )
327 : {
328 : OGRFeature *poFeature;
329 :
330 57 : poFeature = GetNextRawFeature();
331 57 : if( poFeature == NULL )
332 3 : return NULL;
333 :
334 54 : if( (m_poFilterGeom == NULL
335 : || FilterGeometry( poFeature->GetGeometryRef() ) )
336 : && (m_poAttrQuery == NULL
337 : || m_poAttrQuery->Evaluate( poFeature )) )
338 54 : return poFeature;
339 :
340 0 : delete poFeature;
341 : }
342 : }
343 :
344 : /******************************************************************************
345 : Method to get the next feature on the layer
346 :
347 : Args: none
348 :
349 : Returns: The next feature, or NULL if there is no more
350 :
351 : ******************************************************************************/
352 :
353 : OGRFeature *OGRLIBKMLLayer::GetNextRawFeature (
354 57 : )
355 : {
356 57 : FeaturePtr poKmlFeature;
357 57 : OGRFeature *poOgrFeature = NULL;
358 :
359 54 : do {
360 57 : if ( iFeature >= nFeatures )
361 3 : break;
362 :
363 54 : poKmlFeature = m_poKmlLayer->get_feature_array_at ( iFeature++ );
364 :
365 : } while ( poKmlFeature->Type ( ) != kmldom::Type_Placemark );
366 :
367 :
368 57 : if ( iFeature <= nFeatures && poKmlFeature
369 : && poKmlFeature->Type ( ) == kmldom::Type_Placemark ) {
370 : poOgrFeature =
371 : kml2feat ( AsPlacemark ( poKmlFeature ), m_poOgrDS, this,
372 54 : m_poOgrFeatureDefn, m_poOgrSRS );
373 54 : poOgrFeature->SetFID(nFID ++);
374 : }
375 :
376 57 : return poOgrFeature;
377 : }
378 :
379 : /******************************************************************************
380 : method to add a feature to a layer
381 :
382 : Args: poOgrFeat pointer to the feature to add
383 :
384 : Returns: OGRERR_NONE, or OGRERR_UNSUPPORTED_OPERATION of the layer is
385 : not writeable
386 :
387 : ******************************************************************************/
388 :
389 : OGRErr OGRLIBKMLLayer::CreateFeature (
390 9 : OGRFeature * poOgrFeat )
391 : {
392 :
393 9 : if ( !bUpdate )
394 0 : return OGRERR_UNSUPPORTED_OPERATION;
395 :
396 : PlacemarkPtr poKmlPlacemark =
397 9 : feat2kml ( m_poOgrDS, this, poOgrFeat, m_poOgrDS->GetKmlFactory ( ) );
398 :
399 9 : m_poKmlLayer->add_feature ( poKmlPlacemark );
400 :
401 : /***** mark the layer as updated *****/
402 :
403 9 : bUpdated = TRUE;
404 9 : m_poOgrDS->Updated ( );
405 :
406 9 : return OGRERR_NONE;
407 : }
408 :
409 : /******************************************************************************
410 : method to get the number of features on the layer
411 :
412 : Args: bForce no effect as of now
413 :
414 : Returns: the number of feateres on the layer
415 :
416 : Note: the result can include links, folders and other items that are
417 : not supported by OGR
418 :
419 : ******************************************************************************/
420 :
421 : int OGRLIBKMLLayer::GetFeatureCount (
422 1 : int bForce )
423 : {
424 :
425 :
426 1 : int i = 0;
427 1 : if (m_poFilterGeom != NULL || m_poAttrQuery != NULL ) {
428 0 : i = OGRLayer::GetFeatureCount( bForce );
429 : }
430 :
431 : else {
432 : size_t iKmlFeature;
433 1 : size_t nKmlFeatures = m_poKmlLayer->get_feature_array_size ( );
434 :
435 9 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
436 8 : if ( m_poKmlLayer->get_feature_array_at ( iKmlFeature )->
437 : IsA ( kmldom::Type_Placemark ) ) {
438 8 : i++;
439 : }
440 : }
441 : }
442 :
443 1 : return i;
444 : }
445 :
446 : /******************************************************************************
447 : GetExtent()
448 :
449 : Args: psExtent pointer to the Envelope to store the result in
450 : bForce no effect as of now
451 :
452 : Returns: nothing
453 :
454 : ******************************************************************************/
455 :
456 : OGRErr OGRLIBKMLLayer::GetExtent (
457 : OGREnvelope * psExtent,
458 0 : int bForce )
459 : {
460 0 : Bbox oKmlBbox;
461 :
462 0 : if ( kmlengine::
463 : GetFeatureBounds ( AsFeature ( m_poKmlLayer ), &oKmlBbox ) ) {
464 0 : psExtent->MinX = oKmlBbox.get_west ( );
465 0 : psExtent->MinY = oKmlBbox.get_south ( );
466 0 : psExtent->MaxX = oKmlBbox.get_east ( );
467 0 : psExtent->MaxY = oKmlBbox.get_north ( );
468 :
469 0 : return OGRERR_NONE;
470 : }
471 :
472 0 : return OGRERR_FAILURE;
473 : }
474 :
475 :
476 :
477 :
478 : /******************************************************************************
479 : Method to create a field on a layer
480 :
481 : Args: poField pointer to the Field Definition to add
482 : bApproxOK no effect as of now
483 :
484 : Returns: OGRERR_NONE on success or OGRERR_UNSUPPORTED_OPERATION if the
485 : layer is not writeable
486 :
487 : ******************************************************************************/
488 :
489 : OGRErr OGRLIBKMLLayer::CreateField (
490 : OGRFieldDefn * poField,
491 2 : int bApproxOK )
492 : {
493 :
494 2 : if ( !bUpdate )
495 0 : return OGRERR_UNSUPPORTED_OPERATION;
496 :
497 2 : SimpleFieldPtr poKmlSimpleField = NULL;
498 :
499 2 : if ( poKmlSimpleField =
500 : FieldDef2kml ( poField, m_poOgrDS->GetKmlFactory ( ) ) )
501 0 : m_poKmlSchema->add_simplefield ( poKmlSimpleField );
502 :
503 2 : m_poOgrFeatureDefn->AddFieldDefn ( poField );
504 :
505 : /***** mark the layer as updated *****/
506 :
507 2 : bUpdated = TRUE;
508 2 : m_poOgrDS->Updated ( );
509 :
510 2 : return OGRERR_NONE;
511 : }
512 :
513 :
514 : /******************************************************************************
515 : method to write the datasource to disk
516 :
517 : Args: none
518 :
519 : Returns nothing
520 :
521 : ******************************************************************************/
522 :
523 : OGRErr OGRLIBKMLLayer::SyncToDisk (
524 0 : )
525 : {
526 :
527 0 : return OGRERR_NONE;
528 : }
529 :
530 : /******************************************************************************
531 : method to get a layers style table
532 :
533 : Args: none
534 :
535 : Returns: pointer to the layers style table, or NULL if it does
536 : not have one
537 :
538 : ******************************************************************************/
539 :
540 : OGRStyleTable *OGRLIBKMLLayer::GetStyleTable (
541 15 : )
542 : {
543 :
544 15 : return m_poStyleTable;
545 : }
546 :
547 : /******************************************************************************
548 : method to write a style table to a layer
549 :
550 : Args: poStyleTable pointer to the style table to add
551 :
552 : Returns: nothing
553 :
554 : note: this method assumes ownership of the style table
555 : ******************************************************************************/
556 :
557 : void OGRLIBKMLLayer::SetStyleTableDirectly (
558 0 : OGRStyleTable * poStyleTable )
559 : {
560 :
561 0 : if ( !bUpdate )
562 0 : return;
563 :
564 0 : KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
565 :
566 0 : if ( m_poStyleTable )
567 0 : delete m_poStyleTable;
568 :
569 0 : m_poStyleTable = poStyleTable;
570 :
571 0 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
572 :
573 : /***** delete all the styles *****/
574 :
575 0 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
576 0 : size_t nKmlStyles = poKmlDocument->get_schema_array_size ( );
577 : int iKmlStyle;
578 :
579 0 : for ( iKmlStyle = nKmlStyles - 1; iKmlStyle >= 0; iKmlStyle-- ) {
580 0 : poKmlDocument->DeleteStyleSelectorAt ( iKmlStyle );
581 : }
582 :
583 : /***** add the new style table to the document *****/
584 :
585 : styletable2kml ( poStyleTable, poKmlFactory,
586 0 : AsContainer ( poKmlDocument ) );
587 :
588 : }
589 :
590 : /***** mark the layer as updated *****/
591 :
592 0 : bUpdated = TRUE;
593 0 : m_poOgrDS->Updated ( );
594 :
595 0 : return;
596 : }
597 :
598 : /******************************************************************************
599 : method to write a style table to a layer
600 :
601 : Args: poStyleTable pointer to the style table to add
602 :
603 : Returns: nothing
604 :
605 : note: this method copys the style table, and the user will still be
606 : responsible for its destruction
607 : ******************************************************************************/
608 :
609 : void OGRLIBKMLLayer::SetStyleTable (
610 0 : OGRStyleTable * poStyleTable )
611 : {
612 :
613 0 : if ( !bUpdate )
614 0 : return;
615 :
616 0 : if ( poStyleTable )
617 0 : SetStyleTableDirectly ( poStyleTable->Clone ( ) );
618 : else
619 0 : SetStyleTableDirectly ( NULL );
620 0 : return;
621 : }
622 :
623 : /******************************************************************************
624 : Test if capability is available.
625 :
626 : Args: pszCap layer capability name to test
627 :
628 : Returns: True if the layer supports the capability, otherwise false
629 :
630 : ******************************************************************************/
631 :
632 : int OGRLIBKMLLayer::TestCapability (
633 0 : const char *pszCap )
634 : {
635 0 : int result = FALSE;
636 :
637 0 : if ( EQUAL ( pszCap, OLCRandomRead ) )
638 0 : result = FALSE;
639 0 : if ( EQUAL ( pszCap, OLCSequentialWrite ) )
640 0 : result = bUpdate;
641 0 : if ( EQUAL ( pszCap, OLCRandomWrite ) )
642 0 : result = FALSE;
643 0 : if ( EQUAL ( pszCap, OLCFastFeatureCount ) )
644 0 : result = FALSE;
645 0 : if ( EQUAL ( pszCap, OLCFastSetNextByIndex ) )
646 0 : result = FALSE;
647 0 : if ( EQUAL ( pszCap, OLCCreateField ) )
648 0 : result = bUpdate;
649 0 : if ( EQUAL ( pszCap, OLCDeleteFeature ) )
650 0 : result = FALSE;
651 :
652 0 : return result;
653 : }
|