1 : /******************************************************************************
2 : * $Id: hdf4imagedataset.cpp 22765 2011-07-23 09:56:53Z rouault $
3 : *
4 : * Project: Hierarchical Data Format Release 4 (HDF4)
5 : * Purpose: Read subdatasets of HDF4 file.
6 : * This driver initially based on code supplied by Markus Neteler
7 : * Author: Andrey Kiselev, dron@ak4719.spb.edu
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include <string.h>
32 : #include <math.h>
33 :
34 : #include "hdf.h"
35 : #include "mfhdf.h"
36 :
37 : #include "HdfEosDef.h"
38 :
39 : #include "gdal_priv.h"
40 : #include "cpl_string.h"
41 : #include "ogr_spatialref.h"
42 :
43 : #include "hdf4compat.h"
44 : #include "hdf4dataset.h"
45 :
46 : #include "nasakeywordhandler.h"
47 :
48 : CPL_CVSID("$Id: hdf4imagedataset.cpp 22765 2011-07-23 09:56:53Z rouault $");
49 :
50 : CPL_C_START
51 : void GDALRegister_HDF4(void);
52 : CPL_C_END
53 :
54 : #define HDF4_SDS_MAXNAMELEN 65
55 :
56 : // Signature to recognize files written by GDAL
57 : const char *pszGDALSignature =
58 : "Created with GDAL (http://www.remotesensing.org/gdal/)";
59 :
60 : /************************************************************************/
61 : /* ==================================================================== */
62 : /* List of HDF-EOS Swath product types. */
63 : /* ==================================================================== */
64 : /************************************************************************/
65 :
66 : enum HDF4EOSProduct
67 : {
68 : PROD_UNKNOWN,
69 : PROD_ASTER_L1A,
70 : PROD_ASTER_L1B,
71 : PROD_ASTER_L2,
72 : PROD_ASTER_L3,
73 : PROD_AST14DEM,
74 : PROD_MODIS_L1B,
75 : PROD_MODIS_L2
76 : };
77 :
78 : /************************************************************************/
79 : /* ==================================================================== */
80 : /* HDF4ImageDataset */
81 : /* ==================================================================== */
82 : /************************************************************************/
83 :
84 : class HDF4ImageDataset : public HDF4Dataset
85 : {
86 : friend class HDF4ImageRasterBand;
87 :
88 : char *pszFilename;
89 : int32 hHDF4, iGR, iPal, iDataset;
90 : int32 iRank, iNumType, nAttrs,
91 : iInterlaceMode, iPalInterlaceMode, iPalDataType;
92 : int32 nComps, nPalEntries;
93 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
94 : int iXDim, iYDim, iBandDim, i4Dim;
95 : int nBandCount;
96 : char **papszLocalMetadata;
97 : #define N_COLOR_ENTRIES 256
98 : uint8 aiPaletteData[N_COLOR_ENTRIES][3]; // XXX: Static array for now
99 : char szName[HDF4_SDS_MAXNAMELEN];
100 : char *pszSubdatasetName;
101 : char *pszFieldName;
102 :
103 : GDALColorTable *poColorTable;
104 :
105 : OGRSpatialReference oSRS;
106 : int bHasGeoTransform;
107 : double adfGeoTransform[6];
108 : char *pszProjection;
109 : char *pszGCPProjection;
110 : GDAL_GCP *pasGCPList;
111 : int nGCPCount;
112 :
113 : HDF4DatasetType iDatasetType;
114 :
115 : int32 iSDS;
116 :
117 : int nBlockPreferredXSize;
118 : int nBlockPreferredYSize;
119 : bool bReadTile;
120 :
121 : void ToGeoref( double *, double * );
122 : void GetImageDimensions( char * );
123 : void GetSwatAttrs( int32 );
124 : void GetGridAttrs( int32 hGD );
125 : void CaptureNRLGeoTransform(void);
126 : void CaptureL1GMTLInfo(void);
127 : void CaptureCoastwatchGCTPInfo(void);
128 : void ProcessModisSDSGeolocation(void);
129 : int ProcessSwathGeolocation( int32, char ** );
130 :
131 : static long USGSMnemonicToCode( const char* );
132 : static void ReadCoordinates( const char*, double*, double* );
133 :
134 : public:
135 : HDF4ImageDataset();
136 : ~HDF4ImageDataset();
137 :
138 : static GDALDataset *Open( GDALOpenInfo * );
139 : static GDALDataset *Create( const char * pszFilename,
140 : int nXSize, int nYSize, int nBands,
141 : GDALDataType eType, char ** papszParmList );
142 : virtual void FlushCache( void );
143 : CPLErr GetGeoTransform( double * padfTransform );
144 : virtual CPLErr SetGeoTransform( double * );
145 : const char *GetProjectionRef();
146 : virtual CPLErr SetProjection( const char * );
147 : virtual int GetGCPCount();
148 : virtual const char *GetGCPProjection();
149 : virtual const GDAL_GCP *GetGCPs();
150 : };
151 :
152 : /************************************************************************/
153 : /* ==================================================================== */
154 : /* HDF4ImageRasterBand */
155 : /* ==================================================================== */
156 : /************************************************************************/
157 :
158 : class HDF4ImageRasterBand : public GDALPamRasterBand
159 492 : {
160 : friend class HDF4ImageDataset;
161 :
162 : int bNoDataSet;
163 : double dfNoDataValue;
164 :
165 : int bHaveScale, bHaveOffset;
166 : double dfScale;
167 : double dfOffset;
168 :
169 : CPLString osUnitType;
170 :
171 : public:
172 :
173 : HDF4ImageRasterBand( HDF4ImageDataset *, int, GDALDataType );
174 :
175 : virtual CPLErr IReadBlock( int, int, void * );
176 : virtual CPLErr IWriteBlock( int, int, void * );
177 : virtual GDALColorInterp GetColorInterpretation();
178 : virtual GDALColorTable *GetColorTable();
179 : virtual double GetNoDataValue( int * );
180 : virtual CPLErr SetNoDataValue( double );
181 : virtual double GetOffset( int *pbSuccess );
182 : virtual double GetScale( int *pbSuccess );
183 : virtual const char *GetUnitType();
184 : };
185 :
186 : /************************************************************************/
187 : /* HDF4ImageRasterBand() */
188 : /************************************************************************/
189 :
190 492 : HDF4ImageRasterBand::HDF4ImageRasterBand( HDF4ImageDataset *poDS, int nBand,
191 492 : GDALDataType eType )
192 :
193 : {
194 492 : this->poDS = poDS;
195 492 : this->nBand = nBand;
196 492 : eDataType = eType;
197 492 : bNoDataSet = FALSE;
198 492 : dfNoDataValue = -9999.0;
199 :
200 492 : bHaveScale = bHaveOffset = FALSE;
201 492 : dfScale = 1.0;
202 492 : dfOffset = 0.0;
203 :
204 492 : nBlockXSize = poDS->GetRasterXSize();
205 :
206 : // Aim for a block of about 1000000 pixels. Chunking up substantially
207 : // improves performance in some situations. For now we only chunk up for
208 : // SDS and EOS based datasets since other variations haven't been tested. #2208
209 984 : if( poDS->iDatasetType == HDF4_SDS ||
210 : poDS->iDatasetType == HDF4_EOS)
211 : {
212 : int nChunkSize =
213 492 : atoi( CPLGetConfigOption("HDF4_BLOCK_PIXELS", "1000000") );
214 :
215 492 : nBlockYSize = nChunkSize / poDS->GetRasterXSize();
216 492 : nBlockYSize = MAX(1,MIN(nBlockYSize,poDS->GetRasterYSize()));
217 : }
218 : else
219 : {
220 0 : nBlockYSize = 1;
221 : }
222 :
223 : /* HDF4_EOS:EOS_GRID case. We ensure that the block size matches */
224 : /* the raster width, as the IReadBlock() code can only handle multiple */
225 : /* blocks per row */
226 492 : if ( poDS->nBlockPreferredXSize == nBlockXSize &&
227 : poDS->nBlockPreferredYSize > 0 )
228 : {
229 6 : if (poDS->nBlockPreferredYSize == 1)
230 : {
231 : /* Avoid defaulting to tile reading when the preferred height is 1 */
232 : /* as it leads to very poor performance with : */
233 : /* ftp://e4ftl01u.ecs.nasa.gov/MODIS_Composites/MOLT/MOD13Q1.005/2006.06.10/MOD13Q1.A2006161.h21v13.005.2008234103220.hd */
234 2 : poDS->bReadTile = FALSE;
235 : }
236 : else
237 : {
238 4 : nBlockYSize = poDS->nBlockPreferredYSize;
239 : }
240 : }
241 492 : }
242 :
243 : /************************************************************************/
244 : /* IReadBlock() */
245 : /************************************************************************/
246 :
247 179 : CPLErr HDF4ImageRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
248 : void * pImage )
249 : {
250 179 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
251 : int32 aiStart[H4_MAX_NC_DIMS], aiEdges[H4_MAX_NC_DIMS];
252 179 : CPLErr eErr = CE_None;
253 :
254 179 : if( poGDS->eAccess == GA_Update )
255 : {
256 : memset( pImage, 0,
257 0 : nBlockXSize * nBlockYSize * GDALGetDataTypeSize(eDataType) / 8 );
258 0 : return CE_None;
259 : }
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Work out some block oriented details. */
263 : /* -------------------------------------------------------------------- */
264 179 : int nYOff = nBlockYOff * nBlockYSize;
265 179 : int nYSize = MIN(nYOff + nBlockYSize, poDS->GetRasterYSize()) - nYOff;
266 179 : CPLAssert( nBlockXOff == 0 );
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* HDF files with external data files, such as some landsat */
270 : /* products (eg. data/hdf/L1G) need to be told what directory */
271 : /* to look in to find the external files. Normally this is the */
272 : /* directory holding the hdf file. */
273 : /* -------------------------------------------------------------------- */
274 179 : HXsetdir(CPLGetPath(poGDS->pszFilename));
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Handle different configurations. */
278 : /* -------------------------------------------------------------------- */
279 179 : switch ( poGDS->iDatasetType )
280 : {
281 : case HDF4_SDS:
282 : {
283 : /* We avoid doing SDselect() / SDendaccess() for each block access */
284 : /* as this is very slow when zlib compression is used */
285 :
286 78 : if (poGDS->iSDS == FAIL)
287 44 : poGDS->iSDS = SDselect( poGDS->hSD, poGDS->iDataset );
288 :
289 : /* HDF rank:
290 : A rank 2 dataset is an image read in scan-line order (2D).
291 : A rank 3 dataset is a series of images which are read in
292 : an image at a time to form a volume.
293 : A rank 4 dataset may be thought of as a series of volumes.
294 :
295 : The "aiStart" array specifies the multi-dimensional index of the
296 : starting corner of the hyperslab to read. The values are zero
297 : based.
298 :
299 : The "edge" array specifies the number of values to read along
300 : each dimension of the hyperslab.
301 :
302 : The "iStride" array allows for sub-sampling along each
303 : dimension. If a iStride value is specified for a dimension,
304 : that many values will be skipped over when reading along that
305 : dimension. Specifying iStride = NULL in the C interface or
306 : iStride = 1 in either interface specifies contiguous reading
307 : of data. If the iStride values are set to 0, SDreaddata
308 : returns FAIL (or -1). No matter what iStride value is
309 : provided, data is always placed contiguously in buffer.
310 : */
311 78 : switch ( poGDS->iRank )
312 : {
313 : case 4: // 4Dim: volume-time
314 : // FIXME: needs sample file. Does not work currently.
315 0 : aiStart[3] = 0/* range: 0--aiDimSizes[3]-1 */;
316 0 : aiEdges[3] = 1;
317 0 : aiStart[2] = 0/* range: 0--aiDimSizes[2]-1 */;
318 0 : aiEdges[2] = 1;
319 0 : aiStart[1] = nYOff; aiEdges[1] = nYSize;
320 0 : aiStart[0] = nBlockXOff; aiEdges[0] = nBlockXSize;
321 0 : break;
322 : case 3: // 3Dim: volume
323 24 : aiStart[poGDS->iBandDim] = nBand - 1;
324 24 : aiEdges[poGDS->iBandDim] = 1;
325 :
326 24 : aiStart[poGDS->iYDim] = nYOff;
327 24 : aiEdges[poGDS->iYDim] = nYSize;
328 :
329 24 : aiStart[poGDS->iXDim] = nBlockXOff;
330 24 : aiEdges[poGDS->iXDim] = nBlockXSize;
331 24 : break;
332 : case 2: // 2Dim: rows/cols
333 54 : aiStart[poGDS->iYDim] = nYOff;
334 54 : aiEdges[poGDS->iYDim] = nYSize;
335 :
336 54 : aiStart[poGDS->iXDim] = nBlockXOff;
337 54 : aiEdges[poGDS->iXDim] = nBlockXSize;
338 54 : break;
339 : case 1: //1Dim:
340 0 : aiStart[poGDS->iXDim] = nBlockXOff;
341 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
342 : break;
343 : }
344 :
345 : // Read HDF SDS array
346 78 : if( SDreaddata( poGDS->iSDS, aiStart, NULL, aiEdges, pImage ) < 0 )
347 : {
348 : CPLError( CE_Failure, CPLE_AppDefined,
349 0 : "SDreaddata() failed for block." );
350 0 : eErr = CE_Failure;
351 : }
352 :
353 : //SDendaccess( iSDS );
354 : }
355 78 : break;
356 :
357 : case HDF4_GR:
358 : {
359 : int nDataTypeSize =
360 0 : GDALGetDataTypeSize(poGDS->GetDataType(poGDS->iNumType)) / 8;
361 : GByte *pbBuffer = (GByte *)
362 0 : CPLMalloc(nBlockXSize*nBlockYSize*poGDS->iRank*nBlockYSize);
363 : int i, j;
364 :
365 0 : aiStart[poGDS->iYDim] = nYOff;
366 0 : aiEdges[poGDS->iYDim] = nYSize;
367 :
368 0 : aiStart[poGDS->iXDim] = nBlockXOff;
369 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
370 :
371 0 : if( GRreadimage(poGDS->iGR, aiStart, NULL, aiEdges, pbBuffer) < 0 )
372 : {
373 : CPLError( CE_Failure, CPLE_AppDefined,
374 0 : "GRreaddata() failed for block." );
375 0 : eErr = CE_Failure;
376 : }
377 : else
378 : {
379 0 : for ( i = 0, j = (nBand - 1) * nDataTypeSize;
380 : i < nBlockXSize * nDataTypeSize;
381 : i += nDataTypeSize, j += poGDS->nBands * nDataTypeSize )
382 0 : memcpy( (GByte *)pImage + i, pbBuffer + j, nDataTypeSize );
383 : }
384 :
385 0 : CPLFree( pbBuffer );
386 : }
387 0 : break;
388 :
389 : case HDF4_EOS:
390 : {
391 101 : switch ( poGDS->iSubdatasetType )
392 : {
393 : case H4ST_EOS_GRID:
394 : {
395 : int32 hGD;
396 :
397 : hGD = GDattach( poGDS->hHDF4,
398 101 : poGDS->pszSubdatasetName );
399 101 : switch ( poGDS->iRank )
400 : {
401 : case 4: // 4Dim: volume
402 0 : aiStart[poGDS->i4Dim] =
403 : (nBand - 1)
404 0 : / poGDS->aiDimSizes[poGDS->iBandDim];
405 0 : aiEdges[poGDS->i4Dim] = 1;
406 :
407 0 : aiStart[poGDS->iBandDim] =
408 : (nBand - 1)
409 0 : % poGDS->aiDimSizes[poGDS->iBandDim];
410 0 : aiEdges[poGDS->iBandDim] = 1;
411 :
412 0 : aiStart[poGDS->iYDim] = nYOff;
413 0 : aiEdges[poGDS->iYDim] = nYSize;
414 :
415 0 : aiStart[poGDS->iXDim] = nBlockXOff;
416 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
417 0 : break;
418 : case 3: // 3Dim: volume
419 0 : aiStart[poGDS->iBandDim] = nBand - 1;
420 0 : aiEdges[poGDS->iBandDim] = 1;
421 :
422 0 : aiStart[poGDS->iYDim] = nYOff;
423 0 : aiEdges[poGDS->iYDim] = nYSize;
424 :
425 0 : aiStart[poGDS->iXDim] = nBlockXOff;
426 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
427 0 : break;
428 : case 2: // 2Dim: rows/cols
429 101 : aiStart[poGDS->iYDim] = nYOff;
430 101 : aiEdges[poGDS->iYDim] = nYSize;
431 :
432 101 : aiStart[poGDS->iXDim] = nBlockXOff;
433 101 : aiEdges[poGDS->iXDim] = nBlockXSize;
434 : break;
435 : }
436 :
437 : /* Ensure that we don't overlap the bottom or right edges */
438 : /* of the dataset in order to use the GDreadtile() API */
439 177 : if ( poGDS->bReadTile &&
440 : (nBlockXOff + 1) * nBlockXSize <= nRasterXSize &&
441 : (nBlockYOff + 1) * nBlockYSize <= nRasterYSize )
442 : {
443 76 : int32 tilecoords[] = { nBlockYOff , nBlockXOff };
444 76 : if( GDreadtile( hGD, poGDS->pszFieldName , tilecoords , pImage ) != 0 )
445 : {
446 0 : CPLError( CE_Failure, CPLE_AppDefined, "GDreadtile() failed for block." );
447 0 : eErr = CE_Failure;
448 : }
449 : }
450 25 : else if( GDreadfield( hGD, poGDS->pszFieldName,
451 : aiStart, NULL, aiEdges, pImage ) < 0 )
452 : {
453 : CPLError( CE_Failure, CPLE_AppDefined,
454 0 : "GDreadfield() failed for block." );
455 0 : eErr = CE_Failure;
456 : }
457 101 : GDdetach( hGD );
458 : }
459 101 : break;
460 :
461 : case H4ST_EOS_SWATH:
462 : case H4ST_EOS_SWATH_GEOL:
463 : {
464 : int32 hSW;
465 :
466 : hSW = SWattach( poGDS->hHDF4,
467 0 : poGDS->pszSubdatasetName );
468 0 : switch ( poGDS->iRank )
469 : {
470 : case 3: // 3Dim: volume
471 0 : aiStart[poGDS->iBandDim] = nBand - 1;
472 0 : aiEdges[poGDS->iBandDim] = 1;
473 :
474 0 : aiStart[poGDS->iYDim] = nYOff;
475 0 : aiEdges[poGDS->iYDim] = nYSize;
476 :
477 0 : aiStart[poGDS->iXDim] = nBlockXOff;
478 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
479 0 : break;
480 : case 2: // 2Dim: rows/cols
481 0 : aiStart[poGDS->iYDim] = nYOff;
482 0 : aiEdges[poGDS->iYDim] = nYSize;
483 :
484 0 : aiStart[poGDS->iXDim] = nBlockXOff;
485 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
486 : break;
487 : }
488 0 : if( SWreadfield( hSW, poGDS->pszFieldName,
489 : aiStart, NULL, aiEdges, pImage ) < 0 )
490 : {
491 : CPLError( CE_Failure, CPLE_AppDefined,
492 0 : "SWreadfield() failed for block." );
493 0 : eErr = CE_Failure;
494 : }
495 0 : SWdetach( hSW );
496 : }
497 : break;
498 : default:
499 : break;
500 : }
501 : }
502 101 : break;
503 :
504 : default:
505 0 : eErr = CE_Failure;
506 : break;
507 : }
508 :
509 179 : return eErr;
510 : }
511 :
512 : /************************************************************************/
513 : /* IWriteBlock() */
514 : /************************************************************************/
515 :
516 49 : CPLErr HDF4ImageRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
517 : void * pImage )
518 : {
519 49 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *)poDS;
520 : int32 aiStart[H4_MAX_NC_DIMS], aiEdges[H4_MAX_NC_DIMS];
521 49 : CPLErr eErr = CE_None;
522 :
523 : CPLAssert( poGDS != NULL
524 : && nBlockXOff == 0
525 : && nBlockYOff >= 0
526 49 : && pImage != NULL );
527 :
528 : /* -------------------------------------------------------------------- */
529 : /* Work out some block oriented details. */
530 : /* -------------------------------------------------------------------- */
531 49 : int nYOff = nBlockYOff * nBlockYSize;
532 49 : int nYSize = MIN(nYOff + nBlockYSize, poDS->GetRasterYSize()) - nYOff;
533 49 : CPLAssert( nBlockXOff == 0 );
534 :
535 : /* -------------------------------------------------------------------- */
536 : /* Process based on rank. */
537 : /* -------------------------------------------------------------------- */
538 49 : switch ( poGDS->iRank )
539 : {
540 : case 3:
541 : {
542 41 : int32 iSDS = SDselect( poGDS->hSD, poGDS->iDataset );
543 :
544 41 : aiStart[poGDS->iBandDim] = nBand - 1;
545 41 : aiEdges[poGDS->iBandDim] = 1;
546 :
547 41 : aiStart[poGDS->iYDim] = nYOff;
548 41 : aiEdges[poGDS->iYDim] = nYSize;
549 :
550 41 : aiStart[poGDS->iXDim] = nBlockXOff;
551 41 : aiEdges[poGDS->iXDim] = nBlockXSize;
552 :
553 41 : if ( (SDwritedata( iSDS, aiStart, NULL,
554 : aiEdges, (VOIDP)pImage )) < 0 )
555 0 : eErr = CE_Failure;
556 :
557 41 : SDendaccess( iSDS );
558 : }
559 41 : break;
560 :
561 : case 2:
562 : {
563 8 : int32 iSDS = SDselect( poGDS->hSD, nBand - 1 );
564 8 : aiStart[poGDS->iYDim] = nYOff;
565 8 : aiEdges[poGDS->iYDim] = nYSize;
566 :
567 8 : aiStart[poGDS->iXDim] = nBlockXOff;
568 8 : aiEdges[poGDS->iXDim] = nBlockXSize;
569 :
570 8 : if ( (SDwritedata( iSDS, aiStart, NULL,
571 : aiEdges, (VOIDP)pImage )) < 0 )
572 0 : eErr = CE_Failure;
573 :
574 8 : SDendaccess( iSDS );
575 : }
576 8 : break;
577 :
578 : default:
579 0 : eErr = CE_Failure;
580 : break;
581 : }
582 :
583 49 : return eErr;
584 : }
585 :
586 : /************************************************************************/
587 : /* GetColorTable() */
588 : /************************************************************************/
589 :
590 0 : GDALColorTable *HDF4ImageRasterBand::GetColorTable()
591 : {
592 0 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
593 :
594 0 : return poGDS->poColorTable;
595 : }
596 :
597 : /************************************************************************/
598 : /* GetColorInterpretation() */
599 : /************************************************************************/
600 :
601 36 : GDALColorInterp HDF4ImageRasterBand::GetColorInterpretation()
602 : {
603 36 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
604 :
605 36 : if ( poGDS->iDatasetType == HDF4_SDS )
606 36 : return GCI_GrayIndex;
607 0 : else if ( poGDS->iDatasetType == HDF4_GR )
608 : {
609 0 : if ( poGDS->poColorTable != NULL )
610 0 : return GCI_PaletteIndex;
611 0 : else if ( poGDS->nBands != 1 )
612 : {
613 0 : if ( nBand == 1 )
614 0 : return GCI_RedBand;
615 0 : else if ( nBand == 2 )
616 0 : return GCI_GreenBand;
617 0 : else if ( nBand == 3 )
618 0 : return GCI_BlueBand;
619 0 : else if ( nBand == 4 )
620 0 : return GCI_AlphaBand;
621 : else
622 0 : return GCI_Undefined;
623 : }
624 : else
625 0 : return GCI_GrayIndex;
626 : }
627 : else
628 0 : return GCI_GrayIndex;
629 : }
630 :
631 : /************************************************************************/
632 : /* GetNoDataValue() */
633 : /************************************************************************/
634 :
635 64 : double HDF4ImageRasterBand::GetNoDataValue( int * pbSuccess )
636 :
637 : {
638 64 : if( pbSuccess )
639 64 : *pbSuccess = bNoDataSet;
640 :
641 64 : return dfNoDataValue;
642 : }
643 :
644 : /************************************************************************/
645 : /* SetNoDataValue() */
646 : /************************************************************************/
647 :
648 54 : CPLErr HDF4ImageRasterBand::SetNoDataValue( double dfNoData )
649 :
650 : {
651 54 : bNoDataSet = TRUE;
652 54 : dfNoDataValue = dfNoData;
653 :
654 54 : return CE_None;
655 : }
656 :
657 : /************************************************************************/
658 : /* GetUnitType() */
659 : /************************************************************************/
660 :
661 0 : const char *HDF4ImageRasterBand::GetUnitType()
662 :
663 : {
664 0 : if( osUnitType.size() > 0 )
665 0 : return osUnitType;
666 : else
667 0 : return GDALRasterBand::GetUnitType();
668 : }
669 :
670 : /************************************************************************/
671 : /* GetOffset() */
672 : /************************************************************************/
673 :
674 0 : double HDF4ImageRasterBand::GetOffset( int *pbSuccess )
675 :
676 : {
677 0 : if( bHaveOffset )
678 : {
679 0 : if( pbSuccess != NULL )
680 0 : *pbSuccess = TRUE;
681 0 : return dfOffset;
682 : }
683 : else
684 0 : return GDALRasterBand::GetOffset( pbSuccess );
685 : }
686 :
687 : /************************************************************************/
688 : /* GetScale() */
689 : /************************************************************************/
690 :
691 0 : double HDF4ImageRasterBand::GetScale( int *pbSuccess )
692 :
693 : {
694 0 : if( bHaveScale )
695 : {
696 0 : if( pbSuccess != NULL )
697 0 : *pbSuccess = TRUE;
698 0 : return dfScale;
699 : }
700 : else
701 0 : return GDALRasterBand::GetScale( pbSuccess );
702 : }
703 :
704 : /************************************************************************/
705 : /* ==================================================================== */
706 : /* HDF4ImageDataset */
707 : /* ==================================================================== */
708 : /************************************************************************/
709 :
710 : /************************************************************************/
711 : /* HDF4ImageDataset() */
712 : /************************************************************************/
713 :
714 410 : HDF4ImageDataset::HDF4ImageDataset()
715 : {
716 410 : pszFilename = NULL;
717 410 : hHDF4 = 0;
718 410 : iGR = 0;
719 410 : iPal = 0;
720 410 : iDataset = 0;
721 410 : iRank = 0;
722 410 : iNumType = 0;
723 410 : nAttrs = 0;
724 410 : iInterlaceMode = 0;
725 410 : iPalInterlaceMode = 0;
726 410 : iPalDataType = 0;
727 410 : nComps = 0;
728 410 : nPalEntries = 0;
729 410 : memset(aiDimSizes, 0, sizeof(aiDimSizes));
730 410 : iXDim = 0;
731 410 : iYDim = 0;
732 410 : iBandDim = -1;
733 410 : i4Dim = 0;
734 410 : nBandCount = 0;
735 410 : papszLocalMetadata = NULL;
736 410 : memset(aiPaletteData, 0, sizeof(aiPaletteData));
737 410 : memset(szName, 0, sizeof(szName));
738 410 : pszSubdatasetName = NULL;
739 410 : pszFieldName = NULL;
740 410 : poColorTable = NULL;
741 410 : bHasGeoTransform = FALSE;
742 410 : adfGeoTransform[0] = 0.0;
743 410 : adfGeoTransform[1] = 1.0;
744 410 : adfGeoTransform[2] = 0.0;
745 410 : adfGeoTransform[3] = 0.0;
746 410 : adfGeoTransform[4] = 0.0;
747 410 : adfGeoTransform[5] = 1.0;
748 410 : pszProjection = CPLStrdup( "" );
749 410 : pszGCPProjection = CPLStrdup( "" );
750 410 : pasGCPList = NULL;
751 410 : nGCPCount = 0;
752 :
753 410 : iDatasetType = HDF4_UNKNOWN;
754 410 : iSDS = FAIL;
755 :
756 410 : nBlockPreferredXSize = -1;
757 410 : nBlockPreferredYSize = -1;
758 410 : bReadTile = false;
759 :
760 410 : }
761 :
762 : /************************************************************************/
763 : /* ~HDF4ImageDataset() */
764 : /************************************************************************/
765 :
766 410 : HDF4ImageDataset::~HDF4ImageDataset()
767 : {
768 410 : FlushCache();
769 :
770 410 : if ( pszFilename )
771 264 : CPLFree( pszFilename );
772 410 : if ( iSDS != FAIL )
773 44 : SDendaccess( iSDS );
774 410 : if ( hSD > 0 )
775 408 : SDend( hSD );
776 410 : hSD = 0;
777 410 : if ( iGR > 0 )
778 0 : GRendaccess( iGR );
779 410 : if ( hGR > 0 )
780 0 : GRend( hGR );
781 410 : hGR = 0;
782 410 : if ( pszSubdatasetName )
783 8 : CPLFree( pszSubdatasetName );
784 410 : if ( pszFieldName )
785 8 : CPLFree( pszFieldName );
786 410 : if ( papszLocalMetadata )
787 263 : CSLDestroy( papszLocalMetadata );
788 410 : if ( poColorTable != NULL )
789 0 : delete poColorTable;
790 410 : if ( pszProjection )
791 410 : CPLFree( pszProjection );
792 410 : if ( pszGCPProjection )
793 410 : CPLFree( pszGCPProjection );
794 410 : if( nGCPCount > 0 )
795 : {
796 5 : for( int i = 0; i < nGCPCount; i++ )
797 : {
798 4 : if ( pasGCPList[i].pszId )
799 4 : CPLFree( pasGCPList[i].pszId );
800 4 : if ( pasGCPList[i].pszInfo )
801 4 : CPLFree( pasGCPList[i].pszInfo );
802 : }
803 :
804 1 : CPLFree( pasGCPList );
805 : }
806 410 : if ( hHDF4 > 0 )
807 : {
808 264 : switch ( iDatasetType )
809 : {
810 : case HDF4_EOS:
811 8 : switch ( iSubdatasetType )
812 : {
813 : case H4ST_EOS_SWATH:
814 : case H4ST_EOS_SWATH_GEOL:
815 0 : SWclose( hHDF4 );
816 0 : break;
817 : case H4ST_EOS_GRID:
818 8 : GDclose( hHDF4 );
819 : default:
820 : break;
821 : }
822 8 : break;
823 : case HDF4_SDS:
824 : case HDF4_GR:
825 256 : hHDF4 = Hclose( hHDF4 );
826 : break;
827 : default:
828 : break;
829 : }
830 : }
831 410 : }
832 :
833 : /************************************************************************/
834 : /* GetGeoTransform() */
835 : /************************************************************************/
836 :
837 42 : CPLErr HDF4ImageDataset::GetGeoTransform( double * padfTransform )
838 : {
839 42 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
840 :
841 42 : if ( !bHasGeoTransform )
842 0 : return CE_Failure;
843 :
844 42 : return CE_None;
845 : }
846 :
847 : /************************************************************************/
848 : /* SetGeoTransform() */
849 : /************************************************************************/
850 :
851 88 : CPLErr HDF4ImageDataset::SetGeoTransform( double * padfTransform )
852 : {
853 88 : bHasGeoTransform = TRUE;
854 88 : memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
855 :
856 88 : return CE_None;
857 : }
858 :
859 : /************************************************************************/
860 : /* GetProjectionRef() */
861 : /************************************************************************/
862 :
863 17 : const char *HDF4ImageDataset::GetProjectionRef()
864 :
865 : {
866 17 : return pszProjection;
867 : }
868 :
869 : /************************************************************************/
870 : /* SetProjection() */
871 : /************************************************************************/
872 :
873 72 : CPLErr HDF4ImageDataset::SetProjection( const char *pszNewProjection )
874 :
875 : {
876 72 : if ( pszProjection )
877 72 : CPLFree( pszProjection );
878 72 : pszProjection = CPLStrdup( pszNewProjection );
879 :
880 72 : return CE_None;
881 : }
882 :
883 : /************************************************************************/
884 : /* GetGCPCount() */
885 : /************************************************************************/
886 :
887 1 : int HDF4ImageDataset::GetGCPCount()
888 :
889 : {
890 1 : return nGCPCount;
891 : }
892 :
893 : /************************************************************************/
894 : /* GetGCPProjection() */
895 : /************************************************************************/
896 :
897 0 : const char *HDF4ImageDataset::GetGCPProjection()
898 :
899 : {
900 0 : if( nGCPCount > 0 )
901 0 : return pszGCPProjection;
902 : else
903 0 : return "";
904 : }
905 :
906 : /************************************************************************/
907 : /* GetGCPs() */
908 : /************************************************************************/
909 :
910 0 : const GDAL_GCP *HDF4ImageDataset::GetGCPs()
911 : {
912 0 : return pasGCPList;
913 : }
914 :
915 : /************************************************************************/
916 : /* FlushCache() */
917 : /************************************************************************/
918 :
919 410 : void HDF4ImageDataset::FlushCache()
920 :
921 : {
922 : int iBand;
923 : char *pszName;
924 : const char *pszValue;
925 :
926 410 : GDALDataset::FlushCache();
927 :
928 410 : if( eAccess == GA_ReadOnly )
929 266 : return;
930 :
931 : // Write out transformation matrix
932 : pszValue = CPLSPrintf( "%f, %f, %f, %f, %f, %f",
933 : adfGeoTransform[0], adfGeoTransform[1],
934 : adfGeoTransform[2], adfGeoTransform[3],
935 144 : adfGeoTransform[4], adfGeoTransform[5] );
936 144 : if ( (SDsetattr( hSD, "TransformationMatrix", DFNT_CHAR8,
937 : strlen(pszValue) + 1, pszValue )) < 0 )
938 : {
939 : CPLDebug( "HDF4Image",
940 0 : "Cannot write transformation matrix to output file" );
941 : }
942 :
943 : // Write out projection
944 144 : if ( pszProjection != NULL && !EQUAL( pszProjection, "" ) )
945 : {
946 72 : if ( (SDsetattr( hSD, "Projection", DFNT_CHAR8,
947 : strlen(pszProjection) + 1, pszProjection )) < 0 )
948 : {
949 : CPLDebug( "HDF4Image",
950 0 : "Cannot write projection information to output file");
951 : }
952 : }
953 :
954 : // Store all metadata from source dataset as HDF attributes
955 144 : if( GetMetadata() )
956 : {
957 47 : char **papszMeta = GetMetadata();
958 :
959 141 : while ( *papszMeta )
960 : {
961 47 : pszValue = CPLParseNameValue( *papszMeta++, &pszName );
962 47 : if ( (SDsetattr( hSD, pszName, DFNT_CHAR8,
963 : strlen(pszValue) + 1, pszValue )) < 0 )
964 : {
965 : CPLDebug( "HDF4Image",
966 0 : "Cannot write metadata information to output file");
967 : }
968 :
969 47 : CPLFree( pszName );
970 : }
971 : }
972 :
973 : // Write out NoData values
974 328 : for ( iBand = 1; iBand <= nBands; iBand++ )
975 : {
976 : HDF4ImageRasterBand *poBand =
977 184 : (HDF4ImageRasterBand *)GetRasterBand(iBand);
978 :
979 184 : if ( poBand->bNoDataSet )
980 : {
981 16 : pszName = CPLStrdup( CPLSPrintf( "NoDataValue%d", iBand ) );
982 16 : pszValue = CPLSPrintf( "%f", poBand->dfNoDataValue );
983 16 : if ( (SDsetattr( hSD, pszName, DFNT_CHAR8,
984 : strlen(pszValue) + 1, pszValue )) < 0 )
985 : {
986 : CPLDebug( "HDF4Image",
987 : "Cannot write NoData value for band %d "
988 0 : "to output file", iBand);
989 : }
990 :
991 16 : CPLFree( pszName );
992 : }
993 : }
994 :
995 : // Write out band descriptions
996 328 : for ( iBand = 1; iBand <= nBands; iBand++ )
997 : {
998 : HDF4ImageRasterBand *poBand =
999 184 : (HDF4ImageRasterBand *)GetRasterBand(iBand);
1000 :
1001 184 : pszName = CPLStrdup( CPLSPrintf( "BandDesc%d", iBand ) );
1002 184 : pszValue = poBand->GetDescription();
1003 184 : if ( pszValue != NULL && !EQUAL( pszValue, "" ) )
1004 : {
1005 16 : if ( (SDsetattr( hSD, pszName, DFNT_CHAR8,
1006 : strlen(pszValue) + 1, pszValue )) < 0 )
1007 : {
1008 : CPLDebug( "HDF4Image",
1009 : "Cannot write band's %d description to output file",
1010 0 : iBand);
1011 : }
1012 : }
1013 :
1014 184 : CPLFree( pszName );
1015 : }
1016 : }
1017 :
1018 : /************************************************************************/
1019 : /* USGSMnemonicToCode() */
1020 : /************************************************************************/
1021 :
1022 0 : long HDF4ImageDataset::USGSMnemonicToCode( const char* pszMnemonic )
1023 : {
1024 0 : if ( EQUAL(pszMnemonic, "UTM") )
1025 0 : return 1L;
1026 0 : else if ( EQUAL(pszMnemonic, "LAMCC") )
1027 0 : return 4L;
1028 0 : else if ( EQUAL(pszMnemonic, "PS") )
1029 0 : return 6L;
1030 0 : else if ( EQUAL(pszMnemonic, "PC") )
1031 0 : return 7L;
1032 0 : else if ( EQUAL(pszMnemonic, "TM") )
1033 0 : return 9L;
1034 0 : else if ( EQUAL(pszMnemonic, "EQRECT") )
1035 0 : return 17L;
1036 0 : else if ( EQUAL(pszMnemonic, "OM") )
1037 0 : return 20L;
1038 0 : else if ( EQUAL(pszMnemonic, "SOM") )
1039 0 : return 22L;
1040 : else
1041 0 : return 1L; // UTM by default
1042 : }
1043 :
1044 : /************************************************************************/
1045 : /* ToGeoref() */
1046 : /************************************************************************/
1047 :
1048 0 : void HDF4ImageDataset::ToGeoref( double *pdfGeoX, double *pdfGeoY )
1049 : {
1050 0 : OGRCoordinateTransformation *poTransform = NULL;
1051 0 : OGRSpatialReference *poLatLong = NULL;
1052 0 : poLatLong = oSRS.CloneGeogCS();
1053 0 : poTransform = OGRCreateCoordinateTransformation( poLatLong, &oSRS );
1054 :
1055 0 : if( poTransform != NULL )
1056 0 : poTransform->Transform( 1, pdfGeoX, pdfGeoY, NULL );
1057 :
1058 0 : if( poTransform != NULL )
1059 0 : delete poTransform;
1060 :
1061 0 : if( poLatLong != NULL )
1062 0 : delete poLatLong;
1063 0 : }
1064 :
1065 : /************************************************************************/
1066 : /* ReadCoordinates() */
1067 : /************************************************************************/
1068 :
1069 0 : void HDF4ImageDataset::ReadCoordinates( const char *pszString,
1070 : double *pdfX, double *pdfY )
1071 : {
1072 : char **papszStrList;
1073 0 : papszStrList = CSLTokenizeString2( pszString, ", ", 0 );
1074 0 : *pdfX = CPLAtof( papszStrList[0] );
1075 0 : *pdfY = CPLAtof( papszStrList[1] );
1076 0 : CSLDestroy( papszStrList );
1077 0 : }
1078 :
1079 : /************************************************************************/
1080 : /* CaptureL1GMTLInfo() */
1081 : /************************************************************************/
1082 :
1083 : /* FILE L71002025_02520010722_M_MTL.L1G
1084 :
1085 : GROUP = L1_METADATA_FILE
1086 : ...
1087 : GROUP = PRODUCT_METADATA
1088 : PRODUCT_TYPE = "L1G"
1089 : PROCESSING_SOFTWARE = "IAS_5.1"
1090 : EPHEMERIS_TYPE = "DEFINITIVE"
1091 : SPACECRAFT_ID = "Landsat7"
1092 : SENSOR_ID = "ETM+"
1093 : ACQUISITION_DATE = 2001-07-22
1094 : WRS_PATH = 002
1095 : STARTING_ROW = 025
1096 : ENDING_ROW = 025
1097 : BAND_COMBINATION = "12345--7-"
1098 : PRODUCT_UL_CORNER_LAT = 51.2704805
1099 : PRODUCT_UL_CORNER_LON = -53.8914311
1100 : PRODUCT_UR_CORNER_LAT = 50.8458100
1101 : PRODUCT_UR_CORNER_LON = -50.9869091
1102 : PRODUCT_LL_CORNER_LAT = 49.6960897
1103 : PRODUCT_LL_CORNER_LON = -54.4047933
1104 : PRODUCT_LR_CORNER_LAT = 49.2841436
1105 : PRODUCT_LR_CORNER_LON = -51.5900428
1106 : PRODUCT_UL_CORNER_MAPX = 298309.894
1107 : PRODUCT_UL_CORNER_MAPY = 5683875.631
1108 : PRODUCT_UR_CORNER_MAPX = 500921.624
1109 : PRODUCT_UR_CORNER_MAPY = 5632678.683
1110 : PRODUCT_LL_CORNER_MAPX = 254477.193
1111 : PRODUCT_LL_CORNER_MAPY = 5510407.880
1112 : PRODUCT_LR_CORNER_MAPX = 457088.923
1113 : PRODUCT_LR_CORNER_MAPY = 5459210.932
1114 : PRODUCT_SAMPLES_REF = 6967
1115 : PRODUCT_LINES_REF = 5965
1116 : BAND1_FILE_NAME = "L71002025_02520010722_B10.L1G"
1117 : BAND2_FILE_NAME = "L71002025_02520010722_B20.L1G"
1118 : BAND3_FILE_NAME = "L71002025_02520010722_B30.L1G"
1119 : BAND4_FILE_NAME = "L71002025_02520010722_B40.L1G"
1120 : BAND5_FILE_NAME = "L71002025_02520010722_B50.L1G"
1121 : BAND7_FILE_NAME = "L72002025_02520010722_B70.L1G"
1122 : METADATA_L1_FILE_NAME = "L71002025_02520010722_MTL.L1G"
1123 : CPF_FILE_NAME = "L7CPF20010701_20010930_06"
1124 : HDF_DIR_FILE_NAME = "L71002025_02520010722_HDF.L1G"
1125 : END_GROUP = PRODUCT_METADATA
1126 : ...
1127 : GROUP = PROJECTION_PARAMETERS
1128 : REFERENCE_DATUM = "NAD83"
1129 : REFERENCE_ELLIPSOID = "GRS80"
1130 : GRID_CELL_SIZE_PAN = 15.000000
1131 : GRID_CELL_SIZE_THM = 60.000000
1132 : GRID_CELL_SIZE_REF = 30.000000
1133 : ORIENTATION = "NOM"
1134 : RESAMPLING_OPTION = "CC"
1135 : MAP_PROJECTION = "UTM"
1136 : END_GROUP = PROJECTION_PARAMETERS
1137 : GROUP = UTM_PARAMETERS
1138 : ZONE_NUMBER = 22
1139 : END_GROUP = UTM_PARAMETERS
1140 : END_GROUP = L1_METADATA_FILE
1141 : END
1142 : */
1143 :
1144 256 : void HDF4ImageDataset::CaptureL1GMTLInfo()
1145 :
1146 : {
1147 : /* -------------------------------------------------------------------- */
1148 : /* Does the physical file look like it matches our expected */
1149 : /* name pattern? */
1150 : /* -------------------------------------------------------------------- */
1151 256 : if( strlen(pszFilename) < 8
1152 : || !EQUAL(pszFilename+strlen(pszFilename)-8,"_HDF.L1G") )
1153 255 : return;
1154 :
1155 : /* -------------------------------------------------------------------- */
1156 : /* Construct the name of the corresponding MTL file. We should */
1157 : /* likely be able to extract that from the HDF itself but I'm */
1158 : /* not sure where to find it. */
1159 : /* -------------------------------------------------------------------- */
1160 1 : CPLString osMTLFilename = pszFilename;
1161 1 : osMTLFilename.resize(osMTLFilename.length() - 8);
1162 1 : osMTLFilename += "_MTL.L1G";
1163 :
1164 : /* -------------------------------------------------------------------- */
1165 : /* Ingest the MTL using the NASAKeywordHandler written for the */
1166 : /* PDS driver. */
1167 : /* -------------------------------------------------------------------- */
1168 1 : NASAKeywordHandler oMTL;
1169 :
1170 1 : VSILFILE *fp = VSIFOpenL( osMTLFilename, "r" );
1171 1 : if( fp == NULL )
1172 : return;
1173 :
1174 1 : if( !oMTL.Ingest( fp, 0 ) )
1175 : {
1176 0 : VSIFCloseL( fp );
1177 : return;
1178 : }
1179 :
1180 1 : VSIFCloseL( fp );
1181 :
1182 : /* -------------------------------------------------------------------- */
1183 : /* Note: Different variation of MTL files use different group names. */
1184 : /* Check for LPGS_METADATA_FILE and L1_METADATA_FILE. */
1185 : /* -------------------------------------------------------------------- */
1186 : double dfULX, dfULY, dfLRX, dfLRY;
1187 : double dfLLX, dfLLY, dfURX, dfURY;
1188 1 : CPLString osPrefix;
1189 :
1190 1 : if( oMTL.GetKeyword( "LPGS_METADATA_FILE.PRODUCT_METADATA"
1191 : ".PRODUCT_UL_CORNER_LON", NULL ) )
1192 0 : osPrefix = "LPGS_METADATA_FILE.PRODUCT_METADATA.PRODUCT_";
1193 1 : else if( oMTL.GetKeyword( "L1_METADATA_FILE.PRODUCT_METADATA"
1194 : ".PRODUCT_UL_CORNER_LON", NULL ) )
1195 1 : osPrefix = "L1_METADATA_FILE.PRODUCT_METADATA.PRODUCT_";
1196 : else
1197 : return;
1198 :
1199 1 : dfULX = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LON").c_str(), "0" ));
1200 1 : dfULY = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LAT").c_str(), "0" ));
1201 1 : dfLRX = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LON").c_str(), "0" ));
1202 1 : dfLRY = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LAT").c_str(), "0" ));
1203 1 : dfLLX = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LON").c_str(), "0" ));
1204 1 : dfLLY = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LAT").c_str(), "0" ));
1205 1 : dfURX = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LON").c_str(), "0" ));
1206 1 : dfURY = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LAT").c_str(), "0" ));
1207 :
1208 1 : CPLFree( pszGCPProjection );
1209 1 : pszGCPProjection = CPLStrdup( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]" );
1210 :
1211 1 : nGCPCount = 4;
1212 1 : pasGCPList = (GDAL_GCP *) CPLCalloc( nGCPCount, sizeof( GDAL_GCP ) );
1213 1 : GDALInitGCPs( nGCPCount, pasGCPList );
1214 :
1215 1 : pasGCPList[0].dfGCPX = dfULX;
1216 1 : pasGCPList[0].dfGCPY = dfULY;
1217 1 : pasGCPList[0].dfGCPPixel = 0.0;
1218 1 : pasGCPList[0].dfGCPLine = 0.0;
1219 :
1220 1 : pasGCPList[1].dfGCPX = dfURX;
1221 1 : pasGCPList[1].dfGCPY = dfURY;
1222 1 : pasGCPList[1].dfGCPPixel = GetRasterXSize();
1223 1 : pasGCPList[1].dfGCPLine = 0.0;
1224 :
1225 1 : pasGCPList[2].dfGCPX = dfLLX;
1226 1 : pasGCPList[2].dfGCPY = dfLLY;
1227 1 : pasGCPList[2].dfGCPPixel = 0.0;
1228 1 : pasGCPList[2].dfGCPLine = GetRasterYSize();
1229 :
1230 1 : pasGCPList[3].dfGCPX = dfLRX;
1231 1 : pasGCPList[3].dfGCPY = dfLRY;
1232 1 : pasGCPList[3].dfGCPPixel = GetRasterXSize();
1233 1 : pasGCPList[3].dfGCPLine = GetRasterYSize();
1234 : }
1235 :
1236 : /************************************************************************/
1237 : /* CaptureNRLGeoTransform() */
1238 : /* */
1239 : /* Capture geotransform and coordinate system from NRL (Naval */
1240 : /* Research Laboratory, Stennis Space Center) metadata. */
1241 : /************************************************************************/
1242 :
1243 : /* Example metadata:
1244 : Metadata:
1245 : createTime=Fri Oct 1 18:00:07 2004
1246 : createSoftware=APS v2.8.4
1247 : createPlatform=i686-pc-linux-gnu
1248 : createAgency=Naval Research Laboratory, Stennis Space Center
1249 : sensor=MODIS
1250 : sensorPlatform=TERRA-AM
1251 : sensorAgency=NASA
1252 : sensorType=whiskbroom
1253 : sensorSpectrum=Visible/Thermal
1254 : sensorNumberOfBands=36
1255 : sensorBandUnits=nano meters
1256 : sensorBands=645, 858.5, 469, 555, 1240, 1640, 2130, 412.5, 443, 488, 531, 551,
1257 : 667, 678, 748, 869.5, 905, 936, 940, 3750, 3959, 3959, 4050, 4465.5, 4515.5, 13
1258 : 75, 6715, 7325, 8550, 9730, 11130, 12020, 13335, 13635, 13935, 14235
1259 : sensorBandWidths=50, 35, 20, 20, 20, 24, 50, 15, 10, 10, 10, 10, 10, 10, 10, 1
1260 : 5, 30, 10, 50, 90, 60, 60, 60, 65, 67, 30, 360, 300, 300, 300, 500, 500, 300, 30
1261 : 0, 300, 300
1262 : sensorNominalAltitudeInKM=705
1263 : sensorScanWidthInKM=2330
1264 : sensorResolutionInKM=1
1265 : sensorPlatformType=Polar-orbiting Satellite
1266 : timeStartYear=2004
1267 : timeStartDay=275
1268 : timeStartTime=56400000
1269 : timeStart=Fri Oct 1 15:40:00 2004
1270 : timeDayNight=Day
1271 : timeEndYear=2004
1272 : timeEndDay=275
1273 : timeEndTime=56700000
1274 : timeEnd=Fri Oct 1 15:45:00 2004
1275 : inputMasks=HIGLINT,CLDICE,LAND,ATMFAIL
1276 : inputMasksInt=523
1277 : processedVersion=1.2
1278 : file=MODAM2004275.L3_Mosaic_NOAA_GMX
1279 : fileTitle=NRL Level-3 Mosaic
1280 : fileVersion=3.0
1281 : fileClassification=UNCLASSIFIED
1282 : fileStatus=EXPERIMENTAL
1283 : navType=mapped
1284 : mapProjectionSystem=NRL(USGS)
1285 : mapProjection=Gomex
1286 : mapUpperLeft=31, -99
1287 : mapUpperRight=31, -79
1288 : mapLowerLeft=14.9844128048645, -99
1289 : mapLowerRight=14.9844128048645, -79
1290 : inputFiles=MODAM2004275154000.L3_NOAA_GMX
1291 : ...
1292 : */
1293 :
1294 0 : void HDF4ImageDataset::CaptureNRLGeoTransform()
1295 :
1296 : {
1297 : /* -------------------------------------------------------------------- */
1298 : /* Collect the four corners. */
1299 : /* -------------------------------------------------------------------- */
1300 : double adfXY[8];
1301 : static const char *apszItems[] = {
1302 : "mapUpperLeft", "mapUpperRight", "mapLowerLeft", "mapLowerRight" };
1303 : int iCorner;
1304 0 : int bLLPossible = TRUE;
1305 :
1306 0 : for( iCorner = 0; iCorner < 4; iCorner++ )
1307 : {
1308 : const char *pszCornerLoc =
1309 0 : CSLFetchNameValue( papszGlobalMetadata, apszItems[iCorner] );
1310 :
1311 0 : if( pszCornerLoc == NULL )
1312 0 : return;
1313 :
1314 : char **papszTokens = CSLTokenizeStringComplex( pszCornerLoc, ",",
1315 0 : FALSE, FALSE );
1316 0 : if( CSLCount( papszTokens ) != 2 )
1317 0 : return;
1318 :
1319 0 : adfXY[iCorner*2+0] = CPLAtof( papszTokens[1] );
1320 0 : adfXY[iCorner*2+1] = CPLAtof( papszTokens[0] );
1321 :
1322 0 : if( adfXY[iCorner*2+0] < -360 || adfXY[iCorner*2+0] > 360
1323 0 : || adfXY[iCorner*2+1] < -90 || adfXY[iCorner*2+1] > 90 )
1324 0 : bLLPossible = FALSE;
1325 :
1326 0 : CSLDestroy( papszTokens );
1327 : }
1328 :
1329 : /* -------------------------------------------------------------------- */
1330 : /* Does this look like nice clean "northup" lat/long data? */
1331 : /* -------------------------------------------------------------------- */
1332 0 : if( adfXY[0*2+0] == adfXY[2*2+0] && adfXY[0*2+1] == adfXY[1*2+1]
1333 : && bLLPossible )
1334 : {
1335 0 : bHasGeoTransform = TRUE;
1336 0 : adfGeoTransform[0] = adfXY[0*2+0];
1337 0 : adfGeoTransform[1] = (adfXY[1*2+0] - adfXY[0*2+0]) / nRasterXSize;
1338 0 : adfGeoTransform[2] = 0.0;
1339 0 : adfGeoTransform[3] = adfXY[0*2+1];
1340 0 : adfGeoTransform[4] = 0.0;
1341 0 : adfGeoTransform[5] = (adfXY[2*2+1] - adfXY[0*2+1]) / nRasterYSize;
1342 :
1343 0 : oSRS.SetWellKnownGeogCS( "WGS84" );
1344 0 : CPLFree( pszProjection );
1345 0 : oSRS.exportToWkt( &pszProjection );
1346 : }
1347 :
1348 : /* -------------------------------------------------------------------- */
1349 : /* Can we find the USGS Projection Parameters? */
1350 : /* -------------------------------------------------------------------- */
1351 0 : int bGotGCTPProjection = FALSE;
1352 0 : int iSDSIndex = FAIL, iSDS = FAIL;
1353 : const char *mapProjection = CSLFetchNameValue( papszGlobalMetadata,
1354 0 : "mapProjection" );
1355 :
1356 0 : if( mapProjection )
1357 0 : iSDSIndex = SDnametoindex( hSD, mapProjection );
1358 :
1359 0 : if( iSDSIndex != FAIL )
1360 0 : iSDS = SDselect( hSD, iSDSIndex );
1361 :
1362 0 : if( iSDS != FAIL )
1363 : {
1364 : char szName[HDF4_SDS_MAXNAMELEN];
1365 : int32 iRank, iNumType, nAttrs;
1366 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
1367 :
1368 : double adfGCTP[29];
1369 : int32 aiStart[H4_MAX_NC_DIMS], aiEdges[H4_MAX_NC_DIMS];
1370 :
1371 0 : aiStart[0] = 0;
1372 0 : aiEdges[0] = 29;
1373 :
1374 0 : if( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType,
1375 : &nAttrs) == 0
1376 : && iNumType == DFNT_FLOAT64
1377 : && iRank == 1
1378 0 : && aiDimSizes[0] >= 29
1379 : && SDreaddata( iSDS, aiStart, NULL, aiEdges, adfGCTP ) == 0
1380 0 : && oSRS.importFromUSGS( (long) adfGCTP[1], (long) adfGCTP[2],
1381 : adfGCTP+4,
1382 0 : (long) adfGCTP[3] ) == OGRERR_NONE )
1383 : {
1384 : CPLDebug( "HDF4Image", "GCTP Parms = %g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g",
1385 : adfGCTP[0],
1386 : adfGCTP[1],
1387 : adfGCTP[2],
1388 : adfGCTP[3],
1389 : adfGCTP[4],
1390 : adfGCTP[5],
1391 : adfGCTP[6],
1392 : adfGCTP[7],
1393 : adfGCTP[8],
1394 : adfGCTP[9],
1395 : adfGCTP[10],
1396 : adfGCTP[11],
1397 : adfGCTP[12],
1398 : adfGCTP[13],
1399 : adfGCTP[14],
1400 : adfGCTP[15],
1401 : adfGCTP[16],
1402 : adfGCTP[17],
1403 : adfGCTP[18],
1404 : adfGCTP[19],
1405 : adfGCTP[20],
1406 : adfGCTP[21],
1407 : adfGCTP[22],
1408 : adfGCTP[23],
1409 : adfGCTP[24],
1410 : adfGCTP[25],
1411 : adfGCTP[26],
1412 : adfGCTP[27],
1413 0 : adfGCTP[28] );
1414 :
1415 0 : CPLFree( pszProjection );
1416 0 : oSRS.exportToWkt( &pszProjection );
1417 0 : bGotGCTPProjection = TRUE;
1418 : }
1419 :
1420 0 : SDendaccess(iSDS);
1421 : }
1422 :
1423 : /* -------------------------------------------------------------------- */
1424 : /* If we derived a GCTP based projection, then we need to */
1425 : /* transform the lat/long corners into this projection and use */
1426 : /* them to establish the geotransform. */
1427 : /* -------------------------------------------------------------------- */
1428 0 : if( bLLPossible && bGotGCTPProjection )
1429 : {
1430 : double dfULX, dfULY, dfLRX, dfLRY;
1431 0 : OGRSpatialReference oWGS84;
1432 :
1433 0 : oWGS84.SetWellKnownGeogCS( "WGS84" );
1434 :
1435 : OGRCoordinateTransformation *poCT =
1436 0 : OGRCreateCoordinateTransformation( &oWGS84, &oSRS );
1437 :
1438 0 : dfULX = adfXY[0*2+0];
1439 0 : dfULY = adfXY[0*2+1];
1440 :
1441 0 : dfLRX = adfXY[3*2+0];
1442 0 : dfLRY = adfXY[3*2+1];
1443 :
1444 0 : if( poCT->Transform( 1, &dfULX, &dfULY )
1445 0 : && poCT->Transform( 1, &dfLRX, &dfLRY ) )
1446 : {
1447 0 : bHasGeoTransform = TRUE;
1448 0 : adfGeoTransform[0] = dfULX;
1449 0 : adfGeoTransform[1] = (dfLRX - dfULX) / nRasterXSize;
1450 0 : adfGeoTransform[2] = 0.0;
1451 0 : adfGeoTransform[3] = dfULY;
1452 0 : adfGeoTransform[4] = 0.0;
1453 0 : adfGeoTransform[5] = (dfLRY - dfULY) / nRasterYSize;
1454 : }
1455 :
1456 0 : delete poCT;
1457 : }
1458 : }
1459 :
1460 : /************************************************************************/
1461 : /* CaptureCoastwatchGCTPInfo() */
1462 : /************************************************************************/
1463 :
1464 : /* Example Metadata from:
1465 :
1466 : http://coastwatch.noaa.gov/interface/most_recent.php?sensor=MODIS&product=chlorNASA
1467 :
1468 : Definitions at:
1469 : http://coastwatch.noaa.gov/cw_form_hdf.html
1470 :
1471 : Metadata:
1472 : satellite=Aqua
1473 : sensor=MODIS
1474 : origin=USDOC/NOAA/NESDIS CoastWatch
1475 : history=PGE01:4.1.12;PGE02:4.3.1.12;SeaDAS Version ?.?, MSl12 4.0.2, Linux 2.4.21-27.0.1.EL
1476 : cwregister GulfOfMexicoSinusoidal.hdf MODSCW.P2005023.1835.swath09.hdf MODSCW.P2005023.1835.GM16.mapped09.hdf
1477 : cwgraphics MODSCW.P2005023.1835.GM16.closest.hdf
1478 : cwmath --template chlor_a --expr chlor_a=select(and(l2_flags,514)!=0,nan,chlor_a) /data/aps/browse/lvl3/seadas/coastwatch/hdf/MODSCW_P2005023_1835_GM16_closest.hdf /data/aps/browse/lvl3/seadas/coastwatch/maskhdf/MODSCW_P2005023_1835_GM16_closest_chlora.hdf
1479 : cwmath --template latitude --expr latitude=latitude /data/aps/browse/lvl3/seadas/coastwatch/hdf/MODSCW_P2005023_1835_GM16_closest.hdf /data/aps/browse/lvl3/seadas/coastwatch/maskhdf/MODSCW_P2005023_1835_GM16_closest_chlora.hdf
1480 : cwmath --template longitude --expr longitude=longitude /data/aps/browse/lvl3/seadas/coastwatch/hdf/MODSCW_P2005023_1835_GM16_closest.hdf /data/aps/browse/lvl3/seadas/coastwatch/maskhdf/MODSCW_P2005023_1835_GM16_closest_chlora.hdf
1481 : cwhdf_version=3.2
1482 : pass_type=day
1483 : pass_date=12806
1484 : start_time=66906
1485 : temporal_extent=298
1486 : projection_type=mapped
1487 : projection=Sinusoidal
1488 : gctp_sys=16
1489 : gctp_zone=62
1490 : gctp_parm=6378137, 0, 0, 0, -89000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1491 : gctp_datum=12
1492 : et_affine=0, -1008.74836097881, 1008.74836097881, 0, -953126.102425113, 3447041.10282512
1493 : rows=1540
1494 : cols=2000
1495 : polygon_latitude=31, 31, 31, 31, 31, 27.5095879249529, 24.0191758499058, 20.5287637748587, 17.0383516998116, 17.0383516998116, 17.0383516998116, 17.0383516998116, 17.0383516998116, 20.5287637748587, 24.0191758499058, 27.5095879249529, 31
1496 : polygon_longitude=-99, -93.7108573344442, -88.4217146688883, -83.1325720033325, -77.8434293377767, -78.217853417453, -78.5303805448579, -78.7884829057512, -78.9979508907244, -83.7397542896832, -88.481557688642, -93.2233610876007, -97.9651644865595, -98.1529175079091, -98.3842631146439, -98.664391423662, -99
1497 : orbit_type=ascending
1498 : raster_type=RasterPixelIsArea
1499 : swath_sync_lines=1
1500 :
1501 : */
1502 :
1503 0 : void HDF4ImageDataset::CaptureCoastwatchGCTPInfo()
1504 :
1505 : {
1506 0 : if( CSLFetchNameValue( papszGlobalMetadata, "gctp_sys" ) == NULL
1507 : || CSLFetchNameValue( papszGlobalMetadata, "gctp_zone" ) == NULL
1508 : || CSLFetchNameValue( papszGlobalMetadata, "gctp_parm" ) == NULL
1509 : || CSLFetchNameValue( papszGlobalMetadata, "gctp_datum" ) == NULL
1510 : || CSLFetchNameValue( papszGlobalMetadata, "et_affine" ) == NULL )
1511 0 : return;
1512 :
1513 : /* -------------------------------------------------------------------- */
1514 : /* Grab USGS/GCTP Parameters. */
1515 : /* -------------------------------------------------------------------- */
1516 : int nSys, nZone, nDatum, iParm;
1517 : double adfParms[15];
1518 : char **papszTokens;
1519 :
1520 0 : nSys = atoi( CSLFetchNameValue( papszGlobalMetadata, "gctp_sys" ) );
1521 0 : nZone = atoi( CSLFetchNameValue( papszGlobalMetadata, "gctp_zone" ) );
1522 0 : nDatum = atoi( CSLFetchNameValue( papszGlobalMetadata, "gctp_datum" ) );
1523 :
1524 : papszTokens = CSLTokenizeStringComplex(
1525 : CSLFetchNameValue( papszGlobalMetadata, "gctp_parm" ), ",",
1526 0 : FALSE, FALSE );
1527 0 : if( CSLCount(papszTokens) < 15 )
1528 0 : return;
1529 :
1530 0 : for( iParm = 0; iParm < 15; iParm++ )
1531 0 : adfParms[iParm] = CPLAtof( papszTokens[iParm] );
1532 0 : CSLDestroy( papszTokens );
1533 :
1534 : /* -------------------------------------------------------------------- */
1535 : /* Convert into an SRS. */
1536 : /* -------------------------------------------------------------------- */
1537 :
1538 0 : if( oSRS.importFromUSGS( nSys, nZone, adfParms, nDatum ) != OGRERR_NONE )
1539 0 : return;
1540 :
1541 0 : CPLFree( pszProjection );
1542 0 : oSRS.exportToWkt( &pszProjection );
1543 :
1544 : /* -------------------------------------------------------------------- */
1545 : /* Capture the affine transform info. */
1546 : /* -------------------------------------------------------------------- */
1547 :
1548 : papszTokens = CSLTokenizeStringComplex(
1549 : CSLFetchNameValue( papszGlobalMetadata, "et_affine" ), ",",
1550 0 : FALSE, FALSE );
1551 0 : if( CSLCount(papszTokens) != 6 )
1552 0 : return;
1553 :
1554 : // We don't seem to have proper ef_affine docs so I don't
1555 : // know which of these two coefficients goes where.
1556 0 : if( CPLAtof(papszTokens[0]) != 0.0 || CPLAtof(papszTokens[3]) != 0.0 )
1557 0 : return;
1558 :
1559 0 : bHasGeoTransform = TRUE;
1560 0 : adfGeoTransform[0] = CPLAtof( papszTokens[4] );
1561 0 : adfGeoTransform[1] = CPLAtof( papszTokens[2] );
1562 0 : adfGeoTransform[2] = 0.0;
1563 0 : adfGeoTransform[3] = CPLAtof( papszTokens[5] );
1564 0 : adfGeoTransform[4] = 0.0;
1565 0 : adfGeoTransform[5] = CPLAtof( papszTokens[1] );
1566 :
1567 : // Middle of pixel adjustment.
1568 0 : adfGeoTransform[0] -= adfGeoTransform[1] * 0.5;
1569 0 : adfGeoTransform[3] -= adfGeoTransform[5] * 0.5;
1570 : }
1571 :
1572 : /************************************************************************/
1573 : /* GetImageDimensions() */
1574 : /************************************************************************/
1575 :
1576 8 : void HDF4ImageDataset::GetImageDimensions( char *pszDimList )
1577 : {
1578 : char **papszDimList = CSLTokenizeString2( pszDimList, ",",
1579 8 : CSLT_HONOURSTRINGS );
1580 8 : int i, nDimCount = CSLCount( papszDimList );
1581 :
1582 : // TODO: check whether nDimCount is > 1 and do something if it isn't.
1583 :
1584 : // Search for the "Band" word in the name of dimension
1585 : // or take the first one as a number of bands
1586 8 : if ( iRank == 2 )
1587 8 : nBandCount = 1;
1588 : else
1589 : {
1590 0 : for ( i = 0; i < nDimCount; i++ )
1591 : {
1592 0 : if ( strstr( papszDimList[i], "band" ) )
1593 : {
1594 0 : iBandDim = i;
1595 0 : nBandCount = aiDimSizes[i];
1596 : // Handle 4D datasets
1597 0 : if ( iRank > 3 && i < nDimCount - 1 )
1598 : {
1599 : // FIXME: is there a better way to search for
1600 : // the 4th dimension?
1601 0 : i4Dim = i + 1;
1602 0 : nBandCount *= aiDimSizes[i4Dim];
1603 : }
1604 0 : break;
1605 : }
1606 : }
1607 : }
1608 :
1609 : // Search for the starting "X" and "Y" in the names or take
1610 : // the last two dimensions as X and Y sizes
1611 8 : iXDim = nDimCount - 1;
1612 8 : iYDim = nDimCount - 2;
1613 :
1614 24 : for ( i = 0; i < nDimCount; i++ )
1615 : {
1616 24 : if ( EQUALN( papszDimList[i], "X", 1 ) && iBandDim != i )
1617 8 : iXDim = i;
1618 8 : else if ( EQUALN( papszDimList[i], "Y", 1 ) && iBandDim != i )
1619 8 : iYDim = i;
1620 : }
1621 :
1622 : // If didn't get a band dimension yet, but have an extra
1623 : // dimension, use it as the band dimension.
1624 8 : if ( iRank > 2 && iBandDim == -1 )
1625 : {
1626 0 : if( iXDim != 0 && iYDim != 0 )
1627 0 : iBandDim = 0;
1628 0 : else if( iXDim != 1 && iYDim != 1 )
1629 0 : iBandDim = 1;
1630 0 : else if( iXDim != 2 && iYDim != 2 )
1631 0 : iBandDim = 2;
1632 :
1633 0 : nBandCount = aiDimSizes[iBandDim];
1634 : }
1635 :
1636 8 : CSLDestroy( papszDimList );
1637 8 : }
1638 :
1639 : /************************************************************************/
1640 : /* GetSwatAttrs() */
1641 : /************************************************************************/
1642 :
1643 0 : void HDF4ImageDataset::GetSwatAttrs( int32 hSW )
1644 : {
1645 : /* -------------------------------------------------------------------- */
1646 : /* At the start we will fetch the global HDF attributes. */
1647 : /* -------------------------------------------------------------------- */
1648 : int32 hDummy;
1649 :
1650 0 : EHidinfo( hHDF4, &hDummy, &hSD );
1651 0 : ReadGlobalAttributes( hSD );
1652 0 : papszLocalMetadata = CSLDuplicate( papszGlobalMetadata );
1653 :
1654 : /* -------------------------------------------------------------------- */
1655 : /* Fetch the esoteric HDF-EOS attributes then. */
1656 : /* -------------------------------------------------------------------- */
1657 0 : int32 nStrBufSize = 0;
1658 :
1659 0 : if ( SWinqattrs( hSW, NULL, &nStrBufSize ) > 0 && nStrBufSize > 0 )
1660 : {
1661 : char *pszAttrList;
1662 : char **papszAttributes;
1663 : int i, nAttrs;
1664 :
1665 0 : pszAttrList = (char *)CPLMalloc( nStrBufSize + 1 );
1666 0 : SWinqattrs( hSW, pszAttrList, &nStrBufSize );
1667 :
1668 : #ifdef DEBUG
1669 : CPLDebug( "HDF4Image", "List of attributes in swath \"%s\": %s",
1670 0 : pszFieldName, pszAttrList );
1671 : #endif
1672 :
1673 : papszAttributes = CSLTokenizeString2( pszAttrList, ",",
1674 0 : CSLT_HONOURSTRINGS );
1675 0 : nAttrs = CSLCount( papszAttributes );
1676 0 : for ( i = 0; i < nAttrs; i++ )
1677 : {
1678 : int32 iNumType, nValues;
1679 0 : void *pData = NULL;
1680 0 : char *pszTemp = NULL;
1681 :
1682 0 : SWattrinfo( hSW, papszAttributes[i], &iNumType, &nValues );
1683 :
1684 0 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
1685 0 : pData = CPLMalloc( (nValues + 1) * GetDataTypeSize(iNumType) );
1686 : else
1687 0 : pData = CPLMalloc( nValues * GetDataTypeSize(iNumType) );
1688 :
1689 0 : SWreadattr( hSW, papszAttributes[i], pData );
1690 :
1691 0 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
1692 : {
1693 0 : ((char *)pData)[nValues] = '\0';
1694 : papszLocalMetadata = CSLAddNameValue( papszLocalMetadata,
1695 0 : papszAttributes[i],
1696 0 : (const char *) pData );
1697 : }
1698 : else
1699 : {
1700 : pszTemp = SPrintArray( GetDataType(iNumType), pData,
1701 0 : nValues, ", " );
1702 : papszLocalMetadata = CSLAddNameValue( papszLocalMetadata,
1703 0 : papszAttributes[i],
1704 0 : pszTemp );
1705 0 : if ( pszTemp )
1706 0 : CPLFree( pszTemp );
1707 : }
1708 :
1709 0 : if ( pData )
1710 0 : CPLFree( pData );
1711 :
1712 : }
1713 :
1714 0 : CSLDestroy( papszAttributes );
1715 0 : CPLFree( pszAttrList );
1716 : }
1717 :
1718 : /* -------------------------------------------------------------------- */
1719 : /* After fetching HDF-EOS specific stuff we will read the generic */
1720 : /* HDF attributes and append them to the list of metadata. */
1721 : /* -------------------------------------------------------------------- */
1722 : int32 iSDS;
1723 0 : if ( SWsdid(hSW, pszFieldName, &iSDS) != -1 )
1724 : {
1725 : int32 iRank, iNumType, iAttribute, nAttrs, nValues;
1726 : char szName[HDF4_SDS_MAXNAMELEN];
1727 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
1728 :
1729 0 : if( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType,
1730 : &nAttrs) == 0 )
1731 : {
1732 0 : for ( iAttribute = 0; iAttribute < nAttrs; iAttribute++ )
1733 : {
1734 : char szAttrName[H4_MAX_NC_NAME];
1735 : SDattrinfo( iSDS, iAttribute, szAttrName,
1736 0 : &iNumType, &nValues );
1737 : papszLocalMetadata =
1738 : TranslateHDF4Attributes( iSDS, iAttribute,
1739 : szAttrName, iNumType,
1740 0 : nValues, papszLocalMetadata );
1741 : }
1742 : }
1743 : }
1744 :
1745 : /* -------------------------------------------------------------------- */
1746 : /* Finally make the whole list visible. */
1747 : /* -------------------------------------------------------------------- */
1748 0 : SetMetadata( papszLocalMetadata );
1749 0 : }
1750 :
1751 : /************************************************************************/
1752 : /* GetGridAttrs() */
1753 : /************************************************************************/
1754 :
1755 8 : void HDF4ImageDataset::GetGridAttrs( int32 hGD )
1756 : {
1757 : /* -------------------------------------------------------------------- */
1758 : /* At the start we will fetch the global HDF attributes. */
1759 : /* -------------------------------------------------------------------- */
1760 : int32 hDummy;
1761 :
1762 8 : EHidinfo( hHDF4, &hDummy, &hSD );
1763 8 : ReadGlobalAttributes( hSD );
1764 8 : papszLocalMetadata = CSLDuplicate( papszGlobalMetadata );
1765 :
1766 : /* -------------------------------------------------------------------- */
1767 : /* Fetch the esoteric HDF-EOS attributes then. */
1768 : /* -------------------------------------------------------------------- */
1769 8 : int32 nStrBufSize = 0;
1770 :
1771 8 : if ( GDinqattrs( hGD, NULL, &nStrBufSize ) > 0 && nStrBufSize > 0 )
1772 : {
1773 : char *pszAttrList;
1774 : char **papszAttributes;
1775 : int i, nAttrs;
1776 :
1777 0 : pszAttrList = (char *)CPLMalloc( nStrBufSize + 1 );
1778 0 : GDinqattrs( hGD, pszAttrList, &nStrBufSize );
1779 : #ifdef DEBUG
1780 : CPLDebug( "HDF4Image", "List of attributes in grid %s: %s",
1781 0 : pszFieldName, pszAttrList );
1782 : #endif
1783 : papszAttributes = CSLTokenizeString2( pszAttrList, ",",
1784 0 : CSLT_HONOURSTRINGS );
1785 0 : nAttrs = CSLCount( papszAttributes );
1786 0 : for ( i = 0; i < nAttrs; i++ )
1787 : {
1788 : int32 iNumType, nValues;
1789 0 : void *pData = NULL;
1790 0 : char *pszTemp = NULL;
1791 :
1792 0 : GDattrinfo( hGD, papszAttributes[i], &iNumType, &nValues );
1793 :
1794 0 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
1795 0 : pData = CPLMalloc( (nValues + 1) * GetDataTypeSize(iNumType) );
1796 : else
1797 0 : pData = CPLMalloc( nValues * GetDataTypeSize(iNumType) );
1798 :
1799 0 : GDreadattr( hGD, papszAttributes[i], pData );
1800 :
1801 0 : if ( iNumType == DFNT_CHAR8 || iNumType == DFNT_UCHAR8 )
1802 : {
1803 0 : ((char *)pData)[nValues] = '\0';
1804 : papszLocalMetadata = CSLAddNameValue( papszLocalMetadata,
1805 0 : papszAttributes[i],
1806 0 : (const char *) pData );
1807 : }
1808 : else
1809 : {
1810 : pszTemp = SPrintArray( GetDataType(iNumType), pData,
1811 0 : nValues, ", " );
1812 : papszLocalMetadata = CSLAddNameValue( papszLocalMetadata,
1813 0 : papszAttributes[i],
1814 0 : pszTemp );
1815 0 : if ( pszTemp )
1816 0 : CPLFree( pszTemp );
1817 : }
1818 :
1819 0 : if ( pData )
1820 0 : CPLFree( pData );
1821 :
1822 : }
1823 :
1824 0 : CSLDestroy( papszAttributes );
1825 0 : CPLFree( pszAttrList );
1826 : }
1827 :
1828 : /* -------------------------------------------------------------------- */
1829 : /* After fetching HDF-EOS specific stuff we will read the generic */
1830 : /* HDF attributes and append them to the list of metadata. */
1831 : /* -------------------------------------------------------------------- */
1832 : int32 iSDS;
1833 8 : if ( GDsdid(hGD, pszFieldName, &iSDS) != -1 )
1834 : {
1835 : int32 iRank, iNumType, iAttribute, nAttrs, nValues;
1836 : char szName[HDF4_SDS_MAXNAMELEN];
1837 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
1838 :
1839 8 : if( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType,
1840 : &nAttrs) == 0 )
1841 : {
1842 64 : for ( iAttribute = 0; iAttribute < nAttrs; iAttribute++ )
1843 : {
1844 : char szAttrName[H4_MAX_NC_NAME];
1845 : SDattrinfo( iSDS, iAttribute, szAttrName,
1846 56 : &iNumType, &nValues );
1847 : papszLocalMetadata =
1848 : TranslateHDF4Attributes( iSDS, iAttribute,
1849 : szAttrName, iNumType,
1850 56 : nValues, papszLocalMetadata );
1851 : }
1852 : }
1853 : }
1854 :
1855 : /* -------------------------------------------------------------------- */
1856 : /* Finally make the whole list visible. */
1857 : /* -------------------------------------------------------------------- */
1858 8 : SetMetadata( papszLocalMetadata );
1859 8 : }
1860 :
1861 : /************************************************************************/
1862 : /* ProcessModisSDSGeolocation() */
1863 : /* */
1864 : /* Recognise latitude and longitude geolocation arrays in */
1865 : /* simple SDS datasets like: */
1866 : /* */
1867 : /* download.osgeo.org/gdal/data/hdf4/A2006005182000.L2_LAC_SST.x.hdf */
1868 : /* */
1869 : /* As reported in ticket #1895. */
1870 : /* */
1871 : /* Note that we don't check that the dimensions of the latitude */
1872 : /* and longitude exactly match the dimensions of the basedata, */
1873 : /* though we ought to. */
1874 : /************************************************************************/
1875 :
1876 256 : void HDF4ImageDataset::ProcessModisSDSGeolocation(void)
1877 :
1878 : {
1879 256 : int iDSIndex, iXIndex=-1, iYIndex=-1;
1880 :
1881 : // No point in assigning geolocation to the geolocation SDSes themselves.
1882 256 : if( EQUAL(szName,"longitude") || EQUAL(szName,"latitude") )
1883 0 : return;
1884 :
1885 256 : if (nRasterYSize == 1)
1886 0 : return;
1887 :
1888 : /* -------------------------------------------------------------------- */
1889 : /* Scan for latitude and longitude sections. */
1890 : /* -------------------------------------------------------------------- */
1891 : int32 nDatasets, nAttributes;
1892 :
1893 256 : if ( SDfileinfo( hSD, &nDatasets, &nAttributes ) != 0 )
1894 0 : return;
1895 :
1896 672 : for( iDSIndex = 0; iDSIndex < nDatasets; iDSIndex++ )
1897 : {
1898 : int32 iRank, iNumType, nAttrs, iSDS;
1899 : char szName[HDF4_SDS_MAXNAMELEN];
1900 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
1901 :
1902 416 : iSDS = SDselect( hSD, iDSIndex );
1903 :
1904 416 : if( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType,
1905 : &nAttrs) == 0 )
1906 : {
1907 416 : if( EQUAL(szName,"latitude") )
1908 2 : iYIndex = iDSIndex;
1909 :
1910 416 : if( EQUAL(szName,"longitude") )
1911 2 : iXIndex = iDSIndex;
1912 : }
1913 :
1914 416 : SDendaccess(iSDS);
1915 : }
1916 :
1917 256 : if( iXIndex == -1 || iYIndex == -1 )
1918 254 : return;
1919 :
1920 : /* -------------------------------------------------------------------- */
1921 : /* We found geolocation information. Record it as metadata. */
1922 : /* -------------------------------------------------------------------- */
1923 2 : CPLString osWrk;
1924 :
1925 2 : SetMetadataItem( "SRS", SRS_WKT_WGS84, "GEOLOCATION" );
1926 :
1927 : osWrk.Printf( "HDF4_SDS:UNKNOWN:\"%s\":%d",
1928 2 : pszFilename, iXIndex );
1929 2 : SetMetadataItem( "X_DATASET", osWrk, "GEOLOCATION" );
1930 2 : SetMetadataItem( "X_BAND", "1" , "GEOLOCATION" );
1931 :
1932 : osWrk.Printf( "HDF4_SDS:UNKNOWN:\"%s\":%d",
1933 2 : pszFilename, iYIndex );
1934 2 : SetMetadataItem( "Y_DATASET", osWrk, "GEOLOCATION" );
1935 2 : SetMetadataItem( "Y_BAND", "1" , "GEOLOCATION" );
1936 :
1937 2 : SetMetadataItem( "PIXEL_OFFSET", "0", "GEOLOCATION" );
1938 2 : SetMetadataItem( "PIXEL_STEP", "1", "GEOLOCATION" );
1939 :
1940 2 : SetMetadataItem( "LINE_OFFSET", "0", "GEOLOCATION" );
1941 2 : SetMetadataItem( "LINE_STEP", "1", "GEOLOCATION" );
1942 : }
1943 :
1944 : /************************************************************************/
1945 : /* ProcessSwathGeolocation() */
1946 : /* */
1947 : /* Handle the swath geolocation data for a swath. Attach */
1948 : /* geolocation metadata corresponding to it (if there is no */
1949 : /* lattice), and also attach it as GCPs. This is only invoked */
1950 : /* for EOS_SWATH, not EOS_SWATH_GEOL datasets. */
1951 : /************************************************************************/
1952 :
1953 0 : int HDF4ImageDataset::ProcessSwathGeolocation( int32 hSW, char **papszDimList )
1954 : {
1955 0 : char szXGeo[8192] = "";
1956 0 : char szYGeo[8192] = "";
1957 0 : char szPixel[8192]= "";
1958 0 : char szLine[8192] = "";
1959 : int32 iWrkNumType;
1960 0 : void *pLat = NULL, *pLong = NULL;
1961 0 : void *pLatticeX = NULL, *pLatticeY = NULL;
1962 0 : int32 iLatticeType, iLatticeDataSize = 0, iRank;
1963 0 : int32 nLatCount = 0, nLongCount = 0;
1964 0 : int32 nXPoints=0, nYPoints=0;
1965 : int32 nStrBufSize;
1966 0 : int i, j, iDataSize = 0, iPixelDim=-1,iLineDim=-1, iLongDim=-1, iLatDim=-1;
1967 0 : int32 *paiRank = NULL, *paiNumType = NULL,
1968 0 : *paiOffset = NULL, *paiIncrement = NULL;
1969 :
1970 : /* -------------------------------------------------------------------- */
1971 : /* Determine a product name. */
1972 : /* -------------------------------------------------------------------- */
1973 : const char *pszProduct =
1974 0 : CSLFetchNameValue( papszLocalMetadata, "SHORTNAME" );
1975 :
1976 0 : HDF4EOSProduct eProduct = PROD_UNKNOWN;
1977 0 : if ( pszProduct )
1978 : {
1979 0 : if ( EQUALN(pszProduct, "ASTL1A", 6) )
1980 0 : eProduct = PROD_ASTER_L1A;
1981 0 : else if ( EQUALN(pszProduct, "ASTL1B", 6) )
1982 0 : eProduct = PROD_ASTER_L1B;
1983 0 : else if ( EQUALN(pszProduct, "AST_04", 6)
1984 : || EQUALN(pszProduct, "AST_05", 6)
1985 : || EQUALN(pszProduct, "AST_06", 6)
1986 : || EQUALN(pszProduct, "AST_07", 6)
1987 : || EQUALN(pszProduct, "AST_08", 6)
1988 : || EQUALN(pszProduct, "AST_09", 6)
1989 : || EQUALN(pszProduct, "AST13", 5)
1990 : || EQUALN(pszProduct, "AST3", 4) )
1991 0 : eProduct = PROD_ASTER_L2;
1992 0 : else if ( EQUALN(pszProduct, "AST14", 5) )
1993 0 : eProduct = PROD_ASTER_L3;
1994 0 : else if ( EQUALN(pszProduct, "MOD02", 5)
1995 : || EQUALN(pszProduct, "MYD02", 5) )
1996 0 : eProduct = PROD_MODIS_L1B;
1997 0 : else if ( EQUALN(pszProduct, "MOD07_L2", 8) )
1998 0 : eProduct = PROD_MODIS_L2;
1999 : }
2000 :
2001 : /* -------------------------------------------------------------------- */
2002 : /* Read names of geolocation fields and corresponding */
2003 : /* geolocation maps. */
2004 : /* -------------------------------------------------------------------- */
2005 0 : int32 nDataFields = SWnentries( hSW, HDFE_NENTGFLD, &nStrBufSize );
2006 0 : char *pszGeoList = (char *)CPLMalloc( nStrBufSize + 1 );
2007 0 : paiRank = (int32 *)CPLMalloc( nDataFields * sizeof(int32) );
2008 0 : paiNumType = (int32 *)CPLMalloc( nDataFields * sizeof(int32) );
2009 :
2010 0 : if ( nDataFields !=
2011 : SWinqgeofields(hSW, pszGeoList, paiRank, paiNumType) )
2012 : {
2013 : CPLDebug( "HDF4Image",
2014 : "Can't get the list of geolocation fields in swath \"%s\"",
2015 0 : pszSubdatasetName );
2016 : }
2017 :
2018 : #ifdef DEBUG
2019 : else
2020 : {
2021 : char *pszTmp;
2022 : CPLDebug( "HDF4Image",
2023 : "Number of geolocation fields in swath \"%s\": %ld",
2024 0 : pszSubdatasetName, (long)nDataFields );
2025 : CPLDebug( "HDF4Image",
2026 : "List of geolocation fields in swath \"%s\": %s",
2027 0 : pszSubdatasetName, pszGeoList );
2028 : pszTmp = SPrintArray( GDT_UInt32, paiRank,
2029 0 : nDataFields, "," );
2030 : CPLDebug( "HDF4Image",
2031 0 : "Geolocation fields ranks: %s", pszTmp );
2032 0 : CPLFree( pszTmp );
2033 : }
2034 : #endif
2035 :
2036 : // Read geolocation data
2037 0 : int32 nDimMaps = SWnentries( hSW, HDFE_NENTMAP, &nStrBufSize );
2038 0 : if ( nDimMaps <= 0 )
2039 : {
2040 :
2041 : #ifdef DEBUG
2042 : CPLDebug( "HDF4Image", "No geolocation maps in swath \"%s\"",
2043 0 : pszSubdatasetName );
2044 : CPLDebug( "HDF4Image",
2045 : "Suppose one-to-one mapping. X field is \"%s\", Y field is \"%s\"",
2046 0 : papszDimList[iXDim], papszDimList[iYDim] );
2047 : #endif
2048 :
2049 0 : strncpy( szPixel, papszDimList[iXDim], 8192 );
2050 0 : strncpy( szLine, papszDimList[iYDim], 8192 );
2051 0 : strncpy( szXGeo, papszDimList[iXDim], 8192 );
2052 0 : strncpy( szYGeo, papszDimList[iYDim], 8192 );
2053 0 : paiOffset = (int32 *)CPLCalloc( 2, sizeof(int32) );
2054 0 : paiIncrement = (int32 *)CPLCalloc( 2, sizeof(int32) );
2055 0 : paiOffset[0] = paiOffset[1] = 0;
2056 0 : paiIncrement[0] = paiIncrement[1] = 1;
2057 : }
2058 : else
2059 : {
2060 0 : char *pszDimMaps = (char *)CPLMalloc( nStrBufSize + 1 );
2061 0 : paiOffset = (int32 *)CPLCalloc( nDimMaps, sizeof(int32) );
2062 0 : paiIncrement = (int32 *)CPLCalloc( nDimMaps, sizeof(int32) );
2063 :
2064 0 : *pszDimMaps = '\0';
2065 0 : if ( nDimMaps != SWinqmaps(hSW, pszDimMaps, paiOffset, paiIncrement) )
2066 : {
2067 : CPLDebug( "HDF4Image",
2068 : "Can't get the list of geolocation maps in swath \"%s\"",
2069 0 : pszSubdatasetName );
2070 : }
2071 :
2072 : #ifdef DEBUG
2073 : else
2074 : {
2075 : char *pszTmp;
2076 :
2077 : CPLDebug( "HDF4Image",
2078 : "List of geolocation maps in swath \"%s\": %s",
2079 0 : pszSubdatasetName, pszDimMaps );
2080 : pszTmp = SPrintArray( GDT_Int32, paiOffset,
2081 0 : nDimMaps, "," );
2082 : CPLDebug( "HDF4Image",
2083 0 : "Geolocation map offsets: %s", pszTmp );
2084 0 : CPLFree( pszTmp );
2085 : pszTmp = SPrintArray( GDT_Int32, paiIncrement,
2086 0 : nDimMaps, "," );
2087 : CPLDebug( "HDF4Image",
2088 0 : "Geolocation map increments: %s", pszTmp );
2089 0 : CPLFree( pszTmp );
2090 : }
2091 : #endif
2092 :
2093 : char **papszDimMap = CSLTokenizeString2( pszDimMaps, ",",
2094 0 : CSLT_HONOURSTRINGS );
2095 0 : int nDimMapCount = CSLCount(papszDimMap);
2096 :
2097 0 : for ( i = 0; i < nDimMapCount; i++ )
2098 : {
2099 0 : if ( strstr(papszDimMap[i], papszDimList[iXDim]) )
2100 : {
2101 0 : strncpy( szPixel, papszDimList[iXDim], 8192 );
2102 0 : strncpy( szXGeo, papszDimMap[i], 8192 );
2103 0 : char *pszTemp = strchr( szXGeo, '/' );
2104 0 : if ( pszTemp )
2105 0 : *pszTemp = '\0';
2106 : }
2107 0 : else if ( strstr(papszDimMap[i], papszDimList[iYDim]) )
2108 : {
2109 0 : strncpy( szLine, papszDimList[iYDim], 8192 );
2110 0 : strncpy( szYGeo, papszDimMap[i], 8192 );
2111 0 : char *pszTemp = strchr( szYGeo, '/' );
2112 0 : if ( pszTemp )
2113 0 : *pszTemp = '\0';
2114 : }
2115 : }
2116 :
2117 0 : CSLDestroy( papszDimMap );
2118 0 : CPLFree( pszDimMaps );
2119 : }
2120 :
2121 0 : if ( *szXGeo == 0 || *szYGeo == 0 )
2122 0 : return FALSE;
2123 :
2124 : /* -------------------------------------------------------------------- */
2125 : /* Read geolocation fields. */
2126 : /* -------------------------------------------------------------------- */
2127 0 : char szGeoDimList[8192] = "";
2128 : char **papszGeolocations = CSLTokenizeString2( pszGeoList, ",",
2129 0 : CSLT_HONOURSTRINGS );
2130 0 : int nGeolocationsCount = CSLCount( papszGeolocations );
2131 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
2132 :
2133 0 : for ( i = 0; i < nGeolocationsCount; i++ )
2134 : {
2135 0 : char **papszGeoDimList = NULL;
2136 :
2137 0 : if ( SWfieldinfo( hSW, papszGeolocations[i], &iRank,
2138 : aiDimSizes, &iWrkNumType, szGeoDimList ) < 0 )
2139 : {
2140 :
2141 : #ifdef DEBUG
2142 : CPLDebug( "HDF4Image",
2143 : "Can't read attributes of geolocation field \"%s\"",
2144 0 : papszGeolocations[i] );
2145 : #endif
2146 :
2147 0 : return FALSE;
2148 : }
2149 :
2150 : papszGeoDimList = CSLTokenizeString2( szGeoDimList,
2151 0 : ",", CSLT_HONOURSTRINGS );
2152 :
2153 0 : if ( CSLCount(papszGeoDimList) > H4_MAX_VAR_DIMS )
2154 : {
2155 0 : CSLDestroy( papszGeoDimList );
2156 0 : return FALSE;
2157 : }
2158 :
2159 : #ifdef DEBUG
2160 : CPLDebug( "HDF4Image",
2161 : "List of dimensions in geolocation field \"%s\": %s",
2162 0 : papszGeolocations[i], szGeoDimList );
2163 : #endif
2164 :
2165 0 : nXPoints = aiDimSizes[CSLFindString( papszGeoDimList, szXGeo )];
2166 0 : nYPoints = aiDimSizes[CSLFindString( papszGeoDimList, szYGeo )];
2167 :
2168 0 : if ( EQUAL(szPixel, papszDimList[iXDim]) )
2169 : {
2170 0 : iPixelDim = 1;
2171 0 : iLineDim = 0;
2172 : }
2173 : else
2174 : {
2175 0 : iPixelDim = 0;
2176 0 : iLineDim = 1;
2177 : }
2178 :
2179 0 : iDataSize = GetDataTypeSize( iWrkNumType );
2180 0 : if ( strstr( papszGeolocations[i], "Latitude" ) )
2181 : {
2182 0 : iLatDim = i;
2183 0 : nLatCount = nXPoints * nYPoints;
2184 0 : pLat = CPLMalloc( nLatCount * iDataSize );
2185 0 : if (SWreadfield( hSW, papszGeolocations[i], NULL,
2186 : NULL, NULL, (VOIDP)pLat ) < 0)
2187 : {
2188 : CPLDebug( "HDF4Image",
2189 : "Can't read geolocation field %s",
2190 0 : papszGeolocations[i]);
2191 0 : CPLFree( pLat );
2192 0 : pLat = NULL;
2193 : }
2194 : }
2195 0 : else if ( strstr( papszGeolocations[i], "Longitude" ) )
2196 : {
2197 0 : iLongDim = i;
2198 0 : nLongCount = nXPoints * nYPoints;
2199 0 : pLong = CPLMalloc( nLongCount * iDataSize );
2200 0 : if (SWreadfield( hSW, papszGeolocations[i], NULL,
2201 : NULL, NULL, (VOIDP)pLong ) < 0)
2202 : {
2203 : CPLDebug( "HDF4Image",
2204 : "Can't read geolocation field %s",
2205 0 : papszGeolocations[i]);
2206 0 : CPLFree( pLong );
2207 0 : pLong = NULL;
2208 : }
2209 : }
2210 :
2211 0 : CSLDestroy( papszGeoDimList );
2212 : }
2213 :
2214 : /* -------------------------------------------------------------------- */
2215 : /* Do we have a lattice table? */
2216 : /* -------------------------------------------------------------------- */
2217 0 : if (SWfieldinfo(hSW, "LatticePoint", &iRank, aiDimSizes,
2218 : &iLatticeType, szGeoDimList) == 0
2219 : && iRank == 3
2220 0 : && nXPoints == aiDimSizes[1]
2221 0 : && nYPoints == aiDimSizes[0]
2222 0 : && aiDimSizes[2] == 2 )
2223 : {
2224 : int32 iStart[H4_MAX_NC_DIMS], iEdges[H4_MAX_NC_DIMS];
2225 :
2226 : iLatticeDataSize =
2227 0 : GetDataTypeSize( iLatticeType );
2228 :
2229 0 : iStart[1] = 0;
2230 0 : iEdges[1] = nXPoints;
2231 :
2232 0 : iStart[0] = 0;
2233 0 : iEdges[0] = nYPoints;
2234 :
2235 0 : iStart[2] = 0;
2236 0 : iEdges[2] = 1;
2237 :
2238 0 : pLatticeX = CPLMalloc( nLatCount * iLatticeDataSize );
2239 0 : if (SWreadfield( hSW, "LatticePoint", iStart, NULL,
2240 : iEdges, (VOIDP)pLatticeX ) < 0)
2241 : {
2242 0 : CPLDebug( "HDF4Image", "Can't read lattice field" );
2243 0 : CPLFree( pLatticeX );
2244 0 : pLatticeX = NULL;
2245 : }
2246 :
2247 0 : iStart[2] = 1;
2248 0 : iEdges[2] = 1;
2249 :
2250 0 : pLatticeY = CPLMalloc( nLatCount * iLatticeDataSize );
2251 0 : if (SWreadfield( hSW, "LatticePoint", iStart, NULL,
2252 : iEdges, (VOIDP)pLatticeY ) < 0)
2253 : {
2254 0 : CPLDebug( "HDF4Image", "Can't read lattice field" );
2255 0 : CPLFree( pLatticeY );
2256 0 : pLatticeY = NULL;
2257 : }
2258 :
2259 : }
2260 :
2261 : /* -------------------------------------------------------------------- */
2262 : /* Determine whether to use no, partial or full GCPs. */
2263 : /* -------------------------------------------------------------------- */
2264 : const char *pszGEOL_AS_GCPS = CPLGetConfigOption( "GEOL_AS_GCPS",
2265 0 : "PARTIAL" );
2266 : int iGCPStepX, iGCPStepY;
2267 :
2268 0 : if( EQUAL(pszGEOL_AS_GCPS,"NONE") )
2269 : {
2270 0 : iGCPStepX = iGCPStepY = 0;
2271 : }
2272 0 : else if( EQUAL(pszGEOL_AS_GCPS,"FULL") )
2273 : {
2274 0 : iGCPStepX = iGCPStepY = 1;
2275 : }
2276 : else
2277 : {
2278 : // aim for 10x10 grid or so.
2279 0 : iGCPStepX = MAX(1,((nXPoints-1) / 11));
2280 0 : iGCPStepY = MAX(1,((nYPoints-1) / 11));
2281 : }
2282 :
2283 : /* -------------------------------------------------------------------- */
2284 : /* Fetch projection information for various datasets. */
2285 : /* -------------------------------------------------------------------- */
2286 0 : if ( nLatCount && nLongCount && nLatCount == nLongCount
2287 : && pLat && pLong )
2288 : {
2289 0 : CPLFree( pszGCPProjection );
2290 0 : pszGCPProjection = NULL;
2291 :
2292 : // ASTER Level 1A
2293 0 : if ( eProduct == PROD_ASTER_L1A )
2294 : {
2295 0 : pszGCPProjection = CPLStrdup( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]" );
2296 : }
2297 :
2298 : // ASTER Level 1B, Level 2
2299 0 : else if ( eProduct == PROD_ASTER_L1B
2300 : || eProduct == PROD_ASTER_L2 )
2301 : {
2302 : // Constuct the metadata keys.
2303 : // A band number is taken from the field name.
2304 0 : const char *pszBand = strpbrk( pszFieldName, "0123456789" );
2305 :
2306 0 : if ( !pszBand )
2307 0 : pszBand = "";
2308 :
2309 : char *pszProjLine =
2310 0 : CPLStrdup(CPLSPrintf("MPMETHOD%s", pszBand));
2311 : char *pszParmsLine =
2312 : CPLStrdup(CPLSPrintf("PROJECTIONPARAMETERS%s",
2313 0 : pszBand));
2314 : char *pszZoneLine =
2315 : CPLStrdup(CPLSPrintf("UTMZONECODE%s",
2316 0 : pszBand));
2317 : char *pszEllipsoidLine =
2318 : CPLStrdup(CPLSPrintf("ELLIPSOIDANDDATUM%s",
2319 0 : pszBand));
2320 :
2321 : // Fetch projection related values from the
2322 : // metadata.
2323 : const char *pszProj =
2324 : CSLFetchNameValue( papszLocalMetadata,
2325 0 : pszProjLine );
2326 : const char *pszParms =
2327 : CSLFetchNameValue( papszLocalMetadata,
2328 0 : pszParmsLine );
2329 : const char *pszZone =
2330 : CSLFetchNameValue( papszLocalMetadata,
2331 0 : pszZoneLine );
2332 : const char* pszEllipsoid =
2333 : CSLFetchNameValue( papszLocalMetadata,
2334 0 : pszEllipsoidLine );
2335 :
2336 : #ifdef DEBUG
2337 : CPLDebug( "HDF4Image",
2338 : "Projection %s=%s, parameters %s=%s, "
2339 : "zone %s=%s",
2340 : pszProjLine, pszProj, pszParmsLine,
2341 0 : pszParms, pszZoneLine, pszZone );
2342 : CPLDebug( "HDF4Image", "Ellipsoid %s=%s",
2343 0 : pszEllipsoidLine, pszEllipsoid );
2344 : #endif
2345 :
2346 : // Transform all mnemonical codes in the values.
2347 : int i, nParms;
2348 : // Projection is UTM by default
2349 : long iProjSys = (pszProj) ?
2350 0 : USGSMnemonicToCode(pszProj) : 1L;
2351 : long iZone =
2352 0 : (pszZone && iProjSys == 1L) ? atoi(pszZone): 0L;
2353 : char **papszEllipsoid = (pszEllipsoid) ?
2354 : CSLTokenizeString2( pszEllipsoid, ",",
2355 0 : CSLT_HONOURSTRINGS ) : NULL;
2356 :
2357 0 : long iEllipsoid = 8L; // WGS84 by default
2358 0 : if ( papszEllipsoid
2359 : && CSLCount(papszEllipsoid) > 0 )
2360 : {
2361 0 : if (EQUAL( papszEllipsoid[0], "WGS84"))
2362 0 : iEllipsoid = 8L;
2363 : }
2364 :
2365 : double adfProjParms[15];
2366 : char **papszParms = (pszParms) ?
2367 : CSLTokenizeString2( pszParms, ",",
2368 0 : CSLT_HONOURSTRINGS ) : NULL;
2369 0 : nParms = CSLCount(papszParms);
2370 0 : if (nParms >= 15)
2371 0 : nParms = 15;
2372 0 : for (i = 0; i < nParms; i++)
2373 0 : adfProjParms[i] = CPLAtof( papszParms[i] );
2374 0 : for (; i < 15; i++)
2375 0 : adfProjParms[i] = 0.0;
2376 :
2377 : // Create projection definition
2378 : oSRS.importFromUSGS( iProjSys, iZone,
2379 0 : adfProjParms, iEllipsoid );
2380 0 : oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
2381 0 : oSRS.exportToWkt( &pszGCPProjection );
2382 :
2383 0 : CSLDestroy( papszParms );
2384 0 : CPLFree( pszEllipsoidLine );
2385 0 : CPLFree( pszZoneLine );
2386 0 : CPLFree( pszParmsLine );
2387 0 : CPLFree( pszProjLine );
2388 : }
2389 :
2390 : // ASTER Level 3 (DEM)
2391 0 : else if ( eProduct == PROD_ASTER_L3 )
2392 : {
2393 : double dfCenterX, dfCenterY;
2394 : int iZone;
2395 :
2396 : ReadCoordinates( CSLFetchNameValue(
2397 : papszGlobalMetadata, "SCENECENTER" ),
2398 0 : &dfCenterY, &dfCenterX );
2399 :
2400 : // Calculate UTM zone from scene center coordinates
2401 0 : iZone = 30 + (int) ((dfCenterX + 6.0) / 6.0);
2402 :
2403 : // Create projection definition
2404 0 : if( dfCenterY > 0 )
2405 0 : oSRS.SetUTM( iZone, TRUE );
2406 : else
2407 0 : oSRS.SetUTM( - iZone, FALSE );
2408 0 : oSRS.SetWellKnownGeogCS( "WGS84" );
2409 0 : oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
2410 0 : oSRS.exportToWkt( &pszGCPProjection );
2411 : }
2412 :
2413 : // MODIS L1B
2414 0 : else if ( eProduct == PROD_MODIS_L1B
2415 : || eProduct == PROD_MODIS_L2 )
2416 : {
2417 0 : pszGCPProjection = CPLStrdup( SRS_WKT_WGS84 );
2418 : }
2419 : }
2420 :
2421 : /* -------------------------------------------------------------------- */
2422 : /* Fill the GCPs list. */
2423 : /* -------------------------------------------------------------------- */
2424 0 : if( iGCPStepX > 0 )
2425 : {
2426 : nGCPCount = (((nXPoints-1) / iGCPStepX) + 1)
2427 0 : * (((nYPoints-1) / iGCPStepY) + 1);
2428 :
2429 0 : pasGCPList = (GDAL_GCP *) CPLCalloc( nGCPCount, sizeof( GDAL_GCP ) );
2430 0 : GDALInitGCPs( nGCPCount, pasGCPList );
2431 :
2432 0 : int iGCP = 0;
2433 0 : for ( i = 0; i < nYPoints; i += iGCPStepY )
2434 : {
2435 0 : for ( j = 0; j < nXPoints; j += iGCPStepX )
2436 : {
2437 0 : int iGeoOff = i * nXPoints + j;
2438 :
2439 0 : pasGCPList[iGCP].dfGCPX =
2440 : AnyTypeToDouble(iWrkNumType,
2441 0 : (void *)((char*)pLong+ iGeoOff*iDataSize));
2442 0 : pasGCPList[iGCP].dfGCPY =
2443 : AnyTypeToDouble(iWrkNumType,
2444 0 : (void *)((char*)pLat + iGeoOff*iDataSize));
2445 :
2446 : // GCPs in Level 1A/1B dataset are in geocentric
2447 : // coordinates. Convert them in geodetic (we
2448 : // will convert latitudes only, longitudes
2449 : // do not need to be converted, because
2450 : // they are the same).
2451 : // This calculation valid for WGS84 datum only.
2452 0 : if ( eProduct == PROD_ASTER_L1A
2453 : || eProduct == PROD_ASTER_L1B )
2454 : {
2455 0 : pasGCPList[iGCP].dfGCPY =
2456 0 : atan(tan(pasGCPList[iGCP].dfGCPY
2457 0 : *PI/180)/0.99330562)*180/PI;
2458 : }
2459 :
2460 0 : ToGeoref(&pasGCPList[iGCP].dfGCPX,
2461 0 : &pasGCPList[iGCP].dfGCPY);
2462 :
2463 0 : pasGCPList[iGCP].dfGCPZ = 0.0;
2464 :
2465 0 : if ( pLatticeX && pLatticeY )
2466 : {
2467 0 : pasGCPList[iGCP].dfGCPPixel =
2468 : AnyTypeToDouble(iLatticeType,
2469 : (void *)((char *)pLatticeX
2470 0 : + iGeoOff*iLatticeDataSize))+0.5;
2471 0 : pasGCPList[iGCP].dfGCPLine =
2472 : AnyTypeToDouble(iLatticeType,
2473 : (void *)((char *)pLatticeY
2474 0 : + iGeoOff*iLatticeDataSize))+0.5;
2475 : }
2476 0 : else if ( paiOffset && paiIncrement )
2477 : {
2478 0 : pasGCPList[iGCP].dfGCPPixel =
2479 0 : paiOffset[iPixelDim] +
2480 0 : j * paiIncrement[iPixelDim] + 0.5;
2481 0 : pasGCPList[iGCP].dfGCPLine =
2482 0 : paiOffset[iLineDim] +
2483 0 : i * paiIncrement[iLineDim] + 0.5;
2484 : }
2485 :
2486 0 : iGCP++;
2487 : }
2488 : }
2489 : }
2490 :
2491 : /* -------------------------------------------------------------------- */
2492 : /* Establish geolocation metadata, but only if there is no */
2493 : /* lattice. The lattice destroys the regularity of the grid. */
2494 : /* -------------------------------------------------------------------- */
2495 0 : if( pLatticeX == NULL
2496 : && iLatDim != -1 && iLongDim != -1
2497 : && iPixelDim != -1 && iLineDim != -1 )
2498 : {
2499 0 : CPLString osWrk;
2500 :
2501 0 : SetMetadataItem( "SRS", pszGCPProjection, "GEOLOCATION" );
2502 :
2503 : osWrk.Printf( "HDF4_EOS:EOS_SWATH_GEOL:\"%s\":%s:%s",
2504 : pszFilename, pszSubdatasetName,
2505 0 : papszGeolocations[iLongDim] );
2506 0 : SetMetadataItem( "X_DATASET", osWrk, "GEOLOCATION" );
2507 0 : SetMetadataItem( "X_BAND", "1" , "GEOLOCATION" );
2508 :
2509 : osWrk.Printf( "HDF4_EOS:EOS_SWATH_GEOL:\"%s\":%s:%s",
2510 : pszFilename, pszSubdatasetName,
2511 0 : papszGeolocations[iLatDim] );
2512 0 : SetMetadataItem( "Y_DATASET", osWrk, "GEOLOCATION" );
2513 0 : SetMetadataItem( "Y_BAND", "1" , "GEOLOCATION" );
2514 :
2515 0 : if ( paiOffset && paiIncrement )
2516 : {
2517 0 : osWrk.Printf( "%ld", (long)paiOffset[iPixelDim] );
2518 0 : SetMetadataItem( "PIXEL_OFFSET", osWrk, "GEOLOCATION" );
2519 0 : osWrk.Printf( "%ld", (long)paiIncrement[iPixelDim] );
2520 0 : SetMetadataItem( "PIXEL_STEP", osWrk, "GEOLOCATION" );
2521 :
2522 0 : osWrk.Printf( "%ld", (long)paiOffset[iLineDim] );
2523 0 : SetMetadataItem( "LINE_OFFSET", osWrk, "GEOLOCATION" );
2524 0 : osWrk.Printf( "%ld", (long)paiIncrement[iLineDim] );
2525 0 : SetMetadataItem( "LINE_STEP", osWrk, "GEOLOCATION" );
2526 0 : }
2527 : }
2528 :
2529 : /* -------------------------------------------------------------------- */
2530 : /* Cleanup */
2531 : /* -------------------------------------------------------------------- */
2532 0 : CPLFree( pLatticeX );
2533 0 : CPLFree( pLatticeY );
2534 0 : CPLFree( pLat );
2535 0 : CPLFree( pLong );
2536 :
2537 0 : CPLFree( paiOffset );
2538 0 : CPLFree( paiIncrement );
2539 0 : CPLFree( paiNumType );
2540 0 : CPLFree( paiRank );
2541 :
2542 0 : CSLDestroy( papszGeolocations );
2543 0 : CPLFree( pszGeoList );
2544 :
2545 0 : if( iGCPStepX == 0 )
2546 : {
2547 0 : CPLFree( pszGCPProjection );
2548 0 : pszGCPProjection = NULL;
2549 : }
2550 :
2551 0 : return TRUE;
2552 : }
2553 :
2554 : /************************************************************************/
2555 : /* Open() */
2556 : /************************************************************************/
2557 :
2558 11806 : GDALDataset *HDF4ImageDataset::Open( GDALOpenInfo * poOpenInfo )
2559 : {
2560 : int i;
2561 :
2562 11806 : if( !EQUALN( poOpenInfo->pszFilename, "HDF4_SDS:", 9 ) &&
2563 : !EQUALN( poOpenInfo->pszFilename, "HDF4_GR:", 8 ) &&
2564 : !EQUALN( poOpenInfo->pszFilename, "HDF4_GD:", 8 ) &&
2565 : !EQUALN( poOpenInfo->pszFilename, "HDF4_EOS:", 9 ) )
2566 11542 : return NULL;
2567 :
2568 : /* -------------------------------------------------------------------- */
2569 : /* Create a corresponding GDALDataset. */
2570 : /* -------------------------------------------------------------------- */
2571 : char **papszSubdatasetName;
2572 : HDF4ImageDataset *poDS;
2573 :
2574 264 : poDS = new HDF4ImageDataset( );
2575 264 : poDS->fp = poOpenInfo->fp;
2576 264 : poOpenInfo->fp = NULL;
2577 :
2578 : papszSubdatasetName = CSLTokenizeString2( poOpenInfo->pszFilename,
2579 264 : ":", CSLT_HONOURSTRINGS | CSLT_PRESERVEESCAPES);
2580 272 : if ( CSLCount( papszSubdatasetName ) != 4
2581 : && CSLCount( papszSubdatasetName ) != 5
2582 : && CSLCount( papszSubdatasetName ) != 6 )
2583 : {
2584 0 : CSLDestroy( papszSubdatasetName );
2585 0 : delete poDS;
2586 0 : return NULL;
2587 : }
2588 :
2589 : /* -------------------------------------------------------------------- */
2590 : /* Check for drive name in windows HDF4:"D:\... */
2591 : /* -------------------------------------------------------------------- */
2592 264 : if (strlen(papszSubdatasetName[2]) == 1)
2593 : {
2594 0 : char* pszFilename = (char*) CPLMalloc( 2 + strlen(papszSubdatasetName[3]) + 1);
2595 0 : sprintf(pszFilename, "%s:%s", papszSubdatasetName[2], papszSubdatasetName[3]);
2596 0 : CPLFree(papszSubdatasetName[2]);
2597 0 : CPLFree(papszSubdatasetName[3]);
2598 0 : papszSubdatasetName[2] = pszFilename;
2599 :
2600 : /* Move following arguments one rank upper */
2601 0 : papszSubdatasetName[3] = papszSubdatasetName[4];
2602 0 : if (papszSubdatasetName[4] != NULL)
2603 : {
2604 0 : papszSubdatasetName[4] = papszSubdatasetName[5];
2605 0 : papszSubdatasetName[5] = NULL;
2606 : }
2607 : }
2608 :
2609 264 : poDS->pszFilename = CPLStrdup( papszSubdatasetName[2] );
2610 :
2611 264 : if( EQUAL( papszSubdatasetName[0], "HDF4_SDS" ) )
2612 256 : poDS->iDatasetType = HDF4_SDS;
2613 8 : else if ( EQUAL( papszSubdatasetName[0], "HDF4_GR" ) )
2614 0 : poDS->iDatasetType = HDF4_GR;
2615 8 : else if ( EQUAL( papszSubdatasetName[0], "HDF4_EOS" ) )
2616 8 : poDS->iDatasetType = HDF4_EOS;
2617 : else
2618 0 : poDS->iDatasetType = HDF4_UNKNOWN;
2619 :
2620 264 : if( EQUAL( papszSubdatasetName[1], "GDAL_HDF4" ) )
2621 249 : poDS->iSubdatasetType = H4ST_GDAL;
2622 15 : else if( EQUAL( papszSubdatasetName[1], "EOS_GRID" ) )
2623 8 : poDS->iSubdatasetType = H4ST_EOS_GRID;
2624 7 : else if( EQUAL( papszSubdatasetName[1], "EOS_SWATH" ) )
2625 0 : poDS->iSubdatasetType = H4ST_EOS_SWATH;
2626 7 : else if( EQUAL( papszSubdatasetName[1], "EOS_SWATH_GEOL" ) )
2627 0 : poDS->iSubdatasetType = H4ST_EOS_SWATH_GEOL;
2628 7 : else if( EQUAL( papszSubdatasetName[1], "SEAWIFS_L3" ) )
2629 0 : poDS->iSubdatasetType= H4ST_SEAWIFS_L3;
2630 7 : else if( EQUAL( papszSubdatasetName[1], "HYPERION_L1" ) )
2631 0 : poDS->iSubdatasetType= H4ST_HYPERION_L1;
2632 : else
2633 7 : poDS->iSubdatasetType = H4ST_UNKNOWN;
2634 :
2635 : // Is our file still here?
2636 264 : if ( !Hishdf( poDS->pszFilename ) )
2637 : {
2638 0 : CSLDestroy( papszSubdatasetName );
2639 0 : delete poDS;
2640 0 : return NULL;
2641 : }
2642 :
2643 : /* -------------------------------------------------------------------- */
2644 : /* Collect the remain (post filename) components to treat as */
2645 : /* the subdataset name. */
2646 : /* -------------------------------------------------------------------- */
2647 264 : CPLString osSubdatasetName;
2648 :
2649 264 : osSubdatasetName = papszSubdatasetName[3];
2650 264 : if( papszSubdatasetName[4] != NULL )
2651 : {
2652 8 : osSubdatasetName += ":";
2653 8 : osSubdatasetName += papszSubdatasetName[4];
2654 : }
2655 :
2656 : /* -------------------------------------------------------------------- */
2657 : /* Try opening the dataset. */
2658 : /* -------------------------------------------------------------------- */
2659 : int32 iAttribute, nValues, iAttrNumType;
2660 : double dfNoData, dfScale, dfOffset;
2661 264 : int bNoDataSet = FALSE, bHaveScale = FALSE, bHaveOffset = FALSE;
2662 264 : const char *pszUnits = NULL, *pszDescription = NULL;
2663 :
2664 : /* -------------------------------------------------------------------- */
2665 : /* Select SDS or GR to read from. */
2666 : /* -------------------------------------------------------------------- */
2667 264 : if ( poDS->iDatasetType == HDF4_EOS )
2668 : {
2669 8 : poDS->pszSubdatasetName = CPLStrdup( papszSubdatasetName[3] );
2670 8 : if (papszSubdatasetName[4] == NULL)
2671 : {
2672 0 : delete poDS;
2673 0 : return NULL;
2674 : }
2675 8 : poDS->pszFieldName = CPLStrdup( papszSubdatasetName[4] );
2676 : }
2677 : else
2678 256 : poDS->iDataset = atoi( papszSubdatasetName[3] );
2679 264 : CSLDestroy( papszSubdatasetName );
2680 :
2681 264 : switch ( poDS->iDatasetType )
2682 : {
2683 : case HDF4_EOS:
2684 : {
2685 8 : void *pNoDataValue = NULL;
2686 :
2687 8 : switch ( poDS->iSubdatasetType )
2688 : {
2689 :
2690 : /* -------------------------------------------------------------------- */
2691 : /* HDF-EOS Swath. */
2692 : /* -------------------------------------------------------------------- */
2693 : case H4ST_EOS_SWATH:
2694 : case H4ST_EOS_SWATH_GEOL:
2695 : {
2696 : int32 hSW;
2697 0 : char *pszDimList = NULL;
2698 :
2699 0 : if( poOpenInfo->eAccess == GA_ReadOnly )
2700 0 : poDS->hHDF4 = SWopen( poDS->pszFilename, DFACC_READ );
2701 : else
2702 0 : poDS->hHDF4 = SWopen( poDS->pszFilename, DFACC_WRITE );
2703 :
2704 0 : if( poDS->hHDF4 <= 0 )
2705 : {
2706 : CPLDebug( "HDF4Image", "Can't open HDF4 file %s",
2707 0 : poDS->pszFilename );
2708 0 : delete poDS;
2709 0 : return( NULL );
2710 : }
2711 :
2712 0 : hSW = SWattach( poDS->hHDF4, poDS->pszSubdatasetName );
2713 0 : if( hSW < 0 )
2714 : {
2715 : CPLDebug( "HDF4Image", "Can't attach to subdataset %s",
2716 0 : poDS->pszSubdatasetName );
2717 0 : delete poDS;
2718 0 : return( NULL );
2719 : }
2720 :
2721 : /* -------------------------------------------------------------------- */
2722 : /* Decode the dimension map. */
2723 : /* -------------------------------------------------------------------- */
2724 0 : int32 nStrBufSize = 0;
2725 :
2726 0 : if ( SWnentries( hSW, HDFE_NENTDIM, &nStrBufSize ) < 0
2727 : || nStrBufSize <= 0 )
2728 : {
2729 : CPLDebug( "HDF4Image",
2730 0 : "Can't read a number of dimension maps." );
2731 0 : delete poDS;
2732 0 : return NULL;
2733 : }
2734 :
2735 0 : pszDimList = (char *)CPLMalloc( nStrBufSize + 1 );
2736 0 : if ( SWfieldinfo( hSW, poDS->pszFieldName, &poDS->iRank,
2737 : poDS->aiDimSizes, &poDS->iNumType,
2738 : pszDimList ) < 0 )
2739 : {
2740 0 : CPLDebug( "HDF4Image", "Can't read dimension maps." );
2741 0 : CPLFree( pszDimList );
2742 0 : delete poDS;
2743 0 : return NULL;
2744 : }
2745 0 : pszDimList[nStrBufSize] = '\0';
2746 : #ifdef DEBUG
2747 : CPLDebug( "HDF4Image",
2748 : "List of dimensions in swath \"%s\": %s",
2749 0 : poDS->pszFieldName, pszDimList );
2750 : #endif
2751 0 : poDS->GetImageDimensions( pszDimList );
2752 :
2753 : #ifdef DEBUG
2754 : CPLDebug( "HDF4Image",
2755 : "X dimension is %d, Y dimension is %d",
2756 0 : poDS->iXDim, poDS->iYDim );
2757 : #endif
2758 :
2759 : /* -------------------------------------------------------------------- */
2760 : /* Fetch metadata. */
2761 : /* -------------------------------------------------------------------- */
2762 0 : if( poDS->iSubdatasetType == H4ST_EOS_SWATH ) /* Not H4ST_EOS_SWATH_GEOL */
2763 0 : poDS->GetSwatAttrs( hSW );
2764 :
2765 : /* -------------------------------------------------------------------- */
2766 : /* Fetch NODATA value. */
2767 : /* -------------------------------------------------------------------- */
2768 : pNoDataValue =
2769 0 : CPLMalloc( poDS->GetDataTypeSize(poDS->iNumType) );
2770 0 : if ( SWgetfillvalue( hSW, poDS->pszFieldName,
2771 : pNoDataValue ) != -1 )
2772 : {
2773 : dfNoData = poDS->AnyTypeToDouble( poDS->iNumType,
2774 0 : pNoDataValue );
2775 0 : bNoDataSet = TRUE;
2776 : }
2777 : else
2778 : {
2779 : const char *pszNoData =
2780 : CSLFetchNameValue( poDS->papszLocalMetadata,
2781 0 : "_FillValue" );
2782 0 : if ( pszNoData )
2783 : {
2784 0 : dfNoData = CPLAtof( pszNoData );
2785 0 : bNoDataSet = TRUE;
2786 : }
2787 : }
2788 0 : CPLFree( pNoDataValue );
2789 :
2790 : /* -------------------------------------------------------------------- */
2791 : /* Handle Geolocation processing. */
2792 : /* -------------------------------------------------------------------- */
2793 0 : if( poDS->iSubdatasetType == H4ST_EOS_SWATH ) /* Not H4ST_SWATH_GEOL */
2794 : {
2795 : char **papszDimList =
2796 : CSLTokenizeString2( pszDimList, ",",
2797 0 : CSLT_HONOURSTRINGS );
2798 0 : if( !poDS->ProcessSwathGeolocation( hSW, papszDimList ) )
2799 : {
2800 : CPLDebug( "HDF4Image",
2801 0 : "No geolocation available for this swath." );
2802 : }
2803 0 : CSLDestroy( papszDimList );
2804 : }
2805 :
2806 : /* -------------------------------------------------------------------- */
2807 : /* Cleanup. */
2808 : /* -------------------------------------------------------------------- */
2809 0 : CPLFree( pszDimList );
2810 0 : SWdetach( hSW );
2811 : }
2812 0 : break;
2813 :
2814 : /* -------------------------------------------------------------------- */
2815 : /* HDF-EOS Grid. */
2816 : /* -------------------------------------------------------------------- */
2817 : case H4ST_EOS_GRID:
2818 : {
2819 8 : int32 hGD, iProjCode = 0, iZoneCode = 0, iSphereCode = 0;
2820 : int32 nXSize, nYSize;
2821 : char szDimList[8192];
2822 : double adfUpLeft[2], adfLowRight[2], adfProjParms[15];
2823 :
2824 8 : if( poOpenInfo->eAccess == GA_ReadOnly )
2825 8 : poDS->hHDF4 = GDopen( poDS->pszFilename, DFACC_READ );
2826 : else
2827 0 : poDS->hHDF4 = GDopen( poDS->pszFilename, DFACC_WRITE );
2828 :
2829 8 : if( poDS->hHDF4 <= 0 )
2830 : {
2831 0 : delete poDS;
2832 0 : return( NULL );
2833 : }
2834 :
2835 8 : hGD = GDattach( poDS->hHDF4, poDS->pszSubdatasetName );
2836 :
2837 : /* -------------------------------------------------------------------- */
2838 : /* Decode the dimension map. */
2839 : /* -------------------------------------------------------------------- */
2840 : GDfieldinfo( hGD, poDS->pszFieldName, &poDS->iRank,
2841 8 : poDS->aiDimSizes, &poDS->iNumType, szDimList );
2842 : #ifdef DEBUG
2843 : CPLDebug( "HDF4Image",
2844 : "List of dimensions in grid %s: %s",
2845 8 : poDS->pszFieldName, szDimList);
2846 : #endif
2847 8 : poDS->GetImageDimensions( szDimList );
2848 :
2849 : int32 tilecode, tilerank;
2850 8 : if( GDtileinfo( hGD , poDS->pszFieldName , &tilecode, &tilerank, NULL ) == 0 )
2851 : {
2852 8 : if ( tilecode == HDFE_TILE )
2853 : {
2854 6 : int32 *tiledims = NULL;
2855 6 : tiledims = (int32 *) CPLCalloc( tilerank , sizeof( int32 ) );
2856 6 : GDtileinfo( hGD , poDS->pszFieldName , &tilecode, &tilerank, tiledims );
2857 12 : if ( ( tilerank == 2 ) && ( poDS->iRank == tilerank ) )
2858 : {
2859 6 : poDS->nBlockPreferredXSize = tiledims[1];
2860 6 : poDS->nBlockPreferredYSize = tiledims[0];
2861 6 : poDS->bReadTile = true;
2862 : #ifdef DEBUG
2863 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilerank in grid %s: %d",
2864 6 : poDS->pszFieldName , (int)tilerank );
2865 : CPLDebug( "HDF4_EOS:EOS_GRID:","tiledimens in grid %s: %d,%d",
2866 6 : poDS->pszFieldName , (int)tiledims[0] , (int)tiledims[1] );
2867 : #endif
2868 : }
2869 : #ifdef DEBUG
2870 : else
2871 : {
2872 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilerank in grid %s: %d not supported",
2873 0 : poDS->pszFieldName , (int)tilerank );
2874 : }
2875 : #endif
2876 6 : CPLFree(tiledims);
2877 : }
2878 : else
2879 : {
2880 : #ifdef DEBUG
2881 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilecode == HDFE_NOTILE in grid %s: %d",
2882 : poDS->pszFieldName ,
2883 2 : (int)poDS->iRank );
2884 : #endif
2885 : }
2886 : }
2887 : #ifdef DEBUG
2888 : else
2889 : {
2890 0 : CPLDebug( "HDF4_EOS:EOS_GRID:","ERROR GDtileinfo %s", poDS->pszFieldName );
2891 : }
2892 : #endif
2893 :
2894 : /* -------------------------------------------------------------------- */
2895 : /* Fetch projection information */
2896 : /* -------------------------------------------------------------------- */
2897 8 : if ( GDprojinfo( hGD, &iProjCode, &iZoneCode,
2898 : &iSphereCode, adfProjParms) >= 0 )
2899 : {
2900 : #ifdef DEBUG
2901 : CPLDebug( "HDF4Image",
2902 : "Grid projection: "
2903 : "projection code: %ld, zone code %ld, "
2904 : "sphere code %ld",
2905 : (long)iProjCode, (long)iZoneCode,
2906 8 : (long)iSphereCode );
2907 : #endif
2908 : poDS->oSRS.importFromUSGS( iProjCode, iZoneCode,
2909 8 : adfProjParms, iSphereCode );
2910 :
2911 8 : if ( poDS->pszProjection )
2912 8 : CPLFree( poDS->pszProjection );
2913 8 : poDS->oSRS.exportToWkt( &poDS->pszProjection );
2914 : }
2915 :
2916 : /* -------------------------------------------------------------------- */
2917 : /* Fetch geotransformation matrix */
2918 : /* -------------------------------------------------------------------- */
2919 8 : if ( GDgridinfo( hGD, &nXSize, &nYSize,
2920 : adfUpLeft, adfLowRight ) >= 0 )
2921 : {
2922 : #ifdef DEBUG
2923 : CPLDebug( "HDF4Image",
2924 : "Grid geolocation: "
2925 : "top left X %f, top left Y %f, "
2926 : "low right X %f, low right Y %f, "
2927 : "cols %ld, rows %ld",
2928 : adfUpLeft[0], adfUpLeft[1],
2929 : adfLowRight[0], adfLowRight[1],
2930 8 : (long)nXSize, (long)nYSize );
2931 : #endif
2932 8 : if ( iProjCode )
2933 : {
2934 : // For projected systems coordinates are in meters
2935 : poDS->adfGeoTransform[1] =
2936 6 : (adfLowRight[0] - adfUpLeft[0]) / nXSize;
2937 : poDS->adfGeoTransform[5] =
2938 6 : (adfLowRight[1] - adfUpLeft[1]) / nYSize;
2939 6 : poDS->adfGeoTransform[0] = adfUpLeft[0];
2940 6 : poDS->adfGeoTransform[3] = adfUpLeft[1];
2941 : }
2942 : else
2943 : {
2944 : // Handle angular geographic coordinates here
2945 : poDS->adfGeoTransform[1] =
2946 : (CPLPackedDMSToDec(adfLowRight[0]) -
2947 2 : CPLPackedDMSToDec(adfUpLeft[0])) / nXSize;
2948 : poDS->adfGeoTransform[5] =
2949 : (CPLPackedDMSToDec(adfLowRight[1]) -
2950 2 : CPLPackedDMSToDec(adfUpLeft[1])) / nYSize;
2951 : poDS->adfGeoTransform[0] =
2952 2 : CPLPackedDMSToDec(adfUpLeft[0]);
2953 : poDS->adfGeoTransform[3] =
2954 2 : CPLPackedDMSToDec(adfUpLeft[1]);
2955 : }
2956 8 : poDS->adfGeoTransform[2] = 0.0;
2957 8 : poDS->adfGeoTransform[4] = 0.0;
2958 8 : poDS->bHasGeoTransform = TRUE;
2959 : }
2960 :
2961 : /* -------------------------------------------------------------------- */
2962 : /* Fetch metadata. */
2963 : /* -------------------------------------------------------------------- */
2964 8 : poDS->GetGridAttrs( hGD );
2965 :
2966 8 : GDdetach( hGD );
2967 :
2968 : /* -------------------------------------------------------------------- */
2969 : /* Fetch NODATA value. */
2970 : /* -------------------------------------------------------------------- */
2971 : pNoDataValue =
2972 8 : CPLMalloc( poDS->GetDataTypeSize(poDS->iNumType) );
2973 8 : if ( GDgetfillvalue( hGD, poDS->pszFieldName,
2974 : pNoDataValue ) != -1 )
2975 : {
2976 : dfNoData = poDS->AnyTypeToDouble( poDS->iNumType,
2977 0 : pNoDataValue );
2978 0 : bNoDataSet = TRUE;
2979 : }
2980 : else
2981 : {
2982 : const char *pszNoData =
2983 : CSLFetchNameValue( poDS->papszLocalMetadata,
2984 8 : "_FillValue" );
2985 8 : if ( pszNoData )
2986 : {
2987 6 : dfNoData = CPLAtof( pszNoData );
2988 6 : bNoDataSet = TRUE;
2989 : }
2990 : }
2991 8 : CPLFree( pNoDataValue );
2992 : }
2993 : break;
2994 :
2995 : default:
2996 : break;
2997 : }
2998 :
2999 : /* -------------------------------------------------------------------- */
3000 : /* Fetch unit type, scale, offset and description */
3001 : /* Should be similar among various HDF-EOS kinds. */
3002 : /* -------------------------------------------------------------------- */
3003 : {
3004 : const char *pszTmp =
3005 : CSLFetchNameValue( poDS->papszLocalMetadata,
3006 8 : "scale_factor" );
3007 8 : if ( pszTmp )
3008 : {
3009 6 : dfScale = CPLAtof( pszTmp );
3010 6 : bHaveScale = TRUE;
3011 : }
3012 :
3013 : pszTmp =
3014 8 : CSLFetchNameValue( poDS->papszLocalMetadata, "add_offset" );
3015 8 : if ( pszTmp )
3016 : {
3017 4 : dfOffset = CPLAtof( pszTmp );
3018 4 : bHaveOffset = TRUE;
3019 : }
3020 :
3021 : pszUnits = CSLFetchNameValue( poDS->papszLocalMetadata,
3022 8 : "units" );
3023 : pszDescription = CSLFetchNameValue( poDS->papszLocalMetadata,
3024 8 : "long_name" );
3025 : }
3026 : }
3027 8 : break;
3028 :
3029 : /* -------------------------------------------------------------------- */
3030 : /* 'Plain' HDF scientific datasets. */
3031 : /* -------------------------------------------------------------------- */
3032 : case HDF4_SDS:
3033 : {
3034 : int32 iSDS;
3035 :
3036 256 : if( poOpenInfo->eAccess == GA_ReadOnly )
3037 256 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_READ, 0 );
3038 : else
3039 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_WRITE, 0 );
3040 :
3041 256 : if( poDS->hHDF4 <= 0 )
3042 : {
3043 0 : delete poDS;
3044 0 : return( NULL );
3045 : }
3046 :
3047 256 : poDS->hSD = SDstart( poDS->pszFilename, DFACC_READ );
3048 256 : if ( poDS->hSD == -1 )
3049 : {
3050 0 : delete poDS;
3051 0 : return NULL;
3052 : }
3053 :
3054 256 : if ( poDS->ReadGlobalAttributes( poDS->hSD ) != CE_None )
3055 : {
3056 0 : delete poDS;
3057 0 : return NULL;
3058 : }
3059 :
3060 : int32 nDatasets, nAttrs;
3061 :
3062 256 : if ( SDfileinfo( poDS->hSD, &nDatasets, &nAttrs ) != 0 )
3063 : {
3064 0 : delete poDS;
3065 0 : return NULL;
3066 : }
3067 :
3068 256 : if (poDS->iDataset < 0 || poDS->iDataset >= nDatasets)
3069 : {
3070 : CPLError(CE_Failure, CPLE_AppDefined,
3071 : "Subdataset index should be between 0 and %ld",
3072 0 : (long int)nDatasets - 1);
3073 0 : delete poDS;
3074 0 : return NULL;
3075 : }
3076 :
3077 256 : memset( poDS->aiDimSizes, 0, sizeof(int32) * H4_MAX_VAR_DIMS );
3078 256 : iSDS = SDselect( poDS->hSD, poDS->iDataset );
3079 : SDgetinfo( iSDS, poDS->szName, &poDS->iRank, poDS->aiDimSizes,
3080 256 : &poDS->iNumType, &poDS->nAttrs);
3081 :
3082 : // We will duplicate global metadata for every subdataset
3083 : poDS->papszLocalMetadata =
3084 256 : CSLDuplicate( poDS->papszGlobalMetadata );
3085 :
3086 287 : for ( iAttribute = 0; iAttribute < poDS->nAttrs; iAttribute++ )
3087 : {
3088 : char szAttrName[H4_MAX_NC_NAME];
3089 : SDattrinfo( iSDS, iAttribute, szAttrName,
3090 31 : &iAttrNumType, &nValues );
3091 : poDS->papszLocalMetadata =
3092 : poDS->TranslateHDF4Attributes( iSDS, iAttribute,
3093 : szAttrName, iAttrNumType,
3094 : nValues,
3095 31 : poDS->papszLocalMetadata );
3096 : }
3097 256 : poDS->SetMetadata( poDS->papszLocalMetadata, "" );
3098 256 : SDendaccess( iSDS );
3099 :
3100 : #ifdef DEBUG
3101 : CPLDebug( "HDF4Image",
3102 : "aiDimSizes[0]=%ld, aiDimSizes[1]=%ld, "
3103 : "aiDimSizes[2]=%ld, aiDimSizes[3]=%ld",
3104 512 : (long)poDS->aiDimSizes[0], (long)poDS->aiDimSizes[1],
3105 768 : (long)poDS->aiDimSizes[2], (long)poDS->aiDimSizes[3] );
3106 : #endif
3107 :
3108 256 : switch( poDS->iRank )
3109 : {
3110 : case 1:
3111 0 : poDS->nBandCount = 1;
3112 0 : poDS->iXDim = 0;
3113 0 : poDS->iYDim = -1;
3114 0 : break;
3115 : case 2:
3116 110 : poDS->nBandCount = 1;
3117 110 : poDS->iXDim = 1;
3118 110 : poDS->iYDim = 0;
3119 110 : break;
3120 : case 3:
3121 : /* FIXME ? We should probably remove the following test as there are valid datasets */
3122 : /* where the height is lower than the band number : for example
3123 : http://www.iapmw.unibe.ch/research/projects/FriOWL/data/otd/LISOTD_HRAC_V2.2.hdf */
3124 : /* which is a 720x360 x 365 bands */
3125 : /* Use a HACK for now */
3126 146 : if( poDS->aiDimSizes[0] < poDS->aiDimSizes[2] &&
3127 0 : !(poDS->aiDimSizes[0] == 360 &&
3128 0 : poDS->aiDimSizes[1] == 720 &&
3129 0 : poDS->aiDimSizes[2] == 365) )
3130 : {
3131 0 : poDS->iBandDim = 0;
3132 0 : poDS->iXDim = 2;
3133 0 : poDS->iYDim = 1;
3134 : }
3135 : else
3136 : {
3137 292 : if( poDS->aiDimSizes[1] <= poDS->aiDimSizes[0] &&
3138 146 : poDS->aiDimSizes[1] <= poDS->aiDimSizes[2] )
3139 : {
3140 0 : poDS->iBandDim = 1;
3141 0 : poDS->iXDim = 2;
3142 0 : poDS->iYDim = 0;
3143 : }
3144 : else
3145 : {
3146 146 : poDS->iBandDim = 2;
3147 146 : poDS->iXDim = 1;
3148 146 : poDS->iYDim = 0;
3149 :
3150 : }
3151 : }
3152 146 : poDS->nBandCount = poDS->aiDimSizes[poDS->iBandDim];
3153 146 : break;
3154 : case 4: // FIXME
3155 0 : poDS->nBandCount = poDS->aiDimSizes[2] * poDS->aiDimSizes[3];
3156 : break;
3157 : default:
3158 : break;
3159 : }
3160 :
3161 : // We preset this because CaptureNRLGeoTransform needs it.
3162 256 : poDS->nRasterXSize = poDS->aiDimSizes[poDS->iXDim];
3163 256 : if (poDS->iYDim >= 0)
3164 256 : poDS->nRasterYSize = poDS->aiDimSizes[poDS->iYDim];
3165 : else
3166 0 : poDS->nRasterYSize = 1;
3167 :
3168 : // Special case projection info for NRL generated files.
3169 : const char *pszMapProjectionSystem =
3170 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3171 256 : "mapProjectionSystem");
3172 256 : if( pszMapProjectionSystem != NULL
3173 : && EQUAL(pszMapProjectionSystem,"NRL(USGS)") )
3174 : {
3175 0 : poDS->CaptureNRLGeoTransform();
3176 : }
3177 :
3178 : // Special case for coastwatch hdf files.
3179 256 : if( CSLFetchNameValue( poDS->papszGlobalMetadata,
3180 : "gctp_sys" ) != NULL )
3181 0 : poDS->CaptureCoastwatchGCTPInfo();
3182 :
3183 : // Special case for MODIS geolocation
3184 256 : poDS->ProcessModisSDSGeolocation();
3185 :
3186 : // Special case for NASA/CCRS Landsat in HDF
3187 256 : poDS->CaptureL1GMTLInfo();
3188 : }
3189 256 : break;
3190 :
3191 : /* -------------------------------------------------------------------- */
3192 : /* 'Plain' HDF rasters. */
3193 : /* -------------------------------------------------------------------- */
3194 : case HDF4_GR:
3195 0 : if( poOpenInfo->eAccess == GA_ReadOnly )
3196 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_READ, 0 );
3197 : else
3198 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_WRITE, 0 );
3199 :
3200 0 : if( poDS->hHDF4 <= 0 )
3201 : {
3202 0 : delete poDS;
3203 0 : return( NULL );
3204 : }
3205 :
3206 0 : poDS->hGR = GRstart( poDS->hHDF4 );
3207 0 : if ( poDS->hGR == -1 )
3208 : {
3209 0 : delete poDS;
3210 0 : return NULL;
3211 : }
3212 :
3213 0 : poDS->iGR = GRselect( poDS->hGR, poDS->iDataset );
3214 0 : if ( GRgetiminfo( poDS->iGR, poDS->szName,
3215 : &poDS->iRank, &poDS->iNumType,
3216 : &poDS->iInterlaceMode, poDS->aiDimSizes,
3217 : &poDS->nAttrs ) != 0 )
3218 : {
3219 0 : delete poDS;
3220 0 : return NULL;
3221 : }
3222 :
3223 : // We will duplicate global metadata for every subdataset
3224 0 : poDS->papszLocalMetadata = CSLDuplicate( poDS->papszGlobalMetadata );
3225 :
3226 0 : for ( iAttribute = 0; iAttribute < poDS->nAttrs; iAttribute++ )
3227 : {
3228 : char szAttrName[H4_MAX_NC_NAME];
3229 : GRattrinfo( poDS->iGR, iAttribute, szAttrName,
3230 0 : &iAttrNumType, &nValues );
3231 : poDS->papszLocalMetadata =
3232 : poDS->TranslateHDF4Attributes( poDS->iGR, iAttribute,
3233 : szAttrName, iAttrNumType,
3234 : nValues,
3235 0 : poDS->papszLocalMetadata );
3236 : }
3237 0 : poDS->SetMetadata( poDS->papszLocalMetadata, "" );
3238 : // Read colour table
3239 : GDALColorEntry oEntry;
3240 :
3241 0 : poDS->iPal = GRgetlutid ( poDS->iGR, poDS->iDataset );
3242 0 : if ( poDS->iPal != -1 )
3243 : {
3244 : GRgetlutinfo( poDS->iPal, &poDS->nComps, &poDS->iPalDataType,
3245 0 : &poDS->iPalInterlaceMode, &poDS->nPalEntries );
3246 0 : GRreadlut( poDS->iPal, poDS->aiPaletteData );
3247 0 : poDS->poColorTable = new GDALColorTable();
3248 0 : for( i = 0; i < N_COLOR_ENTRIES; i++ )
3249 : {
3250 0 : oEntry.c1 = poDS->aiPaletteData[i][0];
3251 0 : oEntry.c2 = poDS->aiPaletteData[i][1];
3252 0 : oEntry.c3 = poDS->aiPaletteData[i][2];
3253 0 : oEntry.c4 = 255;
3254 :
3255 0 : poDS->poColorTable->SetColorEntry( i, &oEntry );
3256 : }
3257 : }
3258 :
3259 0 : poDS->iXDim = 0;
3260 0 : poDS->iYDim = 1;
3261 0 : poDS->nBandCount = poDS->iRank;
3262 0 : break;
3263 : default:
3264 0 : delete poDS;
3265 0 : return NULL;
3266 : }
3267 :
3268 264 : poDS->nRasterXSize = poDS->aiDimSizes[poDS->iXDim];
3269 264 : if (poDS->iYDim >= 0)
3270 264 : poDS->nRasterYSize = poDS->aiDimSizes[poDS->iYDim];
3271 : else
3272 0 : poDS->nRasterYSize = 1;
3273 :
3274 264 : if ( poDS->iSubdatasetType == H4ST_HYPERION_L1 )
3275 : {
3276 : // XXX: Hyperion SDSs has Height x Bands x Width dimensions scheme
3277 0 : if ( poDS->iRank > 2 )
3278 : {
3279 0 : poDS->nBandCount = poDS->aiDimSizes[1];
3280 0 : poDS->nRasterXSize = poDS->aiDimSizes[2];
3281 0 : poDS->nRasterYSize = poDS->aiDimSizes[0];
3282 : }
3283 : else
3284 : {
3285 0 : poDS->nBandCount = poDS->aiDimSizes[0];
3286 0 : poDS->nRasterXSize = poDS->aiDimSizes[1];
3287 0 : poDS->nRasterYSize = 1;
3288 : }
3289 : }
3290 :
3291 : /* -------------------------------------------------------------------- */
3292 : /* Create band information objects. */
3293 : /* -------------------------------------------------------------------- */
3294 572 : for( i = 1; i <= poDS->nBandCount; i++ )
3295 : {
3296 : HDF4ImageRasterBand *poBand =
3297 : new HDF4ImageRasterBand( poDS, i,
3298 308 : poDS->GetDataType( poDS->iNumType ) );
3299 308 : poDS->SetBand( i, poBand );
3300 :
3301 308 : if ( bNoDataSet )
3302 6 : poBand->SetNoDataValue( dfNoData );
3303 308 : if ( bHaveScale )
3304 : {
3305 6 : poBand->bHaveScale = TRUE;
3306 6 : poBand->dfScale = dfScale;
3307 : }
3308 308 : if ( bHaveOffset )
3309 : {
3310 4 : poBand->bHaveOffset = TRUE;
3311 4 : poBand->dfOffset = dfOffset;
3312 : }
3313 308 : if ( pszUnits )
3314 6 : poBand->osUnitType = pszUnits;
3315 308 : if ( pszDescription )
3316 8 : poBand->SetDescription( pszDescription );
3317 : }
3318 :
3319 : /* -------------------------------------------------------------------- */
3320 : /* Now we will handle particular types of HDF products. Every */
3321 : /* HDF product has its own structure. */
3322 : /* -------------------------------------------------------------------- */
3323 :
3324 : // Variables for reading georeferencing
3325 : double dfULX, dfULY, dfLRX, dfLRY;
3326 :
3327 264 : switch ( poDS->iSubdatasetType )
3328 : {
3329 : /* -------------------------------------------------------------------- */
3330 : /* HDF, created by GDAL. */
3331 : /* -------------------------------------------------------------------- */
3332 : case H4ST_GDAL:
3333 : {
3334 : const char *pszValue;
3335 :
3336 : CPLDebug( "HDF4Image",
3337 249 : "Input dataset interpreted as GDAL_HDF4" );
3338 :
3339 249 : if ( (pszValue =
3340 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3341 : "Projection")) )
3342 : {
3343 105 : if ( poDS->pszProjection )
3344 105 : CPLFree( poDS->pszProjection );
3345 105 : poDS->pszProjection = CPLStrdup( pszValue );
3346 : }
3347 249 : if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata,
3348 : "TransformationMatrix")) )
3349 : {
3350 249 : int i = 0;
3351 249 : char *pszString = (char *) pszValue;
3352 1992 : while ( *pszValue && i < 6 )
3353 : {
3354 1494 : poDS->adfGeoTransform[i++] = strtod(pszString, &pszString);
3355 1494 : pszString++;
3356 : }
3357 249 : poDS->bHasGeoTransform = TRUE;
3358 : }
3359 528 : for( i = 1; i <= poDS->nBands; i++ )
3360 : {
3361 279 : if ( (pszValue =
3362 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3363 : CPLSPrintf("BandDesc%d", i))) )
3364 32 : poDS->GetRasterBand( i )->SetDescription( pszValue );
3365 : }
3366 528 : for( i = 1; i <= poDS->nBands; i++ )
3367 : {
3368 279 : if ( (pszValue =
3369 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3370 : CPLSPrintf("NoDataValue%d", i))) )
3371 32 : poDS->GetRasterBand(i)->SetNoDataValue( CPLAtof(pszValue) );
3372 : }
3373 : }
3374 249 : break;
3375 :
3376 : /* -------------------------------------------------------------------- */
3377 : /* SeaWiFS Level 3 Standard Mapped Image Products. */
3378 : /* Organized similar to MODIS Level 3 products. */
3379 : /* -------------------------------------------------------------------- */
3380 : case H4ST_SEAWIFS_L3:
3381 : {
3382 0 : CPLDebug( "HDF4Image", "Input dataset interpreted as SEAWIFS_L3" );
3383 :
3384 : // Read band description
3385 0 : for ( i = 1; i <= poDS->nBands; i++ )
3386 : {
3387 : poDS->GetRasterBand( i )->SetDescription(
3388 0 : CSLFetchNameValue( poDS->papszGlobalMetadata, "Parameter" ) );
3389 : }
3390 :
3391 : // Read coordinate system and geotransform matrix
3392 0 : poDS->oSRS.SetWellKnownGeogCS( "WGS84" );
3393 :
3394 0 : if ( EQUAL(CSLFetchNameValue(poDS->papszGlobalMetadata,
3395 : "Map Projection"),
3396 : "Equidistant Cylindrical") )
3397 : {
3398 0 : poDS->oSRS.SetEquirectangular( 0.0, 0.0, 0.0, 0.0 );
3399 0 : poDS->oSRS.SetLinearUnits( SRS_UL_METER, 1 );
3400 0 : if ( poDS->pszProjection )
3401 0 : CPLFree( poDS->pszProjection );
3402 0 : poDS->oSRS.exportToWkt( &poDS->pszProjection );
3403 : }
3404 :
3405 : dfULX = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3406 0 : "Westernmost Longitude") );
3407 : dfULY = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3408 0 : "Northernmost Latitude") );
3409 : dfLRX = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3410 0 : "Easternmost Longitude") );
3411 : dfLRY = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3412 0 : "Southernmost Latitude") );
3413 0 : poDS->ToGeoref( &dfULX, &dfULY );
3414 0 : poDS->ToGeoref( &dfLRX, &dfLRY );
3415 0 : poDS->adfGeoTransform[0] = dfULX;
3416 0 : poDS->adfGeoTransform[3] = dfULY;
3417 0 : poDS->adfGeoTransform[1] = (dfLRX - dfULX) / poDS->nRasterXSize;
3418 0 : poDS->adfGeoTransform[5] = (dfULY - dfLRY) / poDS->nRasterYSize;
3419 0 : if ( dfULY > 0) // Northern hemisphere
3420 0 : poDS->adfGeoTransform[5] = - poDS->adfGeoTransform[5];
3421 0 : poDS->adfGeoTransform[2] = 0.0;
3422 0 : poDS->adfGeoTransform[4] = 0.0;
3423 0 : poDS->bHasGeoTransform = TRUE;
3424 : }
3425 0 : break;
3426 :
3427 :
3428 : /* -------------------------------------------------------------------- */
3429 : /* Generic SDS */
3430 : /* -------------------------------------------------------------------- */
3431 : case H4ST_UNKNOWN:
3432 : {
3433 :
3434 : // This is a coastwatch convention.
3435 7 : if( CSLFetchNameValue( poDS->papszLocalMetadata, "missing_value" ) )
3436 : {
3437 : int i;
3438 0 : for( i = 1; i <= poDS->nBands; i++ )
3439 : {
3440 : poDS->GetRasterBand(i)->SetNoDataValue(
3441 : CPLAtof( CSLFetchNameValue(poDS->papszLocalMetadata,
3442 0 : "missing_value") ) );
3443 : }
3444 : }
3445 :
3446 : // Coastwatch offset and scale.
3447 7 : if( CSLFetchNameValue( poDS->papszLocalMetadata, "scale_factor" )
3448 : && CSLFetchNameValue( poDS->papszLocalMetadata, "add_offset" ) )
3449 : {
3450 0 : for( i = 1; i <= poDS->nBands; i++ )
3451 : {
3452 : HDF4ImageRasterBand *poBand =
3453 0 : (HDF4ImageRasterBand *) poDS->GetRasterBand(i);
3454 :
3455 0 : poBand->bHaveScale = poBand->bHaveOffset = TRUE;
3456 : poBand->dfScale =
3457 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3458 0 : "scale_factor" ) );
3459 : poBand->dfOffset = -1 * poBand->dfScale *
3460 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3461 0 : "add_offset" ) );
3462 : }
3463 : }
3464 :
3465 : // this is a modis level3 convention (data from ACT)
3466 : // Eg data/hdf/act/modis/MODAM2004280160000.L3_NOAA_GMX
3467 :
3468 7 : if( CSLFetchNameValue( poDS->papszLocalMetadata,
3469 : "scalingSlope" )
3470 : && CSLFetchNameValue( poDS->papszLocalMetadata,
3471 : "scalingIntercept" ) )
3472 : {
3473 : int i;
3474 0 : CPLString osUnits;
3475 :
3476 0 : if( CSLFetchNameValue( poDS->papszLocalMetadata,
3477 : "productUnits" ) )
3478 : {
3479 : osUnits = CSLFetchNameValue( poDS->papszLocalMetadata,
3480 0 : "productUnits" );
3481 : }
3482 :
3483 0 : for( i = 1; i <= poDS->nBands; i++ )
3484 : {
3485 : HDF4ImageRasterBand *poBand =
3486 0 : (HDF4ImageRasterBand *) poDS->GetRasterBand(i);
3487 :
3488 0 : poBand->bHaveScale = poBand->bHaveOffset = TRUE;
3489 : poBand->dfScale =
3490 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3491 0 : "scalingSlope" ) );
3492 : poBand->dfOffset =
3493 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3494 0 : "scalingIntercept" ) );
3495 :
3496 0 : poBand->osUnitType = osUnits;
3497 0 : }
3498 : }
3499 : }
3500 7 : break;
3501 :
3502 : /* -------------------------------------------------------------------- */
3503 : /* Hyperion Level 1. */
3504 : /* -------------------------------------------------------------------- */
3505 : case H4ST_HYPERION_L1:
3506 : {
3507 0 : CPLDebug( "HDF4Image", "Input dataset interpreted as HYPERION_L1" );
3508 : }
3509 : break;
3510 :
3511 : default:
3512 : break;
3513 : }
3514 :
3515 : /* -------------------------------------------------------------------- */
3516 : /* Setup PAM info for this subdataset */
3517 : /* -------------------------------------------------------------------- */
3518 264 : poDS->SetPhysicalFilename( poDS->pszFilename );
3519 264 : poDS->SetSubdatasetName( osSubdatasetName );
3520 :
3521 264 : poDS->TryLoadXML();
3522 :
3523 264 : poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
3524 :
3525 264 : return( poDS );
3526 : }
3527 :
3528 : /************************************************************************/
3529 : /* Create() */
3530 : /************************************************************************/
3531 :
3532 147 : GDALDataset *HDF4ImageDataset::Create( const char * pszFilename,
3533 : int nXSize, int nYSize, int nBands,
3534 : GDALDataType eType,
3535 : char **papszOptions )
3536 :
3537 : {
3538 : /* -------------------------------------------------------------------- */
3539 : /* Create the dataset. */
3540 : /* -------------------------------------------------------------------- */
3541 : HDF4ImageDataset *poDS;
3542 : const char *pszSDSName;
3543 : int iBand;
3544 147 : int32 iSDS = -1;
3545 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
3546 :
3547 147 : if( nBands == 0 )
3548 : {
3549 : CPLError( CE_Failure, CPLE_NotSupported,
3550 1 : "Unable to export files with zero bands." );
3551 1 : return NULL;
3552 : }
3553 :
3554 146 : poDS = new HDF4ImageDataset();
3555 :
3556 : /* -------------------------------------------------------------------- */
3557 : /* Choose rank for the created dataset. */
3558 : /* -------------------------------------------------------------------- */
3559 146 : poDS->iRank = 3;
3560 250 : if ( CSLFetchNameValue( papszOptions, "RANK" ) != NULL &&
3561 : EQUAL( CSLFetchNameValue( papszOptions, "RANK" ), "2" ) )
3562 48 : poDS->iRank = 2;
3563 :
3564 146 : poDS->hSD = SDstart( pszFilename, DFACC_CREATE );
3565 146 : if ( poDS->hSD == -1 )
3566 : {
3567 : CPLError( CE_Failure, CPLE_OpenFailed,
3568 2 : "Can't create HDF4 file %s", pszFilename );
3569 2 : delete poDS;
3570 2 : return NULL;
3571 : }
3572 144 : poDS->iXDim = 1;
3573 144 : poDS->iYDim = 0;
3574 144 : poDS->iBandDim = 2;
3575 144 : aiDimSizes[poDS->iXDim] = nXSize;
3576 144 : aiDimSizes[poDS->iYDim] = nYSize;
3577 144 : aiDimSizes[poDS->iBandDim] = nBands;
3578 :
3579 144 : if ( poDS->iRank == 2 )
3580 : {
3581 96 : for ( iBand = 0; iBand < nBands; iBand++ )
3582 : {
3583 48 : pszSDSName = CPLSPrintf( "Band%d", iBand );
3584 48 : switch ( eType )
3585 : {
3586 : case GDT_Float64:
3587 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT64,
3588 6 : poDS->iRank, aiDimSizes );
3589 6 : break;
3590 : case GDT_Float32:
3591 : iSDS = SDcreate( poDS-> hSD, pszSDSName, DFNT_FLOAT32,
3592 6 : poDS->iRank, aiDimSizes );
3593 6 : break;
3594 : case GDT_UInt32:
3595 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT32,
3596 6 : poDS->iRank, aiDimSizes );
3597 6 : break;
3598 : case GDT_UInt16:
3599 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT16,
3600 6 : poDS->iRank, aiDimSizes );
3601 6 : break;
3602 : case GDT_Int32:
3603 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT32,
3604 6 : poDS->iRank, aiDimSizes );
3605 6 : break;
3606 : case GDT_Int16:
3607 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT16,
3608 6 : poDS->iRank, aiDimSizes );
3609 6 : break;
3610 : case GDT_Byte:
3611 : default:
3612 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT8,
3613 12 : poDS->iRank, aiDimSizes );
3614 : break;
3615 : }
3616 48 : SDendaccess( iSDS );
3617 : }
3618 : }
3619 96 : else if ( poDS->iRank == 3 )
3620 : {
3621 96 : pszSDSName = "3-dimensional Scientific Dataset";
3622 96 : poDS->iDataset = 0;
3623 96 : switch ( eType )
3624 : {
3625 : case GDT_Float64:
3626 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT64,
3627 10 : poDS->iRank, aiDimSizes );
3628 10 : break;
3629 : case GDT_Float32:
3630 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT32,
3631 10 : poDS->iRank, aiDimSizes );
3632 10 : break;
3633 : case GDT_UInt32:
3634 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT32,
3635 10 : poDS->iRank, aiDimSizes );
3636 10 : break;
3637 : case GDT_UInt16:
3638 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT16,
3639 10 : poDS->iRank, aiDimSizes );
3640 10 : break;
3641 : case GDT_Int32:
3642 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT32,
3643 10 : poDS->iRank, aiDimSizes );
3644 10 : break;
3645 : case GDT_Int16:
3646 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT16,
3647 10 : poDS->iRank, aiDimSizes );
3648 10 : break;
3649 : case GDT_Byte:
3650 : default:
3651 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT8,
3652 36 : poDS->iRank, aiDimSizes );
3653 : break;
3654 : }
3655 : }
3656 : else // Should never happen
3657 0 : return NULL;
3658 :
3659 144 : if ( iSDS < 0 )
3660 : {
3661 : CPLError( CE_Failure, CPLE_AppDefined,
3662 : "Can't create SDS with rank %ld for file %s",
3663 0 : (long)poDS->iRank, pszFilename );
3664 0 : return NULL;
3665 : }
3666 :
3667 144 : poDS->nRasterXSize = nXSize;
3668 144 : poDS->nRasterYSize = nYSize;
3669 144 : poDS->eAccess = GA_Update;
3670 144 : poDS->iDatasetType = HDF4_SDS;
3671 144 : poDS->iSubdatasetType = H4ST_GDAL;
3672 144 : poDS->nBands = nBands;
3673 :
3674 : /* -------------------------------------------------------------------- */
3675 : /* Create band information objects. */
3676 : /* -------------------------------------------------------------------- */
3677 656 : for( iBand = 1; iBand <= nBands; iBand++ )
3678 184 : poDS->SetBand( iBand, new HDF4ImageRasterBand( poDS, iBand, eType ) );
3679 :
3680 : SDsetattr( poDS->hSD, "Signature", DFNT_CHAR8, strlen(pszGDALSignature) + 1,
3681 144 : pszGDALSignature );
3682 :
3683 144 : return (GDALDataset *) poDS;
3684 : }
3685 :
3686 : /************************************************************************/
3687 : /* GDALRegister_HDF4Image() */
3688 : /************************************************************************/
3689 :
3690 558 : void GDALRegister_HDF4Image()
3691 :
3692 : {
3693 : GDALDriver *poDriver;
3694 :
3695 558 : if( GDALGetDriverByName( "HDF4Image" ) == NULL )
3696 : {
3697 537 : poDriver = new GDALDriver();
3698 :
3699 537 : poDriver->SetDescription( "HDF4Image" );
3700 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
3701 537 : "HDF4 Dataset" );
3702 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
3703 537 : "frmt_hdf4.html" );
3704 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
3705 537 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
3706 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
3707 : "<CreationOptionList>"
3708 : " <Option name='RANK' type='int' description='Rank of output SDS'/>"
3709 537 : "</CreationOptionList>" );
3710 :
3711 537 : poDriver->pfnOpen = HDF4ImageDataset::Open;
3712 537 : poDriver->pfnCreate = HDF4ImageDataset::Create;
3713 :
3714 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
3715 : }
3716 558 : }
3717 :
|