• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.33
/frmts/map/mapdataset.cpp
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
    RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
×
67
    {
68
        return poBaseBand;
×
69
    }
70

71
  public:
72
    explicit MAPWrapperRasterBand(GDALRasterBand *poBaseBandIn)
×
73
    {
×
74
        this->poBaseBand = poBaseBandIn;
×
75
        eDataType = poBaseBand->GetRasterDataType();
×
76
        poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
×
77
    }
×
78

79
    ~MAPWrapperRasterBand()
×
80
    {
×
81
    }
×
82
};
83

84
/************************************************************************/
85
/* ==================================================================== */
86
/*                             MAPDataset                               */
87
/* ==================================================================== */
88
/************************************************************************/
89

90
MAPDataset::MAPDataset()
×
91
    : poImageDS(nullptr), bGeoTransformValid(false), nGCPCount(0),
92
      pasGCPList(nullptr), poNeatLine(nullptr)
×
93
{
94
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
95
    adfGeoTransform[0] = 0.0;
×
96
    adfGeoTransform[1] = 1.0;
×
97
    adfGeoTransform[2] = 0.0;
×
98
    adfGeoTransform[3] = 0.0;
×
99
    adfGeoTransform[4] = 0.0;
×
100
    adfGeoTransform[5] = 1.0;
×
101
}
×
102

103
/************************************************************************/
104
/*                            ~MAPDataset()                             */
105
/************************************************************************/
106

107
MAPDataset::~MAPDataset()
×
108

109
{
110
    if (poImageDS != nullptr)
×
111
    {
112
        GDALClose(poImageDS);
×
113
        poImageDS = nullptr;
×
114
    }
115

116
    if (nGCPCount)
×
117
    {
118
        GDALDeinitGCPs(nGCPCount, pasGCPList);
×
119
        CPLFree(pasGCPList);
×
120
    }
121

122
    if (poNeatLine != nullptr)
×
123
    {
124
        delete poNeatLine;
×
125
        poNeatLine = nullptr;
×
126
    }
127
}
×
128

129
/************************************************************************/
130
/*                       CloseDependentDatasets()                       */
131
/************************************************************************/
132

133
int MAPDataset::CloseDependentDatasets()
×
134
{
135
    int bRet = GDALDataset::CloseDependentDatasets();
×
136
    if (poImageDS != nullptr)
×
137
    {
138
        GDALClose(poImageDS);
×
139
        poImageDS = nullptr;
×
140
        bRet = TRUE;
×
141
    }
142
    return bRet;
×
143
}
144

145
/************************************************************************/
146
/*                              Identify()                              */
147
/************************************************************************/
148

149
int MAPDataset::Identify(GDALOpenInfo *poOpenInfo)
53,215✔
150

151
{
152
    if (poOpenInfo->nHeaderBytes < 200 ||
57,144✔
153
        !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MAP"))
3,929✔
154
        return FALSE;
53,216✔
155

156
    if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
×
157
               "OziExplorer Map Data File") == nullptr)
158
        return FALSE;
×
159

160
    return TRUE;
×
161
}
162

163
/************************************************************************/
164
/*                                Open()                                */
165
/************************************************************************/
166

167
GDALDataset *MAPDataset::Open(GDALOpenInfo *poOpenInfo)
×
168
{
169
    if (!Identify(poOpenInfo))
×
170
        return nullptr;
×
171

172
    /* -------------------------------------------------------------------- */
173
    /*      Confirm the requested access is supported.                      */
174
    /* -------------------------------------------------------------------- */
175
    if (poOpenInfo->eAccess == GA_Update)
×
176
    {
177
        CPLError(CE_Failure, CPLE_NotSupported,
×
178
                 "The MAP driver does not support update access to existing"
179
                 " datasets.\n");
180
        return nullptr;
×
181
    }
182

183
    /* -------------------------------------------------------------------- */
184
    /*      Create a corresponding GDALDataset.                             */
185
    /* -------------------------------------------------------------------- */
186

187
    MAPDataset *poDS = new MAPDataset();
×
188

189
    /* -------------------------------------------------------------------- */
190
    /*      Try to load and parse the .MAP file.                            */
191
    /* -------------------------------------------------------------------- */
192

193
    char *pszWKT = nullptr;
×
194
    bool bOziFileOK = CPL_TO_BOOL(
×
195
        GDALLoadOziMapFile(poOpenInfo->pszFilename, poDS->adfGeoTransform,
×
196
                           &pszWKT, &poDS->nGCPCount, &poDS->pasGCPList));
197
    if (pszWKT)
×
198
    {
199
        poDS->m_oSRS.importFromWkt(pszWKT);
×
200
        CPLFree(pszWKT);
×
201
    }
202

203
    if (bOziFileOK && poDS->nGCPCount == 0)
×
204
        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
    char **papszLines = CSLLoad2(poOpenInfo->pszFilename, 200, 200, nullptr);
×
211

212
    if (!papszLines)
×
213
    {
214
        delete poDS;
×
215
        return nullptr;
×
216
    }
217

218
    const int nLines = CSLCount(papszLines);
×
219
    if (nLines < 3)
×
220
    {
221
        delete poDS;
×
222
        CSLDestroy(papszLines);
×
223
        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
    poDS->osImgFilename = papszLines[2];
×
231

232
    const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
×
233
    if (CPLIsFilenameRelative(poDS->osImgFilename))
×
234
    {
235
        poDS->osImgFilename =
236
            CPLFormCIFilename(osPath, poDS->osImgFilename, nullptr);
×
237
    }
238
    else
239
    {
240
        VSIStatBufL sStat;
241
        if (VSIStatL(poDS->osImgFilename, &sStat) != 0)
×
242
        {
243
            poDS->osImgFilename = CPLGetFilename(poDS->osImgFilename);
×
244
            poDS->osImgFilename =
245
                CPLFormCIFilename(osPath, poDS->osImgFilename, nullptr);
×
246
        }
247
    }
248

249
    /* -------------------------------------------------------------------- */
250
    /*      Try and open the file.                                          */
251
    /* -------------------------------------------------------------------- */
252
    poDS->poImageDS =
×
253
        GDALDataset::FromHandle(GDALOpen(poDS->osImgFilename, GA_ReadOnly));
×
254
    if (poDS->poImageDS == nullptr || poDS->poImageDS->GetRasterCount() == 0)
×
255
    {
256
        CSLDestroy(papszLines);
×
257
        delete poDS;
×
258
        return nullptr;
×
259
    }
260

261
    /* -------------------------------------------------------------------- */
262
    /*      Attach the bands.                                               */
263
    /* -------------------------------------------------------------------- */
264
    poDS->nRasterXSize = poDS->poImageDS->GetRasterXSize();
×
265
    poDS->nRasterYSize = poDS->poImageDS->GetRasterYSize();
×
266
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
×
267
    {
268
        CSLDestroy(papszLines);
×
269
        GDALClose(poDS->poImageDS);
×
270
        delete poDS;
×
271
        return nullptr;
×
272
    }
273

274
    for (int iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++)
×
275
        poDS->SetBand(iBand, new MAPWrapperRasterBand(
×
276
                                 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
    bool bNeatLine = false;
×
284
    for (int iLine = 10; iLine < nLines; iLine++)
×
285
    {
286
        if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
×
287
        {
288
            char **papszTok =
289
                CSLTokenizeString2(papszLines[iLine], ",",
×
290
                                   CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
291

292
            if (CSLCount(papszTok) != 4)
×
293
            {
294
                CSLDestroy(papszTok);
×
295
                continue;
×
296
            }
297

298
            const int x = atoi(papszTok[2]);
×
299
            const int y = atoi(papszTok[3]);
×
300
            if ((x != 0 && x != poDS->nRasterXSize) ||
×
301
                (y != 0 && y != poDS->nRasterYSize))
×
302
            {
303
                bNeatLine = true;
×
304
                CSLDestroy(papszTok);
×
305
                break;
×
306
            }
307
            CSLDestroy(papszTok);
×
308
        }
309
    }
310

311
    /* Create and fill the neatline polygon */
312
    if (bNeatLine)
×
313
    {
314
        poDS->poNeatLine =
×
315
            new OGRPolygon(); /* Create a polygon to store the neatline */
×
316
        OGRLinearRing *poRing = new OGRLinearRing();
×
317

318
        if (poDS->bGeoTransformValid) /* Compute the projected coordinates of
×
319
                                         the corners */
320
        {
321
            for (int iLine = 10; iLine < nLines; iLine++)
×
322
            {
323
                if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
×
324
                {
325
                    char **papszTok = CSLTokenizeString2(
×
326
                        papszLines[iLine], ",",
×
327
                        CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
328

329
                    if (CSLCount(papszTok) != 4)
×
330
                    {
331
                        CSLDestroy(papszTok);
×
332
                        continue;
×
333
                    }
334

335
                    const double x = CPLAtofM(papszTok[2]);
×
336
                    const double y = CPLAtofM(papszTok[3]);
×
337
                    const double X = poDS->adfGeoTransform[0] +
×
338
                                     x * poDS->adfGeoTransform[1] +
×
339
                                     y * poDS->adfGeoTransform[2];
×
340
                    const double Y = poDS->adfGeoTransform[3] +
×
341
                                     x * poDS->adfGeoTransform[4] +
×
342
                                     y * poDS->adfGeoTransform[5];
×
343
                    poRing->addPoint(X, Y);
×
344
                    CPLDebug("CORNER MMPXY", "%f, %f, %f, %f", x, y, X, Y);
×
345
                    CSLDestroy(papszTok);
×
346
                }
347
            }
348
        }
349
        else /* Convert the geographic coordinates to projected coordinates */
350
        {
351
            OGRCoordinateTransformation *poTransform = nullptr;
×
352
            if (!poDS->m_oSRS.IsEmpty())
×
353
            {
354
                OGRSpatialReference *poLongLat = poDS->m_oSRS.CloneGeogCS();
×
355
                if (poLongLat)
×
356
                {
357
                    poLongLat->SetAxisMappingStrategy(
×
358
                        OAMS_TRADITIONAL_GIS_ORDER);
359
                    poTransform = OGRCreateCoordinateTransformation(
×
360
                        poLongLat, &poDS->m_oSRS);
×
361
                    delete poLongLat;
×
362
                }
363
            }
364

365
            for (int iLine = 10; iLine < nLines; iLine++)
×
366
            {
367
                if (STARTS_WITH_CI(papszLines[iLine], "MMPLL,"))
×
368
                {
369
                    CPLDebug("MMPLL", "%s", papszLines[iLine]);
×
370

371
                    char **papszTok = CSLTokenizeString2(
×
372
                        papszLines[iLine], ",",
×
373
                        CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
374

375
                    if (CSLCount(papszTok) != 4)
×
376
                    {
377
                        CSLDestroy(papszTok);
×
378
                        continue;
×
379
                    }
380

381
                    double dfLon = CPLAtofM(papszTok[2]);
×
382
                    double dfLat = CPLAtofM(papszTok[3]);
×
383

384
                    if (poTransform)
×
385
                        poTransform->Transform(1, &dfLon, &dfLat);
×
386
                    poRing->addPoint(dfLon, dfLat);
×
387
                    CPLDebug("CORNER MMPLL", "%f, %f", dfLon, dfLat);
×
388
                    CSLDestroy(papszTok);
×
389
                }
390
            }
391
            if (poTransform)
×
392
                delete poTransform;
×
393
        }
394

395
        poRing->closeRings();
×
396
        poDS->poNeatLine->addRingDirectly(poRing);
×
397

398
        char *pszNeatLineWkt = nullptr;
×
399
        poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
×
400
        CPLDebug("NEATLINE", "%s", pszNeatLineWkt);
×
401
        poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
×
402
        CPLFree(pszNeatLineWkt);
×
403
    }
404

405
    CSLDestroy(papszLines);
×
406

407
    return poDS;
×
408
}
409

410
/************************************************************************/
411
/*                          GetSpatialRef()                             */
412
/************************************************************************/
413

414
const OGRSpatialReference *MAPDataset::GetSpatialRef() const
×
415
{
416
    return (!m_oSRS.IsEmpty() && nGCPCount == 0) ? &m_oSRS : nullptr;
×
417
}
418

419
/************************************************************************/
420
/*                          GetGeoTransform()                           */
421
/************************************************************************/
422

423
CPLErr MAPDataset::GetGeoTransform(double *padfTransform)
×
424

425
{
426
    memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
×
427

428
    return (nGCPCount == 0) ? CE_None : CE_Failure;
×
429
}
430

431
/************************************************************************/
432
/*                           GetGCPCount()                              */
433
/************************************************************************/
434

435
int MAPDataset::GetGCPCount()
×
436
{
437
    return nGCPCount;
×
438
}
439

440
/************************************************************************/
441
/*                          GetGCPSpatialRef()                          */
442
/************************************************************************/
443

444
const OGRSpatialReference *MAPDataset::GetGCPSpatialRef() const
×
445
{
446
    return (!m_oSRS.IsEmpty() && nGCPCount != 0) ? &m_oSRS : nullptr;
×
447
}
448

449
/************************************************************************/
450
/*                               GetGCPs()                              */
451
/************************************************************************/
452

453
const GDAL_GCP *MAPDataset::GetGCPs()
×
454
{
455
    return pasGCPList;
×
456
}
457

458
/************************************************************************/
459
/*                            GetFileList()                             */
460
/************************************************************************/
461

462
char **MAPDataset::GetFileList()
×
463
{
464
    char **papszFileList = GDALDataset::GetFileList();
×
465

466
    papszFileList = CSLAddString(papszFileList, osImgFilename);
×
467

468
    return papszFileList;
×
469
}
470

471
/************************************************************************/
472
/*                          GDALRegister_MAP()                          */
473
/************************************************************************/
474

475
void GDALRegister_MAP()
1,686✔
476

477
{
478
    if (GDALGetDriverByName("MAP") != nullptr)
1,686✔
479
        return;
303✔
480

481
    GDALDriver *poDriver = new GDALDriver();
1,383✔
482

483
    poDriver->SetDescription("MAP");
1,383✔
484
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,383✔
485
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OziExplorer .MAP");
1,383✔
486
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/map.html");
1,383✔
487

488
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,383✔
489

490
    poDriver->pfnOpen = MAPDataset::Open;
1,383✔
491
    poDriver->pfnIdentify = MAPDataset::Identify;
1,383✔
492

493
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,383✔
494
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc