1 /******************************************************************************
2 * $Id: ogrkmllayer.cpp 28375 2015-01-30 12:06:11Z rouault $
3 *
4 * Project: KML Driver
5 * Purpose: Implementation of OGRKMLLayer class.
6 * Author: Christopher Condit, condit@sdsc.edu
7 * Jens Oberender, j.obi@troja.net
8 *
9 ******************************************************************************
10 * Copyright (c) 2006, Christopher Condit
11 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at mines-paris dot org>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included
21 * in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 ****************************************************************************/
31
32 #include "ogr_kml.h"
33 #include "ogr_api.h"
34 #include "cpl_conv.h"
35 #include "cpl_string.h"
36 #include "ogr_p.h"
37
38 /* Function utility to dump OGRGeometry to KML text. */
39 char *OGR_G_ExportToKML( OGRGeometryH hGeometry, const char* pszAltitudeMode );
40
41 /************************************************************************/
42 /* OGRKMLLayer() */
43 /************************************************************************/
44
OGRKMLLayer(const char * pszName,OGRSpatialReference * poSRSIn,int bWriterIn,OGRwkbGeometryType eReqType,OGRKMLDataSource * poDSIn)45 OGRKMLLayer::OGRKMLLayer( const char * pszName,
46 OGRSpatialReference *poSRSIn, int bWriterIn,
47 OGRwkbGeometryType eReqType,
48 OGRKMLDataSource *poDSIn )
49 {
50 poCT_ = NULL;
51
52 /* KML should be created as WGS84. */
53 if( poSRSIn != NULL )
54 {
55 poSRS_ = new OGRSpatialReference(NULL);
56 poSRS_->SetWellKnownGeogCS( "WGS84" );
57 if (!poSRS_->IsSame(poSRSIn))
58 {
59 poCT_ = OGRCreateCoordinateTransformation( poSRSIn, poSRS_ );
60 if( poCT_ == NULL && poDSIn->IsFirstCTError() )
61 {
62 /* If we can't create a transformation, issue a warning - but continue the transformation*/
63 char *pszWKT = NULL;
64
65 poSRSIn->exportToPrettyWkt( &pszWKT, FALSE );
66
67 CPLError( CE_Warning, CPLE_AppDefined,
68 "Failed to create coordinate transformation between the\n"
69 "input coordinate system and WGS84. This may be because they\n"
70 "are not transformable, or because projection services\n"
71 "(PROJ.4 DLL/.so) could not be loaded.\n"
72 "KML geometries may not render correctly.\n"
73 "This message will not be issued any more. \n"
74 "\nSource:\n%s\n",
75 pszWKT );
76
77 CPLFree( pszWKT );
78 poDSIn->IssuedFirstCTError();
79 }
80 }
81 }
82 else
83 {
84 poSRS_ = NULL;
85 }
86
87 iNextKMLId_ = 0;
88 nTotalKMLCount_ = -1;
89 nLastAsked = -1;
90 nLastCount = -1;
91
92 poDS_ = poDSIn;
93
94 poFeatureDefn_ = new OGRFeatureDefn( pszName );
95 SetDescription( poFeatureDefn_->GetName() );
96 poFeatureDefn_->Reference();
97 poFeatureDefn_->SetGeomType( eReqType );
98 if( poFeatureDefn_->GetGeomFieldCount() != 0 )
99 poFeatureDefn_->GetGeomFieldDefn(0)->SetSpatialRef(poSRS_);
100
101 OGRFieldDefn oFieldName( "Name", OFTString );
102 poFeatureDefn_->AddFieldDefn( &oFieldName );
103
104 OGRFieldDefn oFieldDesc( "Description", OFTString );
105 poFeatureDefn_->AddFieldDefn( &oFieldDesc );
106
107 bWriter_ = bWriterIn;
108 nWroteFeatureCount_ = 0;
109 bClosedForWriting = (bWriterIn == FALSE);
110 bSchemaWritten_ = FALSE;
111
112 pszName_ = CPLStrdup(pszName);
113 }
114
115 /************************************************************************/
116 /* ~OGRKMLLayer() */
117 /************************************************************************/
118
~OGRKMLLayer()119 OGRKMLLayer::~OGRKMLLayer()
120 {
121 if( NULL != poFeatureDefn_ )
122 poFeatureDefn_->Release();
123
124 if( NULL != poSRS_ )
125 poSRS_->Release();
126
127 if( NULL != poCT_ )
128 delete poCT_;
129
130 CPLFree( pszName_ );
131 }
132
133 /************************************************************************/
134 /* GetLayerDefn() */
135 /************************************************************************/
136
GetLayerDefn()137 OGRFeatureDefn* OGRKMLLayer::GetLayerDefn()
138 {
139 return poFeatureDefn_;
140 }
141
142 /************************************************************************/
143 /* ResetReading() */
144 /************************************************************************/
145
ResetReading()146 void OGRKMLLayer::ResetReading()
147 {
148 iNextKMLId_ = 0;
149 nLastAsked = -1;
150 nLastCount = -1;
151 }
152
153 /************************************************************************/
154 /* GetNextFeature() */
155 /************************************************************************/
156
GetNextFeature()157 OGRFeature *OGRKMLLayer::GetNextFeature()
158 {
159 #ifndef HAVE_EXPAT
160 return NULL;
161 #else
162 /* -------------------------------------------------------------------- */
163 /* Loop till we find a feature matching our criteria. */
164 /* -------------------------------------------------------------------- */
165 KML *poKMLFile = poDS_->GetKMLFile();
166 if( poKMLFile == NULL )
167 return NULL;
168 poKMLFile->selectLayer(nLayerNumber_);
169
170 while(TRUE)
171 {
172 Feature *poFeatureKML = NULL;
173 poFeatureKML = poKMLFile->getFeature(iNextKMLId_++, nLastAsked, nLastCount);
174
175 if(poFeatureKML == NULL)
176 return NULL;
177
178 CPLAssert( poFeatureKML != NULL );
179
180 OGRFeature *poFeature = new OGRFeature( poFeatureDefn_ );
181
182 if(poFeatureKML->poGeom)
183 {
184 poFeature->SetGeometryDirectly(poFeatureKML->poGeom);
185 poFeatureKML->poGeom = NULL;
186 }
187
188 // Add fields
189 poFeature->SetField( poFeatureDefn_->GetFieldIndex("Name"), poFeatureKML->sName.c_str() );
190 poFeature->SetField( poFeatureDefn_->GetFieldIndex("Description"), poFeatureKML->sDescription.c_str() );
191 poFeature->SetFID( iNextKMLId_ - 1 );
192
193 // Clean up
194 delete poFeatureKML;
195
196 if( poFeature->GetGeometryRef() != NULL && poSRS_ != NULL)
197 {
198 poFeature->GetGeometryRef()->assignSpatialReference( poSRS_ );
199 }
200
201 /* Check spatial/attribute filters */
202 if ((m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) &&
203 (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
204 {
205 // Return the feature
206 return poFeature;
207 }
208 else
209 {
210 delete poFeature;
211 }
212 }
213
214 #endif /* HAVE_EXPAT */
215 }
216
217 /************************************************************************/
218 /* GetFeatureCount() */
219 /************************************************************************/
220
GetFeatureCount(CPL_UNUSED int bForce)221 GIntBig OGRKMLLayer::GetFeatureCount(
222 #ifndef HAVE_EXPAT
223 CPL_UNUSED
224 #endif
225 int bForce
226 )
227 {
228 int nCount = 0;
229
230 #ifdef HAVE_EXPAT
231 if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
232 {
233 KML *poKMLFile = poDS_->GetKMLFile();
234 if( NULL != poKMLFile )
235 {
236 poKMLFile->selectLayer(nLayerNumber_);
237 nCount = poKMLFile->getNumFeatures();
238 }
239 }
240 else
241 return OGRLayer::GetFeatureCount(bForce);
242 #endif
243
244 return nCount;
245 }
246
247 /************************************************************************/
248 /* WriteSchema() */
249 /************************************************************************/
250
WriteSchema()251 CPLString OGRKMLLayer::WriteSchema()
252 {
253 CPLString osRet;
254 if ( !(bSchemaWritten_) )
255 {
256 OGRFeatureDefn *featureDefinition = GetLayerDefn();
257 for (int j=0; j < featureDefinition->GetFieldCount(); j++)
258 {
259 OGRFieldDefn *fieldDefinition = featureDefinition->GetFieldDefn(j);
260
261 if (NULL != poDS_->GetNameField() &&
262 EQUAL(fieldDefinition->GetNameRef(), poDS_->GetNameField()) )
263 continue;
264
265 if (NULL != poDS_->GetDescriptionField() &&
266 EQUAL(fieldDefinition->GetNameRef(), poDS_->GetDescriptionField()) )
267 continue;
268
269 if( osRet.size() == 0 )
270 {
271 osRet += CPLSPrintf( "<Schema name=\"%s\" id=\"%s\">\n", pszName_, pszName_ );
272 }
273
274 const char* pszKMLType = NULL;
275 const char* pszKMLEltName = NULL;
276 // Match the OGR type to the GDAL type
277 switch (fieldDefinition->GetType())
278 {
279 case OFTInteger:
280 pszKMLType = "int";
281 pszKMLEltName = "SimpleField";
282 break;
283 case OFTIntegerList:
284 pszKMLType = "int";
285 pszKMLEltName = "SimpleArrayField";
286 break;
287 case OFTReal:
288 pszKMLType = "float";
289 pszKMLEltName = "SimpleField";
290 break;
291 case OFTRealList:
292 pszKMLType = "float";
293 pszKMLEltName = "SimpleArrayField";
294 break;
295 case OFTString:
296 pszKMLType = "string";
297 pszKMLEltName = "SimpleField";
298 break;
299 case OFTStringList:
300 pszKMLType = "string";
301 pszKMLEltName = "SimpleArrayField";
302 break;
303 //TODO: KML doesn't handle these data types yet...
304 case OFTDate:
305 case OFTTime:
306 case OFTDateTime:
307 pszKMLType = "string";
308 pszKMLEltName = "SimpleField";
309 break;
310
311 default:
312 pszKMLType = "string";
313 pszKMLEltName = "SimpleField";
314 break;
315 }
316 osRet += CPLSPrintf( "\t<%s name=\"%s\" type=\"%s\"></%s>\n",
317 pszKMLEltName, fieldDefinition->GetNameRef() ,pszKMLType, pszKMLEltName );
318 }
319 if( osRet.size() )
320 osRet += CPLSPrintf( "%s", "</Schema>\n" );
321 }
322 return osRet;
323 }
324
325 /************************************************************************/
326 /* ICreateFeature() */
327 /************************************************************************/
328
ICreateFeature(OGRFeature * poFeature)329 OGRErr OGRKMLLayer::ICreateFeature( OGRFeature* poFeature )
330 {
331 CPLAssert( NULL != poFeature );
332 CPLAssert( NULL != poDS_ );
333
334 if( !bWriter_ )
335 return OGRERR_FAILURE;
336
337 if( bClosedForWriting )
338 {
339 CPLError(CE_Failure, CPLE_NotSupported,
340 "Interleaved feature adding to different layers is not supported");
341 return OGRERR_FAILURE;
342 }
343
344 VSILFILE *fp = poDS_->GetOutputFP();
345 CPLAssert( NULL != fp );
346
347 if( poDS_->GetLayerCount() == 1 && nWroteFeatureCount_ == 0 )
348 {
349 CPLString osRet = WriteSchema();
350 if( osRet.size() )
351 VSIFPrintfL( fp, "%s", osRet.c_str() );
352 bSchemaWritten_ = TRUE;
353
354 VSIFPrintfL( fp, "<Folder><name>%s</name>\n", pszName_);
355 }
356
357 VSIFPrintfL( fp, " <Placemark>\n" );
358
359 if( poFeature->GetFID() == OGRNullFID )
360 poFeature->SetFID( iNextKMLId_++ );
361
362 // Find and write the name element
363 if (NULL != poDS_->GetNameField())
364 {
365 for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
366 {
367 OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
368
369 if( poFeature->IsFieldSet( iField )
370 && EQUAL(poField->GetNameRef(), poDS_->GetNameField()) )
371 {
372 const char *pszRaw = poFeature->GetFieldAsString( iField );
373 while( *pszRaw == ' ' )
374 pszRaw++;
375
376 char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
377
378 VSIFPrintfL( fp, "\t<name>%s</name>\n", pszEscaped);
379 CPLFree( pszEscaped );
380 }
381 }
382 }
383
384 if (NULL != poDS_->GetDescriptionField())
385 {
386 for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
387 {
388 OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
389
390 if( poFeature->IsFieldSet( iField )
391 && EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()) )
392 {
393 const char *pszRaw = poFeature->GetFieldAsString( iField );
394 while( *pszRaw == ' ' )
395 pszRaw++;
396
397 char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
398
399 VSIFPrintfL( fp, "\t<description>%s</description>\n", pszEscaped);
400 CPLFree( pszEscaped );
401 }
402 }
403 }
404
405 OGRwkbGeometryType eGeomType = wkbNone;
406 if (poFeature->GetGeometryRef() != NULL)
407 eGeomType = wkbFlatten(poFeature->GetGeometryRef()->getGeometryType());
408 if ( wkbPolygon == eGeomType
409 || wkbMultiPolygon == eGeomType
410 || wkbLineString == eGeomType
411 || wkbMultiLineString == eGeomType )
412 {
413 OGRStylePen *poPen = NULL;
414 OGRStyleMgr oSM;
415
416 if( poFeature->GetStyleString() != NULL )
417 {
418 oSM.InitFromFeature( poFeature );
419
420 int i;
421 for(i=0; i<oSM.GetPartCount();i++)
422 {
423 OGRStyleTool *poTool = oSM.GetPart(i);
424 if (poTool && poTool->GetType() == OGRSTCPen )
425 {
426 poPen = (OGRStylePen*) poTool;
427 break;
428 }
429 delete poTool;
430 }
431 }
432
433 VSIFPrintfL( fp, "\t<Style>");
434 if( poPen != NULL )
435 {
436 GBool bDefault;
437 int bHasWidth = FALSE;
438
439 /* Require width to be returned in pixel */
440 poPen->SetUnit(OGRSTUPixel);
441 double fW = poPen->Width(bDefault);
442 if( bDefault )
443 fW = 1;
444 else
445 bHasWidth = TRUE;
446 const char* pszColor = poPen->Color(bDefault);
447 int nColorLen = CPLStrnlen(pszColor, 10);
448 if( pszColor != NULL && pszColor[0] == '#' && !bDefault && nColorLen >= 7)
449 {
450 char acColor[9] = {0};
451 /* Order of KML color is aabbggrr, whereas OGR color is #rrggbb[aa] ! */
452 if(nColorLen == 9)
453 {
454 acColor[0] = pszColor[7]; /* A */
455 acColor[1] = pszColor[8];
456 }
457 else
458 {
459 acColor[0] = 'F';
460 acColor[1] = 'F';
461 }
462 acColor[2] = pszColor[5]; /* B */
463 acColor[3] = pszColor[6];
464 acColor[4] = pszColor[3]; /* G */
465 acColor[5] = pszColor[4];
466 acColor[6] = pszColor[1]; /* R */
467 acColor[7] = pszColor[2];
468 VSIFPrintfL( fp, "<LineStyle><color>%s</color>", acColor);
469 if (bHasWidth)
470 VSIFPrintfL( fp, "<width>%g</width>", fW);
471 VSIFPrintfL( fp, "</LineStyle>");
472 }
473 else
474 VSIFPrintfL( fp, "<LineStyle><color>ff0000ff</color></LineStyle>");
475 }
476 else
477 VSIFPrintfL( fp, "<LineStyle><color>ff0000ff</color></LineStyle>");
478 delete poPen;
479 //If we're dealing with a polygon, add a line style that will stand out a bit
480 VSIFPrintfL( fp, "<PolyStyle><fill>0</fill></PolyStyle></Style>\n" );
481 }
482
483 int bHasFoundOtherField = FALSE;
484
485 // Write all fields as SchemaData
486 for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
487 {
488 OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
489
490 if( poFeature->IsFieldSet( iField ))
491 {
492 if (NULL != poDS_->GetNameField() &&
493 EQUAL(poField->GetNameRef(), poDS_->GetNameField()) )
494 continue;
495
496 if (NULL != poDS_->GetDescriptionField() &&
497 EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()) )
498 continue;
499
500 if (!bHasFoundOtherField)
501 {
502 VSIFPrintfL( fp, "\t<ExtendedData><SchemaData schemaUrl=\"#%s\">\n", pszName_ );
503 bHasFoundOtherField = TRUE;
504 }
505 const char *pszRaw = poFeature->GetFieldAsString( iField );
506
507 while( *pszRaw == ' ' )
508 pszRaw++;
509
510 char *pszEscaped;
511 if (poFeatureDefn_->GetFieldDefn(iField)->GetType() == OFTReal)
512 {
513 pszEscaped = CPLStrdup( pszRaw );
514 }
515 else
516 {
517 pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
518 }
519
520 VSIFPrintfL( fp, "\t\t<SimpleData name=\"%s\">%s</SimpleData>\n",
521 poField->GetNameRef(), pszEscaped);
522
523 CPLFree( pszEscaped );
524 }
525 }
526
527 if (bHasFoundOtherField)
528 {
529 VSIFPrintfL( fp, "\t</SchemaData></ExtendedData>\n" );
530 }
531
532 // Write out Geometry - for now it isn't indented properly.
533 if( poFeature->GetGeometryRef() != NULL )
534 {
535 char* pszGeometry = NULL;
536 OGREnvelope sGeomBounds;
537 OGRGeometry* poWGS84Geom;
538
539 if (NULL != poCT_)
540 {
541 poWGS84Geom = poFeature->GetGeometryRef()->clone();
542 poWGS84Geom->transform( poCT_ );
543 }
544 else
545 {
546 poWGS84Geom = poFeature->GetGeometryRef();
547 }
548
549 // TODO - porting
550 // pszGeometry = poFeature->GetGeometryRef()->exportToKML();
551 pszGeometry =
552 OGR_G_ExportToKML( (OGRGeometryH)poWGS84Geom,
553 poDS_->GetAltitudeMode());
554
555 VSIFPrintfL( fp, " %s\n", pszGeometry );
556 CPLFree( pszGeometry );
557
558 poWGS84Geom->getEnvelope( &sGeomBounds );
559 poDS_->GrowExtents( &sGeomBounds );
560
561 if (NULL != poCT_)
562 {
563 delete poWGS84Geom;
564 }
565 }
566
567 VSIFPrintfL( fp, " </Placemark>\n" );
568 nWroteFeatureCount_++;
569 return OGRERR_NONE;
570 }
571
572 /************************************************************************/
573 /* TestCapability() */
574 /************************************************************************/
575
TestCapability(const char * pszCap)576 int OGRKMLLayer::TestCapability( const char * pszCap )
577 {
578 if( EQUAL(pszCap, OLCSequentialWrite) )
579 {
580 return bWriter_;
581 }
582 else if( EQUAL(pszCap, OLCCreateField) )
583 {
584 return bWriter_ && iNextKMLId_ == 0;
585 }
586 else if( EQUAL(pszCap,OLCFastFeatureCount) )
587 {
588 // if( poFClass == NULL
589 // || m_poFilterGeom != NULL
590 // || m_poAttrQuery != NULL )
591 return FALSE;
592
593 // return poFClass->GetFeatureCount() != -1;
594 }
595
596 else if (EQUAL(pszCap, OLCStringsAsUTF8))
597 return TRUE;
598
599 return FALSE;
600 }
601
602 /************************************************************************/
603 /* CreateField() */
604 /************************************************************************/
605
CreateField(OGRFieldDefn * poField,CPL_UNUSED int bApproxOK)606 OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField,
607 CPL_UNUSED int bApproxOK )
608 {
609 if( !bWriter_ || iNextKMLId_ != 0 )
610 return OGRERR_FAILURE;
611
612 OGRFieldDefn oCleanCopy( poField );
613 poFeatureDefn_->AddFieldDefn( &oCleanCopy );
614
615 return OGRERR_NONE;
616 }
617
618 /************************************************************************/
619 /* SetLayerNumber() */
620 /************************************************************************/
621
SetLayerNumber(int nLayer)622 void OGRKMLLayer::SetLayerNumber( int nLayer )
623 {
624 nLayerNumber_ = nLayer;
625 }
626