LCOV - code coverage report
Current view: top level - ogr - ogr_fromepsg.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 84 108 77.8 %
Date: 2024-05-04 12:52:34 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Generate an OGRSpatialReference object based on an EPSG
       5             :  *           PROJCS, or GEOGCS code.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2000, Frank Warmerdam
      10             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_port.h"
      32             : #include "ogr_srs_api.h"
      33             : 
      34             : #include <cctype>
      35             : 
      36             : #include <cmath>
      37             : #include <cstddef>
      38             : #include <cstdio>
      39             : #include <cstring>
      40             : #include <cstdlib>
      41             : #include <map>
      42             : #include <memory>
      43             : #include <string>
      44             : #include <vector>
      45             : #include <limits>
      46             : 
      47             : #include "cpl_conv.h"
      48             : #include "cpl_csv.h"
      49             : #include "cpl_error.h"
      50             : #include "cpl_multiproc.h"
      51             : #include "cpl_string.h"
      52             : #include "ogr_core.h"
      53             : #include "ogr_p.h"
      54             : #include "ogr_proj_p.h"
      55             : #include "ogr_spatialref.h"
      56             : 
      57             : #include "proj.h"
      58             : 
      59             : extern void OGRsnPrintDouble(char *pszStrBuf, size_t size, double dfValue);
      60             : 
      61             : /************************************************************************/
      62             : /*                         OSRGetEllipsoidInfo()                        */
      63             : /************************************************************************/
      64             : 
      65             : /**
      66             :  * Fetch info about an ellipsoid.
      67             :  *
      68             :  * This helper function will return ellipsoid parameters corresponding to EPSG
      69             :  * code provided. Axes are always returned in meters.  Semi major computed
      70             :  * based on inverse flattening where that is provided.
      71             :  *
      72             :  * @param nCode EPSG code of the requested ellipsoid
      73             :  *
      74             :  * @param ppszName pointer to string where ellipsoid name will be returned. It
      75             :  * is caller responsibility to free this string after using with CPLFree().
      76             :  *
      77             :  * @param pdfSemiMajor pointer to variable where semi major axis will be
      78             :  * returned.
      79             :  *
      80             :  * @param pdfInvFlattening pointer to variable where inverse flattening will
      81             :  * be returned.
      82             :  *
      83             :  * @return OGRERR_NONE on success or an error code in case of failure.
      84             :  **/
      85             : 
      86         245 : OGRErr OSRGetEllipsoidInfo(int nCode, char **ppszName, double *pdfSemiMajor,
      87             :                            double *pdfInvFlattening)
      88             : 
      89             : {
      90         490 :     CPLString osCode;
      91         245 :     osCode.Printf("%d", nCode);
      92         245 :     auto ellipsoid = proj_create_from_database(
      93             :         OSRGetProjTLSContext(), "EPSG", osCode.c_str(), PJ_CATEGORY_ELLIPSOID,
      94             :         false, nullptr);
      95         245 :     if (!ellipsoid)
      96             :     {
      97           0 :         return OGRERR_UNSUPPORTED_SRS;
      98             :     }
      99             : 
     100         245 :     if (ppszName)
     101             :     {
     102          62 :         *ppszName = CPLStrdup(proj_get_name(ellipsoid));
     103             :     }
     104         245 :     proj_ellipsoid_get_parameters(OSRGetProjTLSContext(), ellipsoid,
     105             :                                   pdfSemiMajor, nullptr, nullptr,
     106             :                                   pdfInvFlattening);
     107         245 :     proj_destroy(ellipsoid);
     108             : 
     109         245 :     return OGRERR_NONE;
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                           SetStatePlane()                            */
     114             : /************************************************************************/
     115             : 
     116             : /**
     117             :  * \brief Set State Plane projection definition.
     118             :  *
     119             :  * This will attempt to generate a complete definition of a state plane
     120             :  * zone based on generating the entire SRS from the EPSG tables.  If the
     121             :  * EPSG tables are unavailable, it will produce a stubbed LOCAL_CS definition
     122             :  * and return OGRERR_FAILURE.
     123             :  *
     124             :  * This method is the same as the C function OSRSetStatePlaneWithUnits().
     125             :  *
     126             :  * @param nZone State plane zone number, in the USGS numbering scheme (as
     127             :  * distinct from the Arc/Info and Erdas numbering scheme.
     128             :  *
     129             :  * @param bNAD83 TRUE if the NAD83 zone definition should be used or FALSE
     130             :  * if the NAD27 zone definition should be used.
     131             :  *
     132             :  * @param pszOverrideUnitName Linear unit name to apply overriding the
     133             :  * legal definition for this zone.
     134             :  *
     135             :  * @param dfOverrideUnit Linear unit conversion factor to apply overriding
     136             :  * the legal definition for this zone.
     137             :  *
     138             :  * @return OGRERR_NONE on success, or OGRERR_FAILURE on failure, mostly likely
     139             :  * due to the EPSG tables not being accessible.
     140             :  */
     141             : 
     142          10 : OGRErr OGRSpatialReference::SetStatePlane(int nZone, int bNAD83,
     143             :                                           const char *pszOverrideUnitName,
     144             :                                           double dfOverrideUnit)
     145             : 
     146             : {
     147             : 
     148             :     /* -------------------------------------------------------------------- */
     149             :     /*      Get the index id from stateplane.csv.                           */
     150             :     /* -------------------------------------------------------------------- */
     151             : 
     152          10 :     if (!bNAD83 && nZone > INT_MAX - 10000)
     153           0 :         return OGRERR_FAILURE;
     154             : 
     155          10 :     const int nAdjustedId = bNAD83 ? nZone : nZone + 10000;
     156             : 
     157             :     /* -------------------------------------------------------------------- */
     158             :     /*      Turn this into a PCS code.  We assume there will only be one    */
     159             :     /*      PCS corresponding to each Proj_ code since the proj code        */
     160             :     /*      already effectively indicates NAD27 or NAD83.                   */
     161             :     /* -------------------------------------------------------------------- */
     162          10 :     char szID[32] = {};
     163          10 :     snprintf(szID, sizeof(szID), "%d", nAdjustedId);
     164          10 :     const int nPCSCode = atoi(CSVGetField(CSVFilename("stateplane.csv"), "ID",
     165             :                                           szID, CC_Integer, "EPSG_PCS_CODE"));
     166          10 :     if (nPCSCode < 1)
     167             :     {
     168             :         static bool bFailureReported = false;
     169             : 
     170           0 :         if (!bFailureReported)
     171             :         {
     172           0 :             bFailureReported = true;
     173           0 :             CPLError(CE_Warning, CPLE_OpenFailed,
     174             :                      "Unable to find state plane zone in stateplane.csv, "
     175             :                      "likely because the GDAL data files cannot be found.  "
     176             :                      "Using incomplete definition of state plane zone.");
     177             :         }
     178             : 
     179           0 :         Clear();
     180           0 :         if (bNAD83)
     181             :         {
     182           0 :             char szName[128] = {};
     183           0 :             snprintf(szName, sizeof(szName), "State Plane Zone %d / NAD83",
     184             :                      nZone);
     185           0 :             SetLocalCS(szName);
     186           0 :             SetLinearUnits(SRS_UL_METER, 1.0);
     187             :         }
     188             :         else
     189             :         {
     190           0 :             char szName[128] = {};
     191           0 :             snprintf(szName, sizeof(szName), "State Plane Zone %d / NAD27",
     192             :                      nZone);
     193           0 :             SetLocalCS(szName);
     194           0 :             SetLinearUnits(SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV));
     195             :         }
     196             : 
     197           0 :         return OGRERR_FAILURE;
     198             :     }
     199             : 
     200             :     /* -------------------------------------------------------------------- */
     201             :     /*      Define based on a full EPSG definition of the zone.             */
     202             :     /* -------------------------------------------------------------------- */
     203          10 :     OGRErr eErr = importFromEPSG(nPCSCode);
     204             : 
     205          10 :     if (eErr != OGRERR_NONE)
     206           0 :         return eErr;
     207             : 
     208             :     /* -------------------------------------------------------------------- */
     209             :     /*      Apply units override if required.                               */
     210             :     /*                                                                      */
     211             :     /*      We will need to adjust the linear projection parameter to       */
     212             :     /*      match the provided units, and clear the authority code.         */
     213             :     /* -------------------------------------------------------------------- */
     214          14 :     if (pszOverrideUnitName != nullptr && dfOverrideUnit != 0.0 &&
     215           4 :         fabs(dfOverrideUnit - GetLinearUnits()) > 0.0000000001)
     216             :     {
     217           2 :         const double dfFalseEasting = GetNormProjParm(SRS_PP_FALSE_EASTING);
     218           2 :         const double dfFalseNorthing = GetNormProjParm(SRS_PP_FALSE_NORTHING);
     219             : 
     220           2 :         SetLinearUnits(pszOverrideUnitName, dfOverrideUnit);
     221             : 
     222           2 :         SetNormProjParm(SRS_PP_FALSE_EASTING, dfFalseEasting);
     223           2 :         SetNormProjParm(SRS_PP_FALSE_NORTHING, dfFalseNorthing);
     224             : 
     225           2 :         OGR_SRSNode *const poPROJCS = GetAttrNode("PROJCS");
     226           2 :         if (poPROJCS != nullptr && poPROJCS->FindChild("AUTHORITY") != -1)
     227             :         {
     228           0 :             poPROJCS->DestroyChild(poPROJCS->FindChild("AUTHORITY"));
     229             :         }
     230             :     }
     231             : 
     232          10 :     return OGRERR_NONE;
     233             : }
     234             : 
     235             : /************************************************************************/
     236             : /*                          OSRSetStatePlane()                          */
     237             : /************************************************************************/
     238             : 
     239             : /**
     240             :  * \brief Set State Plane projection definition.
     241             :  *
     242             :  * This function is the same as OGRSpatialReference::SetStatePlane().
     243             :  */
     244             : 
     245           1 : OGRErr OSRSetStatePlane(OGRSpatialReferenceH hSRS, int nZone, int bNAD83)
     246             : 
     247             : {
     248           1 :     VALIDATE_POINTER1(hSRS, "OSRSetStatePlane", OGRERR_FAILURE);
     249             : 
     250           1 :     return reinterpret_cast<OGRSpatialReference *>(hSRS)->SetStatePlane(nZone,
     251           1 :                                                                         bNAD83);
     252             : }
     253             : 
     254             : /************************************************************************/
     255             : /*                     OSRSetStatePlaneWithUnits()                      */
     256             : /************************************************************************/
     257             : 
     258             : /**
     259             :  * \brief Set State Plane projection definition.
     260             :  *
     261             :  * This function is the same as OGRSpatialReference::SetStatePlane().
     262             :  */
     263             : 
     264           3 : OGRErr OSRSetStatePlaneWithUnits(OGRSpatialReferenceH hSRS, int nZone,
     265             :                                  int bNAD83, const char *pszOverrideUnitName,
     266             :                                  double dfOverrideUnit)
     267             : 
     268             : {
     269           3 :     VALIDATE_POINTER1(hSRS, "OSRSetStatePlaneWithUnits", OGRERR_FAILURE);
     270             : 
     271           3 :     return reinterpret_cast<OGRSpatialReference *>(hSRS)->SetStatePlane(
     272           3 :         nZone, bNAD83, pszOverrideUnitName, dfOverrideUnit);
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                          AutoIdentifyEPSG()                          */
     277             : /************************************************************************/
     278             : 
     279             : /**
     280             :  * \brief Set EPSG authority info if possible.
     281             :  *
     282             :  * This method inspects a WKT definition, and adds EPSG authority nodes
     283             :  * where an aspect of the coordinate system can be easily and safely
     284             :  * corresponded with an EPSG identifier.  In practice, this method will
     285             :  * evolve over time.  In theory it can add authority nodes for any object
     286             :  * (i.e. spheroid, datum, GEOGCS, units, and PROJCS) that could have an
     287             :  * authority node.  Mostly this is useful to inserting appropriate
     288             :  * PROJCS codes for common formulations (like UTM n WGS84).
     289             :  *
     290             :  * If it success the OGRSpatialReference is updated in place, and the
     291             :  * method return OGRERR_NONE.  If the method fails to identify the
     292             :  * general coordinate system OGRERR_UNSUPPORTED_SRS is returned but no
     293             :  * error message is posted via CPLError().
     294             :  *
     295             :  * This method is the same as the C function OSRAutoIdentifyEPSG().
     296             :  *
     297             :  * Since GDAL 2.3, the FindMatches() method can also be used for improved
     298             :  * matching by researching the EPSG catalog.
     299             :  *
     300             :  * @return OGRERR_NONE or OGRERR_UNSUPPORTED_SRS.
     301             :  *
     302             :  * @see OGRSpatialReference::FindBestMatch()
     303             :  */
     304             : 
     305         312 : OGRErr OGRSpatialReference::AutoIdentifyEPSG()
     306             : 
     307             : {
     308             :     /* -------------------------------------------------------------------- */
     309             :     /*      Do we have a GEOGCS node, but no authority?  If so, try         */
     310             :     /*      guessing it.                                                    */
     311             :     /* -------------------------------------------------------------------- */
     312         417 :     if ((IsProjected() || IsGeographic()) &&
     313         571 :         GetAuthorityCode("GEOGCS") == nullptr &&
     314         154 :         GetAttrValue("PROJCRS|BASEGEOGCRS|ID") == nullptr)
     315             :     {
     316         152 :         const int nGCS = GetEPSGGeogCS();
     317         152 :         if (nGCS != -1)
     318          46 :             SetAuthority("GEOGCS", "EPSG", nGCS);
     319             :     }
     320             : 
     321         312 :     if (IsProjected() && GetAuthorityCode("PROJCS") == nullptr)
     322             :     {
     323         186 :         const char *pszProjection = GetAttrValue("PROJECTION");
     324             : 
     325             :         /* --------------------------------------------------------------------
     326             :          */
     327             :         /*      Is this a UTM coordinate system with a common GEOGCS? */
     328             :         /* --------------------------------------------------------------------
     329             :          */
     330         186 :         int nZone = 0;
     331         186 :         int bNorth = FALSE;
     332         186 :         if ((nZone = GetUTMZone(&bNorth)) != 0)
     333             :         {
     334         106 :             const char *pszAuthName = GetAuthorityName("PROJCS|GEOGCS");
     335         106 :             const char *pszAuthCode = GetAuthorityCode("PROJCS|GEOGCS");
     336             : 
     337         106 :             if (pszAuthName == nullptr || pszAuthCode == nullptr)
     338             :             {
     339             :                 // Don't exactly recognise datum.
     340             :             }
     341          91 :             else if (EQUAL(pszAuthName, "EPSG") && atoi(pszAuthCode) == 4326)
     342             :             {
     343             :                 // WGS84
     344           0 :                 if (bNorth)
     345           0 :                     SetAuthority("PROJCS", "EPSG", 32600 + nZone);
     346             :                 else
     347           0 :                     SetAuthority("PROJCS", "EPSG", 32700 + nZone);
     348             :             }
     349          91 :             else if (EQUAL(pszAuthName, "EPSG") && atoi(pszAuthCode) == 4267 &&
     350          88 :                      nZone >= 3 && nZone <= 22 && bNorth)
     351             :             {
     352          88 :                 SetAuthority("PROJCS", "EPSG", 26700 + nZone);  // NAD27
     353             :             }
     354           3 :             else if (EQUAL(pszAuthName, "EPSG") && atoi(pszAuthCode) == 4269 &&
     355           1 :                      nZone >= 3 && nZone <= 23 && bNorth)
     356             :             {
     357           1 :                 SetAuthority("PROJCS", "EPSG", 26900 + nZone);  // NAD83
     358             :             }
     359           2 :             else if (EQUAL(pszAuthName, "EPSG") && atoi(pszAuthCode) == 4322)
     360             :             {  // WGS72
     361           0 :                 if (bNorth)
     362           0 :                     SetAuthority("PROJCS", "EPSG", 32200 + nZone);
     363             :                 else
     364           0 :                     SetAuthority("PROJCS", "EPSG", 32300 + nZone);
     365             :             }
     366             :         }
     367             : 
     368             :         /* --------------------------------------------------------------------
     369             :          */
     370             :         /*      Is this a Polar Stereographic system on WGS 84 ? */
     371             :         /* --------------------------------------------------------------------
     372             :          */
     373          80 :         else if (pszProjection != nullptr &&
     374          80 :                  EQUAL(pszProjection, SRS_PT_POLAR_STEREOGRAPHIC))
     375             :         {
     376           4 :             const char *pszAuthName = GetAuthorityName("PROJCS|GEOGCS");
     377           4 :             const char *pszAuthCode = GetAuthorityCode("PROJCS|GEOGCS");
     378             :             const double dfLatOrigin =
     379           4 :                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0);
     380             : 
     381           4 :             if (pszAuthName != nullptr && EQUAL(pszAuthName, "EPSG") &&
     382           4 :                 pszAuthCode != nullptr && atoi(pszAuthCode) == 4326 &&
     383           4 :                 fabs(fabs(dfLatOrigin) - 71.0) < 1e-15 &&
     384           3 :                 fabs(GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0)) < 1e-15 &&
     385           3 :                 fabs(GetProjParm(SRS_PP_SCALE_FACTOR, 1.0) - 1.0) < 1e-15 &&
     386           3 :                 fabs(GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0)) < 1e-15 &&
     387          11 :                 fabs(GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0)) < 1e-15 &&
     388           3 :                 fabs(GetLinearUnits() - 1.0) < 1e-15)
     389             :             {
     390           3 :                 if (dfLatOrigin > 0)
     391             :                     // Arctic Polar Stereographic
     392           1 :                     SetAuthority("PROJCS", "EPSG", 3995);
     393             :                 else
     394             :                     // Antarctic Polar Stereographic
     395           2 :                     SetAuthority("PROJCS", "EPSG", 3031);
     396             :             }
     397             :         }
     398             :     }
     399             : 
     400             :     /* -------------------------------------------------------------------- */
     401             :     /*      Return.                                                         */
     402             :     /* -------------------------------------------------------------------- */
     403         312 :     if (IsProjected() && GetAuthorityCode("PROJCS") != nullptr)
     404         113 :         return OGRERR_NONE;
     405             : 
     406         199 :     if (IsGeographic() && GetAuthorityCode("GEOGCS") != nullptr)
     407          30 :         return OGRERR_NONE;
     408             : 
     409         169 :     return OGRERR_UNSUPPORTED_SRS;
     410             : }
     411             : 
     412             : /************************************************************************/
     413             : /*                        OSRAutoIdentifyEPSG()                         */
     414             : /************************************************************************/
     415             : 
     416             : /**
     417             :  * \brief Set EPSG authority info if possible.
     418             :  *
     419             :  * This function is the same as OGRSpatialReference::AutoIdentifyEPSG().
     420             :  *
     421             :  * Since GDAL 2.3, the OSRFindMatches() function can also be used for improved
     422             :  * matching by researching the EPSG catalog.
     423             :  *
     424             :  */
     425             : 
     426           5 : OGRErr OSRAutoIdentifyEPSG(OGRSpatialReferenceH hSRS)
     427             : 
     428             : {
     429           5 :     VALIDATE_POINTER1(hSRS, "OSRAutoIdentifyEPSG", OGRERR_FAILURE);
     430             : 
     431           5 :     return reinterpret_cast<OGRSpatialReference *>(hSRS)->AutoIdentifyEPSG();
     432             : }

Generated by: LCOV version 1.14