LCOV - code coverage report
Current view: top level - ogr - ogr_srs_ozi.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 60 173 34.7 %
Date: 2024-11-21 22:18:42 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  OGRSpatialReference translation from OziExplorer
       5             :  *           georeferencing information.
       6             :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Andrey Kiselev <dron@ak4719.spb.edu>
      10             :  * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "ogr_spatialref.h"
      17             : 
      18             : #include <cstdlib>
      19             : #include <cstring>
      20             : 
      21             : #include "cpl_conv.h"
      22             : #include "cpl_csv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_string.h"
      25             : #include "ogr_core.h"
      26             : #include "ogr_srs_api.h"
      27             : 
      28             : /************************************************************************/
      29             : /*                          OSRImportFromOzi()                          */
      30             : /************************************************************************/
      31             : 
      32             : /**
      33             :  * Import coordinate system from OziExplorer projection definition.
      34             :  *
      35             :  * This function will import projection definition in style, used by
      36             :  * OziExplorer software.
      37             :  *
      38             :  * Note: another version of this function with a different signature existed
      39             :  * in GDAL 1.X.
      40             :  *
      41             :  * @param hSRS spatial reference object.
      42             :  * @param papszLines Map file lines. This is an array of strings containing
      43             :  * the whole OziExplorer .MAP file. The array is terminated by a NULL pointer.
      44             :  *
      45             :  * @return OGRERR_NONE on success or an error code in case of failure.
      46             :  *
      47             :  * @since OGR 2.0
      48             :  */
      49             : 
      50           3 : OGRErr OSRImportFromOzi(OGRSpatialReferenceH hSRS,
      51             :                         const char *const *papszLines)
      52             : 
      53             : {
      54           3 :     VALIDATE_POINTER1(hSRS, "OSRImportFromOzi", OGRERR_FAILURE);
      55             : 
      56           3 :     return OGRSpatialReference::FromHandle(hSRS)->importFromOzi(papszLines);
      57             : }
      58             : 
      59             : /************************************************************************/
      60             : /*                            importFromOzi()                           */
      61             : /************************************************************************/
      62             : 
      63             : /**
      64             :  * Import coordinate system from OziExplorer projection definition.
      65             :  *
      66             :  * This method will import projection definition in style, used by
      67             :  * OziExplorer software.
      68             :  *
      69             :  * @param papszLines Map file lines. This is an array of strings containing
      70             :  * the whole OziExplorer .MAP file. The array is terminated by a NULL pointer.
      71             :  *
      72             :  * @return OGRERR_NONE on success or an error code in case of failure.
      73             :  *
      74             :  * @since OGR 1.10
      75             :  */
      76             : 
      77           3 : OGRErr OGRSpatialReference::importFromOzi(const char *const *papszLines)
      78             : {
      79             :     const char *pszDatum;
      80           3 :     const char *pszProj = nullptr;
      81           3 :     const char *pszProjParams = nullptr;
      82             : 
      83           3 :     Clear();
      84             : 
      85           3 :     const int nLines = CSLCount(papszLines);
      86           3 :     if (nLines < 5)
      87           0 :         return OGRERR_NOT_ENOUGH_DATA;
      88             : 
      89           3 :     pszDatum = papszLines[4];
      90             : 
      91           9 :     for (int iLine = 5; iLine < nLines; iLine++)
      92             :     {
      93           6 :         if (STARTS_WITH_CI(papszLines[iLine], "Map Projection"))
      94             :         {
      95           3 :             pszProj = papszLines[iLine];
      96             :         }
      97           3 :         else if (STARTS_WITH_CI(papszLines[iLine], "Projection Setup"))
      98             :         {
      99           3 :             pszProjParams = papszLines[iLine];
     100             :         }
     101             :     }
     102             : 
     103           3 :     if (!(pszDatum && pszProj && pszProjParams))
     104           0 :         return OGRERR_NOT_ENOUGH_DATA;
     105             : 
     106             :     /* -------------------------------------------------------------------- */
     107             :     /*      Operate on the basis of the projection name.                    */
     108             :     /* -------------------------------------------------------------------- */
     109           3 :     char **papszProj = CSLTokenizeStringComplex(pszProj, ",", TRUE, TRUE);
     110             :     char **papszProjParams =
     111           3 :         CSLTokenizeStringComplex(pszProjParams, ",", TRUE, TRUE);
     112           3 :     char **papszDatum = nullptr;
     113             : 
     114           3 :     if (CSLCount(papszProj) < 2)
     115             :     {
     116           0 :         goto not_enough_data;
     117             :     }
     118             : 
     119           3 :     if (STARTS_WITH_CI(papszProj[1], "Latitude/Longitude"))
     120             :     {
     121             :         // Do nothing.
     122             :     }
     123           1 :     else if (STARTS_WITH_CI(papszProj[1], "Mercator"))
     124             :     {
     125           0 :         if (CSLCount(papszProjParams) < 6)
     126           0 :             goto not_enough_data;
     127           0 :         double dfScale = CPLAtof(papszProjParams[3]);
     128             :         // If unset, default to scale = 1.
     129           0 :         if (papszProjParams[3][0] == 0)
     130           0 :             dfScale = 1;
     131           0 :         SetMercator(CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
     132           0 :                     dfScale, CPLAtof(papszProjParams[4]),
     133           0 :                     CPLAtof(papszProjParams[5]));
     134             :     }
     135           1 :     else if (STARTS_WITH_CI(papszProj[1], "Transverse Mercator"))
     136             :     {
     137           0 :         if (CSLCount(papszProjParams) < 6)
     138           0 :             goto not_enough_data;
     139           0 :         SetTM(CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
     140           0 :               CPLAtof(papszProjParams[3]), CPLAtof(papszProjParams[4]),
     141           0 :               CPLAtof(papszProjParams[5]));
     142             :     }
     143           1 :     else if (STARTS_WITH_CI(papszProj[1], "Lambert Conformal Conic"))
     144             :     {
     145           1 :         if (CSLCount(papszProjParams) < 8)
     146           0 :             goto not_enough_data;
     147           1 :         SetLCC(CPLAtof(papszProjParams[6]), CPLAtof(papszProjParams[7]),
     148           1 :                CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
     149           1 :                CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]));
     150             :     }
     151           0 :     else if (STARTS_WITH_CI(papszProj[1], "Sinusoidal"))
     152             :     {
     153           0 :         if (CSLCount(papszProjParams) < 6)
     154           0 :             goto not_enough_data;
     155           0 :         SetSinusoidal(CPLAtof(papszProjParams[2]), CPLAtof(papszProjParams[4]),
     156           0 :                       CPLAtof(papszProjParams[5]));
     157             :     }
     158           0 :     else if (STARTS_WITH_CI(papszProj[1], "Albers Equal Area"))
     159             :     {
     160           0 :         if (CSLCount(papszProjParams) < 8)
     161           0 :             goto not_enough_data;
     162           0 :         SetACEA(CPLAtof(papszProjParams[6]), CPLAtof(papszProjParams[7]),
     163           0 :                 CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
     164           0 :                 CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]));
     165             :     }
     166           0 :     else if (STARTS_WITH_CI(papszProj[1],
     167           0 :                             "(UTM) Universal Transverse Mercator") &&
     168             :              nLines > 5)
     169             :     {
     170             :         // Look for the UTM zone in the calibration point data.
     171           0 :         int iLine = 5;  // Used after for.
     172           0 :         for (; iLine < nLines; iLine++)
     173             :         {
     174           0 :             if (STARTS_WITH_CI(papszLines[iLine], "Point"))
     175             :             {
     176           0 :                 char **papszTok = CSLTokenizeString2(papszLines[iLine], ",",
     177             :                                                      CSLT_ALLOWEMPTYTOKENS |
     178             :                                                          CSLT_STRIPLEADSPACES |
     179             :                                                          CSLT_STRIPENDSPACES);
     180           0 :                 if (CSLCount(papszTok) < 17 || EQUAL(papszTok[2], "") ||
     181           0 :                     EQUAL(papszTok[13], "") || EQUAL(papszTok[14], "") ||
     182           0 :                     EQUAL(papszTok[15], "") || EQUAL(papszTok[16], ""))
     183             :                 {
     184           0 :                     CSLDestroy(papszTok);
     185           0 :                     continue;
     186             :                 }
     187           0 :                 SetUTM(atoi(papszTok[13]), EQUAL(papszTok[16], "N"));
     188           0 :                 CSLDestroy(papszTok);
     189           0 :                 break;
     190             :             }
     191             :         }
     192           0 :         if (iLine == nLines)  // Try to guess the UTM zone.
     193             :         {
     194           0 :             float fMinLongitude = 1000.0f;
     195           0 :             float fMaxLongitude = -1000.0f;
     196           0 :             float fMinLatitude = 1000.0f;
     197           0 :             float fMaxLatitude = -1000.0f;
     198           0 :             bool bFoundMMPLL = false;
     199           0 :             for (iLine = 5; iLine < nLines; iLine++)
     200             :             {
     201           0 :                 if (STARTS_WITH_CI(papszLines[iLine], "MMPLL"))
     202             :                 {
     203           0 :                     char **papszTok = CSLTokenizeString2(
     204           0 :                         papszLines[iLine], ",",
     205             :                         CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
     206             :                             CSLT_STRIPENDSPACES);
     207           0 :                     if (CSLCount(papszTok) < 4)
     208             :                     {
     209           0 :                         CSLDestroy(papszTok);
     210           0 :                         continue;
     211             :                     }
     212             :                     const float fLongitude =
     213           0 :                         static_cast<float>(CPLAtofM(papszTok[2]));
     214             :                     const float fLatitude =
     215           0 :                         static_cast<float>(CPLAtofM(papszTok[3]));
     216           0 :                     CSLDestroy(papszTok);
     217             : 
     218           0 :                     bFoundMMPLL = true;
     219             : 
     220           0 :                     if (fMinLongitude > fLongitude)
     221           0 :                         fMinLongitude = fLongitude;
     222           0 :                     if (fMaxLongitude < fLongitude)
     223           0 :                         fMaxLongitude = fLongitude;
     224           0 :                     if (fMinLatitude > fLatitude)
     225           0 :                         fMinLatitude = fLatitude;
     226           0 :                     if (fMaxLatitude < fLatitude)
     227           0 :                         fMaxLatitude = fLatitude;
     228             :                 }
     229             :             }
     230           0 :             const float fMedianLatitude = (fMinLatitude + fMaxLatitude) / 2;
     231           0 :             const float fMedianLongitude = (fMinLongitude + fMaxLongitude) / 2;
     232           0 :             if (bFoundMMPLL && fMaxLatitude <= 90)
     233             :             {
     234           0 :                 int nUtmZone = 0;
     235           0 :                 if (fMedianLatitude >= 56 && fMedianLatitude <= 64 &&
     236           0 :                     fMedianLongitude >= 3 && fMedianLongitude <= 12)
     237           0 :                     nUtmZone = 32;  // Norway exception.
     238           0 :                 else if (fMedianLatitude >= 72 && fMedianLatitude <= 84 &&
     239           0 :                          fMedianLongitude >= 0 && fMedianLongitude <= 42)
     240             :                     // Svalbard exception.
     241           0 :                     nUtmZone =
     242           0 :                         static_cast<int>((fMedianLongitude + 3) / 12) * 2 + 31;
     243             :                 else
     244           0 :                     nUtmZone =
     245           0 :                         static_cast<int>((fMedianLongitude + 180) / 6) + 1;
     246           0 :                 SetUTM(nUtmZone, fMedianLatitude >= 0);
     247             :             }
     248             :             else
     249             :             {
     250           0 :                 CPLDebug("OSR_Ozi", "UTM Zone not found");
     251             :             }
     252           0 :         }
     253             :     }
     254           0 :     else if (STARTS_WITH_CI(papszProj[1], "(I) France Zone I"))
     255             :     {
     256           0 :         SetLCC1SP(49.5, 2.337229167, 0.99987734, 600000, 1200000);
     257             :     }
     258           0 :     else if (STARTS_WITH_CI(papszProj[1], "(II) France Zone II"))
     259             :     {
     260           0 :         SetLCC1SP(46.8, 2.337229167, 0.99987742, 600000, 2200000);
     261             :     }
     262           0 :     else if (STARTS_WITH_CI(papszProj[1], "(III) France Zone III"))
     263             :     {
     264           0 :         SetLCC1SP(44.1, 2.337229167, 0.99987750, 600000, 3200000);
     265             :     }
     266           0 :     else if (STARTS_WITH_CI(papszProj[1], "(IV) France Zone IV"))
     267             :     {
     268           0 :         SetLCC1SP(42.165, 2.337229167, 0.99994471, 234.358, 4185861.369);
     269             :     }
     270             : 
     271             :     /*
     272             :      *  Note: The following projections have not been implemented yet
     273             :      *
     274             :      */
     275             : 
     276             :     /*
     277             :         else if( STARTS_WITH_CI(papszProj[1], "(BNG) British National Grid") )
     278             :         {
     279             :         }
     280             :         else if( STARTS_WITH_CI(papszProj[1], "(IG) Irish Grid") )
     281             :         {
     282             :         }
     283             : 
     284             :         else if( STARTS_WITH_CI(papszProj[1], "(NZG) New Zealand Grid") )
     285             :         {
     286             :         }
     287             :         else if( STARTS_WITH_CI(papszProj[1], "(NZTM2) New Zealand TM 2000") )
     288             :         {
     289             :         }
     290             :         else if( STARTS_WITH_CI(papszProj[1], "(SG) Swedish Grid") )
     291             :         {
     292             :         }
     293             :         else if( STARTS_WITH_CI(papszProj[1], "(SUI) Swiss Grid") )
     294             :         {
     295             :         }
     296             :         else if( STARTS_WITH_CI(papszProj[1], "(A)Lambert Azimuthual Equal
     297             :        Area") )
     298             :         {
     299             :         }
     300             :         else if( STARTS_WITH_CI(papszProj[1], "(EQC) Equidistant Conic") )
     301             :         {
     302             :         }
     303             :         else if( STARTS_WITH_CI(papszProj[1], "Polyconic (American)") )
     304             :         {
     305             :         }
     306             :         else if( STARTS_WITH_CI(papszProj[1], "Van Der Grinten") )
     307             :         {
     308             :         }
     309             :         else if( STARTS_WITH_CI(papszProj[1], "Vertical Near-Sided Perspective")
     310             :        )
     311             :         {
     312             :         }
     313             :         else if( STARTS_WITH_CI(papszProj[1], "(WIV) Wagner IV") )
     314             :         {
     315             :         }
     316             :         else if( STARTS_WITH_CI(papszProj[1], "Bonne") )
     317             :         {
     318             :         }
     319             :         else if( STARTS_WITH_CI(papszProj[1],
     320             :                                 "(MT0) Montana State Plane Zone 2500") )
     321             :         {
     322             :         }
     323             :         else if( STARTS_WITH_CI(papszProj[1], "ITA1) Italy Grid Zone 1") )
     324             :         {
     325             :         }
     326             :         else if( STARTS_WITH_CI(papszProj[1], "ITA2) Italy Grid Zone 2") )
     327             :         {
     328             :         }
     329             :         else if( STARTS_WITH_CI(papszProj[1],
     330             :                                 "(VICMAP-TM) Victoria Aust.(pseudo AMG)") )
     331             :         {
     332             :         }
     333             :         else if( STARTS_WITH_CI(papszProj[1], "VICGRID) Victoria Australia") )
     334             :         {
     335             :         }
     336             :         else if( STARTS_WITH_CI(papszProj[1],
     337             :                                 "(VG94) VICGRID94 Victoria Australia") )
     338             :         {
     339             :         }
     340             :         else if( STARTS_WITH_CI(papszProj[1], "Gnomonic") )
     341             :         {
     342             :         }
     343             :     */
     344             :     else
     345             :     {
     346           0 :         CPLDebug("OSR_Ozi", "Unsupported projection: \"%s\"", papszProj[1]);
     347           0 :         SetLocalCS(
     348           0 :             CPLString().Printf(R"("Ozi" projection "%s")", papszProj[1]));
     349             :     }
     350             : 
     351             :     /* -------------------------------------------------------------------- */
     352             :     /*      Try to translate the datum/spheroid.                            */
     353             :     /* -------------------------------------------------------------------- */
     354           3 :     papszDatum = CSLTokenizeString2(
     355             :         pszDatum, ",",
     356             :         CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     357           3 :     if (papszDatum == nullptr)
     358           0 :         goto not_enough_data;
     359             : 
     360           3 :     if (!IsLocal())
     361             :     {
     362             :         /* --------------------------------------------------------------------
     363             :          */
     364             :         /*      Verify that we can find the CSV file containing the datums */
     365             :         /* --------------------------------------------------------------------
     366             :          */
     367           3 :         if (CSVScanFileByName(CSVFilename("ozi_datum.csv"), "EPSG_DATUM_CODE",
     368           3 :                               "4326", CC_Integer) == nullptr)
     369             :         {
     370           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     371             :                      "Unable to open OZI support file %s.  "
     372             :                      "Try setting the GDAL_DATA environment variable to point "
     373             :                      "to the directory containing OZI csv files.",
     374             :                      CSVFilename("ozi_datum.csv"));
     375           0 :             goto other_error;
     376             :         }
     377             : 
     378             :         /* --------------------------------------------------------------------
     379             :          */
     380             :         /*      Search for matching datum */
     381             :         /* --------------------------------------------------------------------
     382             :          */
     383           3 :         const char *pszOziDatum = CSVFilename("ozi_datum.csv");
     384             :         CPLString osDName = CSVGetField(pszOziDatum, "NAME", papszDatum[0],
     385           3 :                                         CC_ApproxString, "NAME");
     386           3 :         if (osDName.empty())
     387             :         {
     388           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     389             :                      "Failed to find datum %s in ozi_datum.csv.",
     390             :                      papszDatum[0]);
     391           0 :             goto other_error;
     392             :         }
     393             : 
     394             :         const int nDatumCode =
     395           3 :             atoi(CSVGetField(pszOziDatum, "NAME", papszDatum[0],
     396             :                              CC_ApproxString, "EPSG_DATUM_CODE"));
     397             : 
     398           3 :         if (nDatumCode > 0)  // There is a matching EPSG code
     399             :         {
     400           4 :             OGRSpatialReference oGCS;
     401           2 :             oGCS.importFromEPSG(nDatumCode);
     402           2 :             CopyGeogCSFrom(&oGCS);
     403             :         }
     404             :         else  // We use the parameters from the CSV files
     405             :         {
     406             :             CPLString osEllipseCode =
     407             :                 CSVGetField(pszOziDatum, "NAME", papszDatum[0], CC_ApproxString,
     408           1 :                             "ELLIPSOID_CODE");
     409           1 :             const double dfDeltaX = CPLAtof(CSVGetField(
     410             :                 pszOziDatum, "NAME", papszDatum[0], CC_ApproxString, "DELTAX"));
     411           1 :             const double dfDeltaY = CPLAtof(CSVGetField(
     412             :                 pszOziDatum, "NAME", papszDatum[0], CC_ApproxString, "DELTAY"));
     413           1 :             const double dfDeltaZ = CPLAtof(CSVGetField(
     414             :                 pszOziDatum, "NAME", papszDatum[0], CC_ApproxString, "DELTAZ"));
     415             : 
     416             :             /* --------------------------------------------------------------------
     417             :              */
     418             :             /*     Verify that we can find the CSV file containing the
     419             :              * ellipsoids.  */
     420             :             /* --------------------------------------------------------------------
     421             :              */
     422           1 :             if (CSVScanFileByName(CSVFilename("ozi_ellips.csv"),
     423             :                                   "ELLIPSOID_CODE", "20",
     424           1 :                                   CC_Integer) == nullptr)
     425             :             {
     426           0 :                 CPLError(
     427             :                     CE_Failure, CPLE_OpenFailed,
     428             :                     "Unable to open OZI support file %s.  "
     429             :                     "Try setting the GDAL_DATA environment variable to point "
     430             :                     "to the directory containing OZI csv files.",
     431             :                     CSVFilename("ozi_ellips.csv"));
     432           0 :                 goto other_error;
     433             :             }
     434             : 
     435             :             /* --------------------------------------------------------------------
     436             :              */
     437             :             /*      Lookup the ellipse code. */
     438             :             /* --------------------------------------------------------------------
     439             :              */
     440           1 :             const char *pszOziEllipse = CSVFilename("ozi_ellips.csv");
     441             : 
     442             :             CPLString osEName =
     443             :                 CSVGetField(pszOziEllipse, "ELLIPSOID_CODE", osEllipseCode,
     444           1 :                             CC_ApproxString, "NAME");
     445           1 :             if (osEName.empty())
     446             :             {
     447           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     448             :                          "Failed to find ellipsoid %s in ozi_ellips.csv.",
     449             :                          osEllipseCode.c_str());
     450           0 :                 goto other_error;
     451             :             }
     452             : 
     453             :             const double dfA =
     454           1 :                 CPLAtof(CSVGetField(pszOziEllipse, "ELLIPSOID_CODE",
     455             :                                     osEllipseCode, CC_ApproxString, "A"));
     456             :             const double dfInvF =
     457           1 :                 CPLAtof(CSVGetField(pszOziEllipse, "ELLIPSOID_CODE",
     458             :                                     osEllipseCode, CC_ApproxString, "INVF"));
     459             : 
     460             :             /* --------------------------------------------------------------------
     461             :              */
     462             :             /*      Create geographic coordinate system. */
     463             :             /* --------------------------------------------------------------------
     464             :              */
     465           1 :             SetGeogCS(osDName, osDName, osEName, dfA, dfInvF);
     466           1 :             SetTOWGS84(dfDeltaX, dfDeltaY, dfDeltaZ);
     467             :         }
     468             :     }
     469             : 
     470             :     /* -------------------------------------------------------------------- */
     471             :     /*      Grid units translation                                          */
     472             :     /* -------------------------------------------------------------------- */
     473           3 :     if (IsLocal() || IsProjected())
     474           1 :         SetLinearUnits(SRS_UL_METER, 1.0);
     475             : 
     476           3 :     CSLDestroy(papszProj);
     477           3 :     CSLDestroy(papszProjParams);
     478           3 :     CSLDestroy(papszDatum);
     479             : 
     480           3 :     return OGRERR_NONE;
     481             : 
     482           0 : not_enough_data:
     483             : 
     484           0 :     CSLDestroy(papszProj);
     485           0 :     CSLDestroy(papszProjParams);
     486           0 :     CSLDestroy(papszDatum);
     487             : 
     488           0 :     return OGRERR_NOT_ENOUGH_DATA;
     489             : 
     490           0 : other_error:
     491             : 
     492           0 :     CSLDestroy(papszProj);
     493           0 :     CSLDestroy(papszProjParams);
     494           0 :     CSLDestroy(papszDatum);
     495             : 
     496           0 :     return OGRERR_FAILURE;
     497             : }

Generated by: LCOV version 1.14