1 : /******************************************************************************
2 : * $Id: tildataset.cpp 25588 2013-01-31 21:09:01Z bishop $
3 : *
4 : * Project: EarthWatch .TIL Driver
5 : * Purpose: Implementation of the TILDataset class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Frank Warmerdam
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 "cpl_string.h"
34 : #include "vrtdataset.h"
35 : #include "cpl_multiproc.h"
36 : #include "cplkeywordparser.h"
37 :
38 : CPL_CVSID("$Id: tildataset.cpp 25588 2013-01-31 21:09:01Z bishop $");
39 :
40 : /************************************************************************/
41 : /* ==================================================================== */
42 : /* TILDataset */
43 : /* ==================================================================== */
44 : /************************************************************************/
45 :
46 : class CPL_DLL TILDataset : public GDALPamDataset
47 : {
48 : VRTDataset *poVRTDS;
49 : std::vector<GDALDataset *> apoTileDS;
50 :
51 : CPLString osRPBFilename;
52 : CPLString osIMDFilename;
53 :
54 : protected:
55 : virtual int CloseDependentDatasets();
56 :
57 : public:
58 : TILDataset();
59 : ~TILDataset();
60 :
61 : virtual char **GetFileList(void);
62 :
63 : static GDALDataset *Open( GDALOpenInfo * );
64 : static int Identify( GDALOpenInfo *poOpenInfo );
65 : };
66 :
67 : /************************************************************************/
68 : /* ==================================================================== */
69 : /* TILRasterBand */
70 : /* ==================================================================== */
71 : /************************************************************************/
72 :
73 : class TILRasterBand : public GDALPamRasterBand
74 : {
75 : friend class TILDataset;
76 :
77 : VRTSourcedRasterBand *poVRTBand;
78 :
79 : public:
80 : TILRasterBand( TILDataset *, int, VRTSourcedRasterBand * );
81 2 : virtual ~TILRasterBand() {};
82 :
83 : virtual CPLErr IReadBlock( int, int, void * );
84 : virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
85 : void *, int, int, GDALDataType,
86 : int, int );
87 : };
88 :
89 : /************************************************************************/
90 : /* TILRasterBand() */
91 : /************************************************************************/
92 :
93 2 : TILRasterBand::TILRasterBand( TILDataset *poTILDS, int nBand,
94 2 : VRTSourcedRasterBand *poVRTBand )
95 :
96 : {
97 2 : this->poDS = poTILDS;
98 2 : this->poVRTBand = poVRTBand;
99 2 : this->nBand = nBand;
100 2 : this->eDataType = poVRTBand->GetRasterDataType();
101 :
102 2 : poVRTBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
103 2 : }
104 :
105 : /************************************************************************/
106 : /* IReadBlock() */
107 : /************************************************************************/
108 :
109 0 : CPLErr TILRasterBand::IReadBlock( int iBlockX, int iBlockY, void *pBuffer )
110 :
111 : {
112 0 : return poVRTBand->ReadBlock( iBlockX, iBlockY, pBuffer );
113 : }
114 :
115 : /************************************************************************/
116 : /* IRasterIO() */
117 : /************************************************************************/
118 :
119 20 : CPLErr TILRasterBand::IRasterIO( GDALRWFlag eRWFlag,
120 : int nXOff, int nYOff, int nXSize, int nYSize,
121 : void * pData, int nBufXSize, int nBufYSize,
122 : GDALDataType eBufType,
123 : int nPixelSpace, int nLineSpace )
124 :
125 : {
126 20 : if(GetOverviewCount() > 0)
127 : {
128 : return GDALPamRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
129 : pData, nBufXSize, nBufYSize, eBufType,
130 0 : nPixelSpace, nLineSpace );
131 : }
132 : else //if not exist TIL overviews, try to use band source overviews
133 : {
134 : return poVRTBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
135 : pData, nBufXSize, nBufYSize, eBufType,
136 20 : nPixelSpace, nLineSpace );
137 : }
138 : }
139 :
140 : /************************************************************************/
141 : /* ==================================================================== */
142 : /* TILDataset */
143 : /* ==================================================================== */
144 : /************************************************************************/
145 :
146 : /************************************************************************/
147 : /* TILDataset() */
148 : /************************************************************************/
149 :
150 2 : TILDataset::TILDataset()
151 :
152 : {
153 2 : poVRTDS = NULL;
154 2 : }
155 :
156 : /************************************************************************/
157 : /* ~TILDataset() */
158 : /************************************************************************/
159 :
160 2 : TILDataset::~TILDataset()
161 :
162 : {
163 2 : CloseDependentDatasets();
164 2 : }
165 :
166 : /************************************************************************/
167 : /* CloseDependentDatasets() */
168 : /************************************************************************/
169 :
170 2 : int TILDataset::CloseDependentDatasets()
171 : {
172 2 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
173 :
174 2 : if( poVRTDS )
175 : {
176 2 : bHasDroppedRef = TRUE;
177 2 : delete poVRTDS;
178 2 : poVRTDS = NULL;
179 : }
180 :
181 6 : while( !apoTileDS.empty() )
182 : {
183 2 : GDALClose( (GDALDatasetH) apoTileDS.back() );
184 2 : apoTileDS.pop_back();
185 : }
186 :
187 2 : return bHasDroppedRef;
188 : }
189 :
190 : /************************************************************************/
191 : /* Identify() */
192 : /************************************************************************/
193 :
194 12771 : int TILDataset::Identify( GDALOpenInfo *poOpenInfo )
195 :
196 : {
197 12771 : if( poOpenInfo->nHeaderBytes < 200
198 : || !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"TIL") )
199 12769 : return FALSE;
200 :
201 2 : if( strstr((const char *) poOpenInfo->pabyHeader,"numTiles") == NULL )
202 0 : return FALSE;
203 : else
204 2 : return TRUE;
205 : }
206 :
207 : /************************************************************************/
208 : /* Open() */
209 : /************************************************************************/
210 :
211 2640 : GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
212 :
213 : {
214 2640 : if( !Identify( poOpenInfo ) )
215 2638 : return NULL;
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Confirm the requested access is supported. */
219 : /* -------------------------------------------------------------------- */
220 2 : if( poOpenInfo->eAccess == GA_Update )
221 : {
222 : CPLError( CE_Failure, CPLE_NotSupported,
223 : "The TIL driver does not support update access to existing"
224 0 : " datasets.\n" );
225 0 : return NULL;
226 : }
227 :
228 2 : CPLString osDirname = CPLGetDirname(poOpenInfo->pszFilename);
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Try to find the corresponding .IMD file. */
232 : /* -------------------------------------------------------------------- */
233 2 : char **papszIMD = NULL;
234 : CPLString osIMDFilename =
235 : GDALFindAssociatedFile( poOpenInfo->pszFilename, "IMD",
236 2 : poOpenInfo->papszSiblingFiles, 0 );
237 :
238 2 : if( osIMDFilename != "" )
239 2 : papszIMD = GDALLoadIMDFile( osIMDFilename, NULL );
240 :
241 2 : if( papszIMD == NULL )
242 : {
243 : CPLError( CE_Failure, CPLE_OpenFailed,
244 0 : "Unable to open .TIL dataset due to missing .IMD file." );
245 0 : return NULL;
246 : }
247 :
248 2 : if( CSLFetchNameValue( papszIMD, "numRows" ) == NULL
249 : || CSLFetchNameValue( papszIMD, "numColumns" ) == NULL
250 : || CSLFetchNameValue( papszIMD, "bitsPerPixel" ) == NULL )
251 : {
252 : CPLError( CE_Failure, CPLE_OpenFailed,
253 0 : "Missing a required field in the .IMD file." );
254 0 : CSLDestroy( papszIMD );
255 0 : return NULL;
256 : }
257 :
258 : /* -------------------------------------------------------------------- */
259 : /* Try to load and parse the .TIL file. */
260 : /* -------------------------------------------------------------------- */
261 2 : VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
262 :
263 2 : if( fp == NULL )
264 : {
265 0 : CSLDestroy( papszIMD );
266 0 : return NULL;
267 : }
268 :
269 2 : CPLKeywordParser oParser;
270 :
271 2 : if( !oParser.Ingest( fp ) )
272 : {
273 0 : VSIFCloseL( fp );
274 0 : CSLDestroy( papszIMD );
275 0 : return NULL;
276 : }
277 :
278 2 : VSIFCloseL( fp );
279 :
280 2 : char **papszTIL = oParser.GetAllKeywords();
281 :
282 : /* -------------------------------------------------------------------- */
283 : /* Create a corresponding GDALDataset. */
284 : /* -------------------------------------------------------------------- */
285 : TILDataset *poDS;
286 :
287 2 : poDS = new TILDataset();
288 :
289 2 : poDS->osIMDFilename = osIMDFilename;
290 2 : poDS->SetMetadata( papszIMD, "IMD" );
291 2 : poDS->nRasterXSize = atoi(CSLFetchNameValueDef(papszIMD,"numColumns","0"));
292 2 : poDS->nRasterYSize = atoi(CSLFetchNameValueDef(papszIMD,"numRows","0"));
293 2 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
294 : {
295 0 : delete poDS;
296 0 : CSLDestroy( papszIMD );
297 0 : return NULL;
298 : }
299 :
300 : /* -------------------------------------------------------------------- */
301 : /* We need to open one of the images in order to establish */
302 : /* details like the band count and types. */
303 : /* -------------------------------------------------------------------- */
304 : GDALDataset *poTemplateDS;
305 2 : const char *pszFilename = CSLFetchNameValue( papszTIL, "TILE_1.filename" );
306 2 : if( pszFilename == NULL )
307 : {
308 : CPLError( CE_Failure, CPLE_AppDefined,
309 0 : "Missing TILE_1.filename in .TIL file." );
310 0 : delete poDS;
311 0 : CSLDestroy( papszIMD );
312 0 : return NULL;
313 : }
314 :
315 : // trim double quotes.
316 2 : if( pszFilename[0] == '"' )
317 2 : pszFilename++;
318 2 : if( pszFilename[strlen(pszFilename)-1] == '"' )
319 2 : ((char *) pszFilename)[strlen(pszFilename)-1] = '\0';
320 :
321 2 : CPLString osFilename = CPLFormFilename(osDirname, pszFilename, NULL);
322 2 : poTemplateDS = (GDALDataset *) GDALOpen( osFilename, GA_ReadOnly );
323 2 : if( poTemplateDS == NULL || poTemplateDS->GetRasterCount() == 0)
324 : {
325 0 : delete poDS;
326 0 : CSLDestroy( papszIMD );
327 0 : if (poTemplateDS != NULL)
328 0 : GDALClose( poTemplateDS );
329 0 : return NULL;
330 : }
331 :
332 2 : GDALRasterBand *poTemplateBand = poTemplateDS->GetRasterBand(1);
333 2 : GDALDataType eDT = poTemplateBand->GetRasterDataType();
334 2 : int nBandCount = poTemplateDS->GetRasterCount();
335 :
336 : //we suppose the first tile have the same projection as others (usually so)
337 2 : CPLString pszProjection(poTemplateDS->GetProjectionRef());
338 2 : if(!pszProjection.empty())
339 2 : poDS->SetProjection(pszProjection);
340 :
341 : //we suppose the first tile have the same GeoTransform as others (usually so)
342 : double adfGeoTransform[6];
343 2 : if( poTemplateDS->GetGeoTransform( adfGeoTransform ) == CE_None )
344 : {
345 2 : adfGeoTransform[0] = CPLAtof(CSLFetchNameValueDef(papszIMD,"MAP_PROJECTED_PRODUCT.ULX","0"));
346 2 : adfGeoTransform[3] = CPLAtof(CSLFetchNameValueDef(papszIMD,"MAP_PROJECTED_PRODUCT.ULY","0"));
347 2 : poDS->SetGeoTransform(adfGeoTransform);
348 : }
349 :
350 2 : poTemplateBand = NULL;
351 2 : GDALClose( poTemplateDS );
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Create and initialize the corresponding VRT dataset used to */
355 : /* manage the tiled data access. */
356 : /* -------------------------------------------------------------------- */
357 : int iBand;
358 :
359 2 : poDS->poVRTDS = new VRTDataset(poDS->nRasterXSize,poDS->nRasterYSize);
360 :
361 4 : for( iBand = 0; iBand < nBandCount; iBand++ )
362 2 : poDS->poVRTDS->AddBand( eDT, NULL );
363 :
364 : /* Don't try to write a VRT file */
365 2 : poDS->poVRTDS->SetWritable(FALSE);
366 :
367 : /* -------------------------------------------------------------------- */
368 : /* Create band information objects. */
369 : /* -------------------------------------------------------------------- */
370 4 : for( iBand = 1; iBand <= nBandCount; iBand++ )
371 : poDS->SetBand( iBand,
372 : new TILRasterBand( poDS, iBand,
373 2 : (VRTSourcedRasterBand *) poDS->poVRTDS->GetRasterBand(iBand)));
374 :
375 : /* -------------------------------------------------------------------- */
376 : /* Add tiles as sources for each band. */
377 : /* -------------------------------------------------------------------- */
378 2 : int nTileCount = atoi(CSLFetchNameValueDef(papszTIL,"numTiles","0"));
379 2 : int iTile = 0;
380 :
381 2 : for( iTile = 1; iTile <= nTileCount; iTile++ )
382 : {
383 2 : CPLString osKey;
384 :
385 2 : osKey.Printf( "TILE_%d.filename", iTile );
386 2 : pszFilename = CSLFetchNameValue( papszTIL, osKey );
387 2 : if( pszFilename == NULL )
388 : {
389 : CPLError( CE_Failure, CPLE_AppDefined,
390 0 : "Missing TILE_%d.filename in .TIL file.", iTile );
391 0 : delete poDS;
392 0 : CSLDestroy( papszIMD );
393 0 : return NULL;
394 : }
395 :
396 : // trim double quotes.
397 2 : if( pszFilename[0] == '"' )
398 2 : pszFilename++;
399 2 : if( pszFilename[strlen(pszFilename)-1] == '"' )
400 0 : ((char *) pszFilename)[strlen(pszFilename)-1] = '\0';
401 2 : osFilename = CPLFormFilename(osDirname, pszFilename, NULL);
402 :
403 2 : osKey.Printf( "TILE_%d.ULColOffset", iTile );
404 2 : int nULX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
405 :
406 2 : osKey.Printf( "TILE_%d.ULRowOffset", iTile );
407 2 : int nULY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
408 :
409 2 : osKey.Printf( "TILE_%d.LRColOffset", iTile );
410 2 : int nLRX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
411 :
412 2 : osKey.Printf( "TILE_%d.LRRowOffset", iTile );
413 2 : int nLRY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
414 :
415 : GDALDataset *poTileDS =
416 : new GDALProxyPoolDataset( osFilename,
417 2 : nLRX - nULX + 1, nLRY - nULY + 1 );
418 2 : if( poTileDS == NULL )
419 0 : continue;
420 :
421 2 : poDS->apoTileDS.push_back( poTileDS );
422 :
423 4 : for( iBand = 1; iBand <= nBandCount; iBand++ )
424 : {
425 : ((GDALProxyPoolDataset *) poTileDS)->
426 2 : AddSrcBandDescription( eDT, nLRX - nULX + 1, 1 );
427 :
428 2 : GDALRasterBand *poSrcBand = poTileDS->GetRasterBand(iBand);
429 :
430 : VRTSourcedRasterBand *poVRTBand =
431 2 : (VRTSourcedRasterBand *) poDS->poVRTDS->GetRasterBand(iBand);
432 :
433 : poVRTBand->AddSimpleSource( poSrcBand,
434 : 0, 0,
435 : nLRX - nULX + 1, nLRY - nULY + 1,
436 : nULX, nULY,
437 2 : nLRX - nULX + 1, nLRY - nULY + 1 );
438 : }
439 : }
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Set RPC and IMD metadata. */
443 : /* -------------------------------------------------------------------- */
444 : poDS->osRPBFilename =
445 : GDALFindAssociatedFile( poOpenInfo->pszFilename, "RPB",
446 2 : poOpenInfo->papszSiblingFiles, 0 );
447 2 : if( poDS->osRPBFilename != "" )
448 : {
449 : char **papszRPCMD = GDALLoadRPBFile( poOpenInfo->pszFilename,
450 0 : poOpenInfo->papszSiblingFiles );
451 :
452 0 : if( papszRPCMD != NULL )
453 : {
454 0 : poDS->SetMetadata( papszRPCMD, "RPC" );
455 0 : CSLDestroy( papszRPCMD );
456 : }
457 : }
458 :
459 : /* -------------------------------------------------------------------- */
460 : /* Cleanup */
461 : /* -------------------------------------------------------------------- */
462 2 : CSLDestroy( papszIMD );
463 :
464 : /* -------------------------------------------------------------------- */
465 : /* Initialize any PAM information. */
466 : /* -------------------------------------------------------------------- */
467 2 : poDS->SetDescription( poOpenInfo->pszFilename );
468 2 : poDS->TryLoadXML();
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Check for overviews. */
472 : /* -------------------------------------------------------------------- */
473 2 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
474 :
475 2 : return( poDS );
476 : }
477 :
478 : /************************************************************************/
479 : /* GetFileList() */
480 : /************************************************************************/
481 :
482 1 : char **TILDataset::GetFileList()
483 :
484 : {
485 : unsigned int i;
486 1 : char **papszFileList = GDALPamDataset::GetFileList();
487 :
488 2 : for( i = 0; i < apoTileDS.size(); i++ )
489 : papszFileList = CSLAddString( papszFileList,
490 1 : apoTileDS[i]->GetDescription() );
491 :
492 1 : papszFileList = CSLAddString( papszFileList, osIMDFilename );
493 :
494 :
495 1 : if( osRPBFilename != "" )
496 0 : papszFileList = CSLAddString( papszFileList, osRPBFilename );
497 :
498 1 : return papszFileList;
499 : }
500 :
501 : /************************************************************************/
502 : /* GDALRegister_TIL() */
503 : /************************************************************************/
504 :
505 610 : void GDALRegister_TIL()
506 :
507 : {
508 : GDALDriver *poDriver;
509 :
510 610 : if( GDALGetDriverByName( "TIL" ) == NULL )
511 : {
512 588 : poDriver = new GDALDriver();
513 :
514 588 : poDriver->SetDescription( "TIL" );
515 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
516 588 : "EarthWatch .TIL" );
517 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
518 588 : "frmt_til.html" );
519 :
520 588 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
521 :
522 588 : poDriver->pfnOpen = TILDataset::Open;
523 588 : poDriver->pfnIdentify = TILDataset::Identify;
524 :
525 588 : GetGDALDriverManager()->RegisterDriver( poDriver );
526 : }
527 610 : }
528 :
529 :
|