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

Generated by: LCOV version 1.14