1 : /******************************************************************************
2 : * $Id: ogrkmllayer.cpp 22872 2011-08-06 20:32:14Z 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 27 : OGRKMLLayer::OGRKMLLayer( const char * pszName,
45 : OGRSpatialReference *poSRSIn, int bWriterIn,
46 : OGRwkbGeometryType eReqType,
47 27 : OGRKMLDataSource *poDSIn )
48 : {
49 27 : poCT_ = NULL;
50 :
51 : /* KML should be created as WGS84. */
52 27 : if( poSRSIn != NULL )
53 : {
54 24 : poSRS_ = new OGRSpatialReference(NULL);
55 24 : poSRS_->SetWellKnownGeogCS( "WGS84" );
56 24 : 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 27 : iNextKMLId_ = 0;
87 27 : nTotalKMLCount_ = -1;
88 27 : nLastAsked = -1;
89 27 : nLastCount = -1;
90 :
91 27 : poDS_ = poDSIn;
92 :
93 27 : poFeatureDefn_ = new OGRFeatureDefn( pszName );
94 27 : poFeatureDefn_->Reference();
95 27 : poFeatureDefn_->SetGeomType( eReqType );
96 :
97 27 : OGRFieldDefn oFieldName( "Name", OFTString );
98 27 : poFeatureDefn_->AddFieldDefn( &oFieldName );
99 :
100 27 : OGRFieldDefn oFieldDesc( "Description", OFTString );
101 27 : poFeatureDefn_->AddFieldDefn( &oFieldDesc );
102 :
103 27 : bWriter_ = bWriterIn;
104 27 : nWroteFeatureCount_ = 0;
105 27 : bClosedForWriting = (bWriterIn == FALSE);
106 :
107 27 : pszName_ = CPLStrdup(pszName);
108 27 : }
109 :
110 : /************************************************************************/
111 : /* ~OGRKMLLayer() */
112 : /************************************************************************/
113 :
114 27 : OGRKMLLayer::~OGRKMLLayer()
115 : {
116 27 : if( NULL != poFeatureDefn_ )
117 27 : poFeatureDefn_->Release();
118 :
119 27 : if( NULL != poSRS_ )
120 24 : poSRS_->Release();
121 :
122 27 : if( NULL != poCT_ )
123 1 : delete poCT_;
124 :
125 27 : CPLFree( pszName_ );
126 27 : }
127 :
128 : /************************************************************************/
129 : /* GetLayerDefn() */
130 : /************************************************************************/
131 :
132 239 : OGRFeatureDefn* OGRKMLLayer::GetLayerDefn()
133 : {
134 239 : return poFeatureDefn_;
135 : }
136 :
137 : /************************************************************************/
138 : /* ResetReading() */
139 : /************************************************************************/
140 :
141 171 : void OGRKMLLayer::ResetReading()
142 : {
143 171 : iNextKMLId_ = 0;
144 171 : nLastAsked = -1;
145 171 : nLastCount = -1;
146 171 : }
147 :
148 : /************************************************************************/
149 : /* GetNextFeature() */
150 : /************************************************************************/
151 :
152 267 : 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 267 : KML *poKMLFile = poDS_->GetKMLFile();
161 267 : poKMLFile->selectLayer(nLayerNumber_);
162 :
163 63 : while(TRUE)
164 : {
165 330 : Feature *poFeatureKML = NULL;
166 330 : poFeatureKML = poKMLFile->getFeature(iNextKMLId_++, nLastAsked, nLastCount);
167 :
168 330 : if(poFeatureKML == NULL)
169 63 : return NULL;
170 :
171 267 : CPLAssert( poFeatureKML != NULL );
172 :
173 267 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn_ );
174 :
175 267 : if(poFeatureKML->poGeom)
176 : {
177 267 : poFeature->SetGeometryDirectly(poFeatureKML->poGeom);
178 267 : poFeatureKML->poGeom = NULL;
179 : }
180 :
181 : // Add fields
182 267 : poFeature->SetField( poFeatureDefn_->GetFieldIndex("Name"), poFeatureKML->sName.c_str() );
183 267 : poFeature->SetField( poFeatureDefn_->GetFieldIndex("Description"), poFeatureKML->sDescription.c_str() );
184 267 : poFeature->SetFID( iNextKMLId_ - 1 );
185 :
186 : // Clean up
187 267 : delete poFeatureKML;
188 :
189 267 : if( poFeature->GetGeometryRef() != NULL && poSRS_ != NULL)
190 : {
191 267 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS_ );
192 : }
193 :
194 : /* Check spatial/attribute filters */
195 267 : if ((m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) &&
196 : (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
197 : {
198 : // Return the feature
199 204 : return poFeature;
200 : }
201 : else
202 : {
203 63 : delete poFeature;
204 : }
205 : }
206 :
207 : #endif /* HAVE_EXPAT */
208 : }
209 :
210 : /************************************************************************/
211 : /* GetFeatureCount() */
212 : /************************************************************************/
213 :
214 51 : int OGRKMLLayer::GetFeatureCount( int bForce )
215 : {
216 51 : int nCount = 0;
217 :
218 : #ifdef HAVE_EXPAT
219 51 : if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
220 : {
221 27 : KML *poKMLFile = poDS_->GetKMLFile();
222 27 : if( NULL != poKMLFile )
223 : {
224 27 : poKMLFile->selectLayer(nLayerNumber_);
225 27 : nCount = poKMLFile->getNumFeatures();
226 : }
227 : }
228 : else
229 24 : return OGRLayer::GetFeatureCount(bForce);
230 : #endif
231 :
232 27 : 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 2 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
463 :
464 : VSIFPrintfL( fp, "\t\t<SimpleData name=\"%s\">%s</SimpleData>\n",
465 2 : poField->GetNameRef(), pszEscaped);
466 :
467 2 : CPLFree( pszEscaped );
468 : }
469 : }
470 :
471 9 : if (bHasFoundOtherField)
472 : {
473 1 : VSIFPrintfL( fp, "\t</SchemaData></ExtendedData>\n" );
474 : }
475 :
476 : // Write out Geometry - for now it isn't indented properly.
477 9 : if( poFeature->GetGeometryRef() != NULL )
478 : {
479 9 : char* pszGeometry = NULL;
480 9 : OGREnvelope sGeomBounds;
481 : OGRGeometry* poWGS84Geom;
482 :
483 9 : if (NULL != poCT_)
484 : {
485 1 : poWGS84Geom = poFeature->GetGeometryRef()->clone();
486 1 : poWGS84Geom->transform( poCT_ );
487 : }
488 : else
489 : {
490 8 : poWGS84Geom = poFeature->GetGeometryRef();
491 : }
492 :
493 : // TODO - porting
494 : // pszGeometry = poFeature->GetGeometryRef()->exportToKML();
495 : pszGeometry =
496 : OGR_G_ExportToKML( (OGRGeometryH)poWGS84Geom,
497 9 : poDS_->GetAltitudeMode());
498 :
499 9 : VSIFPrintfL( fp, " %s\n", pszGeometry );
500 9 : CPLFree( pszGeometry );
501 :
502 9 : poWGS84Geom->getEnvelope( &sGeomBounds );
503 9 : poDS_->GrowExtents( &sGeomBounds );
504 :
505 9 : if (NULL != poCT_)
506 : {
507 1 : delete poWGS84Geom;
508 : }
509 : }
510 :
511 9 : VSIFPrintfL( fp, " </Placemark>\n" );
512 9 : nWroteFeatureCount_++;
513 9 : return OGRERR_NONE;
514 : }
515 :
516 : /************************************************************************/
517 : /* TestCapability() */
518 : /************************************************************************/
519 :
520 24 : int OGRKMLLayer::TestCapability( const char * pszCap )
521 : {
522 24 : if( EQUAL(pszCap, OLCSequentialWrite) )
523 : {
524 0 : return bWriter_;
525 : }
526 24 : else if( EQUAL(pszCap, OLCCreateField) )
527 : {
528 0 : return bWriter_ && iNextKMLId_ == 0;
529 : }
530 24 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
531 : {
532 : // if( poFClass == NULL
533 : // || m_poFilterGeom != NULL
534 : // || m_poAttrQuery != NULL )
535 0 : return FALSE;
536 :
537 : // return poFClass->GetFeatureCount() != -1;
538 : }
539 :
540 24 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
541 6 : return TRUE;
542 :
543 18 : return FALSE;
544 : }
545 :
546 : /************************************************************************/
547 : /* CreateField() */
548 : /************************************************************************/
549 :
550 0 : OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
551 : {
552 0 : if( !bWriter_ || iNextKMLId_ != 0 )
553 0 : return OGRERR_FAILURE;
554 :
555 0 : OGRFieldDefn oCleanCopy( poField );
556 0 : poFeatureDefn_->AddFieldDefn( &oCleanCopy );
557 :
558 0 : return OGRERR_NONE;
559 : }
560 :
561 : /************************************************************************/
562 : /* GetSpatialRef() */
563 : /************************************************************************/
564 :
565 6 : OGRSpatialReference *OGRKMLLayer::GetSpatialRef()
566 : {
567 6 : return poSRS_;
568 : }
569 :
570 : /************************************************************************/
571 : /* SetLayerNumber() */
572 : /************************************************************************/
573 :
574 23 : void OGRKMLLayer::SetLayerNumber( int nLayer )
575 : {
576 23 : nLayerNumber_ = nLayer;
577 1970 : }
578 :
|