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