LCOV - code coverage report
Current view: top level - frmts/raw - ace2dataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 82 131 62.6 %
Date: 2025-07-09 17:50:03 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ACE2 Driver
       4             :  * Purpose:  Implementation of ACE2 elevation format read support.
       5             :  *           http://tethys.eaprs.cse.dmu.ac.uk/ACE2/shared/documentation
       6             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2011-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_frmts.h"
      15             : #include "ogr_spatialref.h"
      16             : #include "rawdataset.h"
      17             : 
      18             : static const char *const apszCategorySource[] = {
      19             :     "Pure SRTM (above 60deg N pure GLOBE data, below 60S pure ACE [original] "
      20             :     "data)",
      21             :     "SRTM voids filled by interpolation and/or altimeter data",
      22             :     "SRTM data warped using the ERS-1 Geodetic Mission",
      23             :     "SRTM data warped using EnviSat & ERS-2 data",
      24             :     "Mean lake level data derived from Altimetry",
      25             :     "GLOBE/ACE data warped using combined altimetry (only above 60deg N)",
      26             :     "Pure altimetry data (derived from ERS-1 Geodetic Mission, ERS-2 and "
      27             :     "EnviSat data using Delaunay Triangulation",
      28             :     nullptr};
      29             : 
      30             : static const char *const apszCategoryQuality[] = {
      31             :     "Generic - use base datasets",
      32             :     "Accuracy of greater than +/- 16m",
      33             :     "Accuracy between +/- 16m - +/- 10m",
      34             :     "Accuracy between +/-10m - +/-5m",
      35             :     "Accuracy between +/-5m - +/-1m",
      36             :     "Accuracy between +/-1m",
      37             :     nullptr};
      38             : 
      39             : static const char *const apszCategoryConfidence[] = {
      40             :     "No confidence could be derived due to lack of data",
      41             :     "Heights generated by interpolation",
      42             :     "Low confidence",
      43             :     "Low confidence",
      44             :     "Low confidence",
      45             :     "Medium confidence",
      46             :     "Medium confidence",
      47             :     "Medium confidence",
      48             :     "Medium confidence",
      49             :     "Medium confidence",
      50             :     "Medium confidence",
      51             :     "Medium confidence",
      52             :     "Medium confidence",
      53             :     "High confidence",
      54             :     "High confidence",
      55             :     "High confidence",
      56             :     "High confidence",
      57             :     "Inland water confidence",
      58             :     "Inland water confidence",
      59             :     "Inland water confidence",
      60             :     "Inland water confidence",
      61             :     "Inland water confidence",
      62             :     nullptr};
      63             : 
      64             : /************************************************************************/
      65             : /* ==================================================================== */
      66             : /*                             ACE2Dataset                              */
      67             : /* ==================================================================== */
      68             : /************************************************************************/
      69             : 
      70             : class ACE2Dataset final : public GDALPamDataset
      71             : {
      72             :     friend class ACE2RasterBand;
      73             : 
      74             :     OGRSpatialReference m_oSRS{};
      75             :     GDALGeoTransform m_gt{};
      76             : 
      77             :   public:
      78             :     ACE2Dataset();
      79             : 
      80           1 :     const OGRSpatialReference *GetSpatialRef() const override
      81             :     {
      82           1 :         return &m_oSRS;
      83             :     }
      84             : 
      85             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
      86             : 
      87             :     static GDALDataset *Open(GDALOpenInfo *);
      88             :     static int Identify(GDALOpenInfo *);
      89             : };
      90             : 
      91             : /************************************************************************/
      92             : /* ==================================================================== */
      93             : /*                            ACE2RasterBand                            */
      94             : /* ==================================================================== */
      95             : /************************************************************************/
      96             : 
      97             : class ACE2RasterBand final : public RawRasterBand
      98             : {
      99             :   public:
     100             :     ACE2RasterBand(VSILFILE *fpRaw, GDALDataType eDataType, int nXSize,
     101             :                    int nYSize);
     102             : 
     103             :     const char *GetUnitType() override;
     104             :     char **GetCategoryNames() override;
     105             : };
     106             : 
     107             : /************************************************************************/
     108             : /* ==================================================================== */
     109             : /*                             ACE2Dataset                              */
     110             : /* ==================================================================== */
     111             : /************************************************************************/
     112             : 
     113             : /************************************************************************/
     114             : /*                            ACE2Dataset()                             */
     115             : /************************************************************************/
     116             : 
     117           2 : ACE2Dataset::ACE2Dataset()
     118             : {
     119           2 :     m_oSRS.SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
     120           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     121           2 : }
     122             : 
     123             : /************************************************************************/
     124             : /*                          GetGeoTransform()                           */
     125             : /************************************************************************/
     126             : 
     127           1 : CPLErr ACE2Dataset::GetGeoTransform(GDALGeoTransform &gt) const
     128             : 
     129             : {
     130           1 :     gt = m_gt;
     131           1 :     return CE_None;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                          ACE2RasterBand()                            */
     136             : /************************************************************************/
     137             : 
     138           2 : ACE2RasterBand::ACE2RasterBand(VSILFILE *fpRawIn, GDALDataType eDataTypeIn,
     139           2 :                                int nXSize, int nYSize)
     140             :     : RawRasterBand(fpRawIn, 0, GDALGetDataTypeSizeBytes(eDataTypeIn),
     141           4 :                     nXSize * GDALGetDataTypeSizeBytes(eDataTypeIn), eDataTypeIn,
     142           2 :                     CPL_IS_LSB, nXSize, nYSize, RawRasterBand::OwnFP::YES)
     143             : {
     144           2 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                             GetUnitType()                            */
     148             : /************************************************************************/
     149             : 
     150           0 : const char *ACE2RasterBand::GetUnitType()
     151             : {
     152           0 :     if (eDataType == GDT_Float32)
     153           0 :         return "m";
     154             : 
     155           0 :     return "";
     156             : }
     157             : 
     158             : /************************************************************************/
     159             : /*                         GetCategoryNames()                           */
     160             : /************************************************************************/
     161             : 
     162           0 : char **ACE2RasterBand::GetCategoryNames()
     163             : {
     164           0 :     if (eDataType != GDT_Int16)
     165           0 :         return nullptr;
     166             : 
     167           0 :     const char *pszName = poDS->GetDescription();
     168             : 
     169           0 :     if (strstr(pszName, "_SOURCE_"))
     170           0 :         return const_cast<char **>(apszCategorySource);
     171           0 :     if (strstr(pszName, "_QUALITY_"))
     172           0 :         return const_cast<char **>(apszCategoryQuality);
     173           0 :     if (strstr(pszName, "_CONF_"))
     174           0 :         return const_cast<char **>(apszCategoryConfidence);
     175             : 
     176           0 :     return nullptr;
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                             Identify()                               */
     181             : /************************************************************************/
     182             : 
     183       57587 : int ACE2Dataset::Identify(GDALOpenInfo *poOpenInfo)
     184             : 
     185             : {
     186      115169 :     if (!(poOpenInfo->IsExtensionEqualToCI("ACE2") ||
     187       57582 :           strstr(poOpenInfo->pszFilename, ".ACE2.gz") ||
     188       57582 :           strstr(poOpenInfo->pszFilename, ".ace2.gz")))
     189       57583 :         return FALSE;
     190             : 
     191           3 :     return TRUE;
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                                Open()                                */
     196             : /************************************************************************/
     197             : 
     198           2 : GDALDataset *ACE2Dataset::Open(GDALOpenInfo *poOpenInfo)
     199             : 
     200             : {
     201           2 :     if (!Identify(poOpenInfo))
     202           0 :         return nullptr;
     203             : 
     204           4 :     const std::string osBasename = CPLGetBasenameSafe(poOpenInfo->pszFilename);
     205           2 :     const char *pszBasename = osBasename.c_str();
     206             : 
     207           2 :     if (strlen(pszBasename) < 7)
     208           0 :         return nullptr;
     209             : 
     210             :     /* Determine southwest coordinates from filename */
     211             : 
     212             :     /* e.g. 30S120W_5M.ACE2 */
     213           2 :     char pszLatLonValueString[4] = {'\0'};
     214           2 :     memset(pszLatLonValueString, 0, 4);
     215             :     // cppcheck-suppress redundantCopy
     216           2 :     strncpy(pszLatLonValueString, &pszBasename[0], 2);
     217           2 :     int southWestLat = atoi(pszLatLonValueString);
     218           2 :     memset(pszLatLonValueString, 0, 4);
     219             :     // cppcheck-suppress redundantCopy
     220           2 :     strncpy(pszLatLonValueString, &pszBasename[3], 3);
     221           2 :     int southWestLon = atoi(pszLatLonValueString);
     222             : 
     223           2 :     if (pszBasename[2] == 'N' || pszBasename[2] == 'n')
     224             :         /*southWestLat = southWestLat*/;
     225           0 :     else if (pszBasename[2] == 'S' || pszBasename[2] == 's')
     226           0 :         southWestLat = southWestLat * -1;
     227             :     else
     228           0 :         return nullptr;
     229             : 
     230           2 :     if (pszBasename[6] == 'E' || pszBasename[6] == 'e')
     231             :         /*southWestLon = southWestLon*/;
     232           0 :     else if (pszBasename[6] == 'W' || pszBasename[6] == 'w')
     233           0 :         southWestLon = southWestLon * -1;
     234             :     else
     235           0 :         return nullptr;
     236             : 
     237           2 :     GDALDataType eDT = GDT_Unknown;
     238           2 :     if (strstr(pszBasename, "_CONF_") || strstr(pszBasename, "_QUALITY_") ||
     239           2 :         strstr(pszBasename, "_SOURCE_"))
     240           0 :         eDT = GDT_Int16;
     241             :     else
     242           2 :         eDT = GDT_Float32;
     243           2 :     const int nWordSize = GDALGetDataTypeSizeBytes(eDT);
     244             : 
     245             :     VSIStatBufL sStat;
     246           2 :     if (strstr(pszBasename, "_5M"))
     247           2 :         sStat.st_size = 180 * 180 * nWordSize;
     248           0 :     else if (strstr(pszBasename, "_30S"))
     249           0 :         sStat.st_size = 1800 * 1800 * nWordSize;
     250           0 :     else if (strstr(pszBasename, "_9S"))
     251           0 :         sStat.st_size = 6000 * 6000 * nWordSize;
     252           0 :     else if (strstr(pszBasename, "_3S"))
     253           0 :         sStat.st_size = 18000 * 18000 * nWordSize;
     254             :     /* Check file size otherwise */
     255           0 :     else if (VSIStatL(poOpenInfo->pszFilename, &sStat) != 0)
     256             :     {
     257           0 :         return nullptr;
     258             :     }
     259             : 
     260           2 :     int nXSize = 0;
     261           2 :     int nYSize = 0;
     262             : 
     263           2 :     double dfPixelSize = 0;
     264           2 :     if (sStat.st_size == 180 * 180 * nWordSize)
     265             :     {
     266             :         /* 5 minute */
     267           2 :         nXSize = 180;
     268           2 :         nYSize = 180;
     269           2 :         dfPixelSize = 5.0 / 60;
     270             :     }
     271           0 :     else if (sStat.st_size == 1800 * 1800 * nWordSize)
     272             :     {
     273             :         /* 30 s */
     274           0 :         nXSize = 1800;
     275           0 :         nYSize = 1800;
     276           0 :         dfPixelSize = 30.0 / 3600;
     277             :     }
     278           0 :     else if (sStat.st_size == 6000 * 6000 * nWordSize)
     279             :     {
     280             :         /* 9 s */
     281           0 :         nXSize = 6000;
     282           0 :         nYSize = 6000;
     283           0 :         dfPixelSize = 9.0 / 3600;
     284             :     }
     285           0 :     else if (sStat.st_size == 18000 * 18000 * nWordSize)
     286             :     {
     287             :         /* 3 s */
     288           0 :         nXSize = 18000;
     289           0 :         nYSize = 18000;
     290           0 :         dfPixelSize = 3.0 / 3600;
     291             :     }
     292             :     else
     293           0 :         return nullptr;
     294             : 
     295             :     /* -------------------------------------------------------------------- */
     296             :     /*      Open file.                                                      */
     297             :     /* -------------------------------------------------------------------- */
     298             : 
     299           4 :     CPLString osFilename = poOpenInfo->pszFilename;
     300           2 :     if ((strstr(poOpenInfo->pszFilename, ".ACE2.gz") ||
     301           2 :          strstr(poOpenInfo->pszFilename, ".ace2.gz")) &&
     302           0 :         !STARTS_WITH(poOpenInfo->pszFilename, "/vsigzip/"))
     303           0 :         osFilename = "/vsigzip/" + osFilename;
     304             : 
     305           2 :     VSILFILE *fpImage = VSIFOpenL(osFilename, "rb+");
     306           2 :     if (fpImage == nullptr)
     307           0 :         return nullptr;
     308             : 
     309             :     /* -------------------------------------------------------------------- */
     310             :     /*      Create the dataset.                                             */
     311             :     /* -------------------------------------------------------------------- */
     312           4 :     auto poDS = std::make_unique<ACE2Dataset>();
     313             : 
     314           2 :     poDS->nRasterXSize = nXSize;
     315           2 :     poDS->nRasterYSize = nYSize;
     316             : 
     317           2 :     poDS->m_gt[0] = southWestLon;
     318           2 :     poDS->m_gt[1] = dfPixelSize;
     319           2 :     poDS->m_gt[2] = 0.0;
     320           2 :     poDS->m_gt[3] = southWestLat + nYSize * dfPixelSize;
     321           2 :     poDS->m_gt[4] = 0.0;
     322           2 :     poDS->m_gt[5] = -dfPixelSize;
     323             : 
     324             :     /* -------------------------------------------------------------------- */
     325             :     /*      Create band information objects                                 */
     326             :     /* -------------------------------------------------------------------- */
     327             :     auto poBand =
     328           4 :         std::make_unique<ACE2RasterBand>(fpImage, eDT, nXSize, nYSize);
     329           2 :     if (!poBand->IsValid())
     330           0 :         return nullptr;
     331           2 :     poDS->SetBand(1, std::move(poBand));
     332             : 
     333             :     /* -------------------------------------------------------------------- */
     334             :     /*      Initialize any PAM information.                                 */
     335             :     /* -------------------------------------------------------------------- */
     336           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     337           2 :     poDS->TryLoadXML();
     338             : 
     339             :     /* -------------------------------------------------------------------- */
     340             :     /*      Check for overviews.                                            */
     341             :     /* -------------------------------------------------------------------- */
     342           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     343             : 
     344           2 :     return poDS.release();
     345             : }
     346             : 
     347             : /************************************************************************/
     348             : /*                          GDALRegister_ACE2()                         */
     349             : /************************************************************************/
     350             : 
     351        1935 : void GDALRegister_ACE2()
     352             : 
     353             : {
     354        1935 :     if (GDALGetDriverByName("ACE2") != nullptr)
     355         282 :         return;
     356             : 
     357        1653 :     GDALDriver *poDriver = new GDALDriver();
     358             : 
     359        1653 :     poDriver->SetDescription("ACE2");
     360        1653 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     361        1653 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ACE2");
     362        1653 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ace2.html");
     363        1653 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ACE2");
     364        1653 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     365             : 
     366        1653 :     poDriver->pfnOpen = ACE2Dataset::Open;
     367        1653 :     poDriver->pfnIdentify = ACE2Dataset::Identify;
     368             : 
     369        1653 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     370             : }

Generated by: LCOV version 1.14