LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - ogrkmllayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 221 282 78.4 %
Date: 2024-04-27 17:22:41 Functions: 13 13 100.0 %

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

Generated by: LCOV version 1.14