mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-25 06:12:47 -06:00
992 lines
43 KiB
C++
992 lines
43 KiB
C++
/******************************************************************************
|
|
* $Id: irisdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
|
|
*
|
|
* Project: IRIS Reader
|
|
* Purpose: All code for IRIS format Reader
|
|
* Author: Roger Veciana, rveciana@gmail.com
|
|
* Portions are adapted from code copyright (C) 2005-2012
|
|
* Chris Veness under a CC-BY 3.0 licence
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2012, Roger Veciana <rveciana@gmail.com>
|
|
* Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#ifndef DEG2RAD
|
|
# define DEG2RAD (M_PI/180.0)
|
|
#endif
|
|
|
|
#ifndef RAD2DEG
|
|
# define RAD2DEG (180.0/M_PI)
|
|
#endif
|
|
|
|
#include "gdal_pam.h"
|
|
#include "ogr_spatialref.h"
|
|
#include <sstream>
|
|
|
|
|
|
CPL_CVSID("$Id: irisdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
|
|
|
|
CPL_C_START
|
|
void GDALRegister_IRIS(void);
|
|
CPL_C_END
|
|
|
|
#define ARRAY_ELEMENT_COUNT(x) ((sizeof(x))/sizeof(x[0]))
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* IRISDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class IRISRasterBand;
|
|
|
|
class IRISDataset : public GDALPamDataset
|
|
{
|
|
friend class IRISRasterBand;
|
|
|
|
VSILFILE *fp;
|
|
GByte abyHeader[640];
|
|
int bNoDataSet;
|
|
double dfNoDataValue;
|
|
static const char* const aszProductNames[];
|
|
static const char* const aszDataTypeCodes[];
|
|
static const char* const aszDataTypes[];
|
|
static const char* const aszProjections[];
|
|
unsigned short nProductCode;
|
|
unsigned short nDataTypeCode;
|
|
unsigned char nProjectionCode;
|
|
float fNyquistVelocity;
|
|
char* pszSRS_WKT;
|
|
double adfGeoTransform[6];
|
|
int bHasLoadedProjection;
|
|
void LoadProjection();
|
|
std::pair <double,double> GeodesicCalculation(float fLat, float fLon, float fAngle, float fDist, float fEquatorialRadius, float fPolarRadius, float fFlattening);
|
|
public:
|
|
IRISDataset();
|
|
~IRISDataset();
|
|
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
static int Identify( GDALOpenInfo * );
|
|
|
|
CPLErr GetGeoTransform( double * padfTransform );
|
|
const char *GetProjectionRef();
|
|
|
|
};
|
|
|
|
const char* const IRISDataset::aszProductNames[]= {
|
|
"", "PPI", "RHI", "CAPPI", "CROSS", "TOPS", "TRACK", "RAIN1", "RAINN",
|
|
"VVP", "VIL", "SHEAR", "WARN", "CATCH", "RTI", "RAW", "MAX", "USER",
|
|
"USERV", "OTHER", "STATUS", "SLINE", "WIND", "BEAM", "TEXT", "FCAST",
|
|
"NDOP", "IMAGE", "COMP", "TDWR", "GAGE", "DWELL", "SRI", "BASE", "HMAX"};
|
|
|
|
const char* const IRISDataset::aszDataTypeCodes[]={
|
|
"XHDR", "DBT" ,"dBZ", "VEL", "WIDTH", "ZDR", "ORAIN", "dBZC", "DBT2",
|
|
"dBZ2", "VEL2", "WIDTH2", "ZDR2", "RAINRATE2", "KDP", "KDP2", "PHIDP",
|
|
"VELC", "SQI", "RHOHV", "RHOHV2", "dBZC2", "VELC2", "SQI2", "PHIDP2",
|
|
"LDRH", "LDRH2", "LDRV", "LDRV2", "FLAGS", "FLAGS2", "FLOAT32", "HEIGHT",
|
|
"VIL2", "NULL", "SHEAR", "DIVERGE2", "FLIQUID2", "USER", "OTHER", "DEFORM2",
|
|
"VVEL2", "HVEL2", "HDIR2", "AXDIL2", "TIME2", "RHOH", "RHOH2", "RHOV",
|
|
"RHOV2", "PHIH", "PHIH2", "PHIV", "PHIV2", "USER2", "HCLASS", "HCLASS2",
|
|
"ZDRC", "ZDRC2", "TEMPERATURE16", "VIR16", "DBTV8", "DBTV16", "DBZV8",
|
|
"DBZV16", "SNR8", "SNR16", "ALBEDO8", "ALBEDO16", "VILD16", "TURB16"};
|
|
const char* const IRISDataset::aszDataTypes[]={
|
|
"Extended Headers","Total H power (1 byte)","Clutter Corrected H reflectivity (1 byte)",
|
|
"Velocity (1 byte)","Width (1 byte)","Differential reflectivity (1 byte)",
|
|
"Old Rainfall rate (stored as dBZ)","Fully corrected reflectivity (1 byte)",
|
|
"Uncorrected reflectivity (2 byte)","Corrected reflectivity (2 byte)",
|
|
"Velocity (2 byte)","Width (2 byte)","Differential reflectivity (2 byte)",
|
|
"Rainfall rate (2 byte)","Kdp (specific differential phase)(1 byte)",
|
|
"Kdp (specific differential phase)(2 byte)","PHIdp (differential phase)(1 byte)",
|
|
"Corrected Velocity (1 byte)","SQI (1 byte)","RhoHV(0) (1 byte)","RhoHV(0) (2 byte)",
|
|
"Fully corrected reflectivity (2 byte)","Corrected Velocity (2 byte)","SQI (2 byte)",
|
|
"PHIdp (differential phase)(2 byte)","LDR H to V (1 byte)","LDR H to V (2 byte)",
|
|
"LDR V to H (1 byte)","LDR V to H (2 byte)","Individual flag bits for each bin","",
|
|
"Test of floating format", "Height (1/10 km) (1 byte)", "Linear liquid (.001mm) (2 byte)",
|
|
"Data type is not applicable", "Wind Shear (1 byte)", "Divergence (.001 10**-4) (2-byte)",
|
|
"Floated liquid (2 byte)", "User type, unspecified data (1 byte)",
|
|
"Unspecified data, no color legend", "Deformation (.001 10**-4) (2-byte)",
|
|
"Vertical velocity (.01 m/s) (2-byte)", "Horizontal velocity (.01 m/s) (2-byte)",
|
|
"Horizontal wind direction (.1 degree) (2-byte)", "Axis of Dillitation (.1 degree) (2-byte)",
|
|
"Time of data (seconds) (2-byte)", "Rho H to V (1 byte)", "Rho H to V (2 byte)",
|
|
"Rho V to H (1 byte)", "Rho V to H (2 byte)", "Phi H to V (1 byte)", "Phi H to V (2 byte)",
|
|
"Phi V to H (1 byte)", "Phi V to H (2 byte)", "User type, unspecified data (2 byte)",
|
|
"Hydrometeor class (1 byte)", "Hydrometeor class (2 byte)", "Corrected Differential reflectivity (1 byte)",
|
|
"Corrected Differential reflectivity (2 byte)", "Temperature (2 byte)",
|
|
"Vertically Integrated Reflectivity (2 byte)", "Total V Power (1 byte)", "Total V Power (2 byte)",
|
|
"Clutter Corrected V Reflectivity (1 byte)", "Clutter Corrected V Reflectivity (2 byte)",
|
|
"Signal to Noise ratio (1 byte)", "Signal to Noise ratio (2 byte)", "Albedo (1 byte)",
|
|
"Albedo (2 byte)", "VIL Density (2 byte)", "Turbulence (2 byte)"};
|
|
const char* const IRISDataset::aszProjections[]={
|
|
"Azimutal equidistant","Mercator","Polar Stereographic","UTM",
|
|
"Prespective from geosync","Equidistant cylindrical","Gnomonic",
|
|
"Gauss conformal","Lambert conformal conic"};
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* IRISRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class IRISRasterBand : public GDALPamRasterBand
|
|
{
|
|
friend class IRISDataset;
|
|
|
|
|
|
unsigned char* pszRecord;
|
|
int bBufferAllocFailed;
|
|
|
|
public:
|
|
IRISRasterBand( IRISDataset *, int );
|
|
~IRISRasterBand();
|
|
|
|
virtual CPLErr IReadBlock( int, int, void * );
|
|
|
|
virtual double GetNoDataValue( int * );
|
|
virtual CPLErr SetNoDataValue( double );
|
|
};
|
|
|
|
|
|
/************************************************************************/
|
|
/* IRISRasterBand() */
|
|
/************************************************************************/
|
|
|
|
IRISRasterBand::IRISRasterBand( IRISDataset *poDS, int nBand )
|
|
{
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
eDataType = GDT_Float32;
|
|
nBlockXSize = poDS->GetRasterXSize();
|
|
nBlockYSize = 1;
|
|
pszRecord = NULL;
|
|
bBufferAllocFailed = FALSE;
|
|
}
|
|
|
|
IRISRasterBand::~IRISRasterBand()
|
|
{
|
|
VSIFree(pszRecord);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr IRISRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
|
|
int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
IRISDataset *poGDS = (IRISDataset *) poDS;
|
|
|
|
//Every product type has it's own size. TODO: Move it like dataType
|
|
int nDataLength = 1;
|
|
if(poGDS->nDataTypeCode == 2){nDataLength=1;}
|
|
else if(poGDS->nDataTypeCode == 37){nDataLength=2;}
|
|
else if(poGDS->nDataTypeCode == 33){nDataLength=2;}
|
|
else if(poGDS->nDataTypeCode == 32){nDataLength=1;}
|
|
|
|
int i;
|
|
//We allocate space for storing a record:
|
|
if (pszRecord == NULL)
|
|
{
|
|
if (bBufferAllocFailed)
|
|
return CE_Failure;
|
|
|
|
pszRecord = (unsigned char *) VSIMalloc(nBlockXSize*nDataLength);
|
|
|
|
if (pszRecord == NULL)
|
|
{
|
|
CPLError(CE_Failure, CPLE_OutOfMemory,
|
|
"Cannot allocate scanline buffer");
|
|
bBufferAllocFailed = TRUE;
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
//Prepare to read (640 is the header size in bytes) and read (the y axis in the IRIS files in the inverse direction)
|
|
//The previous bands are also added as an offset
|
|
|
|
VSIFSeekL( poGDS->fp, 640 + (vsi_l_offset)nDataLength*poGDS->GetRasterXSize()*poGDS->GetRasterYSize()*(this->nBand-1) +
|
|
(vsi_l_offset)nBlockXSize*nDataLength*(poGDS->GetRasterYSize()-1-nBlockYOff), SEEK_SET );
|
|
|
|
if( (int)VSIFReadL( pszRecord, nBlockXSize*nDataLength, 1, poGDS->fp ) != 1 )
|
|
return CE_Failure;
|
|
|
|
//If datatype is dbZ or dBT:
|
|
//See point 3.3.3 at page 3.33 of the manual
|
|
if(poGDS->nDataTypeCode == 2 || poGDS->nDataTypeCode == 1){
|
|
float fVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
fVal = (((float) *(pszRecord+i*nDataLength)) -64)/2.0;
|
|
if (fVal == 95.5)
|
|
fVal = -9999;
|
|
((float *) pImage)[i] = fVal;
|
|
}
|
|
//If datatype is dbZ2 or dBT2:
|
|
//See point 3.3.4 at page 3.33 of the manual
|
|
} else if(poGDS->nDataTypeCode == 8 || poGDS->nDataTypeCode == 9){
|
|
float fVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
fVal = (((float) CPL_LSBUINT16PTR(pszRecord+i*nDataLength)) - 32768)/100.0;
|
|
if (fVal == 327.67)
|
|
fVal = -9999;
|
|
((float *) pImage)[i] = fVal;
|
|
}
|
|
//Fliquid2 (Rain1 & Rainn products)
|
|
//See point 3.3.11 at page 3.43 of the manual
|
|
} else if(poGDS->nDataTypeCode == 37){
|
|
unsigned short nVal, nExp, nMantissa;
|
|
float fVal2=0;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
nVal = CPL_LSBUINT16PTR(pszRecord+i*nDataLength);
|
|
nExp = nVal>>12;
|
|
nMantissa = nVal - (nExp<<12);
|
|
if (nVal == 65535)
|
|
fVal2 = -9999;
|
|
else if (nExp == 0)
|
|
fVal2 = (float) nMantissa / 1000.0;
|
|
else
|
|
fVal2 = (float)((nMantissa+4096)<<(nExp-1))/1000.0;
|
|
((float *) pImage)[i] = fVal2;
|
|
}
|
|
//VIL2 (VIL products)
|
|
//See point 3.3.41 at page 3.54 of the manual
|
|
} else if(poGDS->nDataTypeCode == 33){
|
|
float fVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
fVal = (float) CPL_LSBUINT16PTR(pszRecord+i*nDataLength);
|
|
if (fVal == 65535)
|
|
((float *) pImage)[i] = -9999;
|
|
else if (fVal == 0)
|
|
((float *) pImage)[i] = -1;
|
|
else
|
|
((float *) pImage)[i] = (fVal-1)/1000;
|
|
}
|
|
//HEIGTH (TOPS products)
|
|
//See point 3.3.14 at page 3.46 of the manual
|
|
} else if(poGDS->nDataTypeCode == 32){
|
|
unsigned char nVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
nVal = *(pszRecord+i*nDataLength) ;
|
|
if (nVal == 255)
|
|
((float *) pImage)[i] = -9999;
|
|
else if (nVal == 0)
|
|
((float *) pImage)[i] = -1;
|
|
else
|
|
((float *) pImage)[i] = ((float) nVal - 1) / 10;
|
|
}
|
|
//VEL (Velocity 1-Byte in PPI & others)
|
|
//See point 3.3.37 at page 3.53 of the manual
|
|
} else if(poGDS->nDataTypeCode == 3){
|
|
float fVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
fVal = (float) *(pszRecord+i*nDataLength);
|
|
if (fVal == 0)
|
|
fVal = -9997;
|
|
else if(fVal == 1)
|
|
fVal = -9998;
|
|
else if(fVal == 255)
|
|
fVal = -9999;
|
|
else
|
|
fVal = poGDS->fNyquistVelocity * (fVal - 128)/127;
|
|
((float *) pImage)[i] = fVal;
|
|
}
|
|
//SHEAR (1-Byte Shear)
|
|
//See point 3.3.23 at page 3.39 of the manual
|
|
} else if(poGDS->nDataTypeCode == 35){
|
|
float fVal;
|
|
for (i=0;i<nBlockXSize;i++){
|
|
fVal = (float) *(pszRecord+i*nDataLength);
|
|
if (fVal == 0.0)
|
|
fVal = -9998;
|
|
else if (fVal == 255.0)
|
|
fVal = -9999;
|
|
else
|
|
fVal = (fVal - 128) * 0.2;
|
|
((float *) pImage)[i] = fVal;
|
|
}
|
|
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetNoDataValue() */
|
|
/************************************************************************/
|
|
|
|
CPLErr IRISRasterBand::SetNoDataValue( double dfNoData )
|
|
|
|
{
|
|
IRISDataset *poGDS = (IRISDataset *) poDS;
|
|
// if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
|
|
// return CE_None;
|
|
|
|
|
|
poGDS->bNoDataSet = TRUE;
|
|
poGDS->dfNoDataValue = dfNoData;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetNoDataValue() */
|
|
/************************************************************************/
|
|
|
|
double IRISRasterBand::GetNoDataValue( int * pbSuccess )
|
|
|
|
{
|
|
IRISDataset *poGDS = (IRISDataset *) poDS;
|
|
|
|
|
|
if( poGDS->bNoDataSet )
|
|
{
|
|
if( pbSuccess )
|
|
*pbSuccess = TRUE;
|
|
|
|
return poGDS->dfNoDataValue;
|
|
}
|
|
|
|
return GDALPamRasterBand::GetNoDataValue( pbSuccess );
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* IRISDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* IRISDataset() */
|
|
/************************************************************************/
|
|
|
|
IRISDataset::IRISDataset()
|
|
|
|
{
|
|
bHasLoadedProjection = FALSE;
|
|
fp = NULL;
|
|
pszSRS_WKT = NULL;
|
|
adfGeoTransform[0] = 0.0;
|
|
adfGeoTransform[1] = 1.0;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = 0.0;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = 1.0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~IRISDataset() */
|
|
/************************************************************************/
|
|
|
|
IRISDataset::~IRISDataset()
|
|
|
|
{
|
|
FlushCache();
|
|
if( fp != NULL )
|
|
VSIFCloseL( fp );
|
|
CPLFree( pszSRS_WKT );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Calculates the projection and Geotransform */
|
|
/************************************************************************/
|
|
void IRISDataset::LoadProjection()
|
|
{
|
|
bHasLoadedProjection = TRUE;
|
|
float fEquatorialRadius = float( (CPL_LSBUINT32PTR (abyHeader+220+320+12)))/100; //They give it in cm
|
|
float fInvFlattening = float( (CPL_LSBUINT32PTR (abyHeader+224+320+12)))/1000000; //Point 3.2.27 pag 3-15
|
|
float fFlattening;
|
|
float fPolarRadius;
|
|
|
|
if(fEquatorialRadius == 0){ // if Radius is 0, change to 6371000 Point 3.2.27 pag 3-15 (old IRIS verions)
|
|
fEquatorialRadius = 6371000;
|
|
fPolarRadius = fEquatorialRadius;
|
|
fInvFlattening = 0;
|
|
fFlattening = 0;
|
|
} else {
|
|
if (fInvFlattening == 0){ //When inverse flattening is infinite, they use 0
|
|
fFlattening = 0;
|
|
fPolarRadius = fEquatorialRadius;
|
|
} else {
|
|
fFlattening = 1/fInvFlattening;
|
|
fPolarRadius = fEquatorialRadius * (1-fFlattening);
|
|
}
|
|
}
|
|
|
|
float fCenterLon = 360 * float((CPL_LSBUINT32PTR (abyHeader+112+320+12))) / 4294967295LL;
|
|
float fCenterLat = 360 * float((CPL_LSBUINT32PTR (abyHeader+108+320+12))) / 4294967295LL;
|
|
|
|
float fProjRefLon = 360 * float((CPL_LSBUINT32PTR (abyHeader+244+320+12))) / 4294967295LL;
|
|
float fProjRefLat = 360 * float((CPL_LSBUINT32PTR (abyHeader+240+320+12))) / 4294967295LL;
|
|
|
|
float fRadarLocX, fRadarLocY, fScaleX, fScaleY;
|
|
|
|
fRadarLocX = float (CPL_LSBSINT32PTR (abyHeader + 112 + 12 )) / 1000;
|
|
fRadarLocY = float (CPL_LSBSINT32PTR (abyHeader + 116 + 12 )) / 1000;
|
|
|
|
fScaleX = float (CPL_LSBSINT32PTR (abyHeader + 88 + 12 )) / 100;
|
|
fScaleY = float (CPL_LSBSINT32PTR (abyHeader + 92 + 12 )) / 100;
|
|
|
|
OGRSpatialReference oSRSOut;
|
|
|
|
////MERCATOR PROJECTION
|
|
if(EQUAL(aszProjections[nProjectionCode],"Mercator")){
|
|
OGRCoordinateTransformation *poTransform = NULL;
|
|
OGRSpatialReference oSRSLatLon;
|
|
|
|
oSRSOut.SetGeogCS("unnamed ellipse",
|
|
"unknown",
|
|
"unnamed",
|
|
fEquatorialRadius, fInvFlattening,
|
|
"Greenwich", 0.0,
|
|
"degree", 0.0174532925199433);
|
|
|
|
oSRSOut.SetMercator(fProjRefLat,fProjRefLon,1,0,0);
|
|
oSRSOut.exportToWkt(&pszSRS_WKT);
|
|
|
|
//The center coordinates are given in LatLon on the defined ellipsoid. Necessary to calculate geotransform.
|
|
|
|
oSRSLatLon.SetGeogCS("unnamed ellipse",
|
|
"unknown",
|
|
"unnamed",
|
|
fEquatorialRadius, fInvFlattening,
|
|
"Greenwich", 0.0,
|
|
"degree", 0.0174532925199433);
|
|
|
|
poTransform = OGRCreateCoordinateTransformation( &oSRSLatLon,
|
|
&oSRSOut );
|
|
std::pair <double,double> oPositionX2 = GeodesicCalculation(fCenterLat, fCenterLon, 90, fScaleX, fEquatorialRadius, fPolarRadius, fFlattening);
|
|
std::pair <double,double> oPositionY2 = GeodesicCalculation(fCenterLat, fCenterLon, 0, fScaleY, fEquatorialRadius, fPolarRadius, fFlattening);
|
|
|
|
double dfLon2, dfLat2;
|
|
dfLon2 = oPositionX2.first;
|
|
dfLat2 = oPositionY2.second;
|
|
double dfX, dfY, dfX2, dfY2;
|
|
dfX = fCenterLon ;
|
|
dfY = fCenterLat ;
|
|
dfX2 = dfLon2;
|
|
dfY2 = dfLat2;
|
|
|
|
if( poTransform == NULL || !poTransform->Transform( 1, &dfX, &dfY ) )
|
|
CPLError( CE_Failure, CPLE_None, "Transformation Failed\n" );
|
|
|
|
if( poTransform == NULL || !poTransform->Transform( 1, &dfX2, &dfY2 ) )
|
|
CPLError( CE_Failure, CPLE_None, "Transformation Failed\n" );
|
|
|
|
adfGeoTransform[0] = dfX - (fRadarLocX * (dfX2 - dfX));
|
|
adfGeoTransform[1] = dfX2 - dfX;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = dfY + (fRadarLocY * (dfY2 - dfY));
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = -1*(dfY2 - dfY);
|
|
|
|
delete poTransform;
|
|
|
|
}else if(EQUAL(aszProjections[nProjectionCode],"Azimutal equidistant")){
|
|
|
|
oSRSOut.SetGeogCS("unnamed ellipse",
|
|
"unknown",
|
|
"unnamed",
|
|
fEquatorialRadius, fInvFlattening,
|
|
"Greenwich", 0.0,
|
|
"degree", 0.0174532925199433);
|
|
oSRSOut.SetAE(fProjRefLat,fProjRefLon,0,0);
|
|
oSRSOut.exportToWkt(&pszSRS_WKT) ;
|
|
adfGeoTransform[0] = -1*(fRadarLocX*fScaleX);
|
|
adfGeoTransform[1] = fScaleX;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = fRadarLocY*fScaleY;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = -1*fScaleY;
|
|
//When the projection is different from Mercator or Azimutal equidistant, we set a standard geotransform
|
|
} else {
|
|
adfGeoTransform[0] = -1*(fRadarLocX*fScaleX);
|
|
adfGeoTransform[1] = fScaleX;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = fRadarLocY*fScaleY;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = -1*fScaleY;
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/* The geotransform in Mercator projection must be calculated transforming */
|
|
/* distance to degrees over the ellipsoid, using Vincenty's formula. */
|
|
/* The following method is ported from a version for Javascript by Chris */
|
|
/* Veness distributed under a CC-BY 3.0 licence, whose conditions is that the */
|
|
/* following copyright notice is retained as well as the link to : */
|
|
/* http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html */
|
|
/******************************************************************************/
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
/* Vincenty Direct Solution of Geodesics on the Ellipsoid (c) Chris Veness 2005-2012 */
|
|
/* */
|
|
/* from: Vincenty direct formula - T Vincenty, "Direct and Inverse Solutions of Geodesics on the */
|
|
/* Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 */
|
|
/* http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf */
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
std::pair <double,double> IRISDataset::GeodesicCalculation(float fLat, float fLon, float fAngle, float fDist, float fEquatorialRadius, float fPolarRadius, float fFlattening)
|
|
{
|
|
std::pair <double,double> oOutput;
|
|
double dfAlpha1 = DEG2RAD * fAngle;
|
|
double dfSinAlpha1 = sin(dfAlpha1);
|
|
double dfCosAlpha1 = cos(dfAlpha1);
|
|
|
|
double dfTanU1 = (1-fFlattening) * tan(fLat*DEG2RAD);
|
|
double dfCosU1 = 1 / sqrt((1 + dfTanU1*dfTanU1));
|
|
double dfSinU1 = dfTanU1*dfCosU1;
|
|
|
|
double dfSigma1 = atan2(dfTanU1, dfCosAlpha1);
|
|
double dfSinAlpha = dfCosU1 * dfSinAlpha1;
|
|
double dfCosSqAlpha = 1 - dfSinAlpha*dfSinAlpha;
|
|
double dfUSq = dfCosSqAlpha * (fEquatorialRadius*fEquatorialRadius - fPolarRadius*fPolarRadius) / (fPolarRadius*fPolarRadius);
|
|
double dfA = 1 + dfUSq/16384*(4096+dfUSq*(-768+dfUSq*(320-175*dfUSq)));
|
|
double dfB = dfUSq/1024 * (256+dfUSq*(-128+dfUSq*(74-47*dfUSq)));
|
|
|
|
double dfSigma = fDist / (fPolarRadius*dfA);
|
|
double dfSigmaP = 2*M_PI;
|
|
|
|
double dfSinSigma = 0.0;
|
|
double dfCosSigma = 0.0;
|
|
double dfCos2SigmaM = 0.0;
|
|
double dfDeltaSigma;
|
|
|
|
while (fabs(dfSigma-dfSigmaP) > 1e-12) {
|
|
dfCos2SigmaM = cos(2*dfSigma1 + dfSigma);
|
|
dfSinSigma = sin(dfSigma);
|
|
dfCosSigma = cos(dfSigma);
|
|
dfDeltaSigma = dfB*dfSinSigma*(dfCos2SigmaM+dfB/4*(dfCosSigma*(-1+2*dfCos2SigmaM*dfCos2SigmaM)-
|
|
dfB/6*dfCos2SigmaM*(-3+4*dfSinSigma*dfSinSigma)*(-3+4*dfCos2SigmaM*dfCos2SigmaM)));
|
|
dfSigmaP = dfSigma;
|
|
dfSigma = fDist / (fPolarRadius*dfA) + dfDeltaSigma;
|
|
}
|
|
|
|
double dfTmp = dfSinU1*dfSinSigma - dfCosU1*dfCosSigma*dfCosAlpha1;
|
|
double dfLat2 = atan2(dfSinU1*dfCosSigma + dfCosU1*dfSinSigma*dfCosAlpha1,
|
|
(1-fFlattening)*sqrt(dfSinAlpha*dfSinAlpha + dfTmp*dfTmp));
|
|
double dfLambda = atan2(dfSinSigma*dfSinAlpha1, dfCosU1*dfCosSigma - dfSinU1*dfSinSigma*dfCosAlpha1);
|
|
double dfC = fFlattening/16*dfCosSqAlpha*(4+fFlattening*(4-3*dfCosSqAlpha));
|
|
double dfL = dfLambda - (1-dfC) * fFlattening * dfSinAlpha *
|
|
(dfSigma + dfC*dfSinSigma*(dfCos2SigmaM+dfC*dfCosSigma*(-1+2*dfCos2SigmaM*dfCos2SigmaM)));
|
|
double dfLon2 = fLon*DEG2RAD+dfL;
|
|
if (dfLon2 > M_PI)
|
|
dfLon2 = dfLon2 - 2*M_PI;
|
|
if (dfLon2 < -1*M_PI)
|
|
dfLon2 = dfLon2 + 2*M_PI;
|
|
oOutput.first = dfLon2*RAD2DEG;
|
|
oOutput.second = dfLat2*RAD2DEG;
|
|
|
|
return oOutput;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr IRISDataset::GetGeoTransform( double * padfTransform )
|
|
|
|
{
|
|
if (!bHasLoadedProjection)
|
|
LoadProjection();
|
|
memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/************************************************************************/
|
|
|
|
const char *IRISDataset::GetProjectionRef(){
|
|
if (!bHasLoadedProjection)
|
|
LoadProjection();
|
|
return pszSRS_WKT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Identify() */
|
|
/************************************************************************/
|
|
|
|
int IRISDataset::Identify( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Confirm that the file is an IRIS file */
|
|
/* -------------------------------------------------------------------- */
|
|
//Si no el posem, peta al fer el translate, quan s'obre Identify des de GDALIdentifyDriver
|
|
if( poOpenInfo->nHeaderBytes < 640 )
|
|
return FALSE;
|
|
|
|
|
|
short nId1 = CPL_LSBSINT16PTR(poOpenInfo->pabyHeader);
|
|
short nId2 = CPL_LSBSINT16PTR(poOpenInfo->pabyHeader+12);
|
|
unsigned short nType = CPL_LSBUINT16PTR (poOpenInfo->pabyHeader+24);
|
|
|
|
/*Check if the two headers are 27 (product hdr) & 26 (product configuration), and the product type is in the range 1 -> 34*/
|
|
if( !(nId1 == 27 && nId2 == 26 && nType > 0 && nType < 35) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* FillString() */
|
|
/************************************************************************/
|
|
|
|
static void FillString(char* szBuffer, size_t nBufferSize, void* pSrcBuffer)
|
|
{
|
|
for(size_t i = 0; i < nBufferSize - 1; i++)
|
|
szBuffer[i] = ((char*)pSrcBuffer)[i];
|
|
szBuffer[nBufferSize-1] = '\0';
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *IRISDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
if (!Identify(poOpenInfo))
|
|
return NULL;
|
|
/* -------------------------------------------------------------------- */
|
|
/* Confirm the requested access is supported. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poOpenInfo->eAccess == GA_Update )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"The IRIS driver does not support update access to existing"
|
|
" datasets.\n" );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
IRISDataset *poDS;
|
|
|
|
poDS = new IRISDataset();
|
|
|
|
poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
|
|
if (poDS->fp == NULL)
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the header. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIFReadL( poDS->abyHeader, 1, 640, poDS->fp );
|
|
int nXSize = CPL_LSBSINT32PTR(poDS->abyHeader+100+12);
|
|
int nYSize = CPL_LSBSINT32PTR(poDS->abyHeader+104+12);
|
|
int nNumBands = CPL_LSBSINT32PTR(poDS->abyHeader+108+12);
|
|
|
|
poDS->nRasterXSize = nXSize;
|
|
|
|
poDS->nRasterYSize = nYSize;
|
|
if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Invalid dimensions : %d x %d",
|
|
poDS->nRasterXSize, poDS->nRasterYSize);
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
if( !GDALCheckBandCount(nNumBands, TRUE) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Setting the Metadata */
|
|
/* -------------------------------------------------------------------- */
|
|
//See point 3.2.26 at page 3.12 of the manual
|
|
poDS->nProductCode = CPL_LSBUINT16PTR (poDS->abyHeader+12+12);
|
|
poDS->SetMetadataItem( "PRODUCT_ID", CPLString().Printf("%d", poDS->nProductCode ));
|
|
if( poDS->nProductCode >= ARRAY_ELEMENT_COUNT(poDS->aszProductNames) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
poDS->SetMetadataItem( "PRODUCT",poDS->aszProductNames[poDS->nProductCode]);
|
|
|
|
poDS->nDataTypeCode = CPL_LSBUINT16PTR (poDS->abyHeader+130+12);
|
|
if( poDS->nDataTypeCode >= ARRAY_ELEMENT_COUNT(poDS->aszDataTypeCodes) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
poDS->SetMetadataItem( "DATA_TYPE_CODE",poDS->aszDataTypeCodes[poDS->nDataTypeCode]);
|
|
|
|
if( poDS->nDataTypeCode >= ARRAY_ELEMENT_COUNT(poDS->aszDataTypes) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
poDS->SetMetadataItem( "DATA_TYPE",poDS->aszDataTypes[poDS->nDataTypeCode]);
|
|
|
|
unsigned short nDataTypeInputCode = CPL_LSBUINT16PTR (poDS->abyHeader+144+12);
|
|
if( nDataTypeInputCode >= ARRAY_ELEMENT_COUNT(poDS->aszDataTypeCodes) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
poDS->SetMetadataItem( "DATA_TYPE_INPUT_CODE",poDS->aszDataTypeCodes[nDataTypeInputCode]);
|
|
|
|
unsigned short nDataTypeInput = CPL_LSBUINT16PTR (poDS->abyHeader+144+12);
|
|
if( nDataTypeInput >= ARRAY_ELEMENT_COUNT(poDS->aszDataTypes) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
poDS->SetMetadataItem( "DATA_TYPE_INPUT",poDS->aszDataTypes[nDataTypeInput]);
|
|
|
|
poDS->nProjectionCode = * (unsigned char *) (poDS->abyHeader+146+12);
|
|
if( poDS->nProjectionCode >= ARRAY_ELEMENT_COUNT(poDS->aszProjections) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
////TIMES
|
|
int nSeconds = CPL_LSBSINT32PTR(poDS->abyHeader+20+12);
|
|
|
|
int nHour = (nSeconds - (nSeconds%3600)) /3600;
|
|
int nMinute = ((nSeconds - nHour * 3600) - (nSeconds - nHour * 3600)%60)/ 60;
|
|
int nSecond = nSeconds - nHour * 3600 - nMinute * 60;
|
|
|
|
short nYear = CPL_LSBSINT16PTR(poDS->abyHeader+26+12);
|
|
short nMonth = CPL_LSBSINT16PTR(poDS->abyHeader+28+12);
|
|
short nDay = CPL_LSBSINT16PTR(poDS->abyHeader+30+12);
|
|
|
|
poDS->SetMetadataItem( "TIME_PRODUCT_GENERATED", CPLString().Printf("%d-%02d-%02d %02d:%02d:%02d", nYear, nMonth, nDay, nHour, nMinute, nSecond ) );
|
|
|
|
|
|
nSeconds = CPL_LSBSINT32PTR(poDS->abyHeader+32+12);
|
|
|
|
nHour = (nSeconds - (nSeconds%3600)) /3600;
|
|
nMinute = ((nSeconds - nHour * 3600) - (nSeconds - nHour * 3600)%60)/ 60;
|
|
nSecond = nSeconds - nHour * 3600 - nMinute * 60;
|
|
|
|
nYear = CPL_LSBSINT16PTR(poDS->abyHeader+26+12);
|
|
nMonth = CPL_LSBSINT16PTR(poDS->abyHeader+28+12);
|
|
nDay = CPL_LSBSINT16PTR(poDS->abyHeader+30+12);
|
|
|
|
poDS->SetMetadataItem( "TIME_INPUT_INGEST_SWEEP", CPLString().Printf("%d-%02d-%02d %02d:%02d:%02d", nYear, nMonth, nDay, nHour, nMinute, nSecond ) );
|
|
|
|
///Site and task information
|
|
|
|
char szSiteName[17] = ""; //Must have one extra char for string end!
|
|
char szVersionName[9] = "";
|
|
|
|
FillString(szSiteName, sizeof(szSiteName), poDS->abyHeader+320+12);
|
|
FillString(szVersionName, sizeof(szVersionName), poDS->abyHeader+16+320+12);
|
|
poDS->SetMetadataItem( "PRODUCT_SITE_NAME",szSiteName);
|
|
poDS->SetMetadataItem( "PRODUCT_SITE_IRIS_VERSION",szVersionName);
|
|
|
|
FillString(szSiteName, sizeof(szSiteName), poDS->abyHeader+90+320+12);
|
|
FillString(szVersionName, sizeof(szVersionName), poDS->abyHeader+24+320+12);
|
|
poDS->SetMetadataItem( "INGEST_SITE_NAME",szSiteName);
|
|
poDS->SetMetadataItem( "INGEST_SITE_IRIS_VERSION",szVersionName);
|
|
|
|
FillString(szSiteName, sizeof(szSiteName), poDS->abyHeader+74+320+12);
|
|
poDS->SetMetadataItem( "INGEST_HARDWARE_NAME",szSiteName);
|
|
|
|
char szConfigFile[13] = "";
|
|
FillString(szConfigFile, sizeof(szConfigFile), poDS->abyHeader+62+12);
|
|
poDS->SetMetadataItem( "PRODUCT_CONFIGURATION_NAME",szConfigFile);
|
|
|
|
char szTaskName[13] = "";
|
|
FillString(szTaskName, sizeof(szTaskName), poDS->abyHeader+74+12);
|
|
poDS->SetMetadataItem( "TASK_NAME",szTaskName);
|
|
|
|
short nRadarHeight = CPL_LSBSINT16PTR(poDS->abyHeader+284+320+12);
|
|
poDS->SetMetadataItem( "RADAR_HEIGHT",CPLString().Printf("%d m",nRadarHeight));
|
|
short nGroundHeight = CPL_LSBSINT16PTR(poDS->abyHeader+118+320+12);
|
|
poDS->SetMetadataItem( "GROUND_HEIGHT",CPLString().Printf("%d m",nRadarHeight-nGroundHeight)); //Ground height over the sea level
|
|
|
|
unsigned short nFlags = CPL_LSBUINT16PTR (poDS->abyHeader+86+12);
|
|
//Get eleventh bit
|
|
nFlags=nFlags<<4;
|
|
nFlags=nFlags>>15;
|
|
if (nFlags == 1){
|
|
poDS->SetMetadataItem( "COMPOSITED_PRODUCT","YES");
|
|
unsigned int compositedMask = CPL_LSBUINT32PTR (poDS->abyHeader+232+320+12);
|
|
poDS->SetMetadataItem( "COMPOSITED_PRODUCT_MASK",CPLString().Printf("0x%08x",compositedMask));
|
|
} else{
|
|
poDS->SetMetadataItem( "COMPOSITED_PRODUCT","NO");
|
|
}
|
|
|
|
//Wave values
|
|
poDS->SetMetadataItem( "PRF",CPLString().Printf("%d Hz",CPL_LSBSINT32PTR(poDS->abyHeader+120+320+12)));
|
|
poDS->SetMetadataItem( "WAVELENGTH",CPLString().Printf("%4.2f cm",(float) CPL_LSBSINT32PTR(poDS->abyHeader+148+320+12)/100));
|
|
unsigned short nPolarizationType = CPL_LSBUINT16PTR (poDS->abyHeader+172+320+12);
|
|
float fNyquist = (CPL_LSBSINT32PTR(poDS->abyHeader+120+320+12))*((float) CPL_LSBSINT32PTR(poDS->abyHeader+148+320+12)/10000)/4; //See section 3.3.37 & 3.2.54
|
|
if (nPolarizationType == 1)
|
|
fNyquist = fNyquist * 2;
|
|
else if(nPolarizationType == 2)
|
|
fNyquist = fNyquist * 3;
|
|
else if(nPolarizationType == 3)
|
|
fNyquist = fNyquist * 4;
|
|
poDS->fNyquistVelocity = fNyquist;
|
|
poDS->SetMetadataItem( "NYQUIST_VELOCITY",CPLString().Printf("%.2f m/s",fNyquist));
|
|
|
|
///Product dependent metadata (stored in 80 bytes fromm 162 bytes at the product header) See point 3.2.30 at page 3.19 of the manual
|
|
//See point 3.2.25 at page 3.12 of the manual
|
|
if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"PPI")){
|
|
//Degrees = 360 * (Binary Angle)*2^N
|
|
//float fElevation = 360 * float((CPL_LSBUINT16PTR (poDS->abyHeader+164+12))) / 65536;
|
|
float fElevation = 360 * float((CPL_LSBSINT16PTR (poDS->abyHeader+164+12))) / 65536;
|
|
|
|
poDS->SetMetadataItem( "PPI_ELEVATION_ANGLE",CPLString().Printf("%f",fElevation));
|
|
if (EQUAL(poDS->aszDataTypeCodes[poDS->nDataTypeCode],"dBZ"))
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","dBZ");
|
|
else
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","m/s");
|
|
//See point 3.2.2 at page 3.2 of the manual
|
|
} else if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"CAPPI")){
|
|
float fElevation = ((float) CPL_LSBSINT32PTR(poDS->abyHeader+4+164+12))/100;
|
|
poDS->SetMetadataItem( "CAPPI_BOTTOM_HEIGHT",CPLString().Printf("%.1f m",fElevation));
|
|
float fAzimuthSmoothingForShear = 360 * float((CPL_LSBUINT16PTR (poDS->abyHeader+10+164+12))) / 65536;
|
|
poDS->SetMetadataItem( "AZIMUTH_SMOOTHING_FOR_SHEAR" ,CPLString().Printf("%.1f", fAzimuthSmoothingForShear));
|
|
unsigned int nMaxAgeVVPCorrection = CPL_LSBUINT32PTR (poDS->abyHeader+24+164+12);
|
|
poDS->SetMetadataItem( "MAX_AGE_FOR_SHEAR_VVP_CORRECTION" ,CPLString().Printf("%d s", nMaxAgeVVPCorrection));
|
|
if (EQUAL(poDS->aszDataTypeCodes[poDS->nDataTypeCode],"dBZ"))
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","dBZ");
|
|
else
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","m/s");
|
|
//See point 3.2.32 at page 3.19 of the manual
|
|
} else if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"RAIN1") || EQUAL(poDS->aszProductNames[poDS->nProductCode],"RAINN")){
|
|
short nNumProducts = CPL_LSBSINT16PTR(poDS->abyHeader+170+320+12);
|
|
poDS->SetMetadataItem( "NUM_FILES_USED",CPLString().Printf("%d",nNumProducts));
|
|
|
|
float fMinZAcum= (float)((CPL_LSBUINT32PTR (poDS->abyHeader+164+12))-32768)/1000;
|
|
poDS->SetMetadataItem( "MINIMUM_Z_TO_ACUMULATE",CPLString().Printf("%f",fMinZAcum));
|
|
|
|
unsigned short nSecondsOfAccumulation = CPL_LSBUINT16PTR (poDS->abyHeader+6+164+12);
|
|
poDS->SetMetadataItem( "SECONDS_OF_ACCUMULATION",CPLString().Printf("%d s",nSecondsOfAccumulation));
|
|
|
|
unsigned int nSpanInputFiles = CPL_LSBUINT32PTR (poDS->abyHeader+24+164+12);
|
|
poDS->SetMetadataItem( "SPAN_OF_INPUT_FILES",CPLString().Printf("%d s",nSpanInputFiles));
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","mm");
|
|
|
|
char szInputProductName[13] = "";
|
|
for(int k=0; k<12;k++)
|
|
szInputProductName[k] = * (char *) (poDS->abyHeader+k+12+164+12);
|
|
poDS->SetMetadataItem( "INPUT_PRODUCT_NAME",CPLString().Printf("%s",szInputProductName));
|
|
|
|
if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"RAINN"))
|
|
poDS->SetMetadataItem( "NUM_HOURS_ACCUMULATE",CPLString().Printf("%d",CPL_LSBUINT16PTR (poDS->abyHeader+10+164+12)));
|
|
|
|
//See point 3.2.73 at page 3.36 of the manual
|
|
} else if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"VIL")){
|
|
float fBottomHeigthInterval = (float) CPL_LSBSINT32PTR(poDS->abyHeader+4+164+12) / 100;
|
|
poDS->SetMetadataItem( "BOTTOM_OF_HEIGTH_INTERVAL",CPLString().Printf("%.1f m",fBottomHeigthInterval));
|
|
float fTopHeigthInterval = (float) CPL_LSBSINT32PTR(poDS->abyHeader+8+164+12) / 100;
|
|
poDS->SetMetadataItem( "TOP_OF_HEIGTH_INTERVAL",CPLString().Printf("%.1f m",fTopHeigthInterval));
|
|
poDS->SetMetadataItem( "VIL_DENSITY_NOT_AVAILABLE_VALUE","-1");
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","mm");
|
|
//See point 3.2.68 at page 3.36 of the manual
|
|
} else if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"TOPS")){
|
|
float fZThreshold = (float) CPL_LSBSINT16PTR(poDS->abyHeader+4+164+12) / 16;
|
|
poDS->SetMetadataItem( "Z_THRESHOLD",CPLString().Printf("%.1f dBZ",fZThreshold));
|
|
poDS->SetMetadataItem( "ECHO_TOPS_NOT_AVAILABLE_VALUE","-1");
|
|
poDS->SetMetadataItem( "DATA_TYPE_UNITS","km");
|
|
//See point 3.2.20 at page 3.10 of the manual
|
|
} else if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"MAX")){
|
|
float fBottomInterval = (float) CPL_LSBSINT32PTR(poDS->abyHeader+4+164+12) / 100;
|
|
poDS->SetMetadataItem( "BOTTOM_OF_INTERVAL",CPLString().Printf("%.1f m",fBottomInterval));
|
|
float fTopInterval = (float) CPL_LSBSINT32PTR(poDS->abyHeader+8+164+12) / 100;
|
|
poDS->SetMetadataItem( "TOP_OF_INTERVAL",CPLString().Printf("%.1f m",fTopInterval));
|
|
int nNumPixelsSidePanels = CPL_LSBSINT32PTR(poDS->abyHeader+12+164+12);
|
|
poDS->SetMetadataItem( "NUM_PIXELS_SIDE_PANELS",CPLString().Printf("%d",nNumPixelsSidePanels));
|
|
short nHorizontalSmootherSidePanels = CPL_LSBSINT16PTR(poDS->abyHeader+16+164+12);
|
|
poDS->SetMetadataItem( "HORIZONTAL_SMOOTHER_SIDE_PANELS",CPLString().Printf("%d",nHorizontalSmootherSidePanels));
|
|
short nVerticalSmootherSidePanels = CPL_LSBSINT16PTR(poDS->abyHeader+18+164+12);
|
|
poDS->SetMetadataItem( "VERTICAL_SMOOTHER_SIDE_PANELS",CPLString().Printf("%d",nVerticalSmootherSidePanels));
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
for (int iBandNum = 1; iBandNum <= nNumBands; iBandNum++) {
|
|
poDS->SetBand( iBandNum, new IRISRasterBand( poDS, iBandNum ));
|
|
|
|
poDS->GetRasterBand(iBandNum)->SetNoDataValue(-9999);
|
|
//Calculating the band height to include it in the band metadata. Only for the CAPPI product
|
|
if (EQUAL(poDS->aszProductNames[poDS->nProductCode],"CAPPI")){
|
|
float fScaleZ = float (CPL_LSBSINT32PTR (poDS->abyHeader + 96 + 12 )) / 100;
|
|
float fOffset = ((float) CPL_LSBSINT32PTR(poDS->abyHeader+4+164+12))/100;
|
|
|
|
poDS->GetRasterBand(iBandNum)->SetMetadataItem("height",CPLString().Printf("%.0f m",fOffset + fScaleZ*(iBandNum-1)));
|
|
}
|
|
}
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize any PAM information. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetDescription( poOpenInfo->pszFilename );
|
|
poDS->TryLoadXML();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check for overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
|
|
|
|
return( poDS );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_IRIS() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_IRIS()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "IRIS" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "IRIS" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"IRIS data (.PPI, .CAPPi etc)" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_various.html#IRIS" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ppi" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
|
|
poDriver->pfnOpen = IRISDataset::Open;
|
|
poDriver->pfnIdentify = IRISDataset::Identify;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|