1 : /******************************************************************************
2 : * $Id: ogrkmllayer.cpp 16908 2009-05-02 14:53:26Z 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 11 : OGRKMLLayer::OGRKMLLayer( const char * pszName,
45 : OGRSpatialReference *poSRSIn, int bWriterIn,
46 : OGRwkbGeometryType eReqType,
47 11 : OGRKMLDataSource *poDSIn )
48 : {
49 11 : poCT_ = NULL;
50 :
51 : /* KML should be created as WGS84. */
52 11 : if( poSRSIn != NULL )
53 : {
54 10 : poSRS_ = new OGRSpatialReference(NULL);
55 10 : poSRS_->SetWellKnownGeogCS( "WGS84" );
56 10 : 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 1 : poSRS_ = NULL;
84 : }
85 :
86 11 : iNextKMLId_ = 0;
87 11 : nTotalKMLCount_ = -1;
88 11 : nLastAsked = -1;
89 11 : nLastCount = -1;
90 :
91 11 : poDS_ = poDSIn;
92 :
93 11 : poFeatureDefn_ = new OGRFeatureDefn( pszName );
94 11 : poFeatureDefn_->Reference();
95 11 : poFeatureDefn_->SetGeomType( eReqType );
96 :
97 11 : OGRFieldDefn oFieldName( "Name", OFTString );
98 11 : poFeatureDefn_->AddFieldDefn( &oFieldName );
99 :
100 11 : OGRFieldDefn oFieldDesc( "Description", OFTString );
101 11 : poFeatureDefn_->AddFieldDefn( &oFieldDesc );
102 :
103 11 : bWriter_ = bWriterIn;
104 11 : nWroteFeatureCount_ = 0;
105 :
106 11 : pszName_ = CPLStrdup(pszName);
107 11 : }
108 :
109 : /************************************************************************/
110 : /* ~OGRKMLLayer() */
111 : /************************************************************************/
112 :
113 22 : OGRKMLLayer::~OGRKMLLayer()
114 : {
115 11 : if( NULL != poFeatureDefn_ )
116 11 : poFeatureDefn_->Release();
117 :
118 11 : if( NULL != poSRS_ )
119 10 : poSRS_->Release();
120 :
121 11 : if( NULL != poCT_ )
122 1 : delete poCT_;
123 :
124 11 : CPLFree( pszName_ );
125 22 : }
126 :
127 : /************************************************************************/
128 : /* GetLayerDefn() */
129 : /************************************************************************/
130 :
131 31 : OGRFeatureDefn* OGRKMLLayer::GetLayerDefn()
132 : {
133 31 : return poFeatureDefn_;
134 : }
135 :
136 : /************************************************************************/
137 : /* ResetReading() */
138 : /************************************************************************/
139 :
140 3 : void OGRKMLLayer::ResetReading()
141 : {
142 3 : iNextKMLId_ = 0;
143 3 : nLastAsked = -1;
144 3 : nLastCount = -1;
145 3 : }
146 :
147 : /************************************************************************/
148 : /* GetNextFeature() */
149 : /************************************************************************/
150 :
151 32 : OGRFeature *OGRKMLLayer::GetNextFeature()
152 : {
153 : #ifndef HAVE_EXPAT
154 : return NULL;
155 : #else
156 : /* -------------------------------------------------------------------- */
157 : /* Loop till we find a feature matching our criteria. */
158 : /* -------------------------------------------------------------------- */
159 32 : KML *poKMLFile = poDS_->GetKMLFile();
160 32 : poKMLFile->selectLayer(nLayerNumber_);
161 :
162 0 : while(TRUE)
163 : {
164 32 : Feature *poFeatureKML = NULL;
165 32 : poFeatureKML = poKMLFile->getFeature(iNextKMLId_++, nLastAsked, nLastCount);
166 :
167 32 : if(poFeatureKML == NULL)
168 2 : return NULL;
169 :
170 : CPLAssert( poFeatureKML != NULL );
171 :
172 30 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn_ );
173 :
174 30 : if(poFeatureKML->poGeom)
175 : {
176 30 : poFeature->SetGeometryDirectly(poFeatureKML->poGeom);
177 30 : poFeatureKML->poGeom = NULL;
178 : }
179 :
180 : // Add fields
181 30 : poFeature->SetField( poFeatureDefn_->GetFieldIndex("Name"), poFeatureKML->sName.c_str() );
182 30 : poFeature->SetField( poFeatureDefn_->GetFieldIndex("Description"), poFeatureKML->sDescription.c_str() );
183 30 : poFeature->SetFID( iNextKMLId_ - 1 );
184 :
185 : // Clean up
186 30 : delete poFeatureKML;
187 :
188 30 : if( poFeature->GetGeometryRef() != NULL && poSRS_ != NULL)
189 : {
190 30 : poFeature->GetGeometryRef()->assignSpatialReference( poSRS_ );
191 : }
192 :
193 : /* Check spatial/attribute filters */
194 30 : if ((m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) &&
195 : (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) )
196 : {
197 : // Return the feature
198 30 : return poFeature;
199 : }
200 : else
201 : {
202 0 : delete poFeature;
203 : }
204 : }
205 :
206 : #endif /* HAVE_EXPAT */
207 : }
208 :
209 : /************************************************************************/
210 : /* GetFeatureCount() */
211 : /************************************************************************/
212 :
213 1 : int OGRKMLLayer::GetFeatureCount( int bForce )
214 : {
215 1 : int nCount = 0;
216 :
217 : #ifdef HAVE_EXPAT
218 1 : if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
219 : {
220 1 : KML *poKMLFile = poDS_->GetKMLFile();
221 1 : if( NULL != poKMLFile )
222 : {
223 1 : poKMLFile->selectLayer(nLayerNumber_);
224 1 : nCount = poKMLFile->getNumFeatures();
225 : }
226 : }
227 : else
228 0 : return OGRLayer::GetFeatureCount(bForce);
229 : #endif
230 :
231 1 : return nCount;
232 : }
233 :
234 : /************************************************************************/
235 : /* CreateFeature() */
236 : /************************************************************************/
237 :
238 9 : OGRErr OGRKMLLayer::CreateFeature( OGRFeature* poFeature )
239 : {
240 : CPLAssert( NULL != poFeature );
241 : CPLAssert( NULL != poDS_ );
242 :
243 9 : if( !bWriter_ )
244 0 : return OGRERR_FAILURE;
245 :
246 9 : FILE *fp = poDS_->GetOutputFP();
247 : CPLAssert( NULL != fp );
248 :
249 : // If we haven't writen any features yet, output the layer's schema
250 9 : if (0 == nWroteFeatureCount_)
251 : {
252 2 : VSIFPrintf( fp, "<Schema name=\"%s\" id=\"%s\">\n", pszName_, pszName_ );
253 2 : OGRFeatureDefn *featureDefinition = GetLayerDefn();
254 6 : for (int j=0; j < featureDefinition->GetFieldCount(); j++)
255 : {
256 4 : OGRFieldDefn *fieldDefinition = featureDefinition->GetFieldDefn(j);
257 4 : const char* pszKMLType = NULL;
258 4 : const char* pszKMLEltName = NULL;
259 : // Match the OGR type to the GDAL type
260 4 : switch (fieldDefinition->GetType())
261 : {
262 : case OFTInteger:
263 0 : pszKMLType = "int";
264 0 : pszKMLEltName = "SimpleField";
265 0 : break;
266 : case OFTIntegerList:
267 0 : pszKMLType = "int";
268 0 : pszKMLEltName = "SimpleArrayField";
269 0 : break;
270 : case OFTReal:
271 0 : pszKMLType = "float";
272 0 : pszKMLEltName = "SimpleField";
273 0 : break;
274 : case OFTRealList:
275 0 : pszKMLType = "float";
276 0 : pszKMLEltName = "SimpleArrayField";
277 0 : break;
278 : case OFTString:
279 4 : pszKMLType = "string";
280 4 : pszKMLEltName = "SimpleField";
281 4 : break;
282 : case OFTStringList:
283 0 : pszKMLType = "string";
284 0 : pszKMLEltName = "SimpleArrayField";
285 0 : break;
286 : case OFTBinary:
287 0 : pszKMLType = "bool";
288 0 : pszKMLEltName = "SimpleField";
289 0 : break;
290 : //TODO: KML doesn't handle these data types yet...
291 : case OFTDate:
292 : case OFTTime:
293 : case OFTDateTime:
294 0 : pszKMLType = "string";
295 0 : pszKMLEltName = "SimpleField";
296 0 : break;
297 :
298 : default:
299 0 : pszKMLType = "string";
300 0 : pszKMLEltName = "SimpleField";
301 : break;
302 : }
303 : VSIFPrintf( fp, "\t<%s name=\"%s\" type=\"%s\"></%s>\n",
304 4 : pszKMLEltName, fieldDefinition->GetNameRef() ,pszKMLType, pszKMLEltName );
305 : }
306 2 : VSIFPrintf( fp, "</Schema>\n" );
307 : }
308 :
309 9 : VSIFPrintf( fp, " <Placemark>\n" );
310 :
311 9 : if( poFeature->GetFID() == OGRNullFID )
312 9 : poFeature->SetFID( iNextKMLId_++ );
313 :
314 : // Find and write the name element
315 9 : if (NULL != poDS_->GetNameField())
316 : {
317 27 : for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
318 : {
319 18 : OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
320 :
321 18 : if( poFeature->IsFieldSet( iField )
322 : && EQUAL(poField->GetNameRef(), poDS_->GetNameField()) )
323 : {
324 1 : const char *pszRaw = poFeature->GetFieldAsString( iField );
325 2 : while( *pszRaw == ' ' )
326 0 : pszRaw++;
327 :
328 1 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
329 :
330 1 : VSIFPrintf( fp, "\t<name>%s</name>\n", pszEscaped);
331 1 : CPLFree( pszEscaped );
332 : }
333 : }
334 : }
335 :
336 9 : if (NULL != poDS_->GetDescriptionField())
337 : {
338 27 : for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
339 : {
340 18 : OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
341 :
342 18 : if( poFeature->IsFieldSet( iField )
343 : && EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()) )
344 : {
345 1 : const char *pszRaw = poFeature->GetFieldAsString( iField );
346 2 : while( *pszRaw == ' ' )
347 0 : pszRaw++;
348 :
349 1 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
350 :
351 1 : VSIFPrintf( fp, "\t<description>%s</description>\n", pszEscaped);
352 1 : CPLFree( pszEscaped );
353 : }
354 : }
355 : }
356 :
357 9 : OGRwkbGeometryType eGeomType = wkbFlatten(poFeatureDefn_->GetGeomType());
358 9 : if ( wkbPolygon == eGeomType
359 : || wkbMultiPolygon == eGeomType
360 : || wkbLineString == eGeomType
361 : || wkbMultiLineString == eGeomType )
362 : {
363 : //If we're dealing with a polygon, add a line style that will stand out a bit
364 0 : VSIFPrintf( fp, " <Style><LineStyle><color>ff0000ff</color></LineStyle>");
365 0 : VSIFPrintf( fp, " <PolyStyle><fill>0</fill></PolyStyle></Style>\n" );
366 : }
367 :
368 9 : int bHasFoundOtherField = FALSE;
369 :
370 : // Write all fields as SchemaData
371 27 : for( int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++ )
372 : {
373 18 : OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn( iField );
374 :
375 18 : if( poFeature->IsFieldSet( iField ))
376 : {
377 2 : if (!bHasFoundOtherField)
378 : {
379 1 : VSIFPrintf( fp, "\t<ExtendedData><SchemaData schemaUrl=\"#%s\">\n", pszName_ );
380 1 : bHasFoundOtherField = TRUE;
381 : }
382 2 : const char *pszRaw = poFeature->GetFieldAsString( iField );
383 :
384 4 : while( *pszRaw == ' ' )
385 0 : pszRaw++;
386 :
387 2 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
388 :
389 : VSIFPrintf( fp, "\t\t<SimpleData name=\"%s\">%s</SimpleData>\n",
390 2 : poField->GetNameRef(), pszEscaped);
391 :
392 2 : CPLFree( pszEscaped );
393 : }
394 : }
395 :
396 9 : if (bHasFoundOtherField)
397 : {
398 1 : VSIFPrintf( fp, "\t</SchemaData></ExtendedData>\n" );
399 : }
400 :
401 : // Write out Geometry - for now it isn't indented properly.
402 9 : if( poFeature->GetGeometryRef() != NULL )
403 : {
404 9 : char* pszGeometry = NULL;
405 9 : OGREnvelope sGeomBounds;
406 : OGRGeometry* poWGS84Geom;
407 :
408 9 : if (NULL != poCT_)
409 : {
410 1 : poWGS84Geom = poFeature->GetGeometryRef()->clone();
411 1 : poWGS84Geom->transform( poCT_ );
412 : }
413 : else
414 : {
415 8 : poWGS84Geom = poFeature->GetGeometryRef();
416 : }
417 :
418 : // TODO - porting
419 : // pszGeometry = poFeature->GetGeometryRef()->exportToKML();
420 : pszGeometry =
421 : OGR_G_ExportToKML( (OGRGeometryH)poWGS84Geom,
422 9 : poDS_->GetAltitudeMode());
423 :
424 9 : VSIFPrintf( fp, " %s\n", pszGeometry );
425 9 : CPLFree( pszGeometry );
426 :
427 9 : poWGS84Geom->getEnvelope( &sGeomBounds );
428 9 : poDS_->GrowExtents( &sGeomBounds );
429 :
430 9 : if (NULL != poCT_)
431 : {
432 1 : delete poWGS84Geom;
433 : }
434 : }
435 :
436 9 : VSIFPrintf( fp, " </Placemark>\n" );
437 9 : nWroteFeatureCount_++;
438 9 : return OGRERR_NONE;
439 : }
440 :
441 : /************************************************************************/
442 : /* TestCapability() */
443 : /************************************************************************/
444 :
445 0 : int OGRKMLLayer::TestCapability( const char * pszCap )
446 : {
447 0 : if( EQUAL(pszCap, OLCSequentialWrite) )
448 : {
449 0 : return bWriter_;
450 : }
451 0 : else if( EQUAL(pszCap, OLCCreateField) )
452 : {
453 0 : return bWriter_ && iNextKMLId_ == 0;
454 : }
455 0 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
456 : {
457 : // if( poFClass == NULL
458 : // || m_poFilterGeom != NULL
459 : // || m_poAttrQuery != NULL )
460 0 : return FALSE;
461 :
462 : // return poFClass->GetFeatureCount() != -1;
463 : }
464 :
465 0 : return FALSE;
466 : }
467 :
468 : /************************************************************************/
469 : /* CreateField() */
470 : /************************************************************************/
471 :
472 0 : OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
473 : {
474 0 : if( !bWriter_ || iNextKMLId_ != 0 )
475 0 : return OGRERR_FAILURE;
476 :
477 0 : OGRFieldDefn oCleanCopy( poField );
478 0 : poFeatureDefn_->AddFieldDefn( &oCleanCopy );
479 :
480 0 : return OGRERR_NONE;
481 : }
482 :
483 : /************************************************************************/
484 : /* GetSpatialRef() */
485 : /************************************************************************/
486 :
487 0 : OGRSpatialReference *OGRKMLLayer::GetSpatialRef()
488 : {
489 0 : return poSRS_;
490 : }
491 :
492 : /************************************************************************/
493 : /* SetLayerNumber() */
494 : /************************************************************************/
495 :
496 9 : void OGRKMLLayer::SetLayerNumber( int nLayer )
497 : {
498 9 : nLayerNumber_ = nLayer;
499 1149 : }
500 :
|