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