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