LCOV - code coverage report
Current view: top level - frmts/map - mapdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 16 192 8.3 %
Date: 2024-11-25 13:07:18 Functions: 2 17 11.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OziExplorer .MAP Driver
       4             :  * Purpose:  GDALDataset driver for OziExplorer .MAP files
       5             :  * Author:   Jean-Claude Repetto, <jrepetto at @free dot fr>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012, Jean-Claude Repetto
       9             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_frmts.h"
      15             : #include "gdal_pam.h"
      16             : #include "gdal_proxy.h"
      17             : #include "ogr_geometry.h"
      18             : #include "ogr_spatialref.h"
      19             : 
      20             : /************************************************************************/
      21             : /* ==================================================================== */
      22             : /*                                MAPDataset                            */
      23             : /* ==================================================================== */
      24             : /************************************************************************/
      25             : 
      26             : class MAPDataset final : public GDALDataset
      27             : {
      28             :     GDALDataset *poImageDS;
      29             : 
      30             :     OGRSpatialReference m_oSRS{};
      31             :     int bGeoTransformValid;
      32             :     double adfGeoTransform[6];
      33             :     int nGCPCount;
      34             :     GDAL_GCP *pasGCPList;
      35             :     OGRPolygon *poNeatLine;
      36             :     CPLString osImgFilename;
      37             : 
      38             :   public:
      39             :     MAPDataset();
      40             :     virtual ~MAPDataset();
      41             : 
      42             :     const OGRSpatialReference *GetSpatialRef() const override;
      43             :     virtual CPLErr GetGeoTransform(double *) override;
      44             :     virtual int GetGCPCount() override;
      45             :     const OGRSpatialReference *GetGCPSpatialRef() const override;
      46             :     virtual const GDAL_GCP *GetGCPs() override;
      47             :     virtual char **GetFileList() override;
      48             : 
      49             :     virtual int CloseDependentDatasets() override;
      50             : 
      51             :     static GDALDataset *Open(GDALOpenInfo *);
      52             :     static int Identify(GDALOpenInfo *poOpenInfo);
      53             : };
      54             : 
      55             : /************************************************************************/
      56             : /* ==================================================================== */
      57             : /*                         MAPWrapperRasterBand                         */
      58             : /* ==================================================================== */
      59             : /************************************************************************/
      60             : class MAPWrapperRasterBand final : public GDALProxyRasterBand
      61             : {
      62             :     GDALRasterBand *poBaseBand;
      63             : 
      64             :   protected:
      65             :     virtual GDALRasterBand *
      66           0 :     RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
      67             :     {
      68           0 :         return poBaseBand;
      69             :     }
      70             : 
      71             :   public:
      72           0 :     explicit MAPWrapperRasterBand(GDALRasterBand *poBaseBandIn)
      73           0 :     {
      74           0 :         this->poBaseBand = poBaseBandIn;
      75           0 :         eDataType = poBaseBand->GetRasterDataType();
      76           0 :         poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
      77           0 :     }
      78             : 
      79           0 :     ~MAPWrapperRasterBand()
      80           0 :     {
      81           0 :     }
      82             : };
      83             : 
      84             : /************************************************************************/
      85             : /* ==================================================================== */
      86             : /*                             MAPDataset                               */
      87             : /* ==================================================================== */
      88             : /************************************************************************/
      89             : 
      90           0 : MAPDataset::MAPDataset()
      91             :     : poImageDS(nullptr), bGeoTransformValid(false), nGCPCount(0),
      92           0 :       pasGCPList(nullptr), poNeatLine(nullptr)
      93             : {
      94           0 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      95           0 :     adfGeoTransform[0] = 0.0;
      96           0 :     adfGeoTransform[1] = 1.0;
      97           0 :     adfGeoTransform[2] = 0.0;
      98           0 :     adfGeoTransform[3] = 0.0;
      99           0 :     adfGeoTransform[4] = 0.0;
     100           0 :     adfGeoTransform[5] = 1.0;
     101           0 : }
     102             : 
     103             : /************************************************************************/
     104             : /*                            ~MAPDataset()                             */
     105             : /************************************************************************/
     106             : 
     107           0 : MAPDataset::~MAPDataset()
     108             : 
     109             : {
     110           0 :     if (poImageDS != nullptr)
     111             :     {
     112           0 :         GDALClose(poImageDS);
     113           0 :         poImageDS = nullptr;
     114             :     }
     115             : 
     116           0 :     if (nGCPCount)
     117             :     {
     118           0 :         GDALDeinitGCPs(nGCPCount, pasGCPList);
     119           0 :         CPLFree(pasGCPList);
     120             :     }
     121             : 
     122           0 :     if (poNeatLine != nullptr)
     123             :     {
     124           0 :         delete poNeatLine;
     125           0 :         poNeatLine = nullptr;
     126             :     }
     127           0 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                       CloseDependentDatasets()                       */
     131             : /************************************************************************/
     132             : 
     133           0 : int MAPDataset::CloseDependentDatasets()
     134             : {
     135           0 :     int bRet = GDALDataset::CloseDependentDatasets();
     136           0 :     if (poImageDS != nullptr)
     137             :     {
     138           0 :         GDALClose(poImageDS);
     139           0 :         poImageDS = nullptr;
     140           0 :         bRet = TRUE;
     141             :     }
     142           0 :     return bRet;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                              Identify()                              */
     147             : /************************************************************************/
     148             : 
     149       52815 : int MAPDataset::Identify(GDALOpenInfo *poOpenInfo)
     150             : 
     151             : {
     152       56656 :     if (poOpenInfo->nHeaderBytes < 200 ||
     153        3841 :         !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MAP"))
     154       52815 :         return FALSE;
     155             : 
     156           0 :     if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     157             :                "OziExplorer Map Data File") == nullptr)
     158           0 :         return FALSE;
     159             : 
     160           0 :     return TRUE;
     161             : }
     162             : 
     163             : /************************************************************************/
     164             : /*                                Open()                                */
     165             : /************************************************************************/
     166             : 
     167           0 : GDALDataset *MAPDataset::Open(GDALOpenInfo *poOpenInfo)
     168             : {
     169           0 :     if (!Identify(poOpenInfo))
     170           0 :         return nullptr;
     171             : 
     172             :     /* -------------------------------------------------------------------- */
     173             :     /*      Confirm the requested access is supported.                      */
     174             :     /* -------------------------------------------------------------------- */
     175           0 :     if (poOpenInfo->eAccess == GA_Update)
     176             :     {
     177           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     178             :                  "The MAP driver does not support update access to existing"
     179             :                  " datasets.\n");
     180           0 :         return nullptr;
     181             :     }
     182             : 
     183             :     /* -------------------------------------------------------------------- */
     184             :     /*      Create a corresponding GDALDataset.                             */
     185             :     /* -------------------------------------------------------------------- */
     186             : 
     187           0 :     MAPDataset *poDS = new MAPDataset();
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      Try to load and parse the .MAP file.                            */
     191             :     /* -------------------------------------------------------------------- */
     192             : 
     193           0 :     char *pszWKT = nullptr;
     194           0 :     bool bOziFileOK = CPL_TO_BOOL(
     195           0 :         GDALLoadOziMapFile(poOpenInfo->pszFilename, poDS->adfGeoTransform,
     196             :                            &pszWKT, &poDS->nGCPCount, &poDS->pasGCPList));
     197           0 :     if (pszWKT)
     198             :     {
     199           0 :         poDS->m_oSRS.importFromWkt(pszWKT);
     200           0 :         CPLFree(pszWKT);
     201             :     }
     202             : 
     203           0 :     if (bOziFileOK && poDS->nGCPCount == 0)
     204           0 :         poDS->bGeoTransformValid = TRUE;
     205             : 
     206             :     /* We need to read again the .map file because the GDALLoadOziMapFile
     207             :        function does not returns all required data . An API change is necessary
     208             :        : maybe in GDAL 2.0 ? */
     209             : 
     210           0 :     char **papszLines = CSLLoad2(poOpenInfo->pszFilename, 200, 200, nullptr);
     211             : 
     212           0 :     if (!papszLines)
     213             :     {
     214           0 :         delete poDS;
     215           0 :         return nullptr;
     216             :     }
     217             : 
     218           0 :     const int nLines = CSLCount(papszLines);
     219           0 :     if (nLines < 3)
     220             :     {
     221           0 :         delete poDS;
     222           0 :         CSLDestroy(papszLines);
     223           0 :         return nullptr;
     224             :     }
     225             : 
     226             :     /* -------------------------------------------------------------------- */
     227             :     /*      We need to open the image in order to establish                 */
     228             :     /*      details like the band count and types.                          */
     229             :     /* -------------------------------------------------------------------- */
     230           0 :     poDS->osImgFilename = papszLines[2];
     231             : 
     232           0 :     const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
     233           0 :     if (CPLIsFilenameRelative(poDS->osImgFilename))
     234             :     {
     235             :         poDS->osImgFilename =
     236           0 :             CPLFormCIFilename(osPath, poDS->osImgFilename, nullptr);
     237             :     }
     238             :     else
     239             :     {
     240             :         VSIStatBufL sStat;
     241           0 :         if (VSIStatL(poDS->osImgFilename, &sStat) != 0)
     242             :         {
     243           0 :             poDS->osImgFilename = CPLGetFilename(poDS->osImgFilename);
     244             :             poDS->osImgFilename =
     245           0 :                 CPLFormCIFilename(osPath, poDS->osImgFilename, nullptr);
     246             :         }
     247             :     }
     248             : 
     249             :     /* -------------------------------------------------------------------- */
     250             :     /*      Try and open the file.                                          */
     251             :     /* -------------------------------------------------------------------- */
     252           0 :     poDS->poImageDS =
     253           0 :         GDALDataset::FromHandle(GDALOpen(poDS->osImgFilename, GA_ReadOnly));
     254           0 :     if (poDS->poImageDS == nullptr || poDS->poImageDS->GetRasterCount() == 0)
     255             :     {
     256           0 :         CSLDestroy(papszLines);
     257           0 :         delete poDS;
     258           0 :         return nullptr;
     259             :     }
     260             : 
     261             :     /* -------------------------------------------------------------------- */
     262             :     /*      Attach the bands.                                               */
     263             :     /* -------------------------------------------------------------------- */
     264           0 :     poDS->nRasterXSize = poDS->poImageDS->GetRasterXSize();
     265           0 :     poDS->nRasterYSize = poDS->poImageDS->GetRasterYSize();
     266           0 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     267             :     {
     268           0 :         CSLDestroy(papszLines);
     269           0 :         GDALClose(poDS->poImageDS);
     270           0 :         delete poDS;
     271           0 :         return nullptr;
     272             :     }
     273             : 
     274           0 :     for (int iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++)
     275           0 :         poDS->SetBand(iBand, new MAPWrapperRasterBand(
     276           0 :                                  poDS->poImageDS->GetRasterBand(iBand)));
     277             : 
     278             :     /* -------------------------------------------------------------------- */
     279             :     /*      Add the neatline/cutline, if required                           */
     280             :     /* -------------------------------------------------------------------- */
     281             : 
     282             :     /* First, we need to check if it is necessary to define a neatline */
     283           0 :     bool bNeatLine = false;
     284           0 :     for (int iLine = 10; iLine < nLines; iLine++)
     285             :     {
     286           0 :         if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
     287             :         {
     288             :             char **papszTok =
     289           0 :                 CSLTokenizeString2(papszLines[iLine], ",",
     290             :                                    CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     291             : 
     292           0 :             if (CSLCount(papszTok) != 4)
     293             :             {
     294           0 :                 CSLDestroy(papszTok);
     295           0 :                 continue;
     296             :             }
     297             : 
     298           0 :             const int x = atoi(papszTok[2]);
     299           0 :             const int y = atoi(papszTok[3]);
     300           0 :             if ((x != 0 && x != poDS->nRasterXSize) ||
     301           0 :                 (y != 0 && y != poDS->nRasterYSize))
     302             :             {
     303           0 :                 bNeatLine = true;
     304           0 :                 CSLDestroy(papszTok);
     305           0 :                 break;
     306             :             }
     307           0 :             CSLDestroy(papszTok);
     308             :         }
     309             :     }
     310             : 
     311             :     /* Create and fill the neatline polygon */
     312           0 :     if (bNeatLine)
     313             :     {
     314           0 :         poDS->poNeatLine =
     315           0 :             new OGRPolygon(); /* Create a polygon to store the neatline */
     316           0 :         OGRLinearRing *poRing = new OGRLinearRing();
     317             : 
     318           0 :         if (poDS->bGeoTransformValid) /* Compute the projected coordinates of
     319             :                                          the corners */
     320             :         {
     321           0 :             for (int iLine = 10; iLine < nLines; iLine++)
     322             :             {
     323           0 :                 if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
     324             :                 {
     325           0 :                     char **papszTok = CSLTokenizeString2(
     326           0 :                         papszLines[iLine], ",",
     327             :                         CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     328             : 
     329           0 :                     if (CSLCount(papszTok) != 4)
     330             :                     {
     331           0 :                         CSLDestroy(papszTok);
     332           0 :                         continue;
     333             :                     }
     334             : 
     335           0 :                     const double x = CPLAtofM(papszTok[2]);
     336           0 :                     const double y = CPLAtofM(papszTok[3]);
     337           0 :                     const double X = poDS->adfGeoTransform[0] +
     338           0 :                                      x * poDS->adfGeoTransform[1] +
     339           0 :                                      y * poDS->adfGeoTransform[2];
     340           0 :                     const double Y = poDS->adfGeoTransform[3] +
     341           0 :                                      x * poDS->adfGeoTransform[4] +
     342           0 :                                      y * poDS->adfGeoTransform[5];
     343           0 :                     poRing->addPoint(X, Y);
     344           0 :                     CPLDebug("CORNER MMPXY", "%f, %f, %f, %f", x, y, X, Y);
     345           0 :                     CSLDestroy(papszTok);
     346             :                 }
     347             :             }
     348             :         }
     349             :         else /* Convert the geographic coordinates to projected coordinates */
     350             :         {
     351           0 :             OGRCoordinateTransformation *poTransform = nullptr;
     352           0 :             if (!poDS->m_oSRS.IsEmpty())
     353             :             {
     354           0 :                 OGRSpatialReference *poLongLat = poDS->m_oSRS.CloneGeogCS();
     355           0 :                 if (poLongLat)
     356             :                 {
     357           0 :                     poLongLat->SetAxisMappingStrategy(
     358             :                         OAMS_TRADITIONAL_GIS_ORDER);
     359           0 :                     poTransform = OGRCreateCoordinateTransformation(
     360           0 :                         poLongLat, &poDS->m_oSRS);
     361           0 :                     delete poLongLat;
     362             :                 }
     363             :             }
     364             : 
     365           0 :             for (int iLine = 10; iLine < nLines; iLine++)
     366             :             {
     367           0 :                 if (STARTS_WITH_CI(papszLines[iLine], "MMPLL,"))
     368             :                 {
     369           0 :                     CPLDebug("MMPLL", "%s", papszLines[iLine]);
     370             : 
     371           0 :                     char **papszTok = CSLTokenizeString2(
     372           0 :                         papszLines[iLine], ",",
     373             :                         CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     374             : 
     375           0 :                     if (CSLCount(papszTok) != 4)
     376             :                     {
     377           0 :                         CSLDestroy(papszTok);
     378           0 :                         continue;
     379             :                     }
     380             : 
     381           0 :                     double dfLon = CPLAtofM(papszTok[2]);
     382           0 :                     double dfLat = CPLAtofM(papszTok[3]);
     383             : 
     384           0 :                     if (poTransform)
     385           0 :                         poTransform->Transform(1, &dfLon, &dfLat);
     386           0 :                     poRing->addPoint(dfLon, dfLat);
     387           0 :                     CPLDebug("CORNER MMPLL", "%f, %f", dfLon, dfLat);
     388           0 :                     CSLDestroy(papszTok);
     389             :                 }
     390             :             }
     391           0 :             if (poTransform)
     392           0 :                 delete poTransform;
     393             :         }
     394             : 
     395           0 :         poRing->closeRings();
     396           0 :         poDS->poNeatLine->addRingDirectly(poRing);
     397             : 
     398           0 :         char *pszNeatLineWkt = nullptr;
     399           0 :         poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
     400           0 :         CPLDebug("NEATLINE", "%s", pszNeatLineWkt);
     401           0 :         poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
     402           0 :         CPLFree(pszNeatLineWkt);
     403             :     }
     404             : 
     405           0 :     CSLDestroy(papszLines);
     406             : 
     407           0 :     return poDS;
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                          GetSpatialRef()                             */
     412             : /************************************************************************/
     413             : 
     414           0 : const OGRSpatialReference *MAPDataset::GetSpatialRef() const
     415             : {
     416           0 :     return (!m_oSRS.IsEmpty() && nGCPCount == 0) ? &m_oSRS : nullptr;
     417             : }
     418             : 
     419             : /************************************************************************/
     420             : /*                          GetGeoTransform()                           */
     421             : /************************************************************************/
     422             : 
     423           0 : CPLErr MAPDataset::GetGeoTransform(double *padfTransform)
     424             : 
     425             : {
     426           0 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
     427             : 
     428           0 :     return (nGCPCount == 0) ? CE_None : CE_Failure;
     429             : }
     430             : 
     431             : /************************************************************************/
     432             : /*                           GetGCPCount()                              */
     433             : /************************************************************************/
     434             : 
     435           0 : int MAPDataset::GetGCPCount()
     436             : {
     437           0 :     return nGCPCount;
     438             : }
     439             : 
     440             : /************************************************************************/
     441             : /*                          GetGCPSpatialRef()                          */
     442             : /************************************************************************/
     443             : 
     444           0 : const OGRSpatialReference *MAPDataset::GetGCPSpatialRef() const
     445             : {
     446           0 :     return (!m_oSRS.IsEmpty() && nGCPCount != 0) ? &m_oSRS : nullptr;
     447             : }
     448             : 
     449             : /************************************************************************/
     450             : /*                               GetGCPs()                              */
     451             : /************************************************************************/
     452             : 
     453           0 : const GDAL_GCP *MAPDataset::GetGCPs()
     454             : {
     455           0 :     return pasGCPList;
     456             : }
     457             : 
     458             : /************************************************************************/
     459             : /*                            GetFileList()                             */
     460             : /************************************************************************/
     461             : 
     462           0 : char **MAPDataset::GetFileList()
     463             : {
     464           0 :     char **papszFileList = GDALDataset::GetFileList();
     465             : 
     466           0 :     papszFileList = CSLAddString(papszFileList, osImgFilename);
     467             : 
     468           0 :     return papszFileList;
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                          GDALRegister_MAP()                          */
     473             : /************************************************************************/
     474             : 
     475        1595 : void GDALRegister_MAP()
     476             : 
     477             : {
     478        1595 :     if (GDALGetDriverByName("MAP") != nullptr)
     479         302 :         return;
     480             : 
     481        1293 :     GDALDriver *poDriver = new GDALDriver();
     482             : 
     483        1293 :     poDriver->SetDescription("MAP");
     484        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     485        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OziExplorer .MAP");
     486        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/map.html");
     487             : 
     488        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     489             : 
     490        1293 :     poDriver->pfnOpen = MAPDataset::Open;
     491        1293 :     poDriver->pfnIdentify = MAPDataset::Identify;
     492             : 
     493        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     494             : }

Generated by: LCOV version 1.14