LCOV - code coverage report
Current view: top level - frmts/raw - hkvdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 274 379 72.3 %
Date: 2025-10-21 01:37:22 Functions: 13 18 72.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GView
       4             :  * Purpose:  Implementation of Atlantis HKV labelled blob support
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam
       9             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include <ctype.h>
      15             : 
      16             : #include "atlsci_spheroid.h"
      17             : #include "cpl_string.h"
      18             : #include "gdal_frmts.h"
      19             : #include "gdal_priv.h"
      20             : #include "ogr_spatialref.h"
      21             : #include "rawdataset.h"
      22             : 
      23             : #include <cmath>
      24             : 
      25             : #include <algorithm>
      26             : 
      27             : /************************************************************************/
      28             : /* ==================================================================== */
      29             : /*                            HKVRasterBand                             */
      30             : /* ==================================================================== */
      31             : /************************************************************************/
      32             : 
      33             : class HKVDataset;
      34             : 
      35           2 : class HKVRasterBand final : public RawRasterBand
      36             : {
      37             :     friend class HKVDataset;
      38             : 
      39             :   public:
      40             :     HKVRasterBand(HKVDataset *poDS, int nBand, VSILFILE *fpRaw,
      41             :                   unsigned int nImgOffset, int nPixelOffset, int nLineOffset,
      42             :                   GDALDataType eDataType, int bNativeOrder);
      43             : 
      44             :     ~HKVRasterBand() override;
      45             : };
      46             : 
      47             : HKVRasterBand::~HKVRasterBand() = default;
      48             : 
      49             : /************************************************************************/
      50             : /*                      HKV Spheroids                                   */
      51             : /************************************************************************/
      52             : 
      53             : class HKVSpheroidList final : public SpheroidList
      54             : {
      55             :   public:
      56             :     HKVSpheroidList();
      57             : };
      58             : 
      59           1 : HKVSpheroidList ::HKVSpheroidList()
      60             : {
      61           1 :     num_spheroids = 58;
      62           1 :     epsilonR = 0.1;
      63           1 :     epsilonI = 0.000001;
      64             : 
      65           1 :     spheroids[0].SetValuesByEqRadiusAndInvFlattening("airy-1830", 6377563.396,
      66             :                                                      299.3249646);
      67           1 :     spheroids[1].SetValuesByEqRadiusAndInvFlattening("modified-airy",
      68             :                                                      6377340.189, 299.3249646);
      69           1 :     spheroids[2].SetValuesByEqRadiusAndInvFlattening("australian-national",
      70             :                                                      6378160, 298.25);
      71           1 :     spheroids[3].SetValuesByEqRadiusAndInvFlattening("bessel-1841-namibia",
      72             :                                                      6377483.865, 299.1528128);
      73           1 :     spheroids[4].SetValuesByEqRadiusAndInvFlattening("bessel-1841", 6377397.155,
      74             :                                                      299.1528128);
      75           1 :     spheroids[5].SetValuesByEqRadiusAndInvFlattening("clarke-1858", 6378294.0,
      76             :                                                      294.297);
      77           1 :     spheroids[6].SetValuesByEqRadiusAndInvFlattening("clarke-1866", 6378206.4,
      78             :                                                      294.9786982);
      79           1 :     spheroids[7].SetValuesByEqRadiusAndInvFlattening("clarke-1880", 6378249.145,
      80             :                                                      293.465);
      81           1 :     spheroids[8].SetValuesByEqRadiusAndInvFlattening("everest-india-1830",
      82             :                                                      6377276.345, 300.8017);
      83           1 :     spheroids[9].SetValuesByEqRadiusAndInvFlattening("everest-sabah-sarawak",
      84             :                                                      6377298.556, 300.8017);
      85           1 :     spheroids[10].SetValuesByEqRadiusAndInvFlattening("everest-india-1956",
      86             :                                                       6377301.243, 300.8017);
      87           1 :     spheroids[11].SetValuesByEqRadiusAndInvFlattening("everest-malaysia-1969",
      88             :                                                       6377295.664, 300.8017);
      89           1 :     spheroids[12].SetValuesByEqRadiusAndInvFlattening("everest-malay-sing",
      90             :                                                       6377304.063, 300.8017);
      91           1 :     spheroids[13].SetValuesByEqRadiusAndInvFlattening("everest-pakistan",
      92             :                                                       6377309.613, 300.8017);
      93           1 :     spheroids[14].SetValuesByEqRadiusAndInvFlattening("modified-fisher-1960",
      94             :                                                       6378155, 298.3);
      95           1 :     spheroids[15].SetValuesByEqRadiusAndInvFlattening("helmert-1906", 6378200,
      96             :                                                       298.3);
      97           1 :     spheroids[16].SetValuesByEqRadiusAndInvFlattening("hough-1960", 6378270,
      98             :                                                       297);
      99           1 :     spheroids[17].SetValuesByEqRadiusAndInvFlattening("hughes", 6378273.0,
     100             :                                                       298.279);
     101           1 :     spheroids[18].SetValuesByEqRadiusAndInvFlattening("indonesian-1974",
     102             :                                                       6378160, 298.247);
     103           1 :     spheroids[19].SetValuesByEqRadiusAndInvFlattening("international-1924",
     104             :                                                       6378388, 297);
     105           1 :     spheroids[20].SetValuesByEqRadiusAndInvFlattening("iugc-67", 6378160.0,
     106             :                                                       298.254);
     107           1 :     spheroids[21].SetValuesByEqRadiusAndInvFlattening("iugc-75", 6378140.0,
     108             :                                                       298.25298);
     109           1 :     spheroids[22].SetValuesByEqRadiusAndInvFlattening("krassovsky-1940",
     110             :                                                       6378245, 298.3);
     111           1 :     spheroids[23].SetValuesByEqRadiusAndInvFlattening("kaula", 6378165.0,
     112             :                                                       292.308);
     113           1 :     spheroids[24].SetValuesByEqRadiusAndInvFlattening("grs-80", 6378137,
     114             :                                                       298.257222101);
     115           1 :     spheroids[25].SetValuesByEqRadiusAndInvFlattening("south-american-1969",
     116             :                                                       6378160, 298.25);
     117           1 :     spheroids[26].SetValuesByEqRadiusAndInvFlattening("wgs-72", 6378135,
     118             :                                                       298.26);
     119           1 :     spheroids[27].SetValuesByEqRadiusAndInvFlattening("wgs-84", 6378137,
     120             :                                                       298.257223563);
     121           1 :     spheroids[28].SetValuesByEqRadiusAndInvFlattening("ev-wgs-84", 6378137.0,
     122             :                                                       298.252841);
     123           1 :     spheroids[29].SetValuesByEqRadiusAndInvFlattening("ev-bessel", 6377397.0,
     124             :                                                       299.1976073);
     125             : 
     126           1 :     spheroids[30].SetValuesByEqRadiusAndInvFlattening("airy_1830", 6377563.396,
     127             :                                                       299.3249646);
     128           1 :     spheroids[31].SetValuesByEqRadiusAndInvFlattening("modified_airy",
     129             :                                                       6377340.189, 299.3249646);
     130           1 :     spheroids[32].SetValuesByEqRadiusAndInvFlattening("australian_national",
     131             :                                                       6378160, 298.25);
     132           1 :     spheroids[33].SetValuesByEqRadiusAndInvFlattening("bessel_1841_namibia",
     133             :                                                       6377483.865, 299.1528128);
     134           1 :     spheroids[34].SetValuesByEqRadiusAndInvFlattening("bessel_1841",
     135             :                                                       6377397.155, 299.1528128);
     136           1 :     spheroids[35].SetValuesByEqRadiusAndInvFlattening("clarke_1858", 6378294.0,
     137             :                                                       294.297);
     138           1 :     spheroids[36].SetValuesByEqRadiusAndInvFlattening("clarke_1866", 6378206.4,
     139             :                                                       294.9786982);
     140           1 :     spheroids[37].SetValuesByEqRadiusAndInvFlattening("clarke_1880",
     141             :                                                       6378249.145, 293.465);
     142           1 :     spheroids[38].SetValuesByEqRadiusAndInvFlattening("everest_india_1830",
     143             :                                                       6377276.345, 300.8017);
     144           1 :     spheroids[39].SetValuesByEqRadiusAndInvFlattening("everest_sabah_sarawak",
     145             :                                                       6377298.556, 300.8017);
     146           1 :     spheroids[40].SetValuesByEqRadiusAndInvFlattening("everest_india_1956",
     147             :                                                       6377301.243, 300.8017);
     148           1 :     spheroids[41].SetValuesByEqRadiusAndInvFlattening("everest_malaysia_1969",
     149             :                                                       6377295.664, 300.8017);
     150           1 :     spheroids[42].SetValuesByEqRadiusAndInvFlattening("everest_malay_sing",
     151             :                                                       6377304.063, 300.8017);
     152           1 :     spheroids[43].SetValuesByEqRadiusAndInvFlattening("everest_pakistan",
     153             :                                                       6377309.613, 300.8017);
     154           1 :     spheroids[44].SetValuesByEqRadiusAndInvFlattening("modified_fisher_1960",
     155             :                                                       6378155, 298.3);
     156           1 :     spheroids[45].SetValuesByEqRadiusAndInvFlattening("helmert_1906", 6378200,
     157             :                                                       298.3);
     158           1 :     spheroids[46].SetValuesByEqRadiusAndInvFlattening("hough_1960", 6378270,
     159             :                                                       297);
     160           1 :     spheroids[47].SetValuesByEqRadiusAndInvFlattening("indonesian_1974",
     161             :                                                       6378160, 298.247);
     162           1 :     spheroids[48].SetValuesByEqRadiusAndInvFlattening("international_1924",
     163             :                                                       6378388, 297);
     164           1 :     spheroids[49].SetValuesByEqRadiusAndInvFlattening("iugc_67", 6378160.0,
     165             :                                                       298.254);
     166           1 :     spheroids[50].SetValuesByEqRadiusAndInvFlattening("iugc_75", 6378140.0,
     167             :                                                       298.25298);
     168           1 :     spheroids[51].SetValuesByEqRadiusAndInvFlattening("krassovsky_1940",
     169             :                                                       6378245, 298.3);
     170           1 :     spheroids[52].SetValuesByEqRadiusAndInvFlattening("grs_80", 6378137,
     171             :                                                       298.257222101);
     172           1 :     spheroids[53].SetValuesByEqRadiusAndInvFlattening("south_american_1969",
     173             :                                                       6378160, 298.25);
     174           1 :     spheroids[54].SetValuesByEqRadiusAndInvFlattening("wgs_72", 6378135,
     175             :                                                       298.26);
     176           1 :     spheroids[55].SetValuesByEqRadiusAndInvFlattening("wgs_84", 6378137,
     177             :                                                       298.257223563);
     178           1 :     spheroids[56].SetValuesByEqRadiusAndInvFlattening("ev_wgs_84", 6378137.0,
     179             :                                                       298.252841);
     180           1 :     spheroids[57].SetValuesByEqRadiusAndInvFlattening("ev_bessel", 6377397.0,
     181             :                                                       299.1976073);
     182           1 : }
     183             : 
     184             : /************************************************************************/
     185             : /* ==================================================================== */
     186             : /*                              HKVDataset                              */
     187             : /* ==================================================================== */
     188             : /************************************************************************/
     189             : 
     190             : class HKVDataset final : public RawDataset
     191             : {
     192             :     friend class HKVRasterBand;
     193             : 
     194             :     char *pszPath;
     195             :     VSILFILE *fpBlob;
     196             : 
     197             :     int nGCPCount;
     198             :     GDAL_GCP *pasGCPList;
     199             : 
     200             :     void ProcessGeoref(const char *);
     201             :     void ProcessGeorefGCP(char **, const char *, double, double);
     202             : 
     203           1 :     void SetVersion(float version_number)
     204             :     {
     205             :         // Update stored info.
     206           1 :         MFF2version = version_number;
     207           1 :     }
     208             : 
     209             :     float MFF2version;
     210             : 
     211             :     GDALDataType eRasterType;
     212             : 
     213             :     void SetNoDataValue(double);
     214             : 
     215             :     OGRSpatialReference m_oSRS{};
     216             :     OGRSpatialReference m_oGCPSRS{};
     217             :     GDALGeoTransform m_gt{};
     218             : 
     219             :     char **papszAttrib;
     220             : 
     221             :     char **papszGeoref;
     222             : 
     223             :     // NOTE: The MFF2 format goes against GDAL's API in that nodata values are
     224             :     // set per-dataset rather than per-band.  To compromise, for writing out,
     225             :     // the dataset's nodata value will be set to the last value set on any of
     226             :     // the raster bands.
     227             : 
     228             :     bool bNoDataSet;
     229             :     double dfNoDataValue;
     230             : 
     231             :     CPL_DISALLOW_COPY_ASSIGN(HKVDataset)
     232             : 
     233             :     CPLErr Close() override;
     234             : 
     235             :   public:
     236             :     HKVDataset();
     237             :     ~HKVDataset() override;
     238             : 
     239           0 :     int GetGCPCount() override /* const */
     240             :     {
     241           0 :         return nGCPCount;
     242             :     }
     243             : 
     244           0 :     const OGRSpatialReference *GetGCPSpatialRef() const override
     245             :     {
     246           0 :         return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS;
     247             :     }
     248             : 
     249             :     const GDAL_GCP *GetGCPs() override;
     250             : 
     251           0 :     const OGRSpatialReference *GetSpatialRef() const override
     252             :     {
     253           0 :         return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     254             :     }
     255             : 
     256             :     CPLErr GetGeoTransform(GDALGeoTransform &) const override;
     257             : 
     258             :     static GDALDataset *Open(GDALOpenInfo *);
     259             : };
     260             : 
     261             : /************************************************************************/
     262             : /* ==================================================================== */
     263             : /*                            HKVRasterBand                             */
     264             : /* ==================================================================== */
     265             : /************************************************************************/
     266             : 
     267             : /************************************************************************/
     268             : /*                           HKVRasterBand()                            */
     269             : /************************************************************************/
     270             : 
     271           1 : HKVRasterBand::HKVRasterBand(HKVDataset *poDSIn, int nBandIn, VSILFILE *fpRawIn,
     272             :                              unsigned int nImgOffsetIn, int nPixelOffsetIn,
     273             :                              int nLineOffsetIn, GDALDataType eDataTypeIn,
     274           1 :                              int bNativeOrderIn)
     275             :     : RawRasterBand(GDALDataset::FromHandle(poDSIn), nBandIn, fpRawIn,
     276             :                     nImgOffsetIn, nPixelOffsetIn, nLineOffsetIn, eDataTypeIn,
     277           1 :                     bNativeOrderIn, RawRasterBand::OwnFP::NO)
     278             : 
     279             : {
     280           1 :     poDS = poDSIn;
     281           1 :     nBand = nBandIn;
     282             : 
     283           1 :     nBlockXSize = poDS->GetRasterXSize();
     284           1 :     nBlockYSize = 1;
     285           1 : }
     286             : 
     287             : /************************************************************************/
     288             : /* ==================================================================== */
     289             : /*                              HKVDataset                              */
     290             : /* ==================================================================== */
     291             : /************************************************************************/
     292             : 
     293             : /************************************************************************/
     294             : /*                            HKVDataset()                             */
     295             : /************************************************************************/
     296             : 
     297           1 : HKVDataset::HKVDataset()
     298             :     : pszPath(nullptr), fpBlob(nullptr), nGCPCount(0), pasGCPList(nullptr),
     299             :       // Initialize datasets to new version; change if necessary.
     300             :       MFF2version(1.1f), eRasterType(GDT_Unknown), papszAttrib(nullptr),
     301           1 :       papszGeoref(nullptr), bNoDataSet(false), dfNoDataValue(0.0)
     302             : {
     303           1 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     304           1 :     m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     305           1 : }
     306             : 
     307             : /************************************************************************/
     308             : /*                            ~HKVDataset()                            */
     309             : /************************************************************************/
     310             : 
     311           2 : HKVDataset::~HKVDataset()
     312             : 
     313             : {
     314           1 :     HKVDataset::Close();
     315           2 : }
     316             : 
     317             : /************************************************************************/
     318             : /*                              Close()                                 */
     319             : /************************************************************************/
     320             : 
     321           2 : CPLErr HKVDataset::Close()
     322             : {
     323           2 :     CPLErr eErr = CE_None;
     324           2 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     325             :     {
     326           1 :         if (HKVDataset::FlushCache(true) != CE_None)
     327           0 :             eErr = CE_Failure;
     328             : 
     329           1 :         if (fpBlob)
     330             :         {
     331           1 :             if (VSIFCloseL(fpBlob) != 0)
     332             :             {
     333           0 :                 eErr = CE_Failure;
     334           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     335             :             }
     336             :         }
     337             : 
     338           1 :         if (nGCPCount > 0)
     339             :         {
     340           1 :             GDALDeinitGCPs(nGCPCount, pasGCPList);
     341           1 :             CPLFree(pasGCPList);
     342             :         }
     343             : 
     344           1 :         CPLFree(pszPath);
     345           1 :         CSLDestroy(papszGeoref);
     346           1 :         CSLDestroy(papszAttrib);
     347             : 
     348           1 :         if (GDALPamDataset::Close() != CE_None)
     349           0 :             eErr = CE_Failure;
     350             :     }
     351           2 :     return eErr;
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                          GetGeoTransform()                           */
     356             : /************************************************************************/
     357             : 
     358           0 : CPLErr HKVDataset::GetGeoTransform(GDALGeoTransform &gt) const
     359             : 
     360             : {
     361           0 :     gt = m_gt;
     362           0 :     return CE_None;
     363             : }
     364             : 
     365             : /************************************************************************/
     366             : /*                               GetGCP()                               */
     367             : /************************************************************************/
     368             : 
     369           0 : const GDAL_GCP *HKVDataset::GetGCPs()
     370             : 
     371             : {
     372           0 :     return pasGCPList;
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                          ProcessGeorefGCP()                          */
     377             : /************************************************************************/
     378             : 
     379           5 : void HKVDataset::ProcessGeorefGCP(char **papszGeorefIn, const char *pszBase,
     380             :                                   double dfRasterX, double dfRasterY)
     381             : 
     382             : {
     383             :     /* -------------------------------------------------------------------- */
     384             :     /*      Fetch the GCP from the string list.                             */
     385             :     /* -------------------------------------------------------------------- */
     386           5 :     char szFieldName[128] = {'\0'};
     387           5 :     snprintf(szFieldName, sizeof(szFieldName), "%s.latitude", pszBase);
     388           5 :     double dfLat = 0.0;
     389           5 :     if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
     390           0 :         return;
     391             :     else
     392           5 :         dfLat = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
     393             : 
     394           5 :     snprintf(szFieldName, sizeof(szFieldName), "%s.longitude", pszBase);
     395           5 :     double dfLong = 0.0;
     396           5 :     if (CSLFetchNameValue(papszGeorefIn, szFieldName) == nullptr)
     397           0 :         return;
     398             :     else
     399           5 :         dfLong = CPLAtof(CSLFetchNameValue(papszGeorefIn, szFieldName));
     400             : 
     401             :     /* -------------------------------------------------------------------- */
     402             :     /*      Add the gcp to the internal list.                               */
     403             :     /* -------------------------------------------------------------------- */
     404           5 :     GDALInitGCPs(1, pasGCPList + nGCPCount);
     405             : 
     406           5 :     CPLFree(pasGCPList[nGCPCount].pszId);
     407             : 
     408           5 :     pasGCPList[nGCPCount].pszId = CPLStrdup(pszBase);
     409             : 
     410           5 :     pasGCPList[nGCPCount].dfGCPX = dfLong;
     411           5 :     pasGCPList[nGCPCount].dfGCPY = dfLat;
     412           5 :     pasGCPList[nGCPCount].dfGCPZ = 0.0;
     413             : 
     414           5 :     pasGCPList[nGCPCount].dfGCPPixel = dfRasterX;
     415           5 :     pasGCPList[nGCPCount].dfGCPLine = dfRasterY;
     416             : 
     417           5 :     nGCPCount++;
     418             : }
     419             : 
     420             : /************************************************************************/
     421             : /*                           ProcessGeoref()                            */
     422             : /************************************************************************/
     423             : 
     424           1 : void HKVDataset::ProcessGeoref(const char *pszFilename)
     425             : 
     426             : {
     427             :     /* -------------------------------------------------------------------- */
     428             :     /*      Load the georef file, and boil white space away from around     */
     429             :     /*      the equal sign.                                                 */
     430             :     /* -------------------------------------------------------------------- */
     431           1 :     CSLDestroy(papszGeoref);
     432           1 :     papszGeoref = CSLLoad(pszFilename);
     433           1 :     if (papszGeoref == nullptr)
     434           0 :         return;
     435             : 
     436           1 :     HKVSpheroidList *hkvEllipsoids = new HKVSpheroidList;
     437             : 
     438          14 :     for (int i = 0; papszGeoref[i] != nullptr; i++)
     439             :     {
     440          13 :         int iDst = 0;
     441          13 :         char *pszLine = papszGeoref[i];
     442             : 
     443         433 :         for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
     444             :         {
     445         420 :             if (pszLine[iSrc] != ' ')
     446             :             {
     447         420 :                 pszLine[iDst++] = pszLine[iSrc];
     448             :             }
     449             :         }
     450          13 :         pszLine[iDst] = '\0';
     451             :     }
     452             : 
     453             :     /* -------------------------------------------------------------------- */
     454             :     /*      Try to get GCPs, in lat/longs                     .             */
     455             :     /* -------------------------------------------------------------------- */
     456           1 :     nGCPCount = 0;
     457           1 :     pasGCPList = static_cast<GDAL_GCP *>(CPLCalloc(sizeof(GDAL_GCP), 5));
     458             : 
     459           1 :     if (MFF2version > 1.0)
     460             :     {
     461           1 :         ProcessGeorefGCP(papszGeoref, "top_left", 0, 0);
     462           1 :         ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize(), 0);
     463           1 :         ProcessGeorefGCP(papszGeoref, "bottom_left", 0, GetRasterYSize());
     464           1 :         ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize(),
     465           1 :                          GetRasterYSize());
     466           1 :         ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
     467           1 :                          GetRasterYSize() / 2.0);
     468             :     }
     469             :     else
     470             :     {
     471           0 :         ProcessGeorefGCP(papszGeoref, "top_left", 0.5, 0.5);
     472           0 :         ProcessGeorefGCP(papszGeoref, "top_right", GetRasterXSize() - 0.5, 0.5);
     473           0 :         ProcessGeorefGCP(papszGeoref, "bottom_left", 0.5,
     474           0 :                          GetRasterYSize() - 0.5);
     475           0 :         ProcessGeorefGCP(papszGeoref, "bottom_right", GetRasterXSize() - 0.5,
     476           0 :                          GetRasterYSize() - 0.5);
     477           0 :         ProcessGeorefGCP(papszGeoref, "centre", GetRasterXSize() / 2.0,
     478           0 :                          GetRasterYSize() / 2.0);
     479             :     }
     480             : 
     481           1 :     if (nGCPCount == 0)
     482             :     {
     483           0 :         CPLFree(pasGCPList);
     484           0 :         pasGCPList = nullptr;
     485             :     }
     486             : 
     487             :     /* -------------------------------------------------------------------- */
     488             :     /*      Do we have a recognised projection?                             */
     489             :     /* -------------------------------------------------------------------- */
     490           1 :     const char *pszProjName = CSLFetchNameValue(papszGeoref, "projection.name");
     491             :     const char *pszOriginLong =
     492           1 :         CSLFetchNameValue(papszGeoref, "projection.origin_longitude");
     493             :     const char *pszSpheroidName =
     494           1 :         CSLFetchNameValue(papszGeoref, "spheroid.name");
     495             : 
     496           2 :     if (pszSpheroidName != nullptr &&
     497           1 :         hkvEllipsoids->SpheroidInList(pszSpheroidName))
     498             :     {
     499             : #if 0
     500             :       // TODO(schwehr): Enable in trunk after 2.1 branch and fix.
     501             :       // Breaks tests on some platforms.
     502             :       CPLError( CE_Failure, CPLE_AppDefined,
     503             :                 "Unrecognized ellipsoid.  Not handled.  "
     504             :                 "Spheroid name not in spheroid list: '%s'",
     505             :                 pszSpheroidName );
     506             : #endif
     507             :         // Why were eq_radius and inv_flattening never used?
     508             :         // eq_radius = hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName);
     509             :         // inv_flattening =
     510             :         //     hkvEllipsoids->GetSpheroidInverseFlattening(pszSpheroidName);
     511             :     }
     512           0 :     else if (pszProjName != nullptr)
     513             :     {
     514           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     515             :                  "Unrecognized ellipsoid.  Not handled.");
     516             :         // TODO(schwehr): This error is was never what was happening.
     517             :         // CPLError( CE_Warning, CPLE_AppDefined,
     518             :         //           "Unrecognized ellipsoid.  Using wgs-84 parameters.");
     519             :         // eq_radius=hkvEllipsoids->GetSpheroidEqRadius("wgs-84"); */
     520             :         // inv_flattening=hkvEllipsoids->GetSpheroidInverseFlattening("wgs-84");
     521             :     }
     522             : 
     523           1 :     if (pszProjName != nullptr && EQUAL(pszProjName, "utm") && nGCPCount == 5)
     524             :     {
     525             :         // int nZone = (int)((CPLAtof(pszOriginLong)+184.5) / 6.0);
     526           1 :         int nZone = 31;  // TODO(schwehr): Where does 31 come from?
     527             : 
     528           1 :         if (pszOriginLong == nullptr)
     529             :         {
     530             :             // If origin not specified, assume 0.0.
     531           0 :             CPLError(
     532             :                 CE_Warning, CPLE_AppDefined,
     533             :                 "No projection origin longitude specified.  Assuming 0.0.");
     534             :         }
     535             :         else
     536             :         {
     537           1 :             nZone = 31 + static_cast<int>(floor(CPLAtof(pszOriginLong) / 6.0));
     538             :         }
     539             : 
     540           2 :         OGRSpatialReference oUTM;
     541             : 
     542           1 :         if (pasGCPList[4].dfGCPY < 0)
     543           0 :             oUTM.SetUTM(nZone, 0);
     544             :         else
     545           1 :             oUTM.SetUTM(nZone, 1);
     546             : 
     547           2 :         OGRSpatialReference oLL;
     548           1 :         oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     549           1 :         if (pszOriginLong != nullptr)
     550             :         {
     551           1 :             oUTM.SetProjParm(SRS_PP_CENTRAL_MERIDIAN, CPLAtof(pszOriginLong));
     552           1 :             oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
     553             :         }
     554             : 
     555           1 :         if ((pszSpheroidName == nullptr) ||
     556           1 :             (EQUAL(pszSpheroidName, "wgs-84")) ||
     557           1 :             (EQUAL(pszSpheroidName, "wgs_84")))
     558             :         {
     559           0 :             oUTM.SetWellKnownGeogCS("WGS84");
     560           0 :             oLL.SetWellKnownGeogCS("WGS84");
     561             :         }
     562             :         else
     563             :         {
     564           1 :             if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
     565             :             {
     566           1 :                 oUTM.SetGeogCS(
     567             :                     "unknown", "unknown", pszSpheroidName,
     568             :                     hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
     569             :                     hkvEllipsoids->GetSpheroidInverseFlattening(
     570             :                         pszSpheroidName));
     571           1 :                 oLL.SetGeogCS(
     572             :                     "unknown", "unknown", pszSpheroidName,
     573             :                     hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
     574             :                     hkvEllipsoids->GetSpheroidInverseFlattening(
     575             :                         pszSpheroidName));
     576             :             }
     577             :             else
     578             :             {
     579           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     580             :                          "Unrecognized ellipsoid.  Using wgs-84 parameters.");
     581           0 :                 oUTM.SetWellKnownGeogCS("WGS84");
     582           0 :                 oLL.SetWellKnownGeogCS("WGS84");
     583             :             }
     584             :         }
     585             : 
     586             :         OGRCoordinateTransformation *poTransform =
     587           1 :             OGRCreateCoordinateTransformation(&oLL, &oUTM);
     588             : 
     589           1 :         bool bSuccess = true;
     590           1 :         if (poTransform == nullptr)
     591             :         {
     592           0 :             CPLErrorReset();
     593           0 :             bSuccess = false;
     594             :         }
     595             : 
     596           1 :         double dfUtmX[5] = {0.0};
     597           1 :         double dfUtmY[5] = {0.0};
     598             : 
     599           1 :         if (poTransform != nullptr)
     600             :         {
     601           6 :             for (int gcp_index = 0; gcp_index < 5; gcp_index++)
     602             :             {
     603           5 :                 dfUtmX[gcp_index] = pasGCPList[gcp_index].dfGCPX;
     604           5 :                 dfUtmY[gcp_index] = pasGCPList[gcp_index].dfGCPY;
     605             : 
     606           5 :                 if (bSuccess && !poTransform->Transform(1, &(dfUtmX[gcp_index]),
     607             :                                                         &(dfUtmY[gcp_index])))
     608           0 :                     bSuccess = false;
     609             :             }
     610             :         }
     611             : 
     612           1 :         if (bSuccess)
     613             :         {
     614             :             // Update GCPS to proper projection.
     615           6 :             for (int gcp_index = 0; gcp_index < 5; gcp_index++)
     616             :             {
     617           5 :                 pasGCPList[gcp_index].dfGCPX = dfUtmX[gcp_index];
     618           5 :                 pasGCPList[gcp_index].dfGCPY = dfUtmY[gcp_index];
     619             :             }
     620             : 
     621           1 :             m_oGCPSRS = oUTM;
     622             : 
     623           2 :             bool transform_ok = CPL_TO_BOOL(
     624           1 :                 GDALGCPsToGeoTransform(5, pasGCPList, m_gt.data(), 0));
     625             : 
     626           1 :             if (!transform_ok)
     627             :             {
     628             :                 // Transform may not be sufficient in all cases (slant range
     629             :                 // projection).
     630           0 :                 m_gt = GDALGeoTransform();
     631           0 :                 m_oGCPSRS.Clear();
     632             :             }
     633             :             else
     634             :             {
     635           1 :                 m_oSRS = std::move(oUTM);
     636             :             }
     637             :         }
     638             : 
     639           1 :         if (poTransform != nullptr)
     640           2 :             delete poTransform;
     641             :     }
     642           0 :     else if (pszProjName != nullptr && nGCPCount == 5)
     643             :     {
     644           0 :         OGRSpatialReference oLL;
     645           0 :         oLL.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     646             : 
     647           0 :         if (pszOriginLong != nullptr)
     648             :         {
     649           0 :             oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN, CPLAtof(pszOriginLong));
     650             :         }
     651             : 
     652           0 :         if (pszSpheroidName == nullptr ||
     653           0 :             EQUAL(pszSpheroidName, "wgs-84") ||  // Dash.
     654           0 :             EQUAL(pszSpheroidName, "wgs_84"))    // Underscore.
     655             :         {
     656           0 :             oLL.SetWellKnownGeogCS("WGS84");
     657             :         }
     658             :         else
     659             :         {
     660           0 :             if (hkvEllipsoids->SpheroidInList(pszSpheroidName))
     661             :             {
     662           0 :                 oLL.SetGeogCS(
     663             :                     "", "", pszSpheroidName,
     664             :                     hkvEllipsoids->GetSpheroidEqRadius(pszSpheroidName),
     665             :                     hkvEllipsoids->GetSpheroidInverseFlattening(
     666             :                         pszSpheroidName));
     667             :             }
     668             :             else
     669             :             {
     670           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     671             :                          "Unrecognized ellipsoid.  "
     672             :                          "Using wgs-84 parameters.");
     673           0 :                 oLL.SetWellKnownGeogCS("WGS84");
     674             :             }
     675             :         }
     676             : 
     677             :         const bool transform_ok =
     678           0 :             CPL_TO_BOOL(GDALGCPsToGeoTransform(5, pasGCPList, m_gt.data(), 0));
     679             : 
     680           0 :         m_oSRS.Clear();
     681             : 
     682           0 :         if (!transform_ok)
     683             :         {
     684           0 :             m_gt = GDALGeoTransform();
     685             :         }
     686             :         else
     687             :         {
     688           0 :             m_oSRS = oLL;
     689             :         }
     690             : 
     691           0 :         m_oGCPSRS = std::move(oLL);
     692             :     }
     693             : 
     694           1 :     delete hkvEllipsoids;
     695             : }
     696             : 
     697             : /************************************************************************/
     698             : /*                                Open()                                */
     699             : /************************************************************************/
     700             : 
     701       34417 : GDALDataset *HKVDataset::Open(GDALOpenInfo *poOpenInfo)
     702             : 
     703             : {
     704             :     /* -------------------------------------------------------------------- */
     705             :     /*      We assume the dataset is passed as a directory.  Check for      */
     706             :     /*      an attrib and blob file as a minimum.                           */
     707             :     /* -------------------------------------------------------------------- */
     708       34417 :     if (!poOpenInfo->bIsDirectory)
     709       34060 :         return nullptr;
     710             : 
     711             :     std::string osFilename =
     712         714 :         CPLFormFilenameSafe(poOpenInfo->pszFilename, "image_data", nullptr);
     713             :     VSIStatBuf sStat;
     714         357 :     if (VSIStat(osFilename.c_str(), &sStat) != 0)
     715             :         osFilename =
     716         356 :             CPLFormFilenameSafe(poOpenInfo->pszFilename, "blob", nullptr);
     717         357 :     if (VSIStat(osFilename.c_str(), &sStat) != 0)
     718         356 :         return nullptr;
     719             : 
     720             :     osFilename =
     721           1 :         CPLFormFilenameSafe(poOpenInfo->pszFilename, "attrib", nullptr);
     722           1 :     if (VSIStat(osFilename.c_str(), &sStat) != 0)
     723           0 :         return nullptr;
     724             : 
     725             :     /* -------------------------------------------------------------------- */
     726             :     /*      Load the attrib file, and boil white space away from around     */
     727             :     /*      the equal sign.                                                 */
     728             :     /* -------------------------------------------------------------------- */
     729           1 :     char **papszAttrib = CSLLoad(osFilename.c_str());
     730           1 :     if (papszAttrib == nullptr)
     731           0 :         return nullptr;
     732             : 
     733          10 :     for (int i = 0; papszAttrib[i] != nullptr; i++)
     734             :     {
     735           9 :         int iDst = 0;
     736           9 :         char *pszLine = papszAttrib[i];
     737             : 
     738         252 :         for (int iSrc = 0; pszLine[iSrc] != '\0'; iSrc++)
     739             :         {
     740         243 :             if (pszLine[iSrc] != ' ')
     741             :             {
     742         211 :                 pszLine[iDst++] = pszLine[iSrc];
     743             :             }
     744             :         }
     745           9 :         pszLine[iDst] = '\0';
     746             :     }
     747             : 
     748             :     /* -------------------------------------------------------------------- */
     749             :     /*      Create a corresponding GDALDataset.                             */
     750             :     /* -------------------------------------------------------------------- */
     751           2 :     auto poDS = std::make_unique<HKVDataset>();
     752             : 
     753           1 :     poDS->pszPath = CPLStrdup(poOpenInfo->pszFilename);
     754           1 :     poDS->papszAttrib = papszAttrib;
     755             : 
     756           1 :     poDS->eAccess = poOpenInfo->eAccess;
     757             : 
     758             :     /* -------------------------------------------------------------------- */
     759             :     /*      Set some dataset wide information.                              */
     760             :     /* -------------------------------------------------------------------- */
     761           1 :     bool bNative = false;
     762           1 :     bool bComplex = false;
     763           1 :     int nRawBands = 0;
     764             : 
     765           2 :     if (CSLFetchNameValue(papszAttrib, "extent.cols") == nullptr ||
     766           1 :         CSLFetchNameValue(papszAttrib, "extent.rows") == nullptr)
     767             :     {
     768           0 :         return nullptr;
     769             :     }
     770             : 
     771           1 :     poDS->nRasterXSize = atoi(CSLFetchNameValue(papszAttrib, "extent.cols"));
     772           1 :     poDS->nRasterYSize = atoi(CSLFetchNameValue(papszAttrib, "extent.rows"));
     773             : 
     774           1 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     775             :     {
     776           0 :         return nullptr;
     777             :     }
     778             : 
     779           1 :     const char *pszValue = CSLFetchNameValue(papszAttrib, "pixel.order");
     780           1 :     if (pszValue == nullptr)
     781           0 :         bNative = true;
     782             :     else
     783             :     {
     784             : #ifdef CPL_MSB
     785             :         bNative = strstr(pszValue, "*msbf") != NULL;
     786             : #else
     787           1 :         bNative = strstr(pszValue, "*lsbf") != nullptr;
     788             : #endif
     789             :     }
     790             : 
     791           1 :     bool bNoDataSet = false;
     792           1 :     double dfNoDataValue = 0.0;
     793           1 :     pszValue = CSLFetchNameValue(papszAttrib, "pixel.no_data");
     794           1 :     if (pszValue != nullptr)
     795             :     {
     796           0 :         bNoDataSet = true;
     797           0 :         dfNoDataValue = CPLAtof(pszValue);
     798             :     }
     799             : 
     800           1 :     pszValue = CSLFetchNameValue(papszAttrib, "channel.enumeration");
     801           1 :     if (pszValue != nullptr)
     802           1 :         nRawBands = atoi(pszValue);
     803             :     else
     804           0 :         nRawBands = 1;
     805             : 
     806           1 :     if (!GDALCheckBandCount(nRawBands, TRUE))
     807             :     {
     808           0 :         return nullptr;
     809             :     }
     810             : 
     811           1 :     pszValue = CSLFetchNameValue(papszAttrib, "pixel.field");
     812           1 :     if (pszValue != nullptr && strstr(pszValue, "*complex") != nullptr)
     813           0 :         bComplex = true;
     814             :     else
     815           1 :         bComplex = false;
     816             : 
     817             :     /* Get the version number, if present (if not, assume old version. */
     818             :     /* Versions differ in their interpretation of corner coordinates.  */
     819             : 
     820           1 :     if (CSLFetchNameValue(papszAttrib, "version") != nullptr)
     821           1 :         poDS->SetVersion(static_cast<float>(
     822           1 :             CPLAtof(CSLFetchNameValue(papszAttrib, "version"))));
     823             :     else
     824           0 :         poDS->SetVersion(1.0);
     825             : 
     826             :     /* -------------------------------------------------------------------- */
     827             :     /*      Figure out the datatype                                         */
     828             :     /* -------------------------------------------------------------------- */
     829           1 :     const char *pszEncoding = CSLFetchNameValue(papszAttrib, "pixel.encoding");
     830           1 :     if (pszEncoding == nullptr)
     831           0 :         pszEncoding = "{ *unsigned }";
     832             : 
     833           1 :     int nSize = 1;
     834           1 :     if (CSLFetchNameValue(papszAttrib, "pixel.size") != nullptr)
     835           1 :         nSize = atoi(CSLFetchNameValue(papszAttrib, "pixel.size")) / 8;
     836             : #if 0
     837             :     int nPseudoBands;
     838             :     if( bComplex )
     839             :         nPseudoBands = 2;
     840             :     else
     841             :         nPseudoBands = 1;
     842             : #endif
     843             : 
     844             :     GDALDataType eType;
     845           1 :     if (nSize == 1)
     846           1 :         eType = GDT_Byte;
     847           0 :     else if (nSize == 2 && strstr(pszEncoding, "*unsigned") != nullptr)
     848           0 :         eType = GDT_UInt16;
     849           0 :     else if (nSize == 4 && bComplex)
     850           0 :         eType = GDT_CInt16;
     851           0 :     else if (nSize == 2)
     852           0 :         eType = GDT_Int16;
     853           0 :     else if (nSize == 4 && strstr(pszEncoding, "*unsigned") != nullptr)
     854           0 :         eType = GDT_UInt32;
     855           0 :     else if (nSize == 8 && strstr(pszEncoding, "*two") != nullptr && bComplex)
     856           0 :         eType = GDT_CInt32;
     857           0 :     else if (nSize == 4 && strstr(pszEncoding, "*two") != nullptr)
     858           0 :         eType = GDT_Int32;
     859           0 :     else if (nSize == 8 && bComplex)
     860           0 :         eType = GDT_CFloat32;
     861           0 :     else if (nSize == 4)
     862           0 :         eType = GDT_Float32;
     863           0 :     else if (nSize == 16 && bComplex)
     864           0 :         eType = GDT_CFloat64;
     865           0 :     else if (nSize == 8)
     866           0 :         eType = GDT_Float64;
     867             :     else
     868             :     {
     869           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     870             :                  "Unsupported pixel data type in %s.\n"
     871             :                  "pixel.size=%d pixel.encoding=%s",
     872           0 :                  poDS->pszPath, nSize, pszEncoding);
     873           0 :         return nullptr;
     874             :     }
     875             : 
     876             :     /* -------------------------------------------------------------------- */
     877             :     /*      Open the blob file.                                             */
     878             :     /* -------------------------------------------------------------------- */
     879           1 :     osFilename = CPLFormFilenameSafe(poDS->pszPath, "image_data", nullptr);
     880           1 :     if (VSIStat(osFilename.c_str(), &sStat) != 0)
     881           0 :         osFilename = CPLFormFilenameSafe(poDS->pszPath, "blob", nullptr);
     882           1 :     if (poOpenInfo->eAccess == GA_ReadOnly)
     883             :     {
     884           1 :         poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb");
     885           1 :         if (poDS->fpBlob == nullptr)
     886             :         {
     887           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     888             :                      "Unable to open file %s for read access.",
     889             :                      osFilename.c_str());
     890           0 :             return nullptr;
     891             :         }
     892             :     }
     893             :     else
     894             :     {
     895           0 :         poDS->fpBlob = VSIFOpenL(osFilename.c_str(), "rb+");
     896           0 :         if (poDS->fpBlob == nullptr)
     897             :         {
     898           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     899             :                      "Unable to open file %s for update access.",
     900             :                      osFilename.c_str());
     901           0 :             return nullptr;
     902             :         }
     903             :     }
     904             : 
     905             :     /* -------------------------------------------------------------------- */
     906             :     /*      Build the overview filename, as blob file = "_ovr".             */
     907             :     /* -------------------------------------------------------------------- */
     908           2 :     std::string osOvrFilename(osFilename);
     909           1 :     osOvrFilename += "_ovr";
     910             : 
     911             :     /* -------------------------------------------------------------------- */
     912             :     /*      Define the bands.                                               */
     913             :     /* -------------------------------------------------------------------- */
     914           1 :     const int nPixelOffset = nRawBands * nSize;
     915           1 :     const int nLineOffset = nPixelOffset * poDS->GetRasterXSize();
     916           1 :     int nOffset = 0;
     917             : 
     918           2 :     for (int iRawBand = 0; iRawBand < nRawBands; iRawBand++)
     919             :     {
     920             :         auto poBand = std::make_unique<HKVRasterBand>(
     921           1 :             poDS.get(), poDS->GetRasterCount() + 1, poDS->fpBlob, nOffset,
     922           1 :             nPixelOffset, nLineOffset, eType, bNative);
     923           1 :         if (!poBand->IsValid())
     924           0 :             return nullptr;
     925             : 
     926           1 :         if (bNoDataSet)
     927           0 :             poBand->SetNoDataValue(dfNoDataValue);
     928           1 :         poDS->SetBand(poDS->GetRasterCount() + 1, std::move(poBand));
     929           1 :         nOffset += GDALGetDataTypeSizeBytes(eType);
     930             :     }
     931             : 
     932           1 :     poDS->eRasterType = eType;
     933             : 
     934             :     /* -------------------------------------------------------------------- */
     935             :     /*      Process the georef file if there is one.                        */
     936             :     /* -------------------------------------------------------------------- */
     937           1 :     osFilename = CPLFormFilenameSafe(poDS->pszPath, "georef", nullptr);
     938           1 :     if (VSIStat(osFilename.c_str(), &sStat) == 0)
     939           1 :         poDS->ProcessGeoref(osFilename.c_str());
     940             : 
     941             :     /* -------------------------------------------------------------------- */
     942             :     /*      Initialize any PAM information.                                 */
     943             :     /* -------------------------------------------------------------------- */
     944           1 :     poDS->SetDescription(osOvrFilename.c_str());
     945           1 :     poDS->TryLoadXML();
     946             : 
     947             :     /* -------------------------------------------------------------------- */
     948             :     /*      Handle overviews.                                               */
     949             :     /* -------------------------------------------------------------------- */
     950           1 :     poDS->oOvManager.Initialize(poDS.get(), osOvrFilename.c_str(), nullptr,
     951             :                                 TRUE);
     952             : 
     953           1 :     return poDS.release();
     954             : }
     955             : 
     956             : /************************************************************************/
     957             : /*                         GDALRegister_HKV()                           */
     958             : /************************************************************************/
     959             : 
     960        2038 : void GDALRegister_HKV()
     961             : 
     962             : {
     963        2038 :     if (GDALGetDriverByName("MFF2") != nullptr)
     964         283 :         return;
     965             : 
     966        1755 :     GDALDriver *poDriver = new GDALDriver();
     967             : 
     968        1755 :     poDriver->SetDescription("MFF2");
     969        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     970        1755 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Vexcel MFF2 (HKV) Raster");
     971        1755 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/mff2.html");
     972             : 
     973        1755 :     poDriver->pfnOpen = HKVDataset::Open;
     974             : 
     975        1755 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     976             : }

Generated by: LCOV version 1.14