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