LCOV - code coverage report
Current view: top level - ogr - ogrgeojsongeometry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 381 403 94.5 %
Date: 2024-11-21 22:18:42 Functions: 16 16 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: MIT
       2             : // Copyright 2007, Mateusz Loskot
       3             : // Copyright 2008-2024, Even Rouault <even.rouault at spatialys.com>
       4             : 
       5             : /*! @cond Doxygen_Suppress */
       6             : 
       7             : #include "ogrgeojsongeometry.h"
       8             : #include "ogrlibjsonutils.h"
       9             : 
      10             : #include "ogr_geometry.h"
      11             : #include "ogr_spatialref.h"
      12             : 
      13             : static OGRPoint *OGRGeoJSONReadPoint(json_object *poObj);
      14             : static OGRMultiPoint *OGRGeoJSONReadMultiPoint(json_object *poObj);
      15             : static OGRLineString *OGRGeoJSONReadLineString(json_object *poObj,
      16             :                                                bool bRaw = false);
      17             : static OGRMultiLineString *OGRGeoJSONReadMultiLineString(json_object *poObj);
      18             : static OGRLinearRing *OGRGeoJSONReadLinearRing(json_object *poObj);
      19             : static OGRMultiPolygon *OGRGeoJSONReadMultiPolygon(json_object *poObj);
      20             : static OGRGeometryCollection *
      21             : OGRGeoJSONReadGeometryCollection(json_object *poObj,
      22             :                                  OGRSpatialReference *poSRS = nullptr);
      23             : 
      24             : /************************************************************************/
      25             : /*                           OGRGeoJSONGetType                          */
      26             : /************************************************************************/
      27             : 
      28        2840 : GeoJSONObject::Type OGRGeoJSONGetType(json_object *poObj)
      29             : {
      30        2840 :     if (nullptr == poObj)
      31           0 :         return GeoJSONObject::eUnknown;
      32             : 
      33        2840 :     json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "type");
      34        2840 :     if (nullptr == poObjType)
      35           2 :         return GeoJSONObject::eUnknown;
      36             : 
      37        2838 :     const char *name = json_object_get_string(poObjType);
      38        2838 :     if (EQUAL(name, "Point"))
      39         358 :         return GeoJSONObject::ePoint;
      40        2480 :     else if (EQUAL(name, "LineString"))
      41          52 :         return GeoJSONObject::eLineString;
      42        2428 :     else if (EQUAL(name, "Polygon"))
      43         992 :         return GeoJSONObject::ePolygon;
      44        1436 :     else if (EQUAL(name, "MultiPoint"))
      45         138 :         return GeoJSONObject::eMultiPoint;
      46        1298 :     else if (EQUAL(name, "MultiLineString"))
      47          34 :         return GeoJSONObject::eMultiLineString;
      48        1264 :     else if (EQUAL(name, "MultiPolygon"))
      49         415 :         return GeoJSONObject::eMultiPolygon;
      50         849 :     else if (EQUAL(name, "GeometryCollection"))
      51          14 :         return GeoJSONObject::eGeometryCollection;
      52         835 :     else if (EQUAL(name, "Feature"))
      53         557 :         return GeoJSONObject::eFeature;
      54         278 :     else if (EQUAL(name, "FeatureCollection"))
      55         278 :         return GeoJSONObject::eFeatureCollection;
      56             :     else
      57           0 :         return GeoJSONObject::eUnknown;
      58             : }
      59             : 
      60             : /************************************************************************/
      61             : /*                   OGRGeoJSONGetOGRGeometryType()                     */
      62             : /************************************************************************/
      63             : 
      64        4606 : OGRwkbGeometryType OGRGeoJSONGetOGRGeometryType(json_object *poObj)
      65             : {
      66        4606 :     if (nullptr == poObj)
      67           1 :         return wkbUnknown;
      68             : 
      69        4605 :     json_object *poObjType = CPL_json_object_object_get(poObj, "type");
      70        4605 :     if (nullptr == poObjType)
      71           0 :         return wkbUnknown;
      72             : 
      73        4605 :     OGRwkbGeometryType eType = wkbUnknown;
      74        4605 :     const char *name = json_object_get_string(poObjType);
      75        4605 :     if (EQUAL(name, "Point"))
      76         325 :         eType = wkbPoint;
      77        4280 :     else if (EQUAL(name, "LineString"))
      78          53 :         eType = wkbLineString;
      79        4227 :     else if (EQUAL(name, "Polygon"))
      80        3927 :         eType = wkbPolygon;
      81         300 :     else if (EQUAL(name, "MultiPoint"))
      82          25 :         eType = wkbMultiPoint;
      83         275 :     else if (EQUAL(name, "MultiLineString"))
      84          28 :         eType = wkbMultiLineString;
      85         247 :     else if (EQUAL(name, "MultiPolygon"))
      86         223 :         eType = wkbMultiPolygon;
      87          24 :     else if (EQUAL(name, "GeometryCollection"))
      88          19 :         eType = wkbGeometryCollection;
      89             :     else
      90           5 :         return wkbUnknown;
      91             : 
      92             :     json_object *poCoordinates;
      93        4600 :     if (eType == wkbGeometryCollection)
      94             :     {
      95             :         json_object *poGeometries =
      96          19 :             CPL_json_object_object_get(poObj, "geometries");
      97          37 :         if (poGeometries &&
      98          37 :             json_object_get_type(poGeometries) == json_type_array &&
      99          18 :             json_object_array_length(poGeometries) > 0)
     100             :         {
     101          17 :             if (OGR_GT_HasZ(OGRGeoJSONGetOGRGeometryType(
     102          17 :                     json_object_array_get_idx(poGeometries, 0))))
     103           7 :                 eType = OGR_GT_SetZ(eType);
     104             :         }
     105             :     }
     106             :     else
     107             :     {
     108        4581 :         poCoordinates = CPL_json_object_object_get(poObj, "coordinates");
     109        9156 :         if (poCoordinates &&
     110        9156 :             json_object_get_type(poCoordinates) == json_type_array &&
     111        4575 :             json_object_array_length(poCoordinates) > 0)
     112             :         {
     113             :             while (true)
     114             :             {
     115       13187 :                 auto poChild = json_object_array_get_idx(poCoordinates, 0);
     116       26364 :                 if (!(poChild &&
     117       13177 :                       json_object_get_type(poChild) == json_type_array &&
     118        8621 :                       json_object_array_length(poChild) > 0))
     119             :                 {
     120        4570 :                     if (json_object_array_length(poCoordinates) == 3)
     121         111 :                         eType = OGR_GT_SetZ(eType);
     122        4570 :                     break;
     123             :                 }
     124        8617 :                 poCoordinates = poChild;
     125        8617 :             }
     126             :         }
     127             :     }
     128             : 
     129        4600 :     return eType;
     130             : }
     131             : 
     132             : /************************************************************************/
     133             : /*                           OGRGeoJSONReadGeometry                     */
     134             : /************************************************************************/
     135             : 
     136        1878 : OGRGeometry *OGRGeoJSONReadGeometry(json_object *poObj,
     137             :                                     OGRSpatialReference *poParentSRS)
     138             : {
     139             : 
     140        1878 :     OGRGeometry *poGeometry = nullptr;
     141        1878 :     OGRSpatialReference *poSRS = nullptr;
     142        1878 :     lh_entry *entry = OGRGeoJSONFindMemberEntryByName(poObj, "crs");
     143        1878 :     if (entry != nullptr)
     144             :     {
     145           4 :         json_object *poObjSrs =
     146             :             static_cast<json_object *>(const_cast<void *>(entry->v));
     147           4 :         if (poObjSrs != nullptr)
     148             :         {
     149           3 :             poSRS = OGRGeoJSONReadSpatialReference(poObj);
     150             :         }
     151             :     }
     152             : 
     153        1878 :     OGRSpatialReference *poSRSToAssign = nullptr;
     154        1878 :     if (entry != nullptr)
     155             :     {
     156           4 :         poSRSToAssign = poSRS;
     157             :     }
     158        1874 :     else if (poParentSRS)
     159             :     {
     160        1261 :         poSRSToAssign = poParentSRS;
     161             :     }
     162             :     else
     163             :     {
     164             :         // Assign WGS84 if no CRS defined on geometry.
     165         613 :         poSRSToAssign = OGRSpatialReference::GetWGS84SRS();
     166             :     }
     167             : 
     168        1878 :     GeoJSONObject::Type objType = OGRGeoJSONGetType(poObj);
     169        1878 :     if (GeoJSONObject::ePoint == objType)
     170         337 :         poGeometry = OGRGeoJSONReadPoint(poObj);
     171        1541 :     else if (GeoJSONObject::eMultiPoint == objType)
     172          58 :         poGeometry = OGRGeoJSONReadMultiPoint(poObj);
     173        1483 :     else if (GeoJSONObject::eLineString == objType)
     174          48 :         poGeometry = OGRGeoJSONReadLineString(poObj);
     175        1435 :     else if (GeoJSONObject::eMultiLineString == objType)
     176          32 :         poGeometry = OGRGeoJSONReadMultiLineString(poObj);
     177        1403 :     else if (GeoJSONObject::ePolygon == objType)
     178         988 :         poGeometry = OGRGeoJSONReadPolygon(poObj);
     179         415 :     else if (GeoJSONObject::eMultiPolygon == objType)
     180         405 :         poGeometry = OGRGeoJSONReadMultiPolygon(poObj);
     181          10 :     else if (GeoJSONObject::eGeometryCollection == objType)
     182          10 :         poGeometry = OGRGeoJSONReadGeometryCollection(poObj, poSRSToAssign);
     183             :     else
     184             :     {
     185           0 :         CPLDebug("GeoJSON", "Unsupported geometry type detected. "
     186             :                             "Feature gets NULL geometry assigned.");
     187             :     }
     188             : 
     189        1878 :     if (poGeometry && GeoJSONObject::eGeometryCollection != objType)
     190        1854 :         poGeometry->assignSpatialReference(poSRSToAssign);
     191             : 
     192        1878 :     if (poSRS)
     193           3 :         poSRS->Release();
     194             : 
     195        1878 :     return poGeometry;
     196             : }
     197             : 
     198             : /************************************************************************/
     199             : /*                        OGRGeoJSONGetCoordinate()                     */
     200             : /************************************************************************/
     201             : 
     202      180123 : static double OGRGeoJSONGetCoordinate(json_object *poObj,
     203             :                                       const char *pszCoordName, int nIndex,
     204             :                                       bool &bValid)
     205             : {
     206      180123 :     json_object *poObjCoord = json_object_array_get_idx(poObj, nIndex);
     207      180123 :     if (nullptr == poObjCoord)
     208             :     {
     209           5 :         CPLDebug("GeoJSON", "Point: got null object for %s.", pszCoordName);
     210           5 :         bValid = false;
     211           5 :         return 0.0;
     212             :     }
     213             : 
     214      180118 :     const int iType = json_object_get_type(poObjCoord);
     215      180118 :     if (json_type_double != iType && json_type_int != iType)
     216             :     {
     217           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     218             :                  "Invalid '%s' coordinate. "
     219             :                  "Type is not double or integer for \'%s\'.",
     220             :                  pszCoordName, json_object_to_json_string(poObjCoord));
     221           0 :         bValid = false;
     222           0 :         return 0.0;
     223             :     }
     224             : 
     225      180118 :     return json_object_get_double(poObjCoord);
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                           OGRGeoJSONReadRawPoint                     */
     230             : /************************************************************************/
     231             : 
     232       89876 : static bool OGRGeoJSONReadRawPoint(json_object *poObj, OGRPoint &point)
     233             : {
     234       89876 :     CPLAssert(nullptr != poObj);
     235             : 
     236       89876 :     if (json_type_array == json_object_get_type(poObj))
     237             :     {
     238       89876 :         const auto nSize = json_object_array_length(poObj);
     239             : 
     240       89876 :         if (nSize < GeoJSONObject::eMinCoordinateDimension)
     241             :         {
     242           1 :             CPLDebug("GeoJSON", "Invalid coord dimension. "
     243             :                                 "At least 2 dimensions must be present.");
     244           1 :             return false;
     245             :         }
     246             : 
     247       89875 :         bool bValid = true;
     248       89875 :         const double dfX = OGRGeoJSONGetCoordinate(poObj, "x", 0, bValid);
     249       89875 :         const double dfY = OGRGeoJSONGetCoordinate(poObj, "y", 1, bValid);
     250       89875 :         point.setX(dfX);
     251       89875 :         point.setY(dfY);
     252             : 
     253             :         // Read Z coordinate.
     254       89875 :         if (nSize >= GeoJSONObject::eMaxCoordinateDimension)
     255             :         {
     256             :             // Don't *expect* mixed-dimension geometries, although the
     257             :             // spec doesn't explicitly forbid this.
     258         373 :             const double dfZ = OGRGeoJSONGetCoordinate(poObj, "z", 2, bValid);
     259         373 :             point.setZ(dfZ);
     260             :         }
     261             :         else
     262             :         {
     263       89502 :             point.flattenTo2D();
     264             :         }
     265       89875 :         return bValid;
     266             :     }
     267             : 
     268           0 :     return false;
     269             : }
     270             : 
     271             : /************************************************************************/
     272             : /*                           OGRGeoJSONReadPoint                        */
     273             : /************************************************************************/
     274             : 
     275         337 : OGRPoint *OGRGeoJSONReadPoint(json_object *poObj)
     276             : {
     277         337 :     CPLAssert(nullptr != poObj);
     278             : 
     279         337 :     json_object *poObjCoords = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     280         337 :     if (nullptr == poObjCoords)
     281             :     {
     282           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     283             :                  "Invalid Point object. Missing \'coordinates\' member.");
     284           2 :         return nullptr;
     285             :     }
     286             : 
     287         335 :     OGRPoint *poPoint = new OGRPoint();
     288         335 :     if (!OGRGeoJSONReadRawPoint(poObjCoords, *poPoint))
     289             :     {
     290           5 :         CPLDebug("GeoJSON", "Point: raw point parsing failure.");
     291           5 :         delete poPoint;
     292           5 :         return nullptr;
     293             :     }
     294             : 
     295         330 :     return poPoint;
     296             : }
     297             : 
     298             : /************************************************************************/
     299             : /*                           OGRGeoJSONReadMultiPoint                   */
     300             : /************************************************************************/
     301             : 
     302          58 : OGRMultiPoint *OGRGeoJSONReadMultiPoint(json_object *poObj)
     303             : {
     304          58 :     CPLAssert(nullptr != poObj);
     305             : 
     306          58 :     json_object *poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     307          58 :     if (nullptr == poObjPoints)
     308             :     {
     309           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     310             :                  "Invalid MultiPoint object. "
     311             :                  "Missing \'coordinates\' member.");
     312           1 :         return nullptr;
     313             :     }
     314             : 
     315          57 :     OGRMultiPoint *poMultiPoint = nullptr;
     316          57 :     if (json_type_array == json_object_get_type(poObjPoints))
     317             :     {
     318          57 :         const auto nPoints = json_object_array_length(poObjPoints);
     319             : 
     320          57 :         poMultiPoint = new OGRMultiPoint();
     321             : 
     322         259 :         for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
     323             :         {
     324             :             json_object *poObjCoords =
     325         202 :                 json_object_array_get_idx(poObjPoints, i);
     326             : 
     327         202 :             OGRPoint pt;
     328         401 :             if (poObjCoords != nullptr &&
     329         199 :                 !OGRGeoJSONReadRawPoint(poObjCoords, pt))
     330             :             {
     331           0 :                 delete poMultiPoint;
     332           0 :                 CPLDebug("GeoJSON", "LineString: raw point parsing failure.");
     333           0 :                 return nullptr;
     334             :             }
     335         202 :             poMultiPoint->addGeometry(&pt);
     336             :         }
     337             :     }
     338             : 
     339          57 :     return poMultiPoint;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                           OGRGeoJSONReadLineString                   */
     344             : /************************************************************************/
     345             : 
     346         101 : OGRLineString *OGRGeoJSONReadLineString(json_object *poObj, bool bRaw)
     347             : {
     348         101 :     CPLAssert(nullptr != poObj);
     349             : 
     350         101 :     json_object *poObjPoints = nullptr;
     351             : 
     352         101 :     if (!bRaw)
     353             :     {
     354          48 :         poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     355          48 :         if (nullptr == poObjPoints)
     356             :         {
     357           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     358             :                      "Invalid LineString object. "
     359             :                      "Missing \'coordinates\' member.");
     360           1 :             return nullptr;
     361             :         }
     362             :     }
     363             :     else
     364             :     {
     365          53 :         poObjPoints = poObj;
     366             :     }
     367             : 
     368         100 :     OGRLineString *poLine = nullptr;
     369             : 
     370         100 :     if (json_type_array == json_object_get_type(poObjPoints))
     371             :     {
     372         100 :         const auto nPoints = json_object_array_length(poObjPoints);
     373             : 
     374         100 :         poLine = new OGRLineString();
     375         100 :         poLine->setNumPoints(static_cast<int>(nPoints));
     376             : 
     377         295 :         for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
     378             :         {
     379             :             json_object *poObjCoords =
     380         199 :                 json_object_array_get_idx(poObjPoints, i);
     381         199 :             if (poObjCoords == nullptr)
     382             :             {
     383           4 :                 delete poLine;
     384           4 :                 CPLDebug("GeoJSON", "LineString: got null object.");
     385           4 :                 return nullptr;
     386             :             }
     387             : 
     388         195 :             OGRPoint pt;
     389         195 :             if (!OGRGeoJSONReadRawPoint(poObjCoords, pt))
     390             :             {
     391           0 :                 delete poLine;
     392           0 :                 CPLDebug("GeoJSON", "LineString: raw point parsing failure.");
     393           0 :                 return nullptr;
     394             :             }
     395         195 :             if (pt.getCoordinateDimension() == 2)
     396             :             {
     397         169 :                 poLine->setPoint(static_cast<int>(i), pt.getX(), pt.getY());
     398             :             }
     399             :             else
     400             :             {
     401          26 :                 poLine->setPoint(static_cast<int>(i), pt.getX(), pt.getY(),
     402             :                                  pt.getZ());
     403             :             }
     404             :         }
     405             :     }
     406             : 
     407          96 :     return poLine;
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                           OGRGeoJSONReadMultiLineString              */
     412             : /************************************************************************/
     413             : 
     414          32 : OGRMultiLineString *OGRGeoJSONReadMultiLineString(json_object *poObj)
     415             : {
     416          32 :     CPLAssert(nullptr != poObj);
     417             : 
     418          32 :     json_object *poObjLines = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     419          32 :     if (nullptr == poObjLines)
     420             :     {
     421           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     422             :                  "Invalid MultiLineString object. "
     423             :                  "Missing \'coordinates\' member.");
     424           1 :         return nullptr;
     425             :     }
     426             : 
     427          31 :     OGRMultiLineString *poMultiLine = nullptr;
     428             : 
     429          31 :     if (json_type_array == json_object_get_type(poObjLines))
     430             :     {
     431          31 :         const auto nLines = json_object_array_length(poObjLines);
     432             : 
     433          31 :         poMultiLine = new OGRMultiLineString();
     434             : 
     435          86 :         for (auto i = decltype(nLines){0}; i < nLines; ++i)
     436             :         {
     437          55 :             json_object *poObjLine = json_object_array_get_idx(poObjLines, i);
     438             : 
     439             :             OGRLineString *poLine;
     440          55 :             if (poObjLine != nullptr)
     441          53 :                 poLine = OGRGeoJSONReadLineString(poObjLine, true);
     442             :             else
     443           2 :                 poLine = new OGRLineString();
     444             : 
     445          55 :             if (nullptr != poLine)
     446             :             {
     447          53 :                 poMultiLine->addGeometryDirectly(poLine);
     448             :             }
     449             :         }
     450             :     }
     451             : 
     452          31 :     return poMultiLine;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                           OGRGeoJSONReadLinearRing                   */
     457             : /************************************************************************/
     458             : 
     459        1674 : OGRLinearRing *OGRGeoJSONReadLinearRing(json_object *poObj)
     460             : {
     461        1674 :     CPLAssert(nullptr != poObj);
     462             : 
     463        1674 :     OGRLinearRing *poRing = nullptr;
     464             : 
     465        1674 :     if (json_type_array == json_object_get_type(poObj))
     466             :     {
     467        1674 :         const auto nPoints = json_object_array_length(poObj);
     468             : 
     469        1674 :         poRing = new OGRLinearRing();
     470        1674 :         poRing->setNumPoints(static_cast<int>(nPoints));
     471             : 
     472       90821 :         for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
     473             :         {
     474       89147 :             json_object *poObjCoords = json_object_array_get_idx(poObj, i);
     475       89147 :             if (poObjCoords == nullptr)
     476             :             {
     477           0 :                 delete poRing;
     478           0 :                 CPLDebug("GeoJSON", "LinearRing: got null object.");
     479           0 :                 return nullptr;
     480             :             }
     481             : 
     482       89147 :             OGRPoint pt;
     483       89147 :             if (!OGRGeoJSONReadRawPoint(poObjCoords, pt))
     484             :             {
     485           0 :                 delete poRing;
     486           0 :                 CPLDebug("GeoJSON", "LinearRing: raw point parsing failure.");
     487           0 :                 return nullptr;
     488             :             }
     489             : 
     490       89147 :             if (2 == pt.getCoordinateDimension())
     491       89006 :                 poRing->setPoint(static_cast<int>(i), pt.getX(), pt.getY());
     492             :             else
     493         141 :                 poRing->setPoint(static_cast<int>(i), pt.getX(), pt.getY(),
     494             :                                  pt.getZ());
     495             :         }
     496             :     }
     497             : 
     498        1674 :     return poRing;
     499             : }
     500             : 
     501             : /************************************************************************/
     502             : /*                           OGRGeoJSONReadPolygon                      */
     503             : /************************************************************************/
     504             : 
     505        1641 : OGRPolygon *OGRGeoJSONReadPolygon(json_object *poObj, bool bRaw)
     506             : {
     507        1641 :     CPLAssert(nullptr != poObj);
     508             : 
     509        1641 :     json_object *poObjRings = nullptr;
     510             : 
     511        1641 :     if (!bRaw)
     512             :     {
     513         988 :         poObjRings = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     514         988 :         if (nullptr == poObjRings)
     515             :         {
     516           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     517             :                      "Invalid Polygon object. "
     518             :                      "Missing \'coordinates\' member.");
     519           1 :             return nullptr;
     520             :         }
     521             :     }
     522             :     else
     523             :     {
     524         653 :         poObjRings = poObj;
     525             :     }
     526             : 
     527        1640 :     OGRPolygon *poPolygon = nullptr;
     528             : 
     529        1640 :     if (json_type_array == json_object_get_type(poObjRings))
     530             :     {
     531        1640 :         const auto nRings = json_object_array_length(poObjRings);
     532        1640 :         if (nRings > 0)
     533             :         {
     534        1636 :             json_object *poObjPoints = json_object_array_get_idx(poObjRings, 0);
     535        1636 :             if (poObjPoints == nullptr)
     536             :             {
     537           2 :                 poPolygon = new OGRPolygon();
     538             :             }
     539             :             else
     540             :             {
     541        1634 :                 OGRLinearRing *poRing = OGRGeoJSONReadLinearRing(poObjPoints);
     542        1634 :                 if (nullptr != poRing)
     543             :                 {
     544        1634 :                     poPolygon = new OGRPolygon();
     545        1634 :                     poPolygon->addRingDirectly(poRing);
     546             :                 }
     547             :             }
     548             : 
     549        1677 :             for (auto i = decltype(nRings){1};
     550        1677 :                  i < nRings && nullptr != poPolygon; ++i)
     551             :             {
     552          41 :                 poObjPoints = json_object_array_get_idx(poObjRings, i);
     553          41 :                 if (poObjPoints != nullptr)
     554             :                 {
     555             :                     OGRLinearRing *poRing =
     556          40 :                         OGRGeoJSONReadLinearRing(poObjPoints);
     557          40 :                     if (nullptr != poRing)
     558             :                     {
     559          40 :                         poPolygon->addRingDirectly(poRing);
     560             :                     }
     561             :                 }
     562             :             }
     563             :         }
     564             :         else
     565             :         {
     566           4 :             poPolygon = new OGRPolygon();
     567             :         }
     568             :     }
     569             : 
     570        1640 :     return poPolygon;
     571             : }
     572             : 
     573             : /************************************************************************/
     574             : /*                           OGRGeoJSONReadMultiPolygon                 */
     575             : /************************************************************************/
     576             : 
     577         405 : OGRMultiPolygon *OGRGeoJSONReadMultiPolygon(json_object *poObj)
     578             : {
     579         405 :     CPLAssert(nullptr != poObj);
     580             : 
     581         405 :     json_object *poObjPolys = OGRGeoJSONFindMemberByName(poObj, "coordinates");
     582         405 :     if (nullptr == poObjPolys)
     583             :     {
     584           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     585             :                  "Invalid MultiPolygon object. "
     586             :                  "Missing \'coordinates\' member.");
     587           1 :         return nullptr;
     588             :     }
     589             : 
     590         404 :     OGRMultiPolygon *poMultiPoly = nullptr;
     591             : 
     592         404 :     if (json_type_array == json_object_get_type(poObjPolys))
     593             :     {
     594         404 :         const auto nPolys = json_object_array_length(poObjPolys);
     595             : 
     596         404 :         poMultiPoly = new OGRMultiPolygon();
     597             : 
     598        1056 :         for (auto i = decltype(nPolys){0}; i < nPolys; ++i)
     599             :         {
     600         652 :             json_object *poObjPoly = json_object_array_get_idx(poObjPolys, i);
     601         652 :             if (poObjPoly == nullptr)
     602             :             {
     603           3 :                 poMultiPoly->addGeometryDirectly(new OGRPolygon());
     604             :             }
     605             :             else
     606             :             {
     607         649 :                 OGRPolygon *poPoly = OGRGeoJSONReadPolygon(poObjPoly, true);
     608         649 :                 if (nullptr != poPoly)
     609             :                 {
     610         649 :                     poMultiPoly->addGeometryDirectly(poPoly);
     611             :                 }
     612             :             }
     613             :         }
     614             :     }
     615             : 
     616         404 :     return poMultiPoly;
     617             : }
     618             : 
     619             : /************************************************************************/
     620             : /*                           OGRGeoJSONReadGeometryCollection           */
     621             : /************************************************************************/
     622             : 
     623             : OGRGeometryCollection *
     624          10 : OGRGeoJSONReadGeometryCollection(json_object *poObj, OGRSpatialReference *poSRS)
     625             : {
     626          10 :     CPLAssert(nullptr != poObj);
     627             : 
     628          10 :     json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
     629          10 :     if (nullptr == poObjGeoms)
     630             :     {
     631           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     632             :                  "Invalid GeometryCollection object. "
     633             :                  "Missing \'geometries\' member.");
     634           1 :         return nullptr;
     635             :     }
     636             : 
     637           9 :     OGRGeometryCollection *poCollection = nullptr;
     638             : 
     639           9 :     if (json_type_array == json_object_get_type(poObjGeoms))
     640             :     {
     641           9 :         poCollection = new OGRGeometryCollection();
     642           9 :         poCollection->assignSpatialReference(poSRS);
     643             : 
     644           9 :         const auto nGeoms = json_object_array_length(poObjGeoms);
     645          25 :         for (auto i = decltype(nGeoms){0}; i < nGeoms; ++i)
     646             :         {
     647          16 :             json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
     648          16 :             if (poObjGeom == nullptr)
     649             :             {
     650           3 :                 CPLDebug("GeoJSON", "Skipping null sub-geometry");
     651           3 :                 continue;
     652             :             }
     653             : 
     654          13 :             OGRGeometry *poGeometry = OGRGeoJSONReadGeometry(poObjGeom, poSRS);
     655          13 :             if (nullptr != poGeometry)
     656             :             {
     657          13 :                 poCollection->addGeometryDirectly(poGeometry);
     658             :             }
     659             :         }
     660             :     }
     661             : 
     662           9 :     return poCollection;
     663             : }
     664             : 
     665             : /************************************************************************/
     666             : /*                           OGRGeoJSONGetGeometryName()                */
     667             : /************************************************************************/
     668             : 
     669        1667 : const char *OGRGeoJSONGetGeometryName(OGRGeometry const *poGeometry)
     670             : {
     671        1667 :     CPLAssert(nullptr != poGeometry);
     672             : 
     673        1667 :     const OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
     674             : 
     675        1667 :     if (wkbPoint == eType)
     676         161 :         return "Point";
     677        1506 :     else if (wkbLineString == eType)
     678          55 :         return "LineString";
     679        1451 :     else if (wkbPolygon == eType)
     680        1282 :         return "Polygon";
     681         169 :     else if (wkbMultiPoint == eType)
     682          66 :         return "MultiPoint";
     683         103 :     else if (wkbMultiLineString == eType)
     684          34 :         return "MultiLineString";
     685          69 :     else if (wkbMultiPolygon == eType)
     686          43 :         return "MultiPolygon";
     687          26 :     else if (wkbGeometryCollection == eType)
     688          25 :         return "GeometryCollection";
     689             : 
     690           1 :     return "Unknown";
     691             : }
     692             : 
     693             : /************************************************************************/
     694             : /*                    OGRGeoJSONReadSpatialReference                    */
     695             : /************************************************************************/
     696             : 
     697         436 : OGRSpatialReference *OGRGeoJSONReadSpatialReference(json_object *poObj)
     698             : {
     699             : 
     700             :     /* -------------------------------------------------------------------- */
     701             :     /*      Read spatial reference definition.                              */
     702             :     /* -------------------------------------------------------------------- */
     703         436 :     OGRSpatialReference *poSRS = nullptr;
     704             : 
     705         436 :     json_object *poObjSrs = OGRGeoJSONFindMemberByName(poObj, "crs");
     706         436 :     if (nullptr != poObjSrs)
     707             :     {
     708             :         json_object *poObjSrsType =
     709          70 :             OGRGeoJSONFindMemberByName(poObjSrs, "type");
     710          70 :         if (poObjSrsType == nullptr)
     711           1 :             return nullptr;
     712             : 
     713          69 :         const char *pszSrsType = json_object_get_string(poObjSrsType);
     714             : 
     715             :         // TODO: Add URL and URN types support.
     716          69 :         if (STARTS_WITH_CI(pszSrsType, "NAME"))
     717             :         {
     718             :             json_object *poObjSrsProps =
     719          49 :                 OGRGeoJSONFindMemberByName(poObjSrs, "properties");
     720          49 :             if (poObjSrsProps == nullptr)
     721           2 :                 return nullptr;
     722             : 
     723             :             json_object *poNameURL =
     724          47 :                 OGRGeoJSONFindMemberByName(poObjSrsProps, "name");
     725          47 :             if (poNameURL == nullptr)
     726           2 :                 return nullptr;
     727             : 
     728          45 :             const char *pszName = json_object_get_string(poNameURL);
     729             : 
     730             :             // Mostly to emulate GDAL 2.x behavior
     731             :             // See https://github.com/OSGeo/gdal/issues/2035
     732          45 :             if (EQUAL(pszName, "urn:ogc:def:crs:OGC:1.3:CRS84"))
     733           9 :                 pszName = "EPSG:4326";
     734             : 
     735          45 :             poSRS = new OGRSpatialReference();
     736          45 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     737          45 :             if (OGRERR_NONE !=
     738          45 :                 poSRS->SetFromUserInput(
     739             :                     pszName,
     740             :                     OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()))
     741             :             {
     742           2 :                 delete poSRS;
     743           2 :                 poSRS = nullptr;
     744             :             }
     745             :         }
     746             : 
     747          20 :         else if (STARTS_WITH_CI(pszSrsType, "EPSG"))
     748             :         {
     749             :             json_object *poObjSrsProps =
     750           7 :                 OGRGeoJSONFindMemberByName(poObjSrs, "properties");
     751           7 :             if (poObjSrsProps == nullptr)
     752           2 :                 return nullptr;
     753             : 
     754             :             json_object *poObjCode =
     755           5 :                 OGRGeoJSONFindMemberByName(poObjSrsProps, "code");
     756           5 :             if (poObjCode == nullptr)
     757           2 :                 return nullptr;
     758             : 
     759           3 :             int nEPSG = json_object_get_int(poObjCode);
     760             : 
     761           3 :             poSRS = new OGRSpatialReference();
     762           3 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     763           3 :             if (OGRERR_NONE != poSRS->importFromEPSG(nEPSG))
     764             :             {
     765           2 :                 delete poSRS;
     766           2 :                 poSRS = nullptr;
     767             :             }
     768             :         }
     769             : 
     770          13 :         else if (STARTS_WITH_CI(pszSrsType, "URL") ||
     771          13 :                  STARTS_WITH_CI(pszSrsType, "LINK"))
     772             :         {
     773             :             json_object *poObjSrsProps =
     774           6 :                 OGRGeoJSONFindMemberByName(poObjSrs, "properties");
     775           6 :             if (poObjSrsProps == nullptr)
     776           2 :                 return nullptr;
     777             : 
     778             :             json_object *poObjURL =
     779           4 :                 OGRGeoJSONFindMemberByName(poObjSrsProps, "url");
     780             : 
     781           4 :             if (nullptr == poObjURL)
     782             :             {
     783           4 :                 poObjURL = OGRGeoJSONFindMemberByName(poObjSrsProps, "href");
     784             :             }
     785           4 :             if (poObjURL == nullptr)
     786           2 :                 return nullptr;
     787             : 
     788           2 :             const char *pszURL = json_object_get_string(poObjURL);
     789             : 
     790           2 :             poSRS = new OGRSpatialReference();
     791           2 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     792           2 :             if (OGRERR_NONE != poSRS->importFromUrl(pszURL))
     793             :             {
     794           2 :                 delete poSRS;
     795           2 :                 poSRS = nullptr;
     796           2 :             }
     797             :         }
     798             : 
     799           7 :         else if (EQUAL(pszSrsType, "OGC"))
     800             :         {
     801             :             json_object *poObjSrsProps =
     802           7 :                 OGRGeoJSONFindMemberByName(poObjSrs, "properties");
     803           7 :             if (poObjSrsProps == nullptr)
     804           2 :                 return nullptr;
     805             : 
     806             :             json_object *poObjURN =
     807           5 :                 OGRGeoJSONFindMemberByName(poObjSrsProps, "urn");
     808           5 :             if (poObjURN == nullptr)
     809           2 :                 return nullptr;
     810             : 
     811           3 :             poSRS = new OGRSpatialReference();
     812           3 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     813           3 :             if (OGRERR_NONE !=
     814           3 :                 poSRS->importFromURN(json_object_get_string(poObjURN)))
     815             :             {
     816           2 :                 delete poSRS;
     817           2 :                 poSRS = nullptr;
     818             :             }
     819             :         }
     820             :     }
     821             : 
     822             :     // Strip AXIS, since geojson has (easting, northing) / (longitude, latitude)
     823             :     // order.  According to http://www.geojson.org/geojson-spec.html#id2 :
     824             :     // "Point coordinates are in x, y order (easting, northing for projected
     825             :     // coordinates, longitude, latitude for geographic coordinates)".
     826         419 :     if (poSRS != nullptr)
     827             :     {
     828          45 :         OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode("GEOGCS");
     829          45 :         if (poGEOGCS != nullptr)
     830          45 :             poGEOGCS->StripNodes("AXIS");
     831             :     }
     832             : 
     833         419 :     return poSRS;
     834             : }
     835             : 
     836             : /************************************************************************/
     837             : /*                       OGR_G_CreateGeometryFromJson                   */
     838             : /************************************************************************/
     839             : 
     840             : /** Create a OGR geometry from a GeoJSON geometry object */
     841          46 : OGRGeometryH OGR_G_CreateGeometryFromJson(const char *pszJson)
     842             : {
     843          46 :     if (nullptr == pszJson)
     844             :     {
     845             :         // Translation failed.
     846           0 :         return nullptr;
     847             :     }
     848             : 
     849          46 :     json_object *poObj = nullptr;
     850          46 :     if (!OGRJSonParse(pszJson, &poObj))
     851           0 :         return nullptr;
     852             : 
     853          46 :     OGRGeometry *poGeometry = OGRGeoJSONReadGeometry(poObj);
     854             : 
     855             :     // Release JSON tree.
     856          46 :     json_object_put(poObj);
     857             : 
     858          46 :     return OGRGeometry::ToHandle(poGeometry);
     859             : }
     860             : 
     861             : /*! @endcond */

Generated by: LCOV version 1.14