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