LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlutils - gmlutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 118 157 75.2 %
Date: 2024-11-21 22:18:42 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GML Utils
       4             :  * Purpose:  GML reader
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "gmlutils.h"
      15             : 
      16             : #include <cstdio>
      17             : #include <cstdlib>
      18             : #include <cstring>
      19             : #include <map>
      20             : #include <string>
      21             : #include <utility>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_string.h"
      25             : #include "ogr_api.h"
      26             : #include "ogr_core.h"
      27             : #include "ogr_p.h"
      28             : #include "ogr_spatialref.h"
      29             : 
      30             : /************************************************************************/
      31             : /*                GML_ExtractSrsNameFromGeometry()                      */
      32             : /************************************************************************/
      33             : 
      34             : const char *
      35        1579 : GML_ExtractSrsNameFromGeometry(const CPLXMLNode *const *papsGeometry,
      36             :                                std::string &osWork, bool bConsiderEPSGAsURN)
      37             : {
      38        1579 :     if (papsGeometry[0] != nullptr && papsGeometry[1] == nullptr)
      39             :     {
      40             :         const char *pszSRSName =
      41        1579 :             CPLGetXMLValue(papsGeometry[0], "srsName", nullptr);
      42        1579 :         if (pszSRSName)
      43             :         {
      44         531 :             const int nLen = static_cast<int>(strlen(pszSRSName));
      45             : 
      46         531 :             if (STARTS_WITH(pszSRSName, "EPSG:") && bConsiderEPSGAsURN)
      47             :             {
      48          36 :                 osWork.reserve(22 + nLen - 5);
      49          36 :                 osWork.assign("urn:ogc:def:crs:EPSG::", 22);
      50          36 :                 osWork.append(pszSRSName + 5, nLen - 5);
      51          36 :                 return osWork.c_str();
      52             :             }
      53         495 :             else if (STARTS_WITH(pszSRSName,
      54             :                                  "http://www.opengis.net/gml/srs/epsg.xml#"))
      55             :             {
      56          47 :                 osWork.reserve(5 + nLen - 40);
      57          47 :                 osWork.assign("EPSG:", 5);
      58          47 :                 osWork.append(pszSRSName + 40, nLen - 40);
      59          47 :                 return osWork.c_str();
      60             :             }
      61             :             else
      62             :             {
      63         448 :                 return pszSRSName;
      64             :             }
      65             :         }
      66             :     }
      67        1048 :     return nullptr;
      68             : }
      69             : 
      70             : /************************************************************************/
      71             : /*                       GML_IsSRSLatLongOrder()                        */
      72             : /************************************************************************/
      73             : 
      74         456 : bool GML_IsSRSLatLongOrder(const char *pszSRSName)
      75             : {
      76         456 :     if (pszSRSName == nullptr)
      77           0 :         return false;
      78             : 
      79         456 :     if (STARTS_WITH(pszSRSName, "urn:") &&
      80         385 :         strstr(pszSRSName, ":4326") != nullptr)
      81             :     {
      82             :         // Shortcut.
      83         327 :         return true;
      84             :     }
      85             :     /* fguuid:jgd20??.bl (Japanese FGD GML v4) */
      86         129 :     else if (EQUALN(pszSRSName, "fguuid:jgd2011.bl", 17) ||
      87         127 :              EQUALN(pszSRSName, "fguuid:jgd2001.bl", 17))
      88             :     {
      89           2 :         return true;
      90             :     }
      91         127 :     else if (!EQUALN(pszSRSName, "EPSG:", 5))
      92             :     {
      93          75 :         OGRSpatialReference oSRS;
      94          75 :         if (oSRS.SetFromUserInput(
      95             :                 pszSRSName,
      96          75 :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) ==
      97             :             OGRERR_NONE)
      98             :         {
      99         137 :             if (oSRS.EPSGTreatsAsLatLong() ||
     100          62 :                 oSRS.EPSGTreatsAsNorthingEasting())
     101          15 :                 return true;
     102             :         }
     103             :     }
     104         112 :     return false;
     105             : }
     106             : 
     107             : /************************************************************************/
     108             : /*                GML_BuildOGRGeometryFromList_CreateCache()            */
     109             : /************************************************************************/
     110             : 
     111             : namespace
     112             : {
     113             : class SRSDesc
     114             : {
     115             :   public:
     116             :     std::string osSRSName{};
     117             :     bool bAxisInvert = false;
     118             :     OGRSpatialReference *poSRS = nullptr;
     119             : 
     120         430 :     SRSDesc() = default;
     121             : 
     122         215 :     SRSDesc &operator=(SRSDesc &&other)
     123             :     {
     124         215 :         osSRSName = std::move(other.osSRSName);
     125         215 :         bAxisInvert = other.bAxisInvert;
     126         215 :         if (poSRS)
     127           0 :             poSRS->Release();
     128         215 :         poSRS = other.poSRS;
     129         215 :         other.poSRS = nullptr;
     130         215 :         return *this;
     131             :     }
     132             : 
     133         430 :     ~SRSDesc()
     134         430 :     {
     135         430 :         if (poSRS)
     136         213 :             poSRS->Release();
     137         430 :     }
     138             : 
     139             :     CPL_DISALLOW_COPY_ASSIGN(SRSDesc)
     140             : };
     141             : 
     142             : class SRSCache
     143             : {
     144             :     std::map<std::string, SRSDesc> oMap{};
     145             :     SRSDesc *poLastDesc = nullptr;
     146             : 
     147             :     CPL_DISALLOW_COPY_ASSIGN(SRSCache)
     148             : 
     149             :   public:
     150         758 :     SRSCache() = default;
     151             : 
     152         414 :     const SRSDesc &Get(const std::string &osSRSName)
     153             :     {
     154         414 :         if (poLastDesc && osSRSName == poLastDesc->osSRSName)
     155         199 :             return *poLastDesc;
     156             : 
     157         215 :         std::map<std::string, SRSDesc>::iterator oIter = oMap.find(osSRSName);
     158         215 :         if (oIter != oMap.end())
     159             :         {
     160           0 :             poLastDesc = &(oIter->second);
     161           0 :             return *poLastDesc;
     162             :         }
     163             : 
     164         215 :         SRSDesc oDesc;
     165         215 :         oDesc.osSRSName = osSRSName;
     166         215 :         oDesc.bAxisInvert = GML_IsSRSLatLongOrder(osSRSName.c_str());
     167         215 :         oDesc.poSRS = new OGRSpatialReference();
     168         215 :         oDesc.poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     169         215 :         if (oDesc.poSRS->SetFromUserInput(
     170             :                 osSRSName.c_str(),
     171         215 :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
     172             :             OGRERR_NONE)
     173             :         {
     174           2 :             delete oDesc.poSRS;
     175           2 :             oDesc.poSRS = nullptr;
     176             :         }
     177         215 :         oMap[osSRSName] = std::move(oDesc);
     178         215 :         poLastDesc = &(oMap[osSRSName]);
     179         215 :         return *poLastDesc;
     180             :     }
     181             : };
     182             : 
     183             : }  // namespace
     184             : 
     185         758 : void *GML_BuildOGRGeometryFromList_CreateCache()
     186             : {
     187         758 :     return new SRSCache();
     188             : }
     189             : 
     190             : /************************************************************************/
     191             : /*                 GML_BuildOGRGeometryFromList_DestroyCache()          */
     192             : /************************************************************************/
     193             : 
     194         758 : void GML_BuildOGRGeometryFromList_DestroyCache(void *hCacheSRS)
     195             : {
     196         758 :     delete static_cast<SRSCache *>(hCacheSRS);
     197         758 : }
     198             : 
     199             : /************************************************************************/
     200             : /*                 GML_BuildOGRGeometryFromList()                       */
     201             : /************************************************************************/
     202             : 
     203        1122 : OGRGeometry *GML_BuildOGRGeometryFromList(
     204             :     const CPLXMLNode *const *papsGeometry, bool bTryToMakeMultipolygons,
     205             :     bool bInvertAxisOrderIfLatLong, const char *pszDefaultSRSName,
     206             :     bool bConsiderEPSGAsURN, GMLSwapCoordinatesEnum eSwapCoordinates,
     207             :     int nPseudoBoolGetSecondaryGeometryOption, void *hCacheSRS,
     208             :     bool bFaceHoleNegative)
     209             : {
     210        1122 :     OGRGeometry *poGeom = nullptr;
     211        1122 :     OGRGeometryCollection *poCollection = nullptr;
     212        2244 :     for (int i = 0; papsGeometry[i] != nullptr; i++)
     213             :     {
     214        2244 :         OGRGeometry *poSubGeom = GML2OGRGeometry_XMLNode(
     215        1122 :             papsGeometry[i], nPseudoBoolGetSecondaryGeometryOption, 0, 0, false,
     216             :             true, bFaceHoleNegative);
     217        1122 :         if (poSubGeom)
     218             :         {
     219        1120 :             if (poGeom == nullptr)
     220             :             {
     221        1120 :                 poGeom = poSubGeom;
     222             :             }
     223             :             else
     224             :             {
     225           0 :                 if (poCollection == nullptr)
     226             :                 {
     227           0 :                     if (bTryToMakeMultipolygons &&
     228           0 :                         wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
     229           0 :                         wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
     230             :                     {
     231             :                         OGRGeometryCollection *poGeomColl =
     232           0 :                             new OGRMultiPolygon();
     233           0 :                         poGeomColl->addGeometryDirectly(poGeom);
     234           0 :                         poGeomColl->addGeometryDirectly(poSubGeom);
     235           0 :                         poGeom = poGeomColl;
     236             :                     }
     237           0 :                     else if (bTryToMakeMultipolygons &&
     238           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     239           0 :                                  wkbMultiPolygon &&
     240           0 :                              wkbFlatten(poSubGeom->getGeometryType()) ==
     241             :                                  wkbPolygon)
     242             :                     {
     243           0 :                         OGRMultiPolygon *poGeomColl = poGeom->toMultiPolygon();
     244           0 :                         poGeomColl->addGeometryDirectly(poSubGeom);
     245             :                     }
     246           0 :                     else if (bTryToMakeMultipolygons &&
     247           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     248           0 :                                  wkbMultiPolygon &&
     249           0 :                              wkbFlatten(poSubGeom->getGeometryType()) ==
     250             :                                  wkbMultiPolygon)
     251             :                     {
     252           0 :                         OGRMultiPolygon *poGeomColl = poGeom->toMultiPolygon();
     253           0 :                         for (auto &&poMember : poSubGeom->toMultiPolygon())
     254             :                         {
     255           0 :                             poGeomColl->addGeometry(poMember);
     256             :                         }
     257           0 :                         delete poSubGeom;
     258             :                     }
     259           0 :                     else if (bTryToMakeMultipolygons &&
     260           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     261             :                                  wkbMultiPolygon)
     262             :                     {
     263           0 :                         delete poGeom;
     264           0 :                         delete poSubGeom;
     265           0 :                         return GML_BuildOGRGeometryFromList(
     266             :                             papsGeometry, false, bInvertAxisOrderIfLatLong,
     267             :                             pszDefaultSRSName, bConsiderEPSGAsURN,
     268             :                             eSwapCoordinates,
     269           0 :                             nPseudoBoolGetSecondaryGeometryOption, hCacheSRS);
     270             :                     }
     271             :                     else
     272             :                     {
     273           0 :                         poCollection = new OGRGeometryCollection();
     274           0 :                         poCollection->addGeometryDirectly(poGeom);
     275           0 :                         poGeom = poCollection;
     276             :                     }
     277             :                 }
     278           0 :                 if (poCollection != nullptr)
     279             :                 {
     280           0 :                     poCollection->addGeometryDirectly(poSubGeom);
     281             :                 }
     282             :             }
     283             :         }
     284             :     }
     285             : 
     286        1122 :     if (poGeom == nullptr)
     287           2 :         return nullptr;
     288             : 
     289        1120 :     std::string osWork;
     290        1120 :     const char *pszSRSName = GML_ExtractSrsNameFromGeometry(
     291             :         papsGeometry, osWork, bConsiderEPSGAsURN);
     292        1120 :     const char *pszNameLookup = pszSRSName;
     293        1120 :     if (pszNameLookup == nullptr)
     294         727 :         pszNameLookup = pszDefaultSRSName;
     295             : 
     296        1120 :     if (pszNameLookup != nullptr)
     297             :     {
     298         414 :         SRSCache *poSRSCache = static_cast<SRSCache *>(hCacheSRS);
     299         414 :         const SRSDesc &oSRSDesc = poSRSCache->Get(pszNameLookup);
     300         414 :         poGeom->assignSpatialReference(oSRSDesc.poSRS);
     301         414 :         if ((eSwapCoordinates == GML_SWAP_AUTO && oSRSDesc.bAxisInvert &&
     302         156 :              bInvertAxisOrderIfLatLong) ||
     303             :             eSwapCoordinates == GML_SWAP_YES)
     304             :         {
     305         260 :             poGeom->swapXY();
     306             :         }
     307             :     }
     308             : 
     309        1120 :     return poGeom;
     310             : }
     311             : 
     312             : /************************************************************************/
     313             : /*                           GML_GetSRSName()                           */
     314             : /************************************************************************/
     315             : 
     316         220 : char *GML_GetSRSName(const OGRSpatialReference *poSRS,
     317             :                      OGRGMLSRSNameFormat eSRSNameFormat, bool *pbCoordSwap)
     318             : {
     319         220 :     *pbCoordSwap = false;
     320         220 :     if (poSRS == nullptr)
     321         116 :         return CPLStrdup("");
     322             : 
     323         104 :     const auto &map = poSRS->GetDataAxisToSRSAxisMapping();
     324         146 :     if (eSRSNameFormat != SRSNAME_SHORT && map.size() >= 2 && map[0] == 2 &&
     325          42 :         map[1] == 1)
     326             :     {
     327          42 :         *pbCoordSwap = true;
     328             :     }
     329             : 
     330         104 :     const char *pszAuthName = poSRS->GetAuthorityName(nullptr);
     331         104 :     const char *pszAuthCode = poSRS->GetAuthorityCode(nullptr);
     332         104 :     if (nullptr != pszAuthName && nullptr != pszAuthCode)
     333             :     {
     334         104 :         if (eSRSNameFormat == SRSNAME_SHORT)
     335             :         {
     336           9 :             return CPLStrdup(
     337           9 :                 CPLSPrintf(" srsName=\"%s:%s\"", pszAuthName, pszAuthCode));
     338             :         }
     339          95 :         else if (eSRSNameFormat == SRSNAME_OGC_URN)
     340             :         {
     341          74 :             return CPLStrdup(CPLSPrintf(" srsName=\"urn:ogc:def:crs:%s::%s\"",
     342          74 :                                         pszAuthName, pszAuthCode));
     343             :         }
     344          21 :         else if (eSRSNameFormat == SRSNAME_OGC_URL)
     345             :         {
     346          21 :             return CPLStrdup(CPLSPrintf(
     347             :                 " srsName=\"http://www.opengis.net/def/crs/%s/0/%s\"",
     348          21 :                 pszAuthName, pszAuthCode));
     349             :         }
     350             :     }
     351           0 :     return CPLStrdup("");
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                       GML_IsLegitSRSName()                           */
     356             : /************************************************************************/
     357             : 
     358          85 : bool GML_IsLegitSRSName(const char *pszSRSName)
     359             : {
     360             : 
     361          85 :     if (STARTS_WITH_CI(pszSRSName, "http"))
     362             :     {
     363           6 :         if (!(STARTS_WITH_CI(pszSRSName, "http://opengis.net/def/crs") ||
     364           6 :               STARTS_WITH_CI(pszSRSName, "http://www.opengis.net/def/crs")))
     365             :         {
     366           0 :             return false;
     367             :         }
     368             :     }
     369          85 :     return true;
     370             : }

Generated by: LCOV version 1.14