1 : /******************************************************************************
2 : * $Id: hdf4imagedataset.cpp 19494 2010-04-22 04:19:35Z warmerdam $
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 19494 2010-04-22 04:19:35Z warmerdam $");
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 : };
76 :
77 : /************************************************************************/
78 : /* ==================================================================== */
79 : /* HDF4ImageDataset */
80 : /* ==================================================================== */
81 : /************************************************************************/
82 :
83 : class HDF4ImageDataset : public HDF4Dataset
84 : {
85 : friend class HDF4ImageRasterBand;
86 :
87 : char *pszFilename;
88 : int32 hHDF4, iGR, iPal, iDataset;
89 : int32 iRank, iNumType, nAttrs,
90 : iInterlaceMode, iPalInterlaceMode, iPalDataType;
91 : int32 nComps, nPalEntries;
92 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
93 : int iXDim, iYDim, iBandDim, i4Dim;
94 : int nBandCount;
95 : char **papszLocalMetadata;
96 : #define N_COLOR_ENTRIES 256
97 : uint8 aiPaletteData[N_COLOR_ENTRIES][3]; // XXX: Static array for now
98 : char szName[HDF4_SDS_MAXNAMELEN];
99 : char *pszSubdatasetName;
100 : char *pszFieldName;
101 :
102 : GDALColorTable *poColorTable;
103 :
104 : OGRSpatialReference oSRS;
105 : int bHasGeoTransform;
106 : double adfGeoTransform[6];
107 : char *pszProjection;
108 : char *pszGCPProjection;
109 : GDAL_GCP *pasGCPList;
110 : int nGCPCount;
111 :
112 : HDF4DatasetType iDatasetType;
113 :
114 : int32 iSDS;
115 :
116 : int nBlockPreferredXSize;
117 : int nBlockPreferredYSize;
118 : bool bReadTile;
119 :
120 : void ToGeoref( double *, double * );
121 : void GetImageDimensions( char * );
122 : void GetSwatAttrs( int32 );
123 : void GetGridAttrs( int32 hGD );
124 : void CaptureNRLGeoTransform(void);
125 : void CaptureL1GMTLInfo(void);
126 : void CaptureCoastwatchGCTPInfo(void);
127 : void ProcessModisSDSGeolocation(void);
128 : int ProcessSwathGeolocation( int32, char ** );
129 :
130 : static long USGSMnemonicToCode( const char* );
131 : static void ReadCoordinates( const char*, double*, double* );
132 :
133 : public:
134 : HDF4ImageDataset();
135 : ~HDF4ImageDataset();
136 :
137 : static GDALDataset *Open( GDALOpenInfo * );
138 : static GDALDataset *Create( const char * pszFilename,
139 : int nXSize, int nYSize, int nBands,
140 : GDALDataType eType, char ** papszParmList );
141 : virtual void FlushCache( void );
142 : CPLErr GetGeoTransform( double * padfTransform );
143 : virtual CPLErr SetGeoTransform( double * );
144 : const char *GetProjectionRef();
145 : virtual CPLErr SetProjection( const char * );
146 : virtual int GetGCPCount();
147 : virtual const char *GetGCPProjection();
148 : virtual const GDAL_GCP *GetGCPs();
149 : };
150 :
151 : /************************************************************************/
152 : /* ==================================================================== */
153 : /* HDF4ImageRasterBand */
154 : /* ==================================================================== */
155 : /************************************************************************/
156 :
157 : class HDF4ImageRasterBand : public GDALPamRasterBand
158 539 : {
159 : friend class HDF4ImageDataset;
160 :
161 : int bNoDataSet;
162 : double dfNoDataValue;
163 :
164 : int bHaveScaleAndOffset;
165 : double dfScale;
166 : double dfOffset;
167 :
168 : CPLString osUnitType;
169 :
170 : public:
171 :
172 : HDF4ImageRasterBand( HDF4ImageDataset *, int, GDALDataType );
173 :
174 : virtual CPLErr IReadBlock( int, int, void * );
175 : virtual CPLErr IWriteBlock( int, int, void * );
176 : virtual GDALColorInterp GetColorInterpretation();
177 : virtual GDALColorTable *GetColorTable();
178 : virtual double GetNoDataValue( int * );
179 : virtual CPLErr SetNoDataValue( double );
180 : virtual double GetOffset( int *pbSuccess );
181 : virtual double GetScale( int *pbSuccess );
182 : virtual const char *GetUnitType();
183 : };
184 :
185 : /************************************************************************/
186 : /* HDF4ImageRasterBand() */
187 : /************************************************************************/
188 :
189 : HDF4ImageRasterBand::HDF4ImageRasterBand( HDF4ImageDataset *poDS, int nBand,
190 539 : GDALDataType eType )
191 :
192 : {
193 539 : this->poDS = poDS;
194 539 : this->nBand = nBand;
195 539 : eDataType = eType;
196 539 : bNoDataSet = FALSE;
197 539 : dfNoDataValue = -9999.0;
198 :
199 539 : bHaveScaleAndOffset = FALSE;
200 539 : dfScale = 1.0;
201 539 : dfOffset = 0.0;
202 :
203 539 : nBlockXSize = poDS->GetRasterXSize();
204 :
205 : // Aim for a block of about 1000000 pixels. Chunking up substantially
206 : // improves performance in some situations. For now we only chunk up for
207 : // SDS and EOS based datasets since other variations haven't been tested. #2208
208 1078 : if( poDS->iDatasetType == HDF4_SDS ||
209 : poDS->iDatasetType == HDF4_EOS)
210 : {
211 : int nChunkSize =
212 539 : atoi( CPLGetConfigOption("HDF4_BLOCK_PIXELS", "1000000") );
213 :
214 539 : nBlockYSize = nChunkSize / poDS->GetRasterXSize();
215 539 : nBlockYSize = MAX(1,MIN(nBlockYSize,poDS->GetRasterYSize()));
216 : }
217 : else
218 : {
219 0 : nBlockYSize = 1;
220 : }
221 :
222 : /* HDF4_EOS:EOS_GRID case. We ensure that the block size matches */
223 : /* the raster width, as the IReadBlock() code can only handle multiple */
224 : /* blocks per row */
225 539 : if ( poDS->nBlockPreferredXSize == nBlockXSize &&
226 : poDS->nBlockPreferredYSize > 0 )
227 : {
228 6 : if (poDS->nBlockPreferredYSize == 1)
229 : {
230 : /* Avoid defaulting to tile reading when the preferred height is 1 */
231 : /* as it leads to very poor performance with : */
232 : /* ftp://e4ftl01u.ecs.nasa.gov/MODIS_Composites/MOLT/MOD13Q1.005/2006.06.10/MOD13Q1.A2006161.h21v13.005.2008234103220.hd */
233 2 : poDS->bReadTile = FALSE;
234 : }
235 : else
236 : {
237 4 : nBlockYSize = poDS->nBlockPreferredYSize;
238 : }
239 : }
240 539 : }
241 :
242 : /************************************************************************/
243 : /* IReadBlock() */
244 : /************************************************************************/
245 :
246 : CPLErr HDF4ImageRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
247 195 : void * pImage )
248 : {
249 195 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
250 : int32 aiStart[H4_MAX_NC_DIMS], aiEdges[H4_MAX_NC_DIMS];
251 195 : CPLErr eErr = CE_None;
252 :
253 195 : if( poGDS->eAccess == GA_Update )
254 : {
255 : memset( pImage, 0,
256 0 : nBlockXSize * nBlockYSize * GDALGetDataTypeSize(eDataType) / 8 );
257 0 : return CE_None;
258 : }
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* Work out some block oriented details. */
262 : /* -------------------------------------------------------------------- */
263 195 : int nYOff = nBlockYOff * nBlockYSize;
264 195 : int nYSize = MIN(nYOff + nBlockYSize, poDS->GetRasterYSize()) - nYOff;
265 195 : CPLAssert( nBlockXOff == 0 );
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* HDF files with external data files, such as some landsat */
269 : /* products (eg. data/hdf/L1G) need to be told what directory */
270 : /* to look in to find the external files. Normally this is the */
271 : /* directory holding the hdf file. */
272 : /* -------------------------------------------------------------------- */
273 195 : HXsetdir(CPLGetPath(poGDS->pszFilename));
274 :
275 : /* -------------------------------------------------------------------- */
276 : /* Handle different configurations. */
277 : /* -------------------------------------------------------------------- */
278 195 : switch ( poGDS->iDatasetType )
279 : {
280 : case HDF4_SDS:
281 : {
282 : /* We avoid doing SDselect() / SDendaccess() for each block access */
283 : /* as this is very slow when zlib compression is used */
284 :
285 94 : if (poGDS->iSDS == FAIL)
286 44 : poGDS->iSDS = SDselect( poGDS->hSD, poGDS->iDataset );
287 :
288 : /* HDF rank:
289 : A rank 2 dataset is an image read in scan-line order (2D).
290 : A rank 3 dataset is a series of images which are read in
291 : an image at a time to form a volume.
292 : A rank 4 dataset may be thought of as a series of volumes.
293 :
294 : The "aiStart" array specifies the multi-dimensional index of the
295 : starting corner of the hyperslab to read. The values are zero
296 : based.
297 :
298 : The "edge" array specifies the number of values to read along
299 : each dimension of the hyperslab.
300 :
301 : The "iStride" array allows for sub-sampling along each
302 : dimension. If a iStride value is specified for a dimension,
303 : that many values will be skipped over when reading along that
304 : dimension. Specifying iStride = NULL in the C interface or
305 : iStride = 1 in either interface specifies contiguous reading
306 : of data. If the iStride values are set to 0, SDreaddata
307 : returns FAIL (or -1). No matter what iStride value is
308 : provided, data is always placed contiguously in buffer.
309 : */
310 94 : switch ( poGDS->iRank )
311 : {
312 : case 4: // 4Dim: volume-time
313 : // FIXME: needs sample file. Does not work currently.
314 0 : aiStart[3] = 0/* range: 0--aiDimSizes[3]-1 */;
315 0 : aiEdges[3] = 1;
316 0 : aiStart[2] = 0/* range: 0--aiDimSizes[2]-1 */;
317 0 : aiEdges[2] = 1;
318 0 : aiStart[1] = nYOff; aiEdges[1] = nYSize;
319 0 : aiStart[0] = nBlockXOff; aiEdges[0] = nBlockXSize;
320 0 : break;
321 : case 3: // 3Dim: volume
322 40 : aiStart[poGDS->iBandDim] = nBand - 1;
323 40 : aiEdges[poGDS->iBandDim] = 1;
324 :
325 40 : aiStart[poGDS->iYDim] = nYOff;
326 40 : aiEdges[poGDS->iYDim] = nYSize;
327 :
328 40 : aiStart[poGDS->iXDim] = nBlockXOff;
329 40 : aiEdges[poGDS->iXDim] = nBlockXSize;
330 40 : break;
331 : case 2: // 2Dim: rows/cols
332 54 : aiStart[poGDS->iYDim] = nYOff;
333 54 : aiEdges[poGDS->iYDim] = nYSize;
334 :
335 54 : aiStart[poGDS->iXDim] = nBlockXOff;
336 54 : aiEdges[poGDS->iXDim] = nBlockXSize;
337 54 : break;
338 : case 1: //1Dim:
339 0 : aiStart[poGDS->iXDim] = nBlockXOff;
340 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
341 : break;
342 : }
343 :
344 : // Read HDF SDS array
345 94 : if( SDreaddata( poGDS->iSDS, aiStart, NULL, aiEdges, pImage ) < 0 )
346 : {
347 : CPLError( CE_Failure, CPLE_AppDefined,
348 0 : "SDreaddata() failed for block." );
349 0 : eErr = CE_Failure;
350 : }
351 :
352 : //SDendaccess( iSDS );
353 : }
354 94 : break;
355 :
356 : case HDF4_GR:
357 : {
358 : int nDataTypeSize =
359 0 : GDALGetDataTypeSize(poGDS->GetDataType(poGDS->iNumType)) / 8;
360 : GByte *pbBuffer = (GByte *)
361 0 : CPLMalloc(nBlockXSize*nBlockYSize*poGDS->iRank*nBlockYSize);
362 : int i, j;
363 :
364 0 : aiStart[poGDS->iYDim] = nYOff;
365 0 : aiEdges[poGDS->iYDim] = nYSize;
366 :
367 0 : aiStart[poGDS->iXDim] = nBlockXOff;
368 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
369 :
370 0 : if( GRreadimage(poGDS->iGR, aiStart, NULL, aiEdges, pbBuffer) < 0 )
371 : {
372 : CPLError( CE_Failure, CPLE_AppDefined,
373 0 : "GRreaddata() failed for block." );
374 0 : eErr = CE_Failure;
375 : }
376 : else
377 : {
378 0 : for ( i = 0, j = (nBand - 1) * nDataTypeSize;
379 : i < nBlockXSize * nDataTypeSize;
380 : i += nDataTypeSize, j += poGDS->nBands * nDataTypeSize )
381 0 : memcpy( (GByte *)pImage + i, pbBuffer + j, nDataTypeSize );
382 : }
383 :
384 0 : CPLFree( pbBuffer );
385 : }
386 0 : break;
387 :
388 : case HDF4_EOS:
389 : {
390 101 : switch ( poGDS->iSubdatasetType )
391 : {
392 : case H4ST_EOS_GRID:
393 : {
394 : int32 hGD;
395 :
396 : hGD = GDattach( poGDS->hHDF4,
397 101 : poGDS->pszSubdatasetName );
398 101 : switch ( poGDS->iRank )
399 : {
400 : case 4: // 4Dim: volume
401 : aiStart[poGDS->i4Dim] =
402 : (nBand - 1)
403 0 : / poGDS->aiDimSizes[poGDS->iBandDim];
404 0 : aiEdges[poGDS->i4Dim] = 1;
405 :
406 : aiStart[poGDS->iBandDim] =
407 : (nBand - 1)
408 0 : % poGDS->aiDimSizes[poGDS->iBandDim];
409 0 : aiEdges[poGDS->iBandDim] = 1;
410 :
411 0 : aiStart[poGDS->iYDim] = nYOff;
412 0 : aiEdges[poGDS->iYDim] = nYSize;
413 :
414 0 : aiStart[poGDS->iXDim] = nBlockXOff;
415 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
416 0 : break;
417 : case 3: // 3Dim: volume
418 0 : aiStart[poGDS->iBandDim] = nBand - 1;
419 0 : aiEdges[poGDS->iBandDim] = 1;
420 :
421 0 : aiStart[poGDS->iYDim] = nYOff;
422 0 : aiEdges[poGDS->iYDim] = nYSize;
423 :
424 0 : aiStart[poGDS->iXDim] = nBlockXOff;
425 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
426 0 : break;
427 : case 2: // 2Dim: rows/cols
428 101 : aiStart[poGDS->iYDim] = nYOff;
429 101 : aiEdges[poGDS->iYDim] = nYSize;
430 :
431 101 : aiStart[poGDS->iXDim] = nBlockXOff;
432 101 : aiEdges[poGDS->iXDim] = nBlockXSize;
433 : break;
434 : }
435 :
436 : /* Ensure that we don't overlap the bottom or right edges */
437 : /* of the dataset in order to use the GDreadtile() API */
438 177 : if ( poGDS->bReadTile &&
439 : (nBlockXOff + 1) * nBlockXSize <= nRasterXSize &&
440 : (nBlockYOff + 1) * nBlockYSize <= nRasterYSize )
441 : {
442 76 : int32 tilecoords[] = { nBlockYOff , nBlockXOff };
443 76 : if( GDreadtile( hGD, poGDS->pszFieldName , tilecoords , pImage ) != 0 )
444 : {
445 0 : CPLError( CE_Failure, CPLE_AppDefined, "GDreadtile() failed for block." );
446 0 : eErr = CE_Failure;
447 : }
448 : }
449 25 : else if( GDreadfield( hGD, poGDS->pszFieldName,
450 : aiStart, NULL, aiEdges, pImage ) < 0 )
451 : {
452 : CPLError( CE_Failure, CPLE_AppDefined,
453 0 : "GDreadfield() failed for block." );
454 0 : eErr = CE_Failure;
455 : }
456 101 : GDdetach( hGD );
457 : }
458 101 : break;
459 :
460 : case H4ST_EOS_SWATH:
461 : case H4ST_EOS_SWATH_GEOL:
462 : {
463 : int32 hSW;
464 :
465 : hSW = SWattach( poGDS->hHDF4,
466 0 : poGDS->pszSubdatasetName );
467 0 : switch ( poGDS->iRank )
468 : {
469 : case 3: // 3Dim: volume
470 0 : aiStart[poGDS->iBandDim] = nBand - 1;
471 0 : aiEdges[poGDS->iBandDim] = 1;
472 :
473 0 : aiStart[poGDS->iYDim] = nYOff;
474 0 : aiEdges[poGDS->iYDim] = nYSize;
475 :
476 0 : aiStart[poGDS->iXDim] = nBlockXOff;
477 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
478 0 : break;
479 : case 2: // 2Dim: rows/cols
480 0 : aiStart[poGDS->iYDim] = nYOff;
481 0 : aiEdges[poGDS->iYDim] = nYSize;
482 :
483 0 : aiStart[poGDS->iXDim] = nBlockXOff;
484 0 : aiEdges[poGDS->iXDim] = nBlockXSize;
485 : break;
486 : }
487 0 : if( SWreadfield( hSW, poGDS->pszFieldName,
488 : aiStart, NULL, aiEdges, pImage ) < 0 )
489 : {
490 : CPLError( CE_Failure, CPLE_AppDefined,
491 0 : "SWreadfield() failed for block." );
492 0 : eErr = CE_Failure;
493 : }
494 0 : SWdetach( hSW );
495 : }
496 : break;
497 : default:
498 : break;
499 : }
500 : }
501 101 : break;
502 :
503 : default:
504 0 : eErr = CE_Failure;
505 : break;
506 : }
507 :
508 195 : return eErr;
509 : }
510 :
511 : /************************************************************************/
512 : /* IWriteBlock() */
513 : /************************************************************************/
514 :
515 : CPLErr HDF4ImageRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
516 65 : void * pImage )
517 : {
518 65 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *)poDS;
519 : int32 aiStart[H4_MAX_NC_DIMS], aiEdges[H4_MAX_NC_DIMS];
520 65 : CPLErr eErr = CE_None;
521 :
522 65 : CPLAssert( poGDS != NULL
523 : && nBlockXOff == 0
524 : && nBlockYOff >= 0
525 : && pImage != NULL );
526 :
527 : /* -------------------------------------------------------------------- */
528 : /* Work out some block oriented details. */
529 : /* -------------------------------------------------------------------- */
530 65 : int nYOff = nBlockYOff * nBlockYSize;
531 65 : int nYSize = MIN(nYOff + nBlockYSize, poDS->GetRasterYSize()) - nYOff;
532 65 : CPLAssert( nBlockXOff == 0 );
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Process based on rank. */
536 : /* -------------------------------------------------------------------- */
537 65 : switch ( poGDS->iRank )
538 : {
539 : case 3:
540 : {
541 57 : int32 iSDS = SDselect( poGDS->hSD, poGDS->iDataset );
542 :
543 57 : aiStart[poGDS->iBandDim] = nBand - 1;
544 57 : aiEdges[poGDS->iBandDim] = 1;
545 :
546 57 : aiStart[poGDS->iYDim] = nYOff;
547 57 : aiEdges[poGDS->iYDim] = nYSize;
548 :
549 57 : aiStart[poGDS->iXDim] = nBlockXOff;
550 57 : aiEdges[poGDS->iXDim] = nBlockXSize;
551 :
552 57 : if ( (SDwritedata( iSDS, aiStart, NULL,
553 : aiEdges, (VOIDP)pImage )) < 0 )
554 0 : eErr = CE_Failure;
555 :
556 57 : SDendaccess( iSDS );
557 : }
558 57 : break;
559 :
560 : case 2:
561 : {
562 8 : int32 iSDS = SDselect( poGDS->hSD, nBand - 1 );
563 8 : aiStart[poGDS->iYDim] = nYOff;
564 8 : aiEdges[poGDS->iYDim] = nYSize;
565 :
566 8 : aiStart[poGDS->iXDim] = nBlockXOff;
567 8 : aiEdges[poGDS->iXDim] = nBlockXSize;
568 :
569 8 : if ( (SDwritedata( iSDS, aiStart, NULL,
570 : aiEdges, (VOIDP)pImage )) < 0 )
571 0 : eErr = CE_Failure;
572 :
573 8 : SDendaccess( iSDS );
574 : }
575 8 : break;
576 :
577 : default:
578 0 : eErr = CE_Failure;
579 : break;
580 : }
581 :
582 65 : return eErr;
583 : }
584 :
585 : /************************************************************************/
586 : /* GetColorTable() */
587 : /************************************************************************/
588 :
589 0 : GDALColorTable *HDF4ImageRasterBand::GetColorTable()
590 : {
591 0 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
592 :
593 0 : return poGDS->poColorTable;
594 : }
595 :
596 : /************************************************************************/
597 : /* GetColorInterpretation() */
598 : /************************************************************************/
599 :
600 36 : GDALColorInterp HDF4ImageRasterBand::GetColorInterpretation()
601 : {
602 36 : HDF4ImageDataset *poGDS = (HDF4ImageDataset *) poDS;
603 :
604 36 : if ( poGDS->iDatasetType == HDF4_SDS )
605 36 : return GCI_GrayIndex;
606 0 : else if ( poGDS->iDatasetType == HDF4_GR )
607 : {
608 0 : if ( poGDS->poColorTable != NULL )
609 0 : return GCI_PaletteIndex;
610 0 : else if ( poGDS->nBands != 1 )
611 : {
612 0 : if ( nBand == 1 )
613 0 : return GCI_RedBand;
614 0 : else if ( nBand == 2 )
615 0 : return GCI_GreenBand;
616 0 : else if ( nBand == 3 )
617 0 : return GCI_BlueBand;
618 0 : else if ( nBand == 4 )
619 0 : return GCI_AlphaBand;
620 : else
621 0 : return GCI_Undefined;
622 : }
623 : else
624 0 : return GCI_GrayIndex;
625 : }
626 : else
627 0 : return GCI_GrayIndex;
628 : }
629 :
630 : /************************************************************************/
631 : /* GetNoDataValue() */
632 : /************************************************************************/
633 :
634 96 : double HDF4ImageRasterBand::GetNoDataValue( int * pbSuccess )
635 :
636 : {
637 96 : if( pbSuccess )
638 96 : *pbSuccess = bNoDataSet;
639 :
640 96 : return dfNoDataValue;
641 : }
642 :
643 : /************************************************************************/
644 : /* SetNoDataValue() */
645 : /************************************************************************/
646 :
647 54 : CPLErr HDF4ImageRasterBand::SetNoDataValue( double dfNoData )
648 :
649 : {
650 54 : bNoDataSet = TRUE;
651 54 : dfNoDataValue = dfNoData;
652 :
653 54 : return CE_None;
654 : }
655 :
656 : /************************************************************************/
657 : /* GetUnitType() */
658 : /************************************************************************/
659 :
660 0 : const char *HDF4ImageRasterBand::GetUnitType()
661 :
662 : {
663 0 : if( osUnitType.size() > 0 )
664 0 : return osUnitType;
665 : else
666 0 : return GDALRasterBand::GetUnitType();
667 : }
668 :
669 : /************************************************************************/
670 : /* GetOffset() */
671 : /************************************************************************/
672 :
673 0 : double HDF4ImageRasterBand::GetOffset( int *pbSuccess )
674 :
675 : {
676 0 : if( bHaveScaleAndOffset )
677 : {
678 0 : if( pbSuccess != NULL )
679 0 : *pbSuccess = TRUE;
680 0 : return dfOffset;
681 : }
682 : else
683 0 : return GDALRasterBand::GetOffset( pbSuccess );
684 : }
685 :
686 : /************************************************************************/
687 : /* GetScale() */
688 : /************************************************************************/
689 :
690 0 : double HDF4ImageRasterBand::GetScale( int *pbSuccess )
691 :
692 : {
693 0 : if( bHaveScaleAndOffset )
694 : {
695 0 : if( pbSuccess != NULL )
696 0 : *pbSuccess = TRUE;
697 0 : return dfScale;
698 : }
699 : else
700 0 : return GDALRasterBand::GetScale( pbSuccess );
701 : }
702 :
703 : /************************************************************************/
704 : /* ==================================================================== */
705 : /* HDF4ImageDataset */
706 : /* ==================================================================== */
707 : /************************************************************************/
708 :
709 : /************************************************************************/
710 : /* HDF4ImageDataset() */
711 : /************************************************************************/
712 :
713 407 : HDF4ImageDataset::HDF4ImageDataset()
714 : {
715 407 : pszFilename = NULL;
716 407 : hHDF4 = 0;
717 407 : iGR = 0;
718 407 : iPal = 0;
719 407 : iDataset = 0;
720 407 : iRank = 0;
721 407 : iNumType = 0;
722 407 : nAttrs = 0;
723 407 : iInterlaceMode = 0;
724 407 : iPalInterlaceMode = 0;
725 407 : iPalDataType = 0;
726 407 : nComps = 0;
727 407 : nPalEntries = 0;
728 407 : memset(aiDimSizes, 0, sizeof(aiDimSizes));
729 407 : iXDim = 0;
730 407 : iYDim = 0;
731 407 : iBandDim = -1;
732 407 : i4Dim = 0;
733 407 : nBandCount = 0;
734 407 : papszLocalMetadata = NULL;
735 407 : memset(aiPaletteData, 0, sizeof(aiPaletteData));
736 407 : memset(szName, 0, sizeof(szName));
737 407 : pszSubdatasetName = NULL;
738 407 : pszFieldName = NULL;
739 407 : poColorTable = NULL;
740 407 : bHasGeoTransform = FALSE;
741 407 : adfGeoTransform[0] = 0.0;
742 407 : adfGeoTransform[1] = 1.0;
743 407 : adfGeoTransform[2] = 0.0;
744 407 : adfGeoTransform[3] = 0.0;
745 407 : adfGeoTransform[4] = 0.0;
746 407 : adfGeoTransform[5] = 1.0;
747 407 : pszProjection = CPLStrdup( "" );
748 407 : pszGCPProjection = CPLStrdup( "" );
749 407 : pasGCPList = NULL;
750 407 : nGCPCount = 0;
751 :
752 407 : iDatasetType = HDF4_UNKNOWN;
753 407 : iSDS = FAIL;
754 :
755 407 : nBlockPreferredXSize = -1;
756 407 : nBlockPreferredYSize = -1;
757 407 : bReadTile = false;
758 :
759 407 : }
760 :
761 : /************************************************************************/
762 : /* ~HDF4ImageDataset() */
763 : /************************************************************************/
764 :
765 407 : HDF4ImageDataset::~HDF4ImageDataset()
766 : {
767 407 : FlushCache();
768 :
769 407 : if ( pszFilename )
770 263 : CPLFree( pszFilename );
771 407 : if ( iSDS != FAIL )
772 44 : SDendaccess( iSDS );
773 407 : if ( hSD > 0 )
774 407 : SDend( hSD );
775 407 : hSD = 0;
776 407 : if ( iGR > 0 )
777 0 : GRendaccess( iGR );
778 407 : if ( hGR > 0 )
779 0 : GRend( hGR );
780 407 : hGR = 0;
781 407 : if ( pszSubdatasetName )
782 8 : CPLFree( pszSubdatasetName );
783 407 : if ( pszFieldName )
784 8 : CPLFree( pszFieldName );
785 407 : if ( papszLocalMetadata )
786 263 : CSLDestroy( papszLocalMetadata );
787 407 : if ( poColorTable != NULL )
788 0 : delete poColorTable;
789 407 : if ( pszProjection )
790 407 : CPLFree( pszProjection );
791 407 : if ( pszGCPProjection )
792 407 : CPLFree( pszGCPProjection );
793 407 : if( nGCPCount > 0 )
794 : {
795 0 : for( int i = 0; i < nGCPCount; i++ )
796 : {
797 0 : if ( pasGCPList[i].pszId )
798 0 : CPLFree( pasGCPList[i].pszId );
799 0 : if ( pasGCPList[i].pszInfo )
800 0 : CPLFree( pasGCPList[i].pszInfo );
801 : }
802 :
803 0 : CPLFree( pasGCPList );
804 : }
805 407 : if ( hHDF4 > 0 )
806 : {
807 263 : switch ( iDatasetType )
808 : {
809 : case HDF4_EOS:
810 8 : switch ( iSubdatasetType )
811 : {
812 : case H4ST_EOS_SWATH:
813 : case H4ST_EOS_SWATH_GEOL:
814 0 : SWclose( hHDF4 );
815 0 : break;
816 : case H4ST_EOS_GRID:
817 8 : GDclose( hHDF4 );
818 : default:
819 : break;
820 :
821 : }
822 8 : break;
823 : case HDF4_SDS:
824 : case HDF4_GR:
825 255 : hHDF4 = Hclose( hHDF4 );
826 : break;
827 : default:
828 : break;
829 : }
830 : }
831 407 : }
832 :
833 : /************************************************************************/
834 : /* GetGeoTransform() */
835 : /************************************************************************/
836 :
837 17 : CPLErr HDF4ImageDataset::GetGeoTransform( double * padfTransform )
838 : {
839 17 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
840 :
841 17 : if ( !bHasGeoTransform )
842 0 : return CE_Failure;
843 :
844 17 : 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 0 : int HDF4ImageDataset::GetGCPCount()
888 :
889 : {
890 0 : 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 407 : void HDF4ImageDataset::FlushCache()
920 :
921 : {
922 : int iBand;
923 : char *pszName;
924 : const char *pszValue;
925 :
926 407 : GDALDataset::FlushCache();
927 :
928 407 : if( eAccess == GA_ReadOnly )
929 263 : 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 47 : "Cannot write metadata information to output file");
967 : }
968 :
969 47 : CPLFree( pszName );
970 : }
971 : }
972 :
973 : // Write out NoData values
974 344 : for ( iBand = 1; iBand <= nBands; iBand++ )
975 : {
976 : HDF4ImageRasterBand *poBand =
977 200 : (HDF4ImageRasterBand *)GetRasterBand(iBand);
978 :
979 200 : if ( poBand->bNoDataSet )
980 : {
981 16 : pszName = CPLStrdup( CPLSPrintf( "NoDataValue%d", iBand ) );
982 16 : pszValue = CPLSPrintf( "%lf", 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 344 : for ( iBand = 1; iBand <= nBands; iBand++ )
997 : {
998 : HDF4ImageRasterBand *poBand =
999 200 : (HDF4ImageRasterBand *)GetRasterBand(iBand);
1000 :
1001 200 : pszName = CPLStrdup( CPLSPrintf( "BandDesc%d", iBand ) );
1002 200 : pszValue = poBand->GetDescription();
1003 200 : 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 200 : 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 : void HDF4ImageDataset::ReadCoordinates( const char *pszString,
1070 0 : 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 255 : void HDF4ImageDataset::CaptureL1GMTLInfo()
1145 :
1146 : {
1147 : /* -------------------------------------------------------------------- */
1148 : /* Does the physical file look like it matches our expected */
1149 : /* name pattern? */
1150 : /* -------------------------------------------------------------------- */
1151 255 : 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 0 : CPLString osMTLFilename = pszFilename;
1161 0 : osMTLFilename.resize(osMTLFilename.length() - 8);
1162 0 : osMTLFilename += "_MTL.L1G";
1163 :
1164 : /* -------------------------------------------------------------------- */
1165 : /* Ingest the MTL using the NASAKeywordHandler written for the */
1166 : /* PDS driver. */
1167 : /* -------------------------------------------------------------------- */
1168 0 : NASAKeywordHandler oMTL;
1169 :
1170 0 : FILE *fp = VSIFOpenL( osMTLFilename, "r" );
1171 0 : if( fp == NULL )
1172 0 : return;
1173 :
1174 0 : if( !oMTL.Ingest( fp, 0 ) )
1175 : {
1176 0 : VSIFCloseL( fp );
1177 : return;
1178 : }
1179 :
1180 0 : 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 0 : CPLString osPrefix;
1189 :
1190 0 : if( oMTL.GetKeyword( "LPGS_METADATA_FILE.PRODUCT_METADATA"
1191 : ".PRODUCT_UL_CORNER_LON", NULL ) )
1192 0 : osPrefix = "LPGS_METADATA_FILE.PRODUCT_METADATA.PRODUCT_";
1193 0 : else if( oMTL.GetKeyword( "L1_METADATA_FILE.PRODUCT_METADATA"
1194 : ".PRODUCT_UL_CORNER_LON", NULL ) )
1195 0 : osPrefix = "L1_METADATA_FILE.PRODUCT_METADATA.PRODUCT_";
1196 : else
1197 : return;
1198 :
1199 0 : dfULX = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LON").c_str(), "0" ));
1200 0 : dfULY = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LAT").c_str(), "0" ));
1201 0 : dfLRX = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LON").c_str(), "0" ));
1202 0 : dfLRY = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LAT").c_str(), "0" ));
1203 0 : dfLLX = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LON").c_str(), "0" ));
1204 0 : dfLLY = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LAT").c_str(), "0" ));
1205 0 : dfURX = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LON").c_str(), "0" ));
1206 0 : dfURY = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LAT").c_str(), "0" ));
1207 :
1208 0 : CPLFree( pszGCPProjection );
1209 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\"]]" );
1210 :
1211 0 : nGCPCount = 4;
1212 0 : pasGCPList = (GDAL_GCP *) CPLCalloc( nGCPCount, sizeof( GDAL_GCP ) );
1213 0 : GDALInitGCPs( nGCPCount, pasGCPList );
1214 :
1215 0 : pasGCPList[0].dfGCPX = dfULX;
1216 0 : pasGCPList[0].dfGCPY = dfULY;
1217 0 : pasGCPList[0].dfGCPPixel = 0.0;
1218 0 : pasGCPList[0].dfGCPLine = 0.0;
1219 :
1220 0 : pasGCPList[1].dfGCPX = dfURX;
1221 0 : pasGCPList[1].dfGCPY = dfURY;
1222 0 : pasGCPList[1].dfGCPPixel = GetRasterXSize();
1223 0 : pasGCPList[1].dfGCPLine = 0.0;
1224 :
1225 0 : pasGCPList[2].dfGCPX = dfLLX;
1226 0 : pasGCPList[2].dfGCPY = dfLLY;
1227 0 : pasGCPList[2].dfGCPPixel = 0.0;
1228 0 : pasGCPList[2].dfGCPLine = GetRasterYSize();
1229 :
1230 0 : pasGCPList[3].dfGCPX = dfLRX;
1231 0 : pasGCPList[3].dfGCPY = dfLRY;
1232 0 : pasGCPList[3].dfGCPPixel = GetRasterXSize();
1233 0 : 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 : || 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 : && aiDimSizes[0] >= 29
1379 : && SDreaddata( iSDS, aiStart, NULL, aiEdges, adfGCTP ) == 0
1380 : && oSRS.importFromUSGS( (long) adfGCTP[1], (long) adfGCTP[2],
1381 : adfGCTP+4,
1382 : (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 : && 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 : 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 : 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 : 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 : 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 255 : void HDF4ImageDataset::ProcessModisSDSGeolocation(void)
1877 :
1878 : {
1879 255 : int iDSIndex, iXIndex=-1, iYIndex=-1;
1880 :
1881 : // No point in assigning geolocation to the geolocation SDSes themselves.
1882 255 : if( EQUAL(szName,"longitude") || EQUAL(szName,"latitude") )
1883 0 : return;
1884 :
1885 255 : if (nRasterYSize == 1)
1886 0 : return;
1887 :
1888 : /* -------------------------------------------------------------------- */
1889 : /* Scan for latitude and longitude sections. */
1890 : /* -------------------------------------------------------------------- */
1891 : int32 nDatasets, nAttributes;
1892 :
1893 255 : if ( SDfileinfo( hSD, &nDatasets, &nAttributes ) != 0 )
1894 0 : return;
1895 :
1896 662 : 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 407 : iSDS = SDselect( hSD, iDSIndex );
1903 :
1904 407 : if( SDgetinfo( iSDS, szName, &iRank, aiDimSizes, &iNumType,
1905 : &nAttrs) == 0 )
1906 : {
1907 407 : if( EQUAL(szName,"latitude") )
1908 2 : iYIndex = iDSIndex;
1909 :
1910 407 : if( EQUAL(szName,"longitude") )
1911 2 : iXIndex = iDSIndex;
1912 : }
1913 :
1914 407 : SDendaccess(iSDS);
1915 : }
1916 :
1917 255 : if( iXIndex == -1 || iYIndex == -1 )
1918 253 : 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 0 : char *pszGeoList = NULL;
1960 0 : char szGeoDimList[8192] = "";
1961 : int32 iWrkNumType;
1962 : int32 nDataFields, nDimMaps;
1963 0 : void *pLat = NULL, *pLong = NULL;
1964 0 : void *pLatticeX = NULL, *pLatticeY = NULL;
1965 0 : int32 iLatticeType, iLatticeDataSize = 0, iRank;
1966 0 : int32 nLatCount = 0, nLongCount = 0;
1967 0 : int32 nXPoints=0, nYPoints=0;
1968 : int32 nStrBufSize;
1969 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
1970 0 : int i, j, iDataSize = 0, iPixelDim=-1,iLineDim=-1, iLongDim=-1, iLatDim=-1;
1971 0 : int32 *paiRank = NULL, *paiNumType = NULL,
1972 0 : *paiOffset = NULL, *paiIncrement = NULL;
1973 0 : char **papszGeolocations = NULL;
1974 0 : char *pszDimMaps = NULL;
1975 :
1976 : /* -------------------------------------------------------------------- */
1977 : /* Determine a product name. */
1978 : /* -------------------------------------------------------------------- */
1979 : const char *pszProduct =
1980 0 : CSLFetchNameValue( papszLocalMetadata, "SHORTNAME" );
1981 :
1982 0 : HDF4EOSProduct eProduct = PROD_UNKNOWN;
1983 0 : if ( pszProduct )
1984 : {
1985 0 : if ( EQUALN(pszProduct, "ASTL1A", 6) )
1986 0 : eProduct = PROD_ASTER_L1A;
1987 0 : else if ( EQUALN(pszProduct, "ASTL1B", 6) )
1988 0 : eProduct = PROD_ASTER_L1B;
1989 0 : else if ( EQUALN(pszProduct, "AST_04", 6)
1990 : || EQUALN(pszProduct, "AST_05", 6)
1991 : || EQUALN(pszProduct, "AST_06", 6)
1992 : || EQUALN(pszProduct, "AST_07", 6)
1993 : || EQUALN(pszProduct, "AST_08", 6)
1994 : || EQUALN(pszProduct, "AST_09", 6)
1995 : || EQUALN(pszProduct, "AST13", 5)
1996 : || EQUALN(pszProduct, "AST3", 4) )
1997 0 : eProduct = PROD_ASTER_L2;
1998 0 : else if ( EQUALN(pszProduct, "AST14", 5) )
1999 0 : eProduct = PROD_ASTER_L3;
2000 0 : else if ( EQUALN(pszProduct, "MOD02", 5)
2001 : || EQUALN(pszProduct, "MYD02", 5) )
2002 0 : eProduct = PROD_MODIS_L1B;
2003 : }
2004 :
2005 : /* -------------------------------------------------------------------- */
2006 : /* xx */
2007 : /* -------------------------------------------------------------------- */
2008 0 : nDataFields = SWnentries( hSW, HDFE_NENTGFLD, &nStrBufSize );
2009 0 : pszGeoList = (char *)CPLMalloc( nStrBufSize + 1 );
2010 0 : paiRank = (int32 *)CPLMalloc( nDataFields * sizeof(int32) );
2011 0 : paiNumType = (int32 *)CPLMalloc( nDataFields * sizeof(int32) );
2012 0 : if ( nDataFields !=
2013 : SWinqgeofields(hSW, pszGeoList, paiRank, paiNumType) )
2014 : {
2015 : CPLDebug( "HDF4Image",
2016 : "Can't get the list of geolocation fields in swath %s",
2017 0 : pszSubdatasetName );
2018 : }
2019 :
2020 : #ifdef DEBUG
2021 : else
2022 : {
2023 : char *pszTmp;
2024 : CPLDebug( "HDF4Image",
2025 : "Number of geolocation fields in swath %s: %ld",
2026 0 : pszSubdatasetName, (long)nDataFields );
2027 : CPLDebug( "HDF4Image",
2028 : "List of geolocation fields in swath %s: %s",
2029 0 : pszSubdatasetName, pszGeoList );
2030 : pszTmp = SPrintArray( GDT_UInt32, paiRank,
2031 0 : nDataFields, "," );
2032 : CPLDebug( "HDF4Image",
2033 0 : "Geolocation fields ranks: %s", pszTmp );
2034 0 : CPLFree( pszTmp );
2035 : }
2036 : #endif
2037 :
2038 : papszGeolocations = CSLTokenizeString2( pszGeoList, ",",
2039 0 : CSLT_HONOURSTRINGS );
2040 : // Read geolocation data
2041 0 : nDimMaps = SWnentries( hSW, HDFE_NENTMAP, &nStrBufSize );
2042 0 : if ( nDimMaps <= 0 )
2043 : {
2044 : CPLDebug( "HDF4Image", "No geolocation maps in swath %s",
2045 0 : pszSubdatasetName );
2046 : }
2047 : else
2048 : {
2049 0 : pszDimMaps = (char *)CPLMalloc( nStrBufSize + 1 );
2050 0 : paiOffset = (int32 *)CPLMalloc( nDimMaps * sizeof(int32) );
2051 0 : memset( paiOffset, 0, nDimMaps * sizeof(int32) );
2052 0 : paiIncrement = (int32 *)CPLMalloc( nDimMaps * sizeof(int32) );
2053 0 : memset( paiIncrement, 0, nDimMaps * sizeof(int32) );
2054 :
2055 :
2056 0 : *pszDimMaps = '\0';
2057 0 : if ( nDimMaps != SWinqmaps(hSW, pszDimMaps, paiOffset, paiIncrement) )
2058 : {
2059 : CPLDebug( "HDF4Image",
2060 : "Can't get the list of geolocation maps in swath %s",
2061 0 : pszSubdatasetName );
2062 : }
2063 :
2064 : #ifdef DEBUG
2065 : else
2066 : {
2067 : char *pszTmp;
2068 :
2069 : CPLDebug( "HDF4Image",
2070 : "List of geolocation maps in swath %s: %s",
2071 0 : pszSubdatasetName, pszDimMaps );
2072 : pszTmp = SPrintArray( GDT_Int32, paiOffset,
2073 0 : nDimMaps, "," );
2074 : CPLDebug( "HDF4Image",
2075 0 : "Geolocation map offsets: %s", pszTmp );
2076 0 : CPLFree( pszTmp );
2077 : pszTmp = SPrintArray( GDT_Int32, paiIncrement,
2078 0 : nDimMaps, "," );
2079 : CPLDebug( "HDF4Image",
2080 0 : "Geolocation map increments: %s", pszTmp );
2081 0 : CPLFree( pszTmp );
2082 : }
2083 : #endif
2084 :
2085 : char **papszDimMap;
2086 :
2087 : papszDimMap = CSLTokenizeString2( pszDimMaps, ",",
2088 0 : CSLT_HONOURSTRINGS );
2089 0 : CPLFree( pszDimMaps );
2090 0 : pszDimMaps = NULL;
2091 :
2092 0 : for ( i = 0; i < CSLCount(papszDimMap); i++ )
2093 : {
2094 0 : if ( strstr(papszDimMap[i], papszDimList[iXDim]) )
2095 : {
2096 0 : strncpy( szPixel, papszDimList[iXDim], 8192 );
2097 0 : strncpy( szXGeo, papszDimMap[i], 8192 );
2098 0 : char *pszTemp = strchr( szXGeo, '/' );
2099 0 : if ( pszTemp )
2100 0 : *pszTemp = '\0';
2101 : }
2102 0 : else if ( strstr(papszDimMap[i], papszDimList[iYDim]) )
2103 : {
2104 0 : strncpy( szLine, papszDimList[iYDim], 8192 );
2105 0 : strncpy( szYGeo, papszDimMap[i], 8192 );
2106 0 : char *pszTemp = strchr( szYGeo, '/' );
2107 0 : if ( pszTemp )
2108 0 : *pszTemp = '\0';
2109 : }
2110 : }
2111 0 : CSLDestroy( papszDimMap );
2112 0 : papszDimMap = NULL;
2113 : }
2114 :
2115 0 : for ( i = 0; i < CSLCount(papszGeolocations); i++ )
2116 : {
2117 0 : char **papszGeoDimList = NULL;
2118 :
2119 : SWfieldinfo( hSW, papszGeolocations[i], &iRank,
2120 0 : aiDimSizes, &iWrkNumType, szGeoDimList );
2121 : papszGeoDimList = CSLTokenizeString2( szGeoDimList,
2122 0 : ",", CSLT_HONOURSTRINGS );
2123 :
2124 : #ifdef DEBUG
2125 : CPLDebug( "HDF4Image",
2126 : "List of dimensions in geolocation field %s: %s",
2127 0 : papszGeolocations[i], szGeoDimList );
2128 : #endif
2129 :
2130 0 : if (szXGeo[0] == 0 || szYGeo[0] == 0)
2131 0 : return FALSE;
2132 :
2133 0 : nXPoints = aiDimSizes[CSLFindString( papszGeoDimList, szXGeo )];
2134 0 : nYPoints = aiDimSizes[CSLFindString( papszGeoDimList, szYGeo )];
2135 :
2136 0 : if ( EQUAL(szPixel, papszDimList[iXDim]) )
2137 : {
2138 0 : iPixelDim = 1;
2139 0 : iLineDim = 0;
2140 : }
2141 : else
2142 : {
2143 0 : iPixelDim = 0;
2144 0 : iLineDim = 1;
2145 : }
2146 :
2147 0 : iDataSize = GetDataTypeSize( iWrkNumType );
2148 0 : if ( strstr( papszGeolocations[i], "Latitude" ) )
2149 : {
2150 0 : iLatDim = i;
2151 0 : nLatCount = nXPoints * nYPoints;
2152 0 : pLat = CPLMalloc( nLatCount * iDataSize );
2153 0 : if (SWreadfield( hSW, papszGeolocations[i], NULL,
2154 : NULL, NULL, (VOIDP)pLat ) < 0)
2155 : {
2156 : CPLDebug( "HDF4Image",
2157 : "Can't read geolocation field %s",
2158 0 : papszGeolocations[i]);
2159 0 : CPLFree( pLat );
2160 0 : pLat = NULL;
2161 : }
2162 : }
2163 0 : else if ( strstr( papszGeolocations[i], "Longitude" ) )
2164 : {
2165 0 : iLongDim = i;
2166 0 : nLongCount = nXPoints * nYPoints;
2167 0 : pLong = CPLMalloc( nLongCount * iDataSize );
2168 0 : if (SWreadfield( hSW, papszGeolocations[i], NULL,
2169 : NULL, NULL, (VOIDP)pLong ) < 0)
2170 : {
2171 : CPLDebug( "HDF4Image",
2172 : "Can't read geolocation field %s",
2173 0 : papszGeolocations[i]);
2174 0 : CPLFree( pLong );
2175 0 : pLong = NULL;
2176 : }
2177 : }
2178 :
2179 0 : CSLDestroy( papszGeoDimList );
2180 :
2181 : }
2182 :
2183 : /* -------------------------------------------------------------------- */
2184 : /* Do we have a lattice table? */
2185 : /* -------------------------------------------------------------------- */
2186 0 : if (SWfieldinfo(hSW, "LatticePoint", &iRank, aiDimSizes,
2187 : &iLatticeType, szGeoDimList) == 0
2188 : && iRank == 3
2189 : && nXPoints == aiDimSizes[1]
2190 : && nYPoints == aiDimSizes[0]
2191 : && aiDimSizes[2] == 2 )
2192 : {
2193 : int32 iStart[H4_MAX_NC_DIMS], iEdges[H4_MAX_NC_DIMS];
2194 :
2195 : iLatticeDataSize =
2196 0 : GetDataTypeSize( iLatticeType );
2197 :
2198 0 : iStart[1] = 0;
2199 0 : iEdges[1] = nXPoints;
2200 :
2201 0 : iStart[0] = 0;
2202 0 : iEdges[0] = nYPoints;
2203 :
2204 0 : iStart[2] = 0;
2205 0 : iEdges[2] = 1;
2206 :
2207 0 : pLatticeX = CPLMalloc( nLatCount * iLatticeDataSize );
2208 0 : if (SWreadfield( hSW, "LatticePoint", iStart, NULL,
2209 : iEdges, (VOIDP)pLatticeX ) < 0)
2210 : {
2211 0 : CPLDebug( "HDF4Image", "Can't read lattice field" );
2212 0 : CPLFree( pLatticeX );
2213 0 : pLatticeX = NULL;
2214 : }
2215 :
2216 0 : iStart[2] = 1;
2217 0 : iEdges[2] = 1;
2218 :
2219 0 : pLatticeY = CPLMalloc( nLatCount * iLatticeDataSize );
2220 0 : if (SWreadfield( hSW, "LatticePoint", iStart, NULL,
2221 : iEdges, (VOIDP)pLatticeY ) < 0)
2222 : {
2223 0 : CPLDebug( "HDF4Image", "Can't read lattice field" );
2224 0 : CPLFree( pLatticeY );
2225 0 : pLatticeY = NULL;
2226 : }
2227 :
2228 : }
2229 :
2230 : /* -------------------------------------------------------------------- */
2231 : /* Determine whether to use no, partial or full GCPs. */
2232 : /* -------------------------------------------------------------------- */
2233 : const char *pszGEOL_AS_GCPS = CPLGetConfigOption( "GEOL_AS_GCPS",
2234 0 : "PARTIAL" );
2235 : int iGCPStepX, iGCPStepY;
2236 :
2237 0 : if( EQUAL(pszGEOL_AS_GCPS,"NONE") )
2238 : {
2239 0 : iGCPStepX = iGCPStepY = 0;
2240 : }
2241 0 : else if( EQUAL(pszGEOL_AS_GCPS,"FULL") )
2242 : {
2243 0 : iGCPStepX = iGCPStepY = 1;
2244 : }
2245 : else
2246 : {
2247 : // aim for 10x10 grid or so.
2248 0 : iGCPStepX = MAX(1,((nXPoints-1) / 11));
2249 0 : iGCPStepY = MAX(1,((nYPoints-1) / 11));
2250 : }
2251 :
2252 : /* -------------------------------------------------------------------- */
2253 : /* Fetch projection information for various datasets. */
2254 : /* -------------------------------------------------------------------- */
2255 0 : if ( nLatCount && nLongCount && nLatCount == nLongCount
2256 : && pLat && pLong )
2257 : {
2258 0 : CPLFree( pszGCPProjection );
2259 0 : pszGCPProjection = NULL;
2260 :
2261 : // ASTER Level 1A
2262 0 : if ( eProduct == PROD_ASTER_L1A )
2263 : {
2264 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\"]]" );
2265 : }
2266 :
2267 : // ASTER Level 1B, Level 2
2268 0 : else if ( eProduct == PROD_ASTER_L1B
2269 : || eProduct == PROD_ASTER_L2 )
2270 : {
2271 : // Constuct the metadata keys.
2272 : // A band number is taken from the field name.
2273 0 : const char *pszBand = strpbrk( pszFieldName, "0123456789" );
2274 :
2275 0 : if ( !pszBand )
2276 0 : pszBand = "";
2277 :
2278 : char *pszProjLine =
2279 0 : CPLStrdup(CPLSPrintf("MPMETHOD%s", pszBand));
2280 : char *pszParmsLine =
2281 : CPLStrdup(CPLSPrintf("PROJECTIONPARAMETERS%s",
2282 0 : pszBand));
2283 : char *pszZoneLine =
2284 : CPLStrdup(CPLSPrintf("UTMZONECODE%s",
2285 0 : pszBand));
2286 : char *pszEllipsoidLine =
2287 : CPLStrdup(CPLSPrintf("ELLIPSOIDANDDATUM%s",
2288 0 : pszBand));
2289 :
2290 : // Fetch projection related values from the
2291 : // metadata.
2292 : const char *pszProj =
2293 : CSLFetchNameValue( papszLocalMetadata,
2294 0 : pszProjLine );
2295 : const char *pszParms =
2296 : CSLFetchNameValue( papszLocalMetadata,
2297 0 : pszParmsLine );
2298 : const char *pszZone =
2299 : CSLFetchNameValue( papszLocalMetadata,
2300 0 : pszZoneLine );
2301 : const char* pszEllipsoid =
2302 : CSLFetchNameValue( papszLocalMetadata,
2303 0 : pszEllipsoidLine );
2304 :
2305 : #ifdef DEBUG
2306 : CPLDebug( "HDF4Image",
2307 : "Projection %s=%s, parameters %s=%s, "
2308 : "zone %s=%s",
2309 : pszProjLine, pszProj, pszParmsLine,
2310 0 : pszParms, pszZoneLine, pszZone );
2311 : CPLDebug( "HDF4Image", "Ellipsoid %s=%s",
2312 0 : pszEllipsoidLine, pszEllipsoid );
2313 : #endif
2314 :
2315 : // Transform all mnemonical codes in the values.
2316 : int i, nParms;
2317 : // Projection is UTM by default
2318 : long iProjSys = (pszProj) ?
2319 0 : USGSMnemonicToCode(pszProj) : 1L;
2320 : long iZone =
2321 0 : (pszZone && iProjSys == 1L) ? atoi(pszZone): 0L;
2322 : char **papszEllipsoid = (pszEllipsoid) ?
2323 : CSLTokenizeString2( pszEllipsoid, ",",
2324 0 : CSLT_HONOURSTRINGS ) : NULL;
2325 :
2326 0 : long iEllipsoid = 8L; // WGS84 by default
2327 0 : if ( papszEllipsoid
2328 : && CSLCount(papszEllipsoid) > 0 )
2329 : {
2330 0 : if (EQUAL( papszEllipsoid[0], "WGS84"))
2331 0 : iEllipsoid = 8L;
2332 : }
2333 :
2334 : double adfProjParms[15];
2335 : char **papszParms = (pszParms) ?
2336 : CSLTokenizeString2( pszParms, ",",
2337 0 : CSLT_HONOURSTRINGS ) : NULL;
2338 0 : nParms = CSLCount(papszParms);
2339 0 : if (nParms >= 15)
2340 0 : nParms = 15;
2341 0 : for (i = 0; i < nParms; i++)
2342 0 : adfProjParms[i] = CPLAtof( papszParms[i] );
2343 0 : for (; i < 15; i++)
2344 0 : adfProjParms[i] = 0.0;
2345 :
2346 : // Create projection definition
2347 : oSRS.importFromUSGS( iProjSys, iZone,
2348 0 : adfProjParms, iEllipsoid );
2349 0 : oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
2350 0 : oSRS.exportToWkt( &pszGCPProjection );
2351 :
2352 0 : CSLDestroy( papszParms );
2353 0 : CPLFree( pszEllipsoidLine );
2354 0 : CPLFree( pszZoneLine );
2355 0 : CPLFree( pszParmsLine );
2356 0 : CPLFree( pszProjLine );
2357 : }
2358 :
2359 : // ASTER Level 3 (DEM)
2360 0 : else if ( eProduct == PROD_ASTER_L3 )
2361 : {
2362 : double dfCenterX, dfCenterY;
2363 : int iZone;
2364 :
2365 : ReadCoordinates( CSLFetchNameValue(
2366 : papszGlobalMetadata, "SCENECENTER" ),
2367 0 : &dfCenterY, &dfCenterX );
2368 :
2369 : // Calculate UTM zone from scene center coordinates
2370 0 : iZone = 30 + (int) ((dfCenterX + 6.0) / 6.0);
2371 :
2372 : // Create projection definition
2373 0 : if( dfCenterY > 0 )
2374 0 : oSRS.SetUTM( iZone, TRUE );
2375 : else
2376 0 : oSRS.SetUTM( - iZone, FALSE );
2377 0 : oSRS.SetWellKnownGeogCS( "WGS84" );
2378 0 : oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
2379 0 : oSRS.exportToWkt( &pszGCPProjection );
2380 : }
2381 :
2382 : // MODIS L1B
2383 0 : else if ( eProduct == PROD_MODIS_L1B )
2384 : {
2385 0 : pszGCPProjection = CPLStrdup( SRS_WKT_WGS84 );
2386 : }
2387 : }
2388 :
2389 : /* -------------------------------------------------------------------- */
2390 : /* Fill the GCPs list. */
2391 : /* -------------------------------------------------------------------- */
2392 0 : if( iGCPStepX > 0 )
2393 : {
2394 : nGCPCount = (((nXPoints-1) / iGCPStepX) + 1)
2395 0 : * (((nYPoints-1) / iGCPStepY) + 1);
2396 :
2397 0 : pasGCPList = (GDAL_GCP *) CPLCalloc( nGCPCount, sizeof( GDAL_GCP ) );
2398 0 : GDALInitGCPs( nGCPCount, pasGCPList );
2399 :
2400 0 : int iGCP = 0;
2401 0 : for ( i = 0; i < nYPoints; i += iGCPStepY )
2402 : {
2403 0 : for ( j = 0; j < nXPoints; j += iGCPStepX )
2404 : {
2405 0 : int iGeoOff = i * nXPoints + j;
2406 :
2407 : pasGCPList[iGCP].dfGCPX =
2408 : AnyTypeToDouble(iWrkNumType,
2409 0 : (void *)((char*)pLong+ iGeoOff*iDataSize));
2410 : pasGCPList[iGCP].dfGCPY =
2411 : AnyTypeToDouble(iWrkNumType,
2412 0 : (void *)((char*)pLat + iGeoOff*iDataSize));
2413 :
2414 : // GCPs in Level 1A/1B dataset are in geocentric
2415 : // coordinates. Convert them in geodetic (we
2416 : // will convert latitudes only, longitudes
2417 : // do not need to be converted, because
2418 : // they are the same).
2419 : // This calculation valid for WGS84 datum only.
2420 0 : if ( eProduct == PROD_ASTER_L1A
2421 : || eProduct == PROD_ASTER_L1B )
2422 : {
2423 : pasGCPList[iGCP].dfGCPY =
2424 : atan(tan(pasGCPList[iGCP].dfGCPY
2425 0 : *PI/180)/0.99330562)*180/PI;
2426 : }
2427 :
2428 : ToGeoref(&pasGCPList[iGCP].dfGCPX,
2429 0 : &pasGCPList[iGCP].dfGCPY);
2430 :
2431 0 : pasGCPList[iGCP].dfGCPZ = 0.0;
2432 :
2433 0 : if ( pLatticeX && pLatticeY )
2434 : {
2435 : pasGCPList[iGCP].dfGCPPixel =
2436 : AnyTypeToDouble(iLatticeType,
2437 : (void *)((char *)pLatticeX
2438 0 : + iGeoOff*iLatticeDataSize))+0.5;
2439 : pasGCPList[iGCP].dfGCPLine =
2440 : AnyTypeToDouble(iLatticeType,
2441 : (void *)((char *)pLatticeY
2442 0 : + iGeoOff*iLatticeDataSize))+0.5;
2443 : }
2444 0 : else if ( paiOffset && paiIncrement )
2445 : {
2446 : pasGCPList[iGCP].dfGCPPixel =
2447 : paiOffset[iPixelDim] +
2448 0 : j * paiIncrement[iPixelDim] + 0.5;
2449 : pasGCPList[iGCP].dfGCPLine =
2450 : paiOffset[iLineDim] +
2451 0 : i * paiIncrement[iLineDim] + 0.5;
2452 : }
2453 :
2454 0 : iGCP++;
2455 : }
2456 : }
2457 : }
2458 :
2459 : /* -------------------------------------------------------------------- */
2460 : /* Establish geolocation metadata, but only if there is no */
2461 : /* lattice. The lattice destroys the regularity of the grid. */
2462 : /* -------------------------------------------------------------------- */
2463 0 : if( pLatticeX == NULL
2464 : && iLatDim != -1 && iLongDim != -1
2465 : && iPixelDim != -1 && iLineDim != -1 )
2466 : {
2467 0 : CPLString osWrk;
2468 :
2469 0 : SetMetadataItem( "SRS", pszGCPProjection, "GEOLOCATION" );
2470 :
2471 : osWrk.Printf( "HDF4_EOS:EOS_SWATH_GEOL:\"%s\":%s:%s",
2472 : pszFilename, pszSubdatasetName,
2473 0 : papszGeolocations[iLongDim] );
2474 0 : SetMetadataItem( "X_DATASET", osWrk, "GEOLOCATION" );
2475 0 : SetMetadataItem( "X_BAND", "1" , "GEOLOCATION" );
2476 :
2477 : osWrk.Printf( "HDF4_EOS:EOS_SWATH_GEOL:\"%s\":%s:%s",
2478 : pszFilename, pszSubdatasetName,
2479 0 : papszGeolocations[iLatDim] );
2480 0 : SetMetadataItem( "Y_DATASET", osWrk, "GEOLOCATION" );
2481 0 : SetMetadataItem( "Y_BAND", "1" , "GEOLOCATION" );
2482 :
2483 0 : if ( paiOffset && paiIncrement )
2484 : {
2485 0 : osWrk.Printf( "%ld", (long)paiOffset[iPixelDim] );
2486 0 : SetMetadataItem( "PIXEL_OFFSET", osWrk, "GEOLOCATION" );
2487 0 : osWrk.Printf( "%ld", (long)paiIncrement[iPixelDim] );
2488 0 : SetMetadataItem( "PIXEL_STEP", osWrk, "GEOLOCATION" );
2489 :
2490 0 : osWrk.Printf( "%ld", (long)paiOffset[iLineDim] );
2491 0 : SetMetadataItem( "LINE_OFFSET", osWrk, "GEOLOCATION" );
2492 0 : osWrk.Printf( "%ld", (long)paiIncrement[iLineDim] );
2493 0 : SetMetadataItem( "LINE_STEP", osWrk, "GEOLOCATION" );
2494 0 : }
2495 : }
2496 :
2497 : /* -------------------------------------------------------------------- */
2498 : /* Cleanup */
2499 : /* -------------------------------------------------------------------- */
2500 0 : CPLFree( pLatticeX );
2501 0 : CPLFree( pLatticeY );
2502 0 : CPLFree( pLat );
2503 0 : CPLFree( pLong );
2504 :
2505 0 : CPLFree( paiOffset );
2506 0 : CPLFree( paiIncrement );
2507 0 : CPLFree( paiNumType );
2508 0 : CPLFree( paiRank );
2509 :
2510 0 : CSLDestroy( papszGeolocations );
2511 0 : CPLFree( pszGeoList );
2512 :
2513 0 : if( iGCPStepX == 0 )
2514 : {
2515 0 : CPLFree( pszGCPProjection );
2516 0 : pszGCPProjection = NULL;
2517 : }
2518 :
2519 0 : return TRUE;
2520 : }
2521 :
2522 : /************************************************************************/
2523 : /* Open() */
2524 : /************************************************************************/
2525 :
2526 10562 : GDALDataset *HDF4ImageDataset::Open( GDALOpenInfo * poOpenInfo )
2527 : {
2528 : int i;
2529 :
2530 10562 : if( !EQUALN( poOpenInfo->pszFilename, "HDF4_SDS:", 9 ) &&
2531 : !EQUALN( poOpenInfo->pszFilename, "HDF4_GR:", 8 ) &&
2532 : !EQUALN( poOpenInfo->pszFilename, "HDF4_GD:", 8 ) &&
2533 : !EQUALN( poOpenInfo->pszFilename, "HDF4_EOS:", 9 ) )
2534 10299 : return NULL;
2535 :
2536 : /* -------------------------------------------------------------------- */
2537 : /* Create a corresponding GDALDataset. */
2538 : /* -------------------------------------------------------------------- */
2539 : char **papszSubdatasetName;
2540 : HDF4ImageDataset *poDS;
2541 :
2542 263 : poDS = new HDF4ImageDataset( );
2543 263 : poDS->fp = poOpenInfo->fp;
2544 263 : poOpenInfo->fp = NULL;
2545 :
2546 : papszSubdatasetName = CSLTokenizeString2( poOpenInfo->pszFilename,
2547 263 : ":", CSLT_HONOURSTRINGS | CSLT_PRESERVEESCAPES);
2548 271 : if ( CSLCount( papszSubdatasetName ) != 4
2549 : && CSLCount( papszSubdatasetName ) != 5
2550 : && CSLCount( papszSubdatasetName ) != 6 )
2551 : {
2552 0 : CSLDestroy( papszSubdatasetName );
2553 0 : delete poDS;
2554 0 : return NULL;
2555 : }
2556 :
2557 : /* -------------------------------------------------------------------- */
2558 : /* Check for drive name in windows HDF4:"D:\... */
2559 : /* -------------------------------------------------------------------- */
2560 263 : if (strlen(papszSubdatasetName[2]) == 1)
2561 : {
2562 0 : char* pszFilename = (char*) CPLMalloc( 2 + strlen(papszSubdatasetName[3]) + 1);
2563 0 : sprintf(pszFilename, "%s:%s", papszSubdatasetName[2], papszSubdatasetName[3]);
2564 0 : CPLFree(papszSubdatasetName[2]);
2565 0 : CPLFree(papszSubdatasetName[3]);
2566 0 : papszSubdatasetName[2] = pszFilename;
2567 :
2568 : /* Move following arguments one rank upper */
2569 0 : papszSubdatasetName[3] = papszSubdatasetName[4];
2570 0 : if (papszSubdatasetName[4] != NULL)
2571 : {
2572 0 : papszSubdatasetName[4] = papszSubdatasetName[5];
2573 0 : papszSubdatasetName[5] = NULL;
2574 : }
2575 : }
2576 :
2577 263 : poDS->pszFilename = CPLStrdup( papszSubdatasetName[2] );
2578 :
2579 263 : if( EQUAL( papszSubdatasetName[0], "HDF4_SDS" ) )
2580 255 : poDS->iDatasetType = HDF4_SDS;
2581 8 : else if ( EQUAL( papszSubdatasetName[0], "HDF4_GR" ) )
2582 0 : poDS->iDatasetType = HDF4_GR;
2583 8 : else if ( EQUAL( papszSubdatasetName[0], "HDF4_EOS" ) )
2584 8 : poDS->iDatasetType = HDF4_EOS;
2585 : else
2586 0 : poDS->iDatasetType = HDF4_UNKNOWN;
2587 :
2588 263 : if( EQUAL( papszSubdatasetName[1], "GDAL_HDF4" ) )
2589 249 : poDS->iSubdatasetType = H4ST_GDAL;
2590 14 : else if( EQUAL( papszSubdatasetName[1], "EOS_GRID" ) )
2591 8 : poDS->iSubdatasetType = H4ST_EOS_GRID;
2592 6 : else if( EQUAL( papszSubdatasetName[1], "EOS_SWATH" ) )
2593 0 : poDS->iSubdatasetType = H4ST_EOS_SWATH;
2594 6 : else if( EQUAL( papszSubdatasetName[1], "EOS_SWATH_GEOL" ) )
2595 0 : poDS->iSubdatasetType = H4ST_EOS_SWATH_GEOL;
2596 6 : else if( EQUAL( papszSubdatasetName[1], "SEAWIFS_L3" ) )
2597 0 : poDS->iSubdatasetType= H4ST_SEAWIFS_L3;
2598 6 : else if( EQUAL( papszSubdatasetName[1], "HYPERION_L1" ) )
2599 0 : poDS->iSubdatasetType= H4ST_HYPERION_L1;
2600 : else
2601 6 : poDS->iSubdatasetType = H4ST_UNKNOWN;
2602 :
2603 : // Is our file still here?
2604 263 : if ( !Hishdf( poDS->pszFilename ) )
2605 : {
2606 0 : CSLDestroy( papszSubdatasetName );
2607 0 : delete poDS;
2608 0 : return NULL;
2609 : }
2610 :
2611 : /* -------------------------------------------------------------------- */
2612 : /* Collect the remain (post filename) components to treat as */
2613 : /* the subdataset name. */
2614 : /* -------------------------------------------------------------------- */
2615 263 : CPLString osSubdatasetName;
2616 :
2617 263 : osSubdatasetName = papszSubdatasetName[3];
2618 263 : if( papszSubdatasetName[4] != NULL )
2619 : {
2620 8 : osSubdatasetName += ":";
2621 8 : osSubdatasetName += papszSubdatasetName[4];
2622 : }
2623 :
2624 : /* -------------------------------------------------------------------- */
2625 : /* Try opening the dataset. */
2626 : /* -------------------------------------------------------------------- */
2627 : int32 iAttribute, nValues, iAttrNumType;
2628 263 : double dfNoData = 0.0;
2629 263 : int bNoDataSet = FALSE;
2630 :
2631 : /* -------------------------------------------------------------------- */
2632 : /* Select SDS or GR to read from. */
2633 : /* -------------------------------------------------------------------- */
2634 263 : if ( poDS->iDatasetType == HDF4_EOS )
2635 : {
2636 8 : poDS->pszSubdatasetName = CPLStrdup( papszSubdatasetName[3] );
2637 8 : if (papszSubdatasetName[4] == NULL)
2638 : {
2639 0 : delete poDS;
2640 263 : return NULL;
2641 : }
2642 8 : poDS->pszFieldName = CPLStrdup( papszSubdatasetName[4] );
2643 : }
2644 : else
2645 255 : poDS->iDataset = atoi( papszSubdatasetName[3] );
2646 263 : CSLDestroy( papszSubdatasetName );
2647 :
2648 263 : switch ( poDS->iDatasetType )
2649 : {
2650 : case HDF4_EOS:
2651 : {
2652 8 : void *pNoDataValue = NULL;
2653 :
2654 8 : switch ( poDS->iSubdatasetType )
2655 : {
2656 :
2657 : /* -------------------------------------------------------------------- */
2658 : /* HDF-EOS Swath. */
2659 : /* -------------------------------------------------------------------- */
2660 : case H4ST_EOS_SWATH:
2661 : case H4ST_EOS_SWATH_GEOL:
2662 : {
2663 : int32 hSW, nStrBufSize;
2664 0 : char *pszDimList = NULL;
2665 :
2666 0 : if( poOpenInfo->eAccess == GA_ReadOnly )
2667 0 : poDS->hHDF4 = SWopen( poDS->pszFilename, DFACC_READ );
2668 : else
2669 0 : poDS->hHDF4 = SWopen( poDS->pszFilename, DFACC_WRITE );
2670 :
2671 0 : if( poDS->hHDF4 <= 0 )
2672 : {
2673 : CPLDebug( "HDF4Image", "Can't open HDF4 file %s",
2674 0 : poDS->pszFilename );
2675 0 : delete poDS;
2676 0 : return( NULL );
2677 : }
2678 :
2679 0 : hSW = SWattach( poDS->hHDF4, poDS->pszSubdatasetName );
2680 0 : if( hSW < 0 )
2681 : {
2682 : CPLDebug( "HDF4Image", "Can't attach to subdataset %s",
2683 0 : poDS->pszSubdatasetName );
2684 0 : delete poDS;
2685 0 : return( NULL );
2686 : }
2687 :
2688 : /* -------------------------------------------------------------------- */
2689 : /* Decode the dimension map. */
2690 : /* -------------------------------------------------------------------- */
2691 0 : SWnentries( hSW, HDFE_NENTDIM, &nStrBufSize );
2692 0 : pszDimList = (char *)CPLMalloc( nStrBufSize + 1 );
2693 : SWfieldinfo( hSW, poDS->pszFieldName, &poDS->iRank,
2694 0 : poDS->aiDimSizes, &poDS->iNumType, pszDimList );
2695 : #ifdef DEBUG
2696 : CPLDebug( "HDF4Image",
2697 : "List of dimensions in swath %s: %s",
2698 0 : poDS->pszFieldName, pszDimList );
2699 : #endif
2700 0 : poDS->GetImageDimensions( pszDimList );
2701 :
2702 : #ifdef DEBUG
2703 : CPLDebug( "HDF4Image",
2704 : "X dimension is %d, Y dimension is %d",
2705 0 : poDS->iXDim, poDS->iYDim );
2706 : #endif
2707 :
2708 : /* -------------------------------------------------------------------- */
2709 : /* Fetch metadata. */
2710 : /* -------------------------------------------------------------------- */
2711 0 : if( poDS->iSubdatasetType == H4ST_EOS_SWATH ) /* Not H4ST_EOS_SWATH_GEOL */
2712 0 : poDS->GetSwatAttrs( hSW );
2713 :
2714 : /* -------------------------------------------------------------------- */
2715 : /* Fetch NODATA value. */
2716 : /* -------------------------------------------------------------------- */
2717 : pNoDataValue =
2718 0 : CPLMalloc( poDS->GetDataTypeSize(poDS->iNumType) );
2719 0 : if ( SWgetfillvalue( hSW, poDS->pszFieldName,
2720 : pNoDataValue ) != -1 )
2721 : {
2722 : dfNoData = poDS->AnyTypeToDouble( poDS->iNumType,
2723 0 : pNoDataValue );
2724 0 : bNoDataSet = TRUE;
2725 : }
2726 : else
2727 : {
2728 : const char *pszNoData =
2729 : CSLFetchNameValue( poDS->papszLocalMetadata,
2730 0 : "_FillValue" );
2731 0 : if ( pszNoData )
2732 : {
2733 0 : dfNoData = CPLAtof( pszNoData );
2734 0 : bNoDataSet = TRUE;
2735 : }
2736 : }
2737 0 : CPLFree( pNoDataValue );
2738 :
2739 : /* -------------------------------------------------------------------- */
2740 : /* Handle Geolocation processing. */
2741 : /* -------------------------------------------------------------------- */
2742 0 : if( poDS->iSubdatasetType == H4ST_EOS_SWATH ) /* Not H4ST_SWATH_GEOL */
2743 : {
2744 : char **papszDimList =
2745 : CSLTokenizeString2( pszDimList, ",",
2746 0 : CSLT_HONOURSTRINGS );
2747 0 : if( !poDS->ProcessSwathGeolocation( hSW, papszDimList ) )
2748 : {
2749 : CPLDebug( "HDF4Image",
2750 0 : "No geolocation available for this swath." );
2751 : }
2752 0 : CSLDestroy( papszDimList );
2753 : }
2754 :
2755 : /* -------------------------------------------------------------------- */
2756 : /* Cleanup. */
2757 : /* -------------------------------------------------------------------- */
2758 0 : CPLFree( pszDimList );
2759 0 : SWdetach( hSW );
2760 : }
2761 0 : break;
2762 :
2763 : /* -------------------------------------------------------------------- */
2764 : /* HDF-EOS Grid. */
2765 : /* -------------------------------------------------------------------- */
2766 : case H4ST_EOS_GRID:
2767 : {
2768 8 : int32 hGD, iProjCode = 0, iZoneCode = 0, iSphereCode = 0;
2769 : int32 nXSize, nYSize;
2770 : char szDimList[8192];
2771 : double adfUpLeft[2], adfLowRight[2], adfProjParms[15];
2772 :
2773 8 : if( poOpenInfo->eAccess == GA_ReadOnly )
2774 8 : poDS->hHDF4 = GDopen( poDS->pszFilename, DFACC_READ );
2775 : else
2776 0 : poDS->hHDF4 = GDopen( poDS->pszFilename, DFACC_WRITE );
2777 :
2778 8 : if( poDS->hHDF4 <= 0 )
2779 : {
2780 0 : delete poDS;
2781 0 : return( NULL );
2782 : }
2783 :
2784 8 : hGD = GDattach( poDS->hHDF4, poDS->pszSubdatasetName );
2785 :
2786 : /* -------------------------------------------------------------------- */
2787 : /* Decode the dimension map. */
2788 : /* -------------------------------------------------------------------- */
2789 : GDfieldinfo( hGD, poDS->pszFieldName, &poDS->iRank,
2790 8 : poDS->aiDimSizes, &poDS->iNumType, szDimList );
2791 : #ifdef DEBUG
2792 : CPLDebug( "HDF4Image",
2793 : "List of dimensions in grid %s: %s",
2794 8 : poDS->pszFieldName, szDimList);
2795 : #endif
2796 8 : poDS->GetImageDimensions( szDimList );
2797 :
2798 : int32 tilecode, tilerank;
2799 8 : if( GDtileinfo( hGD , poDS->pszFieldName , &tilecode, &tilerank, NULL ) == 0 )
2800 : {
2801 8 : if ( tilecode == HDFE_TILE )
2802 : {
2803 6 : int32 *tiledims = NULL;
2804 6 : tiledims = (int32 *) CPLCalloc( tilerank , sizeof( int32 ) );
2805 6 : GDtileinfo( hGD , poDS->pszFieldName , &tilecode, &tilerank, tiledims );
2806 12 : if ( ( tilerank == 2 ) && ( poDS->iRank == tilerank ) )
2807 : {
2808 6 : poDS->nBlockPreferredXSize = tiledims[1];
2809 6 : poDS->nBlockPreferredYSize = tiledims[0];
2810 6 : poDS->bReadTile = true;
2811 : #ifdef DEBUG
2812 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilerank in grid %s: %d",
2813 6 : poDS->pszFieldName , (int)tilerank );
2814 : CPLDebug( "HDF4_EOS:EOS_GRID:","tiledimens in grid %s: %d,%d",
2815 6 : poDS->pszFieldName , (int)tiledims[0] , (int)tiledims[1] );
2816 : #endif
2817 : }
2818 : #ifdef DEBUG
2819 : else
2820 : {
2821 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilerank in grid %s: %d not supported",
2822 0 : poDS->pszFieldName , (int)tilerank );
2823 : }
2824 : #endif
2825 6 : CPLFree(tiledims);
2826 : }
2827 : else
2828 : {
2829 : #ifdef DEBUG
2830 : CPLDebug( "HDF4_EOS:EOS_GRID:","tilecode == HDFE_NOTILE in grid %s: %d",
2831 : poDS->pszFieldName ,
2832 2 : (int)poDS->iRank );
2833 : #endif
2834 : }
2835 : }
2836 : #ifdef DEBUG
2837 : else
2838 : {
2839 0 : CPLDebug( "HDF4_EOS:EOS_GRID:","ERROR GDtileinfo %s", poDS->pszFieldName );
2840 : }
2841 : #endif
2842 :
2843 : /* -------------------------------------------------------------------- */
2844 : /* Fetch projection information */
2845 : /* -------------------------------------------------------------------- */
2846 8 : if ( GDprojinfo( hGD, &iProjCode, &iZoneCode,
2847 : &iSphereCode, adfProjParms) >= 0 )
2848 : {
2849 : #ifdef DEBUG
2850 : CPLDebug( "HDF4Image",
2851 : "Grid projection: "
2852 : "projection code: %ld, zone code %ld, "
2853 : "sphere code %ld",
2854 : (long)iProjCode, (long)iZoneCode,
2855 8 : (long)iSphereCode );
2856 : #endif
2857 : poDS->oSRS.importFromUSGS( iProjCode, iZoneCode,
2858 8 : adfProjParms, iSphereCode );
2859 :
2860 8 : if ( poDS->pszProjection )
2861 8 : CPLFree( poDS->pszProjection );
2862 8 : poDS->oSRS.exportToWkt( &poDS->pszProjection );
2863 : }
2864 :
2865 : /* -------------------------------------------------------------------- */
2866 : /* Fetch geotransformation matrix */
2867 : /* -------------------------------------------------------------------- */
2868 8 : if ( GDgridinfo( hGD, &nXSize, &nYSize,
2869 : adfUpLeft, adfLowRight ) >= 0 )
2870 : {
2871 : #ifdef DEBUG
2872 : CPLDebug( "HDF4Image",
2873 : "Grid geolocation: "
2874 : "top left X %f, top left Y %f, "
2875 : "low right X %f, low right Y %f, "
2876 : "cols %ld, rows %ld",
2877 : adfUpLeft[0], adfUpLeft[1],
2878 : adfLowRight[0], adfLowRight[1],
2879 8 : (long)nXSize, (long)nYSize );
2880 : #endif
2881 8 : if ( iProjCode )
2882 : {
2883 : // For projected systems coordinates are in meters
2884 : poDS->adfGeoTransform[1] =
2885 6 : (adfLowRight[0] - adfUpLeft[0]) / nXSize;
2886 : poDS->adfGeoTransform[5] =
2887 6 : (adfLowRight[1] - adfUpLeft[1]) / nYSize;
2888 6 : poDS->adfGeoTransform[0] = adfUpLeft[0];
2889 6 : poDS->adfGeoTransform[3] = adfUpLeft[1];
2890 : }
2891 : else
2892 : {
2893 : // Handle angular geographic coordinates here
2894 : poDS->adfGeoTransform[1] =
2895 : (CPLPackedDMSToDec(adfLowRight[0]) -
2896 2 : CPLPackedDMSToDec(adfUpLeft[0])) / nXSize;
2897 : poDS->adfGeoTransform[5] =
2898 : (CPLPackedDMSToDec(adfLowRight[1]) -
2899 2 : CPLPackedDMSToDec(adfUpLeft[1])) / nYSize;
2900 : poDS->adfGeoTransform[0] =
2901 2 : CPLPackedDMSToDec(adfUpLeft[0]);
2902 : poDS->adfGeoTransform[3] =
2903 2 : CPLPackedDMSToDec(adfUpLeft[1]);
2904 : }
2905 8 : poDS->adfGeoTransform[2] = 0.0;
2906 8 : poDS->adfGeoTransform[4] = 0.0;
2907 8 : poDS->bHasGeoTransform = TRUE;
2908 : }
2909 :
2910 : /* -------------------------------------------------------------------- */
2911 : /* Fetch metadata. */
2912 : /* -------------------------------------------------------------------- */
2913 8 : poDS->GetGridAttrs( hGD );
2914 :
2915 8 : GDdetach( hGD );
2916 :
2917 : /* -------------------------------------------------------------------- */
2918 : /* Fetch NODATA value. */
2919 : /* -------------------------------------------------------------------- */
2920 : pNoDataValue =
2921 8 : CPLMalloc( poDS->GetDataTypeSize(poDS->iNumType) );
2922 8 : if ( GDgetfillvalue( hGD, poDS->pszFieldName,
2923 : pNoDataValue ) != -1 )
2924 : {
2925 : dfNoData = poDS->AnyTypeToDouble( poDS->iNumType,
2926 0 : pNoDataValue );
2927 0 : bNoDataSet = TRUE;
2928 : }
2929 : else
2930 : {
2931 : const char *pszNoData =
2932 : CSLFetchNameValue( poDS->papszLocalMetadata,
2933 8 : "_FillValue" );
2934 8 : if ( pszNoData )
2935 : {
2936 6 : dfNoData = CPLAtof( pszNoData );
2937 6 : bNoDataSet = TRUE;
2938 : }
2939 : }
2940 8 : CPLFree( pNoDataValue );
2941 : }
2942 : break;
2943 :
2944 : default:
2945 : break;
2946 : }
2947 : }
2948 8 : break;
2949 :
2950 : /* -------------------------------------------------------------------- */
2951 : /* 'Plain' HDF scientific datasets. */
2952 : /* -------------------------------------------------------------------- */
2953 : case HDF4_SDS:
2954 : {
2955 : int32 iSDS;
2956 :
2957 255 : if( poOpenInfo->eAccess == GA_ReadOnly )
2958 255 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_READ, 0 );
2959 : else
2960 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_WRITE, 0 );
2961 :
2962 255 : if( poDS->hHDF4 <= 0 )
2963 : {
2964 0 : delete poDS;
2965 0 : return( NULL );
2966 : }
2967 :
2968 255 : poDS->hSD = SDstart( poDS->pszFilename, DFACC_READ );
2969 255 : if ( poDS->hSD == -1 )
2970 : {
2971 0 : delete poDS;
2972 0 : return NULL;
2973 : }
2974 :
2975 255 : if ( poDS->ReadGlobalAttributes( poDS->hSD ) != CE_None )
2976 : {
2977 0 : delete poDS;
2978 0 : return NULL;
2979 : }
2980 :
2981 : int32 nDatasets, nAttrs;
2982 :
2983 255 : if ( SDfileinfo( poDS->hSD, &nDatasets, &nAttrs ) != 0 )
2984 : {
2985 0 : delete poDS;
2986 0 : return NULL;
2987 : }
2988 :
2989 255 : if (poDS->iDataset < 0 || poDS->iDataset >= nDatasets)
2990 : {
2991 : CPLError(CE_Failure, CPLE_AppDefined,
2992 0 : "Subdataset index should be between 0 and %d", nDatasets - 1);
2993 0 : delete poDS;
2994 0 : return NULL;
2995 : }
2996 :
2997 255 : memset( poDS->aiDimSizes, 0, sizeof(int32) * H4_MAX_VAR_DIMS );
2998 255 : iSDS = SDselect( poDS->hSD, poDS->iDataset );
2999 : SDgetinfo( iSDS, poDS->szName, &poDS->iRank, poDS->aiDimSizes,
3000 255 : &poDS->iNumType, &poDS->nAttrs);
3001 :
3002 : // We will duplicate global metadata for every subdataset
3003 : poDS->papszLocalMetadata =
3004 255 : CSLDuplicate( poDS->papszGlobalMetadata );
3005 :
3006 286 : for ( iAttribute = 0; iAttribute < poDS->nAttrs; iAttribute++ )
3007 : {
3008 : char szAttrName[H4_MAX_NC_NAME];
3009 : SDattrinfo( iSDS, iAttribute, szAttrName,
3010 31 : &iAttrNumType, &nValues );
3011 : poDS->papszLocalMetadata =
3012 : poDS->TranslateHDF4Attributes( iSDS, iAttribute,
3013 : szAttrName, iAttrNumType,
3014 : nValues,
3015 31 : poDS->papszLocalMetadata );
3016 : }
3017 255 : poDS->SetMetadata( poDS->papszLocalMetadata, "" );
3018 255 : SDendaccess( iSDS );
3019 :
3020 : #ifdef DEBUG
3021 : CPLDebug( "HDF4Image",
3022 : "aiDimSizes[0]=%ld, aiDimSizes[1]=%ld, "
3023 : "aiDimSizes[2]=%ld, aiDimSizes[3]=%ld",
3024 : (long)poDS->aiDimSizes[0], (long)poDS->aiDimSizes[1],
3025 255 : (long)poDS->aiDimSizes[2], (long)poDS->aiDimSizes[3] );
3026 : #endif
3027 :
3028 255 : switch( poDS->iRank )
3029 : {
3030 : case 1:
3031 0 : poDS->nBandCount = 1;
3032 0 : poDS->iXDim = 0;
3033 0 : poDS->iYDim = -1;
3034 0 : break;
3035 : case 2:
3036 109 : poDS->nBandCount = 1;
3037 109 : poDS->iXDim = 1;
3038 109 : poDS->iYDim = 0;
3039 109 : break;
3040 : case 3:
3041 : /* FIXME ? We should probably remove the following test as there are valid datasets */
3042 : /* where the height is lower than the band number : for example
3043 : http://www.iapmw.unibe.ch/research/projects/FriOWL/data/otd/LISOTD_HRAC_V2.2.hdf */
3044 : /* which is a 720x360 x 365 bands */
3045 : /* Use a HACK for now */
3046 146 : if( poDS->aiDimSizes[0] < poDS->aiDimSizes[2] &&
3047 : !(poDS->aiDimSizes[0] == 360 &&
3048 : poDS->aiDimSizes[1] == 720 &&
3049 : poDS->aiDimSizes[2] == 365) )
3050 : {
3051 0 : poDS->iBandDim = 0;
3052 0 : poDS->iXDim = 2;
3053 0 : poDS->iYDim = 1;
3054 : }
3055 : else
3056 : {
3057 146 : if( poDS->aiDimSizes[1] <= poDS->aiDimSizes[0] &&
3058 : poDS->aiDimSizes[1] <= poDS->aiDimSizes[2] )
3059 : {
3060 0 : poDS->iBandDim = 1;
3061 0 : poDS->iXDim = 2;
3062 0 : poDS->iYDim = 0;
3063 : }
3064 : else
3065 : {
3066 146 : poDS->iBandDim = 2;
3067 146 : poDS->iXDim = 1;
3068 146 : poDS->iYDim = 0;
3069 :
3070 : }
3071 : }
3072 146 : poDS->nBandCount = poDS->aiDimSizes[poDS->iBandDim];
3073 146 : break;
3074 : case 4: // FIXME
3075 0 : poDS->nBandCount = poDS->aiDimSizes[2] * poDS->aiDimSizes[3];
3076 : break;
3077 : default:
3078 : break;
3079 : }
3080 :
3081 : // We preset this because CaptureNRLGeoTransform needs it.
3082 255 : poDS->nRasterXSize = poDS->aiDimSizes[poDS->iXDim];
3083 255 : if (poDS->iYDim >= 0)
3084 255 : poDS->nRasterYSize = poDS->aiDimSizes[poDS->iYDim];
3085 : else
3086 0 : poDS->nRasterYSize = 1;
3087 :
3088 : // Special case projection info for NRL generated files.
3089 : const char *pszMapProjectionSystem =
3090 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3091 255 : "mapProjectionSystem");
3092 255 : if( pszMapProjectionSystem != NULL
3093 : && EQUAL(pszMapProjectionSystem,"NRL(USGS)") )
3094 : {
3095 0 : poDS->CaptureNRLGeoTransform();
3096 : }
3097 :
3098 : // Special case for coastwatch hdf files.
3099 255 : if( CSLFetchNameValue( poDS->papszGlobalMetadata,
3100 : "gctp_sys" ) != NULL )
3101 0 : poDS->CaptureCoastwatchGCTPInfo();
3102 :
3103 : // Special case for MODIS geolocation
3104 255 : poDS->ProcessModisSDSGeolocation();
3105 :
3106 : // Special case for NASA/CCRS Landsat in HDF
3107 255 : poDS->CaptureL1GMTLInfo();
3108 : }
3109 255 : break;
3110 :
3111 : /* -------------------------------------------------------------------- */
3112 : /* 'Plain' HDF rasters. */
3113 : /* -------------------------------------------------------------------- */
3114 : case HDF4_GR:
3115 0 : if( poOpenInfo->eAccess == GA_ReadOnly )
3116 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_READ, 0 );
3117 : else
3118 0 : poDS->hHDF4 = Hopen( poDS->pszFilename, DFACC_WRITE, 0 );
3119 :
3120 0 : if( poDS->hHDF4 <= 0 )
3121 : {
3122 0 : delete poDS;
3123 0 : return( NULL );
3124 : }
3125 :
3126 0 : poDS->hGR = GRstart( poDS->hHDF4 );
3127 0 : if ( poDS->hGR == -1 )
3128 : {
3129 0 : delete poDS;
3130 0 : return NULL;
3131 : }
3132 :
3133 0 : poDS->iGR = GRselect( poDS->hGR, poDS->iDataset );
3134 0 : if ( GRgetiminfo( poDS->iGR, poDS->szName,
3135 : &poDS->iRank, &poDS->iNumType,
3136 : &poDS->iInterlaceMode, poDS->aiDimSizes,
3137 : &poDS->nAttrs ) != 0 )
3138 : {
3139 0 : delete poDS;
3140 0 : return NULL;
3141 : }
3142 :
3143 : // We will duplicate global metadata for every subdataset
3144 0 : poDS->papszLocalMetadata = CSLDuplicate( poDS->papszGlobalMetadata );
3145 :
3146 0 : for ( iAttribute = 0; iAttribute < poDS->nAttrs; iAttribute++ )
3147 : {
3148 : char szAttrName[H4_MAX_NC_NAME];
3149 : GRattrinfo( poDS->iGR, iAttribute, szAttrName,
3150 0 : &iAttrNumType, &nValues );
3151 : poDS->papszLocalMetadata =
3152 : poDS->TranslateHDF4Attributes( poDS->iGR, iAttribute,
3153 : szAttrName, iAttrNumType,
3154 : nValues,
3155 0 : poDS->papszLocalMetadata );
3156 : }
3157 0 : poDS->SetMetadata( poDS->papszLocalMetadata, "" );
3158 : // Read colour table
3159 : GDALColorEntry oEntry;
3160 :
3161 0 : poDS->iPal = GRgetlutid ( poDS->iGR, poDS->iDataset );
3162 0 : if ( poDS->iPal != -1 )
3163 : {
3164 : GRgetlutinfo( poDS->iPal, &poDS->nComps, &poDS->iPalDataType,
3165 0 : &poDS->iPalInterlaceMode, &poDS->nPalEntries );
3166 0 : GRreadlut( poDS->iPal, poDS->aiPaletteData );
3167 0 : poDS->poColorTable = new GDALColorTable();
3168 0 : for( i = 0; i < N_COLOR_ENTRIES; i++ )
3169 : {
3170 0 : oEntry.c1 = poDS->aiPaletteData[i][0];
3171 0 : oEntry.c2 = poDS->aiPaletteData[i][1];
3172 0 : oEntry.c3 = poDS->aiPaletteData[i][2];
3173 0 : oEntry.c4 = 255;
3174 :
3175 0 : poDS->poColorTable->SetColorEntry( i, &oEntry );
3176 : }
3177 : }
3178 :
3179 0 : poDS->iXDim = 0;
3180 0 : poDS->iYDim = 1;
3181 0 : poDS->nBandCount = poDS->iRank;
3182 0 : break;
3183 : default:
3184 0 : delete poDS;
3185 0 : return NULL;
3186 : }
3187 :
3188 263 : poDS->nRasterXSize = poDS->aiDimSizes[poDS->iXDim];
3189 263 : if (poDS->iYDim >= 0)
3190 263 : poDS->nRasterYSize = poDS->aiDimSizes[poDS->iYDim];
3191 : else
3192 0 : poDS->nRasterYSize = 1;
3193 :
3194 263 : if ( poDS->iSubdatasetType == H4ST_HYPERION_L1 )
3195 : {
3196 : // XXX: Hyperion SDSs has Height x Bands x Width dimensions scheme
3197 0 : if ( poDS->iRank > 2 )
3198 : {
3199 0 : poDS->nBandCount = poDS->aiDimSizes[1];
3200 0 : poDS->nRasterXSize = poDS->aiDimSizes[2];
3201 0 : poDS->nRasterYSize = poDS->aiDimSizes[0];
3202 : }
3203 : else
3204 : {
3205 0 : poDS->nBandCount = poDS->aiDimSizes[0];
3206 0 : poDS->nRasterXSize = poDS->aiDimSizes[1];
3207 0 : poDS->nRasterYSize = 1;
3208 : }
3209 : }
3210 :
3211 : /* -------------------------------------------------------------------- */
3212 : /* Create band information objects. */
3213 : /* -------------------------------------------------------------------- */
3214 602 : for( i = 1; i <= poDS->nBandCount; i++ )
3215 : {
3216 : HDF4ImageRasterBand *poBand =
3217 : new HDF4ImageRasterBand( poDS, i,
3218 339 : poDS->GetDataType( poDS->iNumType ) );
3219 339 : poDS->SetBand( i, poBand );
3220 :
3221 339 : if ( bNoDataSet )
3222 6 : poBand->SetNoDataValue( dfNoData );
3223 : }
3224 :
3225 : /* -------------------------------------------------------------------- */
3226 : /* Now we will handle particular types of HDF products. Every */
3227 : /* HDF product has its own structure. */
3228 : /* -------------------------------------------------------------------- */
3229 :
3230 : // Variables for reading georeferencing
3231 : double dfULX, dfULY, dfLRX, dfLRY;
3232 :
3233 263 : switch ( poDS->iSubdatasetType )
3234 : {
3235 : /* -------------------------------------------------------------------- */
3236 : /* HDF, created by GDAL. */
3237 : /* -------------------------------------------------------------------- */
3238 : case H4ST_GDAL:
3239 : {
3240 : const char *pszValue;
3241 :
3242 : CPLDebug( "HDF4Image",
3243 249 : "Input dataset interpreted as GDAL_HDF4" );
3244 :
3245 249 : if ( (pszValue =
3246 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3247 : "Projection")) )
3248 : {
3249 105 : if ( poDS->pszProjection )
3250 105 : CPLFree( poDS->pszProjection );
3251 105 : poDS->pszProjection = CPLStrdup( pszValue );
3252 : }
3253 249 : if ( (pszValue = CSLFetchNameValue(poDS->papszGlobalMetadata,
3254 : "TransformationMatrix")) )
3255 : {
3256 249 : int i = 0;
3257 249 : char *pszString = (char *) pszValue;
3258 1992 : while ( *pszValue && i < 6 )
3259 : {
3260 1494 : poDS->adfGeoTransform[i++] = strtod(pszString, &pszString);
3261 1494 : pszString++;
3262 : }
3263 249 : poDS->bHasGeoTransform = TRUE;
3264 : }
3265 560 : for( i = 1; i <= poDS->nBands; i++ )
3266 : {
3267 311 : if ( (pszValue =
3268 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3269 : CPLSPrintf("BandDesc%d", i))) )
3270 32 : poDS->GetRasterBand( i )->SetDescription( pszValue );
3271 : }
3272 560 : for( i = 1; i <= poDS->nBands; i++ )
3273 : {
3274 311 : if ( (pszValue =
3275 : CSLFetchNameValue(poDS->papszGlobalMetadata,
3276 : CPLSPrintf("NoDataValue%d", i))) )
3277 32 : poDS->GetRasterBand(i)->SetNoDataValue( CPLAtof(pszValue) );
3278 : }
3279 : }
3280 249 : break;
3281 :
3282 : /* -------------------------------------------------------------------- */
3283 : /* SeaWiFS Level 3 Standard Mapped Image Products. */
3284 : /* Organized similar to MODIS Level 3 products. */
3285 : /* -------------------------------------------------------------------- */
3286 : case H4ST_SEAWIFS_L3:
3287 : {
3288 0 : CPLDebug( "HDF4Image", "Input dataset interpreted as SEAWIFS_L3" );
3289 :
3290 : // Read band description
3291 0 : for ( i = 1; i <= poDS->nBands; i++ )
3292 : {
3293 : poDS->GetRasterBand( i )->SetDescription(
3294 0 : CSLFetchNameValue( poDS->papszGlobalMetadata, "Parameter" ) );
3295 : }
3296 :
3297 : // Read coordinate system and geotransform matrix
3298 0 : poDS->oSRS.SetWellKnownGeogCS( "WGS84" );
3299 :
3300 0 : if ( EQUAL(CSLFetchNameValue(poDS->papszGlobalMetadata,
3301 : "Map Projection"),
3302 : "Equidistant Cylindrical") )
3303 : {
3304 0 : poDS->oSRS.SetEquirectangular( 0.0, 0.0, 0.0, 0.0 );
3305 0 : poDS->oSRS.SetLinearUnits( SRS_UL_METER, 1 );
3306 0 : if ( poDS->pszProjection )
3307 0 : CPLFree( poDS->pszProjection );
3308 0 : poDS->oSRS.exportToWkt( &poDS->pszProjection );
3309 : }
3310 :
3311 : dfULX = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3312 0 : "Westernmost Longitude") );
3313 : dfULY = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3314 0 : "Northernmost Latitude") );
3315 : dfLRX = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3316 0 : "Easternmost Longitude") );
3317 : dfLRY = CPLAtof( CSLFetchNameValue(poDS->papszGlobalMetadata,
3318 0 : "Southernmost Latitude") );
3319 0 : poDS->ToGeoref( &dfULX, &dfULY );
3320 0 : poDS->ToGeoref( &dfLRX, &dfLRY );
3321 0 : poDS->adfGeoTransform[0] = dfULX;
3322 0 : poDS->adfGeoTransform[3] = dfULY;
3323 0 : poDS->adfGeoTransform[1] = (dfLRX - dfULX) / poDS->nRasterXSize;
3324 0 : poDS->adfGeoTransform[5] = (dfULY - dfLRY) / poDS->nRasterYSize;
3325 0 : if ( dfULY > 0) // Northern hemisphere
3326 0 : poDS->adfGeoTransform[5] = - poDS->adfGeoTransform[5];
3327 0 : poDS->adfGeoTransform[2] = 0.0;
3328 0 : poDS->adfGeoTransform[4] = 0.0;
3329 0 : poDS->bHasGeoTransform = TRUE;
3330 : }
3331 0 : break;
3332 :
3333 :
3334 : /* -------------------------------------------------------------------- */
3335 : /* Generic SDS */
3336 : /* -------------------------------------------------------------------- */
3337 : case H4ST_UNKNOWN:
3338 : {
3339 :
3340 : // This is a coastwatch convention.
3341 6 : if( CSLFetchNameValue( poDS->papszLocalMetadata, "missing_value" ) )
3342 : {
3343 : int i;
3344 0 : for( i = 1; i <= poDS->nBands; i++ )
3345 : {
3346 : poDS->GetRasterBand(i)->SetNoDataValue(
3347 : CPLAtof( CSLFetchNameValue(poDS->papszLocalMetadata,
3348 0 : "missing_value") ) );
3349 : }
3350 : }
3351 :
3352 : // Coastwatch offset and scale.
3353 6 : if( CSLFetchNameValue( poDS->papszLocalMetadata, "scale_factor" )
3354 : && CSLFetchNameValue( poDS->papszLocalMetadata, "add_offset" ) )
3355 : {
3356 0 : for( i = 1; i <= poDS->nBands; i++ )
3357 : {
3358 : HDF4ImageRasterBand *poBand =
3359 0 : (HDF4ImageRasterBand *) poDS->GetRasterBand(i);
3360 :
3361 0 : poBand->bHaveScaleAndOffset = TRUE;
3362 : poBand->dfScale =
3363 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3364 0 : "scale_factor" ) );
3365 : poBand->dfOffset = -1 * poBand->dfScale *
3366 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3367 0 : "add_offset" ) );
3368 : }
3369 : }
3370 :
3371 : // this is a modis level3 convention (data from ACT)
3372 : // Eg data/hdf/act/modis/MODAM2004280160000.L3_NOAA_GMX
3373 :
3374 6 : if( CSLFetchNameValue( poDS->papszLocalMetadata,
3375 : "scalingSlope" )
3376 : && CSLFetchNameValue( poDS->papszLocalMetadata,
3377 : "scalingIntercept" ) )
3378 : {
3379 : int i;
3380 0 : CPLString osUnits;
3381 :
3382 0 : if( CSLFetchNameValue( poDS->papszLocalMetadata,
3383 : "productUnits" ) )
3384 : {
3385 : osUnits = CSLFetchNameValue( poDS->papszLocalMetadata,
3386 0 : "productUnits" );
3387 : }
3388 :
3389 0 : for( i = 1; i <= poDS->nBands; i++ )
3390 : {
3391 : HDF4ImageRasterBand *poBand =
3392 0 : (HDF4ImageRasterBand *) poDS->GetRasterBand(i);
3393 :
3394 0 : poBand->bHaveScaleAndOffset = TRUE;
3395 : poBand->dfScale =
3396 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3397 0 : "scalingSlope" ) );
3398 : poBand->dfOffset =
3399 : CPLAtof( CSLFetchNameValue( poDS->papszLocalMetadata,
3400 0 : "scalingIntercept" ) );
3401 :
3402 0 : poBand->osUnitType = osUnits;
3403 0 : }
3404 : }
3405 : }
3406 6 : break;
3407 :
3408 : /* -------------------------------------------------------------------- */
3409 : /* Hyperion Level 1. */
3410 : /* -------------------------------------------------------------------- */
3411 : case H4ST_HYPERION_L1:
3412 : {
3413 0 : CPLDebug( "HDF4Image", "Input dataset interpreted as HYPERION_L1" );
3414 : }
3415 : break;
3416 :
3417 : default:
3418 : break;
3419 : }
3420 :
3421 : /* -------------------------------------------------------------------- */
3422 : /* Setup PAM info for this subdataset */
3423 : /* -------------------------------------------------------------------- */
3424 263 : poDS->SetPhysicalFilename( poDS->pszFilename );
3425 263 : poDS->SetSubdatasetName( osSubdatasetName );
3426 :
3427 263 : poDS->TryLoadXML();
3428 :
3429 263 : poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
3430 :
3431 263 : return( poDS );
3432 : }
3433 :
3434 : /************************************************************************/
3435 : /* Create() */
3436 : /************************************************************************/
3437 :
3438 : GDALDataset *HDF4ImageDataset::Create( const char * pszFilename,
3439 : int nXSize, int nYSize, int nBands,
3440 : GDALDataType eType,
3441 145 : char **papszOptions )
3442 :
3443 : {
3444 : /* -------------------------------------------------------------------- */
3445 : /* Create the dataset. */
3446 : /* -------------------------------------------------------------------- */
3447 : HDF4ImageDataset *poDS;
3448 : const char *pszSDSName;
3449 : int iBand;
3450 145 : int32 iSDS = -1;
3451 : int32 aiDimSizes[H4_MAX_VAR_DIMS];
3452 :
3453 145 : if( nBands == 0 )
3454 : {
3455 : CPLError( CE_Failure, CPLE_NotSupported,
3456 1 : "Unable to export files with zero bands." );
3457 1 : return NULL;
3458 : }
3459 :
3460 144 : poDS = new HDF4ImageDataset();
3461 :
3462 : /* -------------------------------------------------------------------- */
3463 : /* Choose rank for the created dataset. */
3464 : /* -------------------------------------------------------------------- */
3465 144 : poDS->iRank = 3;
3466 248 : if ( CSLFetchNameValue( papszOptions, "RANK" ) != NULL &&
3467 : EQUAL( CSLFetchNameValue( papszOptions, "RANK" ), "2" ) )
3468 48 : poDS->iRank = 2;
3469 :
3470 144 : poDS->hSD = SDstart( pszFilename, DFACC_CREATE );
3471 144 : if ( poDS->hSD == -1 )
3472 : {
3473 : CPLError( CE_Failure, CPLE_OpenFailed,
3474 0 : "Can't create HDF4 file %s", pszFilename );
3475 0 : return NULL;
3476 : }
3477 144 : poDS->iXDim = 1;
3478 144 : poDS->iYDim = 0;
3479 144 : poDS->iBandDim = 2;
3480 144 : aiDimSizes[poDS->iXDim] = nXSize;
3481 144 : aiDimSizes[poDS->iYDim] = nYSize;
3482 144 : aiDimSizes[poDS->iBandDim] = nBands;
3483 :
3484 144 : if ( poDS->iRank == 2 )
3485 : {
3486 96 : for ( iBand = 0; iBand < nBands; iBand++ )
3487 : {
3488 48 : pszSDSName = CPLSPrintf( "Band%d", iBand );
3489 48 : switch ( eType )
3490 : {
3491 : case GDT_Float64:
3492 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT64,
3493 6 : poDS->iRank, aiDimSizes );
3494 6 : break;
3495 : case GDT_Float32:
3496 : iSDS = SDcreate( poDS-> hSD, pszSDSName, DFNT_FLOAT32,
3497 6 : poDS->iRank, aiDimSizes );
3498 6 : break;
3499 : case GDT_UInt32:
3500 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT32,
3501 6 : poDS->iRank, aiDimSizes );
3502 6 : break;
3503 : case GDT_UInt16:
3504 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT16,
3505 6 : poDS->iRank, aiDimSizes );
3506 6 : break;
3507 : case GDT_Int32:
3508 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT32,
3509 6 : poDS->iRank, aiDimSizes );
3510 6 : break;
3511 : case GDT_Int16:
3512 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT16,
3513 6 : poDS->iRank, aiDimSizes );
3514 6 : break;
3515 : case GDT_Byte:
3516 : default:
3517 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT8,
3518 12 : poDS->iRank, aiDimSizes );
3519 : break;
3520 : }
3521 48 : SDendaccess( iSDS );
3522 : }
3523 : }
3524 96 : else if ( poDS->iRank == 3 )
3525 : {
3526 96 : pszSDSName = "3-dimensional Scientific Dataset";
3527 96 : poDS->iDataset = 0;
3528 96 : switch ( eType )
3529 : {
3530 : case GDT_Float64:
3531 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT64,
3532 10 : poDS->iRank, aiDimSizes );
3533 10 : break;
3534 : case GDT_Float32:
3535 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_FLOAT32,
3536 10 : poDS->iRank, aiDimSizes );
3537 10 : break;
3538 : case GDT_UInt32:
3539 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT32,
3540 10 : poDS->iRank, aiDimSizes );
3541 10 : break;
3542 : case GDT_UInt16:
3543 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT16,
3544 10 : poDS->iRank, aiDimSizes );
3545 10 : break;
3546 : case GDT_Int32:
3547 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT32,
3548 10 : poDS->iRank, aiDimSizes );
3549 10 : break;
3550 : case GDT_Int16:
3551 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_INT16,
3552 10 : poDS->iRank, aiDimSizes );
3553 10 : break;
3554 : case GDT_Byte:
3555 : default:
3556 : iSDS = SDcreate( poDS->hSD, pszSDSName, DFNT_UINT8,
3557 36 : poDS->iRank, aiDimSizes );
3558 : break;
3559 : }
3560 : }
3561 : else // Should never happen
3562 0 : return NULL;
3563 :
3564 144 : if ( iSDS < 0 )
3565 : {
3566 : CPLError( CE_Failure, CPLE_AppDefined,
3567 : "Can't create SDS with rank %ld for file %s",
3568 0 : (long)poDS->iRank, pszFilename );
3569 0 : return NULL;
3570 : }
3571 :
3572 144 : poDS->nRasterXSize = nXSize;
3573 144 : poDS->nRasterYSize = nYSize;
3574 144 : poDS->eAccess = GA_Update;
3575 144 : poDS->iDatasetType = HDF4_SDS;
3576 144 : poDS->iSubdatasetType = H4ST_GDAL;
3577 144 : poDS->nBands = nBands;
3578 :
3579 : /* -------------------------------------------------------------------- */
3580 : /* Create band information objects. */
3581 : /* -------------------------------------------------------------------- */
3582 688 : for( iBand = 1; iBand <= nBands; iBand++ )
3583 200 : poDS->SetBand( iBand, new HDF4ImageRasterBand( poDS, iBand, eType ) );
3584 :
3585 : SDsetattr( poDS->hSD, "Signature", DFNT_CHAR8, strlen(pszGDALSignature) + 1,
3586 144 : pszGDALSignature );
3587 :
3588 144 : return (GDALDataset *) poDS;
3589 : }
3590 :
3591 : /************************************************************************/
3592 : /* GDALRegister_HDF4Image() */
3593 : /************************************************************************/
3594 :
3595 409 : void GDALRegister_HDF4Image()
3596 :
3597 : {
3598 : GDALDriver *poDriver;
3599 :
3600 409 : if( GDALGetDriverByName( "HDF4Image" ) == NULL )
3601 : {
3602 392 : poDriver = new GDALDriver();
3603 :
3604 392 : poDriver->SetDescription( "HDF4Image" );
3605 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
3606 392 : "HDF4 Dataset" );
3607 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
3608 392 : "frmt_hdf4.html" );
3609 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
3610 392 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
3611 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
3612 : "<CreationOptionList>"
3613 : " <Option name='RANK' type='int' description='Rank of output SDS'/>"
3614 392 : "</CreationOptionList>" );
3615 :
3616 392 : poDriver->pfnOpen = HDF4ImageDataset::Open;
3617 392 : poDriver->pfnCreate = HDF4ImageDataset::Create;
3618 :
3619 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
3620 : }
3621 409 : }
3622 :
|