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

Generated by: LCOV version 1.14