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