LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gml - gmlutils.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 114 152 75.0 %
Date: 2024-05-07 17:03:27 Functions: 11 11 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "gmlutils.h"
      31             : 
      32             : #include <cstdio>
      33             : #include <cstdlib>
      34             : #include <cstring>
      35             : #include <map>
      36             : #include <string>
      37             : #include <utility>
      38             : 
      39             : #include "cpl_conv.h"
      40             : #include "cpl_string.h"
      41             : #include "ogr_api.h"
      42             : #include "ogr_core.h"
      43             : #include "ogr_p.h"
      44             : #include "ogr_spatialref.h"
      45             : 
      46             : /************************************************************************/
      47             : /*                GML_ExtractSrsNameFromGeometry()                      */
      48             : /************************************************************************/
      49             : 
      50             : const char *
      51        1567 : GML_ExtractSrsNameFromGeometry(const CPLXMLNode *const *papsGeometry,
      52             :                                std::string &osWork, bool bConsiderEPSGAsURN)
      53             : {
      54        1567 :     if (papsGeometry[0] != nullptr && papsGeometry[1] == nullptr)
      55             :     {
      56             :         const char *pszSRSName =
      57        1567 :             CPLGetXMLValue(papsGeometry[0], "srsName", nullptr);
      58        1567 :         if (pszSRSName)
      59             :         {
      60         526 :             const int nLen = static_cast<int>(strlen(pszSRSName));
      61             : 
      62         526 :             if (STARTS_WITH(pszSRSName, "EPSG:") && bConsiderEPSGAsURN)
      63             :             {
      64          36 :                 osWork.reserve(22 + nLen - 5);
      65          36 :                 osWork.assign("urn:ogc:def:crs:EPSG::", 22);
      66          36 :                 osWork.append(pszSRSName + 5, nLen - 5);
      67          36 :                 return osWork.c_str();
      68             :             }
      69         490 :             else if (STARTS_WITH(pszSRSName,
      70             :                                  "http://www.opengis.net/gml/srs/epsg.xml#"))
      71             :             {
      72          47 :                 osWork.reserve(5 + nLen - 40);
      73          47 :                 osWork.assign("EPSG:", 5);
      74          47 :                 osWork.append(pszSRSName + 40, nLen - 40);
      75          47 :                 return osWork.c_str();
      76             :             }
      77             :             else
      78             :             {
      79         443 :                 return pszSRSName;
      80             :             }
      81             :         }
      82             :     }
      83        1041 :     return nullptr;
      84             : }
      85             : 
      86             : /************************************************************************/
      87             : /*                       GML_IsSRSLatLongOrder()                        */
      88             : /************************************************************************/
      89             : 
      90         443 : bool GML_IsSRSLatLongOrder(const char *pszSRSName)
      91             : {
      92         443 :     if (pszSRSName == nullptr)
      93           0 :         return false;
      94             : 
      95         443 :     if (STARTS_WITH(pszSRSName, "urn:") &&
      96         383 :         strstr(pszSRSName, ":4326") != nullptr)
      97             :     {
      98             :         // Shortcut.
      99         327 :         return true;
     100             :     }
     101             :     /* fguuid:jgd20??.bl (Japanese FGD GML v4) */
     102         116 :     else if (EQUALN(pszSRSName, "fguuid:jgd2011.bl", 17) ||
     103         114 :              EQUALN(pszSRSName, "fguuid:jgd2001.bl", 17))
     104             :     {
     105           2 :         return true;
     106             :     }
     107         114 :     else if (!EQUALN(pszSRSName, "EPSG:", 5))
     108             :     {
     109          73 :         OGRSpatialReference oSRS;
     110          73 :         if (oSRS.SetFromUserInput(
     111             :                 pszSRSName,
     112          73 :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) ==
     113             :             OGRERR_NONE)
     114             :         {
     115         133 :             if (oSRS.EPSGTreatsAsLatLong() ||
     116          60 :                 oSRS.EPSGTreatsAsNorthingEasting())
     117          15 :                 return true;
     118             :         }
     119             :     }
     120          99 :     return false;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                GML_BuildOGRGeometryFromList_CreateCache()            */
     125             : /************************************************************************/
     126             : 
     127             : class SRSDesc
     128             : {
     129             :   public:
     130             :     std::string osSRSName;
     131             :     bool bAxisInvert;
     132             :     OGRSpatialReference *poSRS;
     133             : 
     134         940 :     SRSDesc() : bAxisInvert(false), poSRS(nullptr)
     135             :     {
     136         940 :     }
     137             : };
     138             : 
     139             : class SRSCache
     140             : {
     141             :     std::map<std::string, SRSDesc> oMap;
     142             :     SRSDesc oLastDesc;
     143             : 
     144             :   public:
     145         730 :     SRSCache()
     146         730 :     {
     147         730 :     }
     148             : 
     149         730 :     ~SRSCache()
     150         730 :     {
     151         730 :         std::map<std::string, SRSDesc>::iterator oIter;
     152         940 :         for (oIter = oMap.begin(); oIter != oMap.end(); ++oIter)
     153             :         {
     154         210 :             if (oIter->second.poSRS != nullptr)
     155         208 :                 oIter->second.poSRS->Release();
     156             :         }
     157         730 :     }
     158             : 
     159         409 :     SRSDesc &Get(const std::string &osSRSName)
     160             :     {
     161         409 :         if (osSRSName == oLastDesc.osSRSName)
     162         199 :             return oLastDesc;
     163             : 
     164         210 :         std::map<std::string, SRSDesc>::iterator oIter = oMap.find(osSRSName);
     165         210 :         if (oIter != oMap.end())
     166             :         {
     167           0 :             oLastDesc = oIter->second;
     168           0 :             return oLastDesc;
     169             :         }
     170             : 
     171         210 :         oLastDesc.osSRSName = osSRSName;
     172         210 :         oLastDesc.bAxisInvert = GML_IsSRSLatLongOrder(osSRSName.c_str());
     173         210 :         oLastDesc.poSRS = new OGRSpatialReference();
     174         210 :         oLastDesc.poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     175         210 :         if (oLastDesc.poSRS->SetFromUserInput(
     176             :                 osSRSName.c_str(),
     177         210 :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
     178             :             OGRERR_NONE)
     179             :         {
     180           2 :             delete oLastDesc.poSRS;
     181           2 :             oLastDesc.poSRS = nullptr;
     182             :         }
     183         210 :         oMap[osSRSName] = oLastDesc;
     184         210 :         return oLastDesc;
     185             :     }
     186             : };
     187             : 
     188         730 : void *GML_BuildOGRGeometryFromList_CreateCache()
     189             : {
     190         730 :     return new SRSCache();
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                 GML_BuildOGRGeometryFromList_DestroyCache()          */
     195             : /************************************************************************/
     196             : 
     197         730 : void GML_BuildOGRGeometryFromList_DestroyCache(void *hCacheSRS)
     198             : {
     199         730 :     delete static_cast<SRSCache *>(hCacheSRS);
     200         730 : }
     201             : 
     202             : /************************************************************************/
     203             : /*                 GML_BuildOGRGeometryFromList()                       */
     204             : /************************************************************************/
     205             : 
     206        1112 : OGRGeometry *GML_BuildOGRGeometryFromList(
     207             :     const CPLXMLNode *const *papsGeometry, bool bTryToMakeMultipolygons,
     208             :     bool bInvertAxisOrderIfLatLong, const char *pszDefaultSRSName,
     209             :     bool bConsiderEPSGAsURN, GMLSwapCoordinatesEnum eSwapCoordinates,
     210             :     int nPseudoBoolGetSecondaryGeometryOption, void *hCacheSRS,
     211             :     bool bFaceHoleNegative)
     212             : {
     213        1112 :     OGRGeometry *poGeom = nullptr;
     214        1112 :     OGRGeometryCollection *poCollection = nullptr;
     215        2224 :     for (int i = 0; papsGeometry[i] != nullptr; i++)
     216             :     {
     217        2224 :         OGRGeometry *poSubGeom = GML2OGRGeometry_XMLNode(
     218        1112 :             papsGeometry[i], nPseudoBoolGetSecondaryGeometryOption, 0, 0, false,
     219             :             true, bFaceHoleNegative);
     220        1112 :         if (poSubGeom)
     221             :         {
     222        1111 :             if (poGeom == nullptr)
     223             :             {
     224        1111 :                 poGeom = poSubGeom;
     225             :             }
     226             :             else
     227             :             {
     228           0 :                 if (poCollection == nullptr)
     229             :                 {
     230           0 :                     if (bTryToMakeMultipolygons &&
     231           0 :                         wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
     232           0 :                         wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon)
     233             :                     {
     234             :                         OGRGeometryCollection *poGeomColl =
     235           0 :                             new OGRMultiPolygon();
     236           0 :                         poGeomColl->addGeometryDirectly(poGeom);
     237           0 :                         poGeomColl->addGeometryDirectly(poSubGeom);
     238           0 :                         poGeom = poGeomColl;
     239             :                     }
     240           0 :                     else if (bTryToMakeMultipolygons &&
     241           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     242           0 :                                  wkbMultiPolygon &&
     243           0 :                              wkbFlatten(poSubGeom->getGeometryType()) ==
     244             :                                  wkbPolygon)
     245             :                     {
     246           0 :                         OGRMultiPolygon *poGeomColl = poGeom->toMultiPolygon();
     247           0 :                         poGeomColl->addGeometryDirectly(poSubGeom);
     248             :                     }
     249           0 :                     else if (bTryToMakeMultipolygons &&
     250           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     251           0 :                                  wkbMultiPolygon &&
     252           0 :                              wkbFlatten(poSubGeom->getGeometryType()) ==
     253             :                                  wkbMultiPolygon)
     254             :                     {
     255           0 :                         OGRMultiPolygon *poGeomColl = poGeom->toMultiPolygon();
     256           0 :                         for (auto &&poMember : poSubGeom->toMultiPolygon())
     257             :                         {
     258           0 :                             poGeomColl->addGeometry(poMember);
     259             :                         }
     260           0 :                         delete poSubGeom;
     261             :                     }
     262           0 :                     else if (bTryToMakeMultipolygons &&
     263           0 :                              wkbFlatten(poGeom->getGeometryType()) ==
     264             :                                  wkbMultiPolygon)
     265             :                     {
     266           0 :                         delete poGeom;
     267           0 :                         delete poSubGeom;
     268           0 :                         return GML_BuildOGRGeometryFromList(
     269             :                             papsGeometry, false, bInvertAxisOrderIfLatLong,
     270             :                             pszDefaultSRSName, bConsiderEPSGAsURN,
     271             :                             eSwapCoordinates,
     272           0 :                             nPseudoBoolGetSecondaryGeometryOption, hCacheSRS);
     273             :                     }
     274             :                     else
     275             :                     {
     276           0 :                         poCollection = new OGRGeometryCollection();
     277           0 :                         poCollection->addGeometryDirectly(poGeom);
     278           0 :                         poGeom = poCollection;
     279             :                     }
     280             :                 }
     281           0 :                 if (poCollection != nullptr)
     282             :                 {
     283           0 :                     poCollection->addGeometryDirectly(poSubGeom);
     284             :                 }
     285             :             }
     286             :         }
     287             :     }
     288             : 
     289        1112 :     if (poGeom == nullptr)
     290           1 :         return nullptr;
     291             : 
     292        1111 :     std::string osWork;
     293        1111 :     const char *pszSRSName = GML_ExtractSrsNameFromGeometry(
     294             :         papsGeometry, osWork, bConsiderEPSGAsURN);
     295        1111 :     const char *pszNameLookup = pszSRSName;
     296        1111 :     if (pszNameLookup == nullptr)
     297         723 :         pszNameLookup = pszDefaultSRSName;
     298             : 
     299        1111 :     if (pszNameLookup != nullptr)
     300             :     {
     301         409 :         SRSCache *poSRSCache = static_cast<SRSCache *>(hCacheSRS);
     302         409 :         const SRSDesc &oSRSDesc = poSRSCache->Get(pszNameLookup);
     303         409 :         poGeom->assignSpatialReference(oSRSDesc.poSRS);
     304         409 :         if ((eSwapCoordinates == GML_SWAP_AUTO && oSRSDesc.bAxisInvert &&
     305         151 :              bInvertAxisOrderIfLatLong) ||
     306             :             eSwapCoordinates == GML_SWAP_YES)
     307             :         {
     308         260 :             poGeom->swapXY();
     309             :         }
     310             :     }
     311             : 
     312        1111 :     return poGeom;
     313             : }
     314             : 
     315             : /************************************************************************/
     316             : /*                           GML_GetSRSName()                           */
     317             : /************************************************************************/
     318             : 
     319         201 : char *GML_GetSRSName(const OGRSpatialReference *poSRS,
     320             :                      OGRGMLSRSNameFormat eSRSNameFormat, bool *pbCoordSwap)
     321             : {
     322         201 :     *pbCoordSwap = false;
     323         201 :     if (poSRS == nullptr)
     324         110 :         return CPLStrdup("");
     325             : 
     326          91 :     const auto &map = poSRS->GetDataAxisToSRSAxisMapping();
     327         121 :     if (eSRSNameFormat != SRSNAME_SHORT && map.size() >= 2 && map[0] == 2 &&
     328          30 :         map[1] == 1)
     329             :     {
     330          30 :         *pbCoordSwap = true;
     331             :     }
     332             : 
     333          91 :     const char *pszAuthName = poSRS->GetAuthorityName(nullptr);
     334          91 :     const char *pszAuthCode = poSRS->GetAuthorityCode(nullptr);
     335          91 :     if (nullptr != pszAuthName && nullptr != pszAuthCode)
     336             :     {
     337          91 :         if (eSRSNameFormat == SRSNAME_SHORT)
     338             :         {
     339           9 :             return CPLStrdup(
     340           9 :                 CPLSPrintf(" srsName=\"%s:%s\"", pszAuthName, pszAuthCode));
     341             :         }
     342          82 :         else if (eSRSNameFormat == SRSNAME_OGC_URN)
     343             :         {
     344          61 :             return CPLStrdup(CPLSPrintf(" srsName=\"urn:ogc:def:crs:%s::%s\"",
     345          61 :                                         pszAuthName, pszAuthCode));
     346             :         }
     347          21 :         else if (eSRSNameFormat == SRSNAME_OGC_URL)
     348             :         {
     349          21 :             return CPLStrdup(CPLSPrintf(
     350             :                 " srsName=\"http://www.opengis.net/def/crs/%s/0/%s\"",
     351          21 :                 pszAuthName, pszAuthCode));
     352             :         }
     353             :     }
     354           0 :     return CPLStrdup("");
     355             : }
     356             : 
     357             : /************************************************************************/
     358             : /*                       GML_IsLegitSRSName()                           */
     359             : /************************************************************************/
     360             : 
     361          80 : bool GML_IsLegitSRSName(const char *pszSRSName)
     362             : {
     363             : 
     364          80 :     if (STARTS_WITH_CI(pszSRSName, "http"))
     365             :     {
     366           6 :         if (!(STARTS_WITH_CI(pszSRSName, "http://opengis.net/def/crs") ||
     367           6 :               STARTS_WITH_CI(pszSRSName, "http://www.opengis.net/def/crs")))
     368             :         {
     369           0 :             return false;
     370             :         }
     371             :     }
     372          80 :     return true;
     373             : }

Generated by: LCOV version 1.14