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