LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/jsonfg - ogrjsonfgwritelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 228 237 96.2 %
Date: 2025-10-01 17:07:58 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGC Features and Geometries JSON (JSON-FG)
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_jsonfg.h"
      14             : #include "cpl_time.h"
      15             : #include "ogrlibjsonutils.h"  // OGRJSonParse()
      16             : 
      17             : #include <algorithm>
      18             : 
      19             : /************************************************************************/
      20             : /*                         OGRJSONFGWriteLayer()                        */
      21             : /************************************************************************/
      22             : 
      23         123 : OGRJSONFGWriteLayer::OGRJSONFGWriteLayer(
      24             :     const char *pszName, const OGRSpatialReference *poSRS,
      25             :     std::unique_ptr<OGRCoordinateTransformation> &&poCTToWGS84,
      26             :     const std::string &osCoordRefSys, OGRwkbGeometryType eGType,
      27         123 :     CSLConstList papszOptions, OGRJSONFGDataset *poDS)
      28         123 :     : poDS_(poDS), poFeatureDefn_(new OGRFeatureDefn(pszName)),
      29         246 :       poCTToWGS84_(std::move(poCTToWGS84)), osCoordRefSys_(osCoordRefSys)
      30             : {
      31         123 :     poFeatureDefn_->Reference();
      32         123 :     poFeatureDefn_->SetGeomType(eGType);
      33         123 :     if (eGType != wkbNone && poSRS)
      34             :     {
      35          66 :         auto poSRSClone = poSRS->Clone();
      36          66 :         poFeatureDefn_->GetGeomFieldDefn(0)->SetSpatialRef(poSRSClone);
      37          66 :         poSRSClone->Release();
      38          66 :         m_bMustSwapForPlace = OGRJSONFGMustSwapXY(poSRS);
      39             :     }
      40         123 :     SetDescription(poFeatureDefn_->GetName());
      41             : 
      42         123 :     bIsWGS84CRS_ =
      43         123 :         osCoordRefSys_.find("\"http://www.opengis.net/def/crs/OGC/0/CRS84\"") !=
      44         123 :             std::string::npos ||
      45         123 :         osCoordRefSys_.find(
      46             :             "\"http://www.opengis.net/def/crs/OGC/0/CRS84h\"") !=
      47         122 :             std::string::npos ||
      48         122 :         osCoordRefSys_.find("\"http://www.opengis.net/def/crs/EPSG/0/4326\"") !=
      49         246 :             std::string::npos ||
      50         106 :         osCoordRefSys_.find("\"http://www.opengis.net/def/crs/EPSG/0/4979\"") !=
      51             :             std::string::npos;
      52             : 
      53         123 :     oWriteOptions_.nXYCoordPrecision = atoi(CSLFetchNameValueDef(
      54             :         papszOptions, "XY_COORD_PRECISION_GEOMETRY", "-1"));
      55         123 :     oWriteOptions_.nZCoordPrecision = atoi(
      56             :         CSLFetchNameValueDef(papszOptions, "Z_COORD_PRECISION_GEOMETRY", "-1"));
      57         123 :     oWriteOptions_.nSignificantFigures =
      58         123 :         atoi(CSLFetchNameValueDef(papszOptions, "SIGNIFICANT_FIGURES", "-1"));
      59         123 :     oWriteOptions_.SetRFC7946Settings();
      60         123 :     oWriteOptions_.SetIDOptions(papszOptions);
      61             : 
      62         123 :     oWriteOptionsPlace_.nXYCoordPrecision = atoi(
      63             :         CSLFetchNameValueDef(papszOptions, "XY_COORD_PRECISION_PLACE", "-1"));
      64         123 :     oWriteOptionsPlace_.nZCoordPrecision = atoi(
      65             :         CSLFetchNameValueDef(papszOptions, "Z_COORD_PRECISION_PLACE", "-1"));
      66         123 :     oWriteOptionsPlace_.nSignificantFigures =
      67         123 :         atoi(CSLFetchNameValueDef(papszOptions, "SIGNIFICANT_FIGURES", "-1"));
      68         123 :     oWriteOptionsPlace_.bAllowCurve = true;
      69         123 :     oWriteOptionsPlace_.bAllowMeasure = true;
      70             : 
      71         123 :     bWriteFallbackGeometry_ = CPLTestBool(
      72             :         CSLFetchNameValueDef(papszOptions, "WRITE_GEOMETRY", "TRUE"));
      73             : 
      74         123 :     osMeasureUnit_ = CSLFetchNameValueDef(papszOptions, "MEASURE_UNIT", "");
      75             :     osMeasureDescription_ =
      76         123 :         CSLFetchNameValueDef(papszOptions, "MEASURE_DESCRIPTION", "");
      77             : 
      78         123 :     VSILFILE *fp = poDS_->GetOutputFile();
      79         123 :     if (poDS_->IsSingleOutputLayer())
      80             :     {
      81          15 :         auto poFeatureType = json_object_new_string(pszName);
      82          15 :         VSIFPrintfL(fp, "\"featureType\" : %s,\n",
      83             :                     json_object_to_json_string_ext(poFeatureType,
      84             :                                                    JSON_C_TO_STRING_SPACED));
      85          15 :         json_object_put(poFeatureType);
      86          15 :         if (!osCoordRefSys.empty())
      87          15 :             VSIFPrintfL(fp, "\"coordRefSys\" : %s,\n", osCoordRefSys.c_str());
      88             : 
      89          15 :         if (!osMeasureUnit_.empty() || !osMeasureDescription_.empty())
      90             :         {
      91           3 :             m_bMeasureWritten = true;
      92           3 :             bLayerLevelMeasuresWritten_ = true;
      93           3 :             VSIFPrintfL(fp, "\"measures\": {\n");
      94           3 :             VSIFPrintfL(fp, "  \"enabled\": true");
      95           3 :             if (!osMeasureUnit_.empty())
      96             :             {
      97           3 :                 auto poUnit = json_object_new_string(osMeasureUnit_.c_str());
      98           3 :                 VSIFPrintfL(fp, ",\n  \"unit\": %s",
      99             :                             json_object_to_json_string_ext(
     100             :                                 poUnit, JSON_C_TO_STRING_SPACED));
     101           3 :                 json_object_put(poUnit);
     102             :             }
     103           3 :             if (!osMeasureDescription_.empty())
     104             :             {
     105             :                 auto poDescription =
     106           3 :                     json_object_new_string(osMeasureDescription_.c_str());
     107           3 :                 VSIFPrintfL(fp, ",\n  \"description\": %s",
     108             :                             json_object_to_json_string_ext(
     109             :                                 poDescription, JSON_C_TO_STRING_SPACED));
     110           3 :                 json_object_put(poDescription);
     111             :             }
     112           3 :             VSIFPrintfL(fp, "\n},\n");
     113             :         }
     114             :     }
     115         123 : }
     116             : 
     117             : /************************************************************************/
     118             : /*                        ~OGRJSONFGWriteLayer()                        */
     119             : /************************************************************************/
     120             : 
     121         246 : OGRJSONFGWriteLayer::~OGRJSONFGWriteLayer()
     122             : {
     123         123 :     poFeatureDefn_->Release();
     124         246 : }
     125             : 
     126             : /************************************************************************/
     127             : /*                           SyncToDisk()                               */
     128             : /************************************************************************/
     129             : 
     130           6 : OGRErr OGRJSONFGWriteLayer::SyncToDisk()
     131             : {
     132           6 :     return poDS_->SyncToDiskInternal();
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                       GetValueAsDateOrDateTime()                     */
     137             : /************************************************************************/
     138             : 
     139          16 : static const char *GetValueAsDateOrDateTime(const OGRField *psRawValue,
     140             :                                             OGRFieldType eType)
     141             : {
     142          16 :     if (eType == OFTDate)
     143             :     {
     144          22 :         return CPLSPrintf("%04d-%02d-%02d", psRawValue->Date.Year,
     145          11 :                           psRawValue->Date.Month, psRawValue->Date.Day);
     146             :     }
     147             :     else
     148             :     {
     149             :         struct tm brokenDown;
     150           5 :         memset(&brokenDown, 0, sizeof(brokenDown));
     151           5 :         brokenDown.tm_year = psRawValue->Date.Year - 1900;
     152           5 :         brokenDown.tm_mon = psRawValue->Date.Month - 1;
     153           5 :         brokenDown.tm_mday = psRawValue->Date.Day;
     154           5 :         brokenDown.tm_hour = psRawValue->Date.Hour;
     155           5 :         brokenDown.tm_min = psRawValue->Date.Minute;
     156           5 :         brokenDown.tm_sec = 0;
     157           5 :         if (psRawValue->Date.TZFlag > 0)
     158             :         {
     159             :             // Force to UTC
     160           5 :             GIntBig nVal = CPLYMDHMSToUnixTime(&brokenDown);
     161           5 :             nVal -= (psRawValue->Date.TZFlag - 100) * 15 * 60;
     162           5 :             CPLUnixTimeToYMDHMS(nVal, &brokenDown);
     163             :         }
     164           5 :         if (std::fabs(std::round(psRawValue->Date.Second) -
     165           5 :                       psRawValue->Date.Second) < 1e-3)
     166             :         {
     167           8 :             return CPLSPrintf(
     168           4 :                 "%04d-%02d-%02dT%02d:%02d:%02dZ", brokenDown.tm_year + 1900,
     169           4 :                 brokenDown.tm_mon + 1, brokenDown.tm_mday, brokenDown.tm_hour,
     170             :                 brokenDown.tm_min,
     171           8 :                 static_cast<int>(std::round(psRawValue->Date.Second)));
     172             :         }
     173             :         else
     174             :         {
     175           2 :             return CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%06.3fZ",
     176           1 :                               brokenDown.tm_year + 1900, brokenDown.tm_mon + 1,
     177             :                               brokenDown.tm_mday, brokenDown.tm_hour,
     178           1 :                               brokenDown.tm_min, psRawValue->Date.Second);
     179             :         }
     180             :     }
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                     OGRJSONFGWriteGeometry()                         */
     185             : /************************************************************************/
     186             : 
     187             : static json_object *
     188           3 : OGRJSONFGWriteGeometry(const OGRGeometry *poGeometry,
     189             :                        const OGRGeoJSONWriteOptions &oOptions)
     190             : {
     191           3 :     if (wkbFlatten(poGeometry->getGeometryType()) == wkbPolyhedralSurface)
     192             :     {
     193           3 :         const auto poPS = poGeometry->toPolyhedralSurface();
     194           3 :         json_object *poObj = json_object_new_object();
     195           3 :         json_object_object_add(poObj, "type",
     196             :                                json_object_new_string("Polyhedron"));
     197           3 :         json_object *poCoordinates = json_object_new_array();
     198           3 :         json_object_object_add(poObj, "coordinates", poCoordinates);
     199           3 :         json_object *poOuterShell = json_object_new_array();
     200           3 :         json_object_array_add(poCoordinates, poOuterShell);
     201           8 :         for (const auto *poPoly : *poPS)
     202             :         {
     203           5 :             json_object_array_add(poOuterShell,
     204             :                                   OGRGeoJSONWritePolygon(poPoly, oOptions));
     205             :         }
     206           3 :         return poObj;
     207             :     }
     208             :     else
     209             :     {
     210           0 :         return nullptr;
     211             :     }
     212             : }
     213             : 
     214             : /************************************************************************/
     215             : /*                           ICreateFeature()                           */
     216             : /************************************************************************/
     217             : 
     218         173 : OGRErr OGRJSONFGWriteLayer::ICreateFeature(OGRFeature *poFeature)
     219             : {
     220         173 :     VSILFILE *fp = poDS_->GetOutputFile();
     221         173 :     poDS_->BeforeCreateFeature();
     222             : 
     223         173 :     if (oWriteOptions_.bGenerateID && poFeature->GetFID() == OGRNullFID)
     224             :     {
     225           0 :         poFeature->SetFID(nOutCounter_);
     226             :     }
     227             : 
     228         173 :     json_object *poObj = json_object_new_object();
     229             : 
     230         173 :     json_object_object_add(poObj, "type", json_object_new_string("Feature"));
     231             : 
     232             :     /* -------------------------------------------------------------------- */
     233             :     /*      Write FID if available                                          */
     234             :     /* -------------------------------------------------------------------- */
     235         173 :     OGRGeoJSONWriteId(poFeature, poObj, /* bIdAlreadyWritten = */ false,
     236         173 :                       oWriteOptions_);
     237             : 
     238         173 :     if (!poDS_->IsSingleOutputLayer())
     239             :     {
     240         149 :         json_object_object_add(poObj, "featureType",
     241         149 :                                json_object_new_string(GetDescription()));
     242         149 :         if (!osCoordRefSys_.empty() && !bIsWGS84CRS_)
     243             :         {
     244         102 :             json_object *poCoordRefSys = nullptr;
     245         102 :             CPL_IGNORE_RET_VAL(
     246         102 :                 OGRJSonParse(osCoordRefSys_.c_str(), &poCoordRefSys));
     247         102 :             json_object_object_add(poObj, "coordRefSys", poCoordRefSys);
     248             :         }
     249             :     }
     250             : 
     251             :     /* -------------------------------------------------------------------- */
     252             :     /*      Write feature attributes to "properties" object.                */
     253             :     /* -------------------------------------------------------------------- */
     254         346 :     json_object *poObjProps = OGRGeoJSONWriteAttributes(
     255         173 :         poFeature, /* bWriteIdIfFoundInAttributes = */ true, oWriteOptions_);
     256             : 
     257             :     /* -------------------------------------------------------------------- */
     258             :     /*      Deal with time properties.                                      */
     259             :     /* -------------------------------------------------------------------- */
     260         173 :     json_object *poTime = nullptr;
     261         173 :     int nFieldTimeIdx = poFeatureDefn_->GetFieldIndex("jsonfg_time");
     262         173 :     if (nFieldTimeIdx < 0)
     263         171 :         nFieldTimeIdx = poFeatureDefn_->GetFieldIndex("time");
     264         173 :     if (nFieldTimeIdx >= 0 && poFeature->IsFieldSetAndNotNull(nFieldTimeIdx))
     265             :     {
     266           6 :         const auto poFieldDefn = poFeatureDefn_->GetFieldDefn(nFieldTimeIdx);
     267           6 :         const auto eType = poFieldDefn->GetType();
     268           6 :         if (eType == OFTDate || eType == OFTDateTime)
     269             :         {
     270           6 :             json_object_object_del(poObjProps, poFieldDefn->GetNameRef());
     271           6 :             poTime = json_object_new_object();
     272           6 :             json_object_object_add(
     273             :                 poTime, eType == OFTDate ? "date" : "timestamp",
     274             :                 json_object_new_string(GetValueAsDateOrDateTime(
     275           6 :                     poFeature->GetRawFieldRef(nFieldTimeIdx), eType)));
     276             :         }
     277             :     }
     278             :     else
     279             :     {
     280         167 :         bool bHasStartOrStop = false;
     281         167 :         json_object *poTimeStart = nullptr;
     282             :         int nFieldTimeStartIdx =
     283         167 :             poFeatureDefn_->GetFieldIndex("jsonfg_time_start");
     284         167 :         if (nFieldTimeStartIdx < 0)
     285         166 :             nFieldTimeStartIdx = poFeatureDefn_->GetFieldIndex("time_start");
     286         174 :         if (nFieldTimeStartIdx >= 0 &&
     287           7 :             poFeature->IsFieldSetAndNotNull(nFieldTimeStartIdx))
     288             :         {
     289             :             const auto poFieldDefnStart =
     290           5 :                 poFeatureDefn_->GetFieldDefn(nFieldTimeStartIdx);
     291           5 :             const auto eType = poFieldDefnStart->GetType();
     292           5 :             if (eType == OFTDate || eType == OFTDateTime)
     293             :             {
     294           5 :                 json_object_object_del(poObjProps,
     295             :                                        poFieldDefnStart->GetNameRef());
     296           5 :                 poTimeStart = json_object_new_string(GetValueAsDateOrDateTime(
     297           5 :                     poFeature->GetRawFieldRef(nFieldTimeStartIdx), eType));
     298           5 :                 bHasStartOrStop = true;
     299             :             }
     300             :         }
     301             : 
     302         167 :         json_object *poTimeEnd = nullptr;
     303         167 :         int nFieldTimeEndIdx = poFeatureDefn_->GetFieldIndex("jsonfg_time_end");
     304         167 :         if (nFieldTimeEndIdx < 0)
     305         166 :             nFieldTimeEndIdx = poFeatureDefn_->GetFieldIndex("time_end");
     306         174 :         if (nFieldTimeEndIdx >= 0 &&
     307           7 :             poFeature->IsFieldSetAndNotNull(nFieldTimeEndIdx))
     308             :         {
     309             :             const auto poFieldDefnEnd =
     310           5 :                 poFeatureDefn_->GetFieldDefn(nFieldTimeEndIdx);
     311           5 :             const auto eType = poFieldDefnEnd->GetType();
     312           5 :             if (eType == OFTDate || eType == OFTDateTime)
     313             :             {
     314           5 :                 json_object_object_del(poObjProps,
     315             :                                        poFieldDefnEnd->GetNameRef());
     316           5 :                 poTimeEnd = json_object_new_string(GetValueAsDateOrDateTime(
     317           5 :                     poFeature->GetRawFieldRef(nFieldTimeEndIdx), eType));
     318           5 :                 bHasStartOrStop = true;
     319             :             }
     320             :         }
     321             : 
     322         167 :         if (bHasStartOrStop)
     323             :         {
     324           7 :             poTime = json_object_new_object();
     325           7 :             json_object *poInterval = json_object_new_array();
     326           7 :             json_object_object_add(poTime, "interval", poInterval);
     327           9 :             json_object_array_add(poInterval,
     328             :                                   poTimeStart ? poTimeStart
     329           2 :                                               : json_object_new_string(".."));
     330           9 :             json_object_array_add(poInterval,
     331             :                                   poTimeEnd ? poTimeEnd
     332           2 :                                             : json_object_new_string(".."));
     333             :         }
     334             :     }
     335             : 
     336         173 :     json_object_object_add(poObj, "properties", poObjProps);
     337             : 
     338             :     /* -------------------------------------------------------------------- */
     339             :     /*      Write place and/or geometry                                     */
     340             :     /* -------------------------------------------------------------------- */
     341         173 :     json_object *poJSONGeometry = nullptr;
     342         173 :     json_object *poPlace = nullptr;
     343         173 :     if (const OGRGeometry *poGeom = poFeature->GetGeometryRef())
     344             :     {
     345         122 :         const bool bHasCurve = poGeom->hasCurveGeometry(true);
     346         122 :         if (bHasCurve)
     347          22 :             m_bCurveWritten = true;
     348         122 :         const bool bHasMeasure = CPL_TO_BOOL(poGeom->IsMeasured());
     349         122 :         if (bHasMeasure)
     350          17 :             m_bMeasureWritten = true;
     351         122 :         bool bWritePlace = false;
     352         122 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbPolyhedralSurface)
     353             :         {
     354           3 :             m_bPolyhedraWritten = true;
     355           3 :             bWritePlace = true;
     356             :         }
     357         119 :         else if (bIsWGS84CRS_)
     358             :         {
     359          29 :             bWritePlace = bHasCurve || bHasMeasure;
     360          29 :             poJSONGeometry = OGRGeoJSONWriteGeometry(poGeom, oWriteOptions_);
     361             :         }
     362             :         else
     363             :         {
     364          90 :             if (bWriteFallbackGeometry_ && poCTToWGS84_)
     365             :             {
     366             :                 auto poGeomClone =
     367          88 :                     std::unique_ptr<OGRGeometry>(poGeom->clone());
     368          44 :                 if (poGeomClone->transform(poCTToWGS84_.get()) == OGRERR_NONE)
     369             :                 {
     370          44 :                     poJSONGeometry = OGRGeoJSONWriteGeometry(poGeomClone.get(),
     371          44 :                                                              oWriteOptions_);
     372             :                 }
     373             :             }
     374             : 
     375          90 :             bWritePlace = true;
     376             :         }
     377             : 
     378         122 :         std::unique_ptr<OGRGeometry> poGeomClone;  // keep in that scope
     379         122 :         if (bWritePlace)
     380             :         {
     381         117 :             if (m_bMustSwapForPlace)
     382             :             {
     383           3 :                 poGeomClone.reset(poGeom->clone());
     384           3 :                 poGeomClone->swapXY();
     385           3 :                 poGeom = poGeomClone.get();
     386             :             }
     387         117 :             if (wkbFlatten(poGeom->getGeometryType()) == wkbPolyhedralSurface)
     388             :             {
     389           3 :                 poPlace = OGRJSONFGWriteGeometry(poGeom, oWriteOptionsPlace_);
     390             :             }
     391             :             else
     392             :             {
     393         114 :                 poPlace = OGRGeoJSONWriteGeometry(poGeom, oWriteOptionsPlace_);
     394             :             }
     395             :         }
     396             : 
     397         122 :         if (poGeom->IsMeasured())
     398             :         {
     399          17 :             if (!bLayerLevelMeasuresWritten_)
     400             :             {
     401          14 :                 json_object *poMeasures = json_object_new_object();
     402          14 :                 json_object_object_add(poMeasures, "enabled",
     403             :                                        json_object_new_boolean(true));
     404          14 :                 if (!poDS_->IsSingleOutputLayer())
     405             :                 {
     406          13 :                     if (!osMeasureUnit_.empty())
     407             :                     {
     408           1 :                         json_object_object_add(
     409             :                             poMeasures, "unit",
     410             :                             json_object_new_string(osMeasureUnit_.c_str()));
     411             :                     }
     412          13 :                     if (!osMeasureDescription_.empty())
     413             :                     {
     414           1 :                         json_object_object_add(
     415             :                             poMeasures, "description",
     416             :                             json_object_new_string(
     417             :                                 osMeasureDescription_.c_str()));
     418             :                     }
     419             :                 }
     420          14 :                 json_object_object_add(poObj, "measures", poMeasures);
     421             :             }
     422             :         }
     423         105 :         else if (bLayerLevelMeasuresWritten_)
     424             :         {
     425           0 :             json_object *poMeasures = json_object_new_object();
     426           0 :             json_object_object_add(poMeasures, "enabled",
     427             :                                    json_object_new_boolean(false));
     428           0 :             json_object_object_add(poObj, "measures", poMeasures);
     429             :         }
     430             :     }
     431             : 
     432         173 :     json_object_object_add(poObj, "geometry", poJSONGeometry);
     433         173 :     json_object_object_add(poObj, "place", poPlace);
     434             : 
     435         173 :     json_object_object_add(poObj, "time", poTime);
     436             : 
     437         173 :     VSIFPrintfL(fp, "%s",
     438             :                 json_object_to_json_string_ext(
     439             :                     poObj, JSON_C_TO_STRING_SPACED
     440             : #ifdef JSON_C_TO_STRING_NOSLASHESCAPE
     441             :                                | JSON_C_TO_STRING_NOSLASHESCAPE
     442             : #endif
     443             :                     ));
     444             : 
     445         173 :     json_object_put(poObj);
     446             : 
     447         173 :     ++nOutCounter_;
     448             : 
     449         173 :     return OGRERR_NONE;
     450             : }
     451             : 
     452             : /************************************************************************/
     453             : /*                           CreateField()                              */
     454             : /************************************************************************/
     455             : 
     456         122 : OGRErr OGRJSONFGWriteLayer::CreateField(const OGRFieldDefn *poField,
     457             :                                         int /* bApproxOK */)
     458             : {
     459         122 :     if (poFeatureDefn_->GetFieldIndexCaseSensitive(poField->GetNameRef()) >= 0)
     460             :     {
     461           0 :         CPLDebug("JSONFG", "Field '%s' already present in schema",
     462             :                  poField->GetNameRef());
     463             : 
     464           0 :         return OGRERR_NONE;
     465             :     }
     466             : 
     467         122 :     poFeatureDefn_->AddFieldDefn(poField);
     468             : 
     469         122 :     return OGRERR_NONE;
     470             : }
     471             : 
     472             : /************************************************************************/
     473             : /*                           TestCapability()                           */
     474             : /************************************************************************/
     475             : 
     476         251 : int OGRJSONFGWriteLayer::TestCapability(const char *pszCap) const
     477             : {
     478         251 :     if (EQUAL(pszCap, OLCCreateField))
     479          16 :         return TRUE;
     480         235 :     else if (EQUAL(pszCap, OLCSequentialWrite))
     481          16 :         return TRUE;
     482         219 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     483           0 :         return TRUE;
     484         219 :     else if (EQUAL(pszCap, OLCMeasuredGeometries) ||
     485         112 :              EQUAL(pszCap, OLCZGeometries) || EQUAL(pszCap, OLCCurveGeometries))
     486         219 :         return TRUE;
     487           0 :     return FALSE;
     488             : }
     489             : 
     490             : /************************************************************************/
     491             : /*                             GetDataset()                             */
     492             : /************************************************************************/
     493             : 
     494          24 : GDALDataset *OGRJSONFGWriteLayer::GetDataset()
     495             : {
     496          24 :     return poDS_;
     497             : }

Generated by: LCOV version 1.14