LCOV - code coverage report
Current view: directory - frmts/grib - gribdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 256 190 74.2 %
Date: 2010-01-09 Functions: 16 13 81.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: gribdataset.cpp 18099 2009-11-25 20:02:16Z warmerdam $
       3                 :  *
       4                 :  * Project:  GRIB Driver
       5                 :  * Purpose:  GDALDataset driver for GRIB translator for read support
       6                 :  * Author:   Bas Retsios, retsios@itc.nl
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, ITC
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ******************************************************************************
      29                 :  * 
      30                 :  */
      31                 : 
      32                 : #include "gdal_pam.h"
      33                 : #include "cpl_multiproc.h"
      34                 : 
      35                 : #include "degrib18/degrib/degrib2.h"
      36                 : #include "degrib18/degrib/inventory.h"
      37                 : #include "degrib18/degrib/myerror.h"
      38                 : #include "degrib18/degrib/filedatasource.h"
      39                 : #include "degrib18/degrib/memorydatasource.h"
      40                 : 
      41                 : #include "ogr_spatialref.h"
      42                 : 
      43                 : CPL_CVSID("$Id: gribdataset.cpp 18099 2009-11-25 20:02:16Z warmerdam $");
      44                 : 
      45                 : CPL_C_START
      46                 : void  GDALRegister_GRIB(void);
      47                 : CPL_C_END
      48                 : 
      49                 : /************************************************************************/
      50                 : /* ==================================================================== */
      51                 : /*        GRIBDataset       */
      52                 : /* ==================================================================== */
      53                 : /************************************************************************/
      54                 : 
      55                 : class GRIBRasterBand;
      56                 : 
      57                 : class GRIBDataset : public GDALPamDataset
      58                 : {
      59                 :     friend class GRIBRasterBand;
      60                 : 
      61                 :   public:
      62                 :     GRIBDataset();
      63                 :     ~GRIBDataset();
      64                 :     
      65                 :     static GDALDataset *Open( GDALOpenInfo * );
      66                 :     static int          Identify( GDALOpenInfo * );
      67                 : 
      68                 :     CPLErr  GetGeoTransform( double * padfTransform );
      69                 :     const char *GetProjectionRef();
      70                 :   private:
      71                 :     void SetGribMetaData(grib_MetaData* meta);
      72                 :     FILE  *fp;
      73                 :     char  *pszProjection;
      74                 :     char  *pszDescription;
      75                 :     OGRCoordinateTransformation *poTransform;
      76                 :     double adfGeoTransform[6]; // Calculate and store once as GetGeoTransform may be called multiple times
      77                 : };
      78                 : 
      79                 : /************************************************************************/
      80                 : /* ==================================================================== */
      81                 : /*                            GRIBRasterBand                             */
      82                 : /* ==================================================================== */
      83                 : /************************************************************************/
      84                 : 
      85                 : class GRIBRasterBand : public GDALPamRasterBand
      86                 : {
      87                 :     friend class GRIBDataset;
      88                 :     
      89                 : public:
      90                 :     GRIBRasterBand( GRIBDataset*, int, inventoryType* );
      91                 :     virtual ~GRIBRasterBand();
      92                 :     virtual CPLErr IReadBlock( int, int, void * );
      93                 :     virtual const char *GetDescription() const;
      94                 : 
      95                 :     void    FindPDSTemplate();
      96                 : 
      97                 : private:
      98                 :     static void ReadGribData( DataSource &, sInt4, int, double**, grib_MetaData**);
      99                 :     sInt4 start;
     100                 :     int subgNum;
     101                 :     char *longFstLevel;
     102                 : 
     103                 :     double * m_Grib_Data;
     104                 :     grib_MetaData* m_Grib_MetaData;
     105                 : 
     106                 :     int      nGribDataXSize;
     107                 :     int      nGribDataYSize;
     108                 : };
     109                 : 
     110                 : 
     111                 : /************************************************************************/
     112                 : /*                           GRIBRasterBand()                            */
     113                 : /************************************************************************/
     114                 : 
     115              18 : GRIBRasterBand::GRIBRasterBand( GRIBDataset *poDS, int nBand, 
     116                 :                                 inventoryType *psInv )
     117              18 :   : m_Grib_Data(NULL), m_Grib_MetaData(NULL)
     118                 : {
     119              18 :     this->poDS = poDS;
     120              18 :     this->nBand = nBand;
     121              18 :     this->start = psInv->start;
     122              18 :     this->subgNum = psInv->subgNum;
     123              18 :     this->longFstLevel = CPLStrdup(psInv->longFstLevel);
     124                 : 
     125              18 :     eDataType = GDT_Float64; // let user do -ot Float32 if needed for saving space, GRIB contains Float64 (though not fully utilized most of the time)
     126                 : 
     127              18 :     nBlockXSize = poDS->nRasterXSize;
     128              18 :     nBlockYSize = 1;
     129                 : 
     130              18 :     nGribDataXSize = poDS->nRasterXSize;
     131              18 :     nGribDataYSize = poDS->nRasterYSize;
     132                 : 
     133              18 :     SetMetadataItem( "GRIB_UNIT", psInv->unitName );
     134              18 :     SetMetadataItem( "GRIB_COMMENT", psInv->comment );
     135              18 :     SetMetadataItem( "GRIB_ELEMENT", psInv->element );
     136              18 :     SetMetadataItem( "GRIB_SHORT_NAME", psInv->shortFstLevel );
     137                 :     SetMetadataItem( "GRIB_REF_TIME", 
     138              18 :                      CPLString().Printf("%12.0f sec UTC", psInv->refTime ) );
     139                 :     SetMetadataItem( "GRIB_VALID_TIME", 
     140              18 :                      CPLString().Printf("%12.0f sec UTC", psInv->validTime ) );
     141                 :     SetMetadataItem( "GRIB_FORECAST_SECONDS", 
     142              18 :                      CPLString().Printf("%.0f sec", psInv->foreSec ) );
     143              18 : }
     144                 : 
     145                 : /************************************************************************/
     146                 : /*                          FindPDSTemplate()                           */
     147                 : /*                                                                      */
     148                 : /*      Scan the file for the PDS template info and represent it as     */
     149                 : /*      metadata.                                                       */
     150                 : /************************************************************************/
     151                 : 
     152               1 : void GRIBRasterBand::FindPDSTemplate()
     153                 : 
     154                 : {
     155               1 :     GRIBDataset *poGDS = (GRIBDataset *) poDS;
     156                 : 
     157                 : /* -------------------------------------------------------------------- */
     158                 : /*      Collect section 4 octet information ... we read the file        */
     159                 : /*      ourselves since the GRIB API does not appear to preserve all    */
     160                 : /*      this for us.                                                    */
     161                 : /* -------------------------------------------------------------------- */
     162               1 :     GIntBig nOffset = VSIFTellL( poGDS->fp );
     163                 :     GByte abyHead[5];
     164                 :     GUInt32 nSectSize;
     165                 : 
     166               1 :     VSIFSeekL( poGDS->fp, start+16, SEEK_SET );
     167               1 :     VSIFReadL( abyHead, 5, 1, poGDS->fp );
     168                 : 
     169               1 :     while( abyHead[4] != 4 )
     170                 :     {
     171               1 :         memcpy( &nSectSize, abyHead, 4 );
     172               1 :         CPL_MSBPTR32( &nSectSize );
     173                 : 
     174               1 :         if( VSIFSeekL( poGDS->fp, nSectSize-5, SEEK_CUR ) != 0
     175                 :             || VSIFReadL( abyHead, 5, 1, poGDS->fp ) != 1 )
     176               1 :             break;
     177                 :     }
     178                 :         
     179               1 :     if( abyHead[4] == 4 )
     180                 :     {
     181                 :         GUInt16 nCoordCount;
     182                 :         GUInt16 nPDTN;
     183               0 :         CPLString osOctet;
     184                 :         int i;
     185                 :         GByte *pabyBody;
     186                 : 
     187               0 :         memcpy( &nSectSize, abyHead, 4 );
     188               0 :         CPL_MSBPTR32( &nSectSize );
     189                 : 
     190               0 :         pabyBody = (GByte *) CPLMalloc(nSectSize-5);
     191               0 :         VSIFReadL( pabyBody, 1, nSectSize-5, poGDS->fp );
     192                 : 
     193               0 :         memcpy( &nCoordCount, pabyBody + 5 - 5, 2 );
     194               0 :         CPL_MSBPTR16( &nCoordCount );
     195                 : 
     196               0 :         memcpy( &nPDTN, pabyBody + 7 - 5, 2 );
     197               0 :         CPL_MSBPTR16( &nPDTN );
     198                 : 
     199                 :         SetMetadataItem( "GRIB_PDS_PDTN",
     200               0 :                          CPLString().Printf( "%d", nPDTN ) );
     201                 : 
     202               0 :         for( i = 9; i < (int) nSectSize; i++ )
     203                 :         {
     204                 :             char szByte[10];
     205                 : 
     206               0 :             if( i == 9 )
     207               0 :                 sprintf( szByte, "%d", pabyBody[i-5] );
     208                 :             else
     209               0 :                 sprintf( szByte, " %d", pabyBody[i-5] );
     210               0 :             osOctet += szByte;
     211                 :         }
     212                 :         
     213               0 :         SetMetadataItem( "GRIB_PDS_TEMPLATE_NUMBERS", osOctet );
     214                 : 
     215               0 :         CPLFree( pabyBody );
     216                 :     }
     217                 : 
     218               1 :     VSIFSeekL( poGDS->fp, nOffset, SEEK_SET );
     219               1 : }
     220                 : 
     221                 : /************************************************************************/
     222                 : /*                         GetDescription()                             */
     223                 : /************************************************************************/
     224                 : 
     225               0 : const char * GRIBRasterBand::GetDescription() const
     226                 : {
     227               0 :     if( longFstLevel == NULL )
     228               0 :         return GDALPamRasterBand::GetDescription();
     229                 :     else
     230               0 :         return longFstLevel;
     231                 : }
     232                 :  
     233                 : /************************************************************************/
     234                 : /*                             IReadBlock()                             */
     235                 : /************************************************************************/
     236                 : 
     237             281 : CPLErr GRIBRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     238                 :                                    void * pImage )
     239                 : 
     240                 : {
     241             281 :     if (!m_Grib_Data)
     242                 :     {
     243               3 :         GRIBDataset *poGDS = (GRIBDataset *) poDS;
     244                 : 
     245               3 :         FileDataSource grib_fp (poGDS->fp);
     246                 : 
     247                 :         // we don't seem to have any way to detect errors in this!
     248               3 :         ReadGribData(grib_fp, start, subgNum, &m_Grib_Data, &m_Grib_MetaData);
     249                 : 
     250                 : /* -------------------------------------------------------------------- */
     251                 : /*      Check that this band matches the dataset as a whole, size       */
     252                 : /*      wise. (#3246)                                                   */
     253                 : /* -------------------------------------------------------------------- */
     254               3 :         nGribDataXSize = m_Grib_MetaData->gds.Nx;
     255               3 :         nGribDataYSize = m_Grib_MetaData->gds.Ny;
     256                 : 
     257               3 :         if( nGribDataXSize != nRasterXSize 
     258                 :             || nGribDataYSize != nRasterYSize )
     259                 :         {
     260                 :             CPLError( CE_Warning, CPLE_AppDefined,
     261                 :                       "Band %d of GRIB dataset is %dx%d, while the first band and dataset is %dx%d.  Georeferencing of band %d may be incorrect, and data access may be incomplete.", 
     262                 :                       nBand, 
     263                 :                       nGribDataXSize, nGribDataYSize, 
     264                 :                       nRasterXSize, nRasterYSize, 
     265               1 :                       nBand );
     266               3 :         }
     267                 :     }
     268                 : 
     269                 : /* -------------------------------------------------------------------- */
     270                 : /*      The image as read is always upside down to our normal           */
     271                 : /*      orientation so we need to effectively flip it at this           */
     272                 : /*      point.  We also need to deal with bands that are a different    */
     273                 : /*      size than the dataset as a whole.                               */
     274                 : /* -------------------------------------------------------------------- */
     275             281 :     if( nGribDataXSize == nRasterXSize
     276                 :         && nGribDataYSize == nRasterYSize )
     277                 :     {
     278                 :         // Simple 1:1 case.
     279                 :         memcpy(pImage, 
     280                 :                m_Grib_Data + nRasterXSize * (nRasterYSize - nBlockYOff - 1), 
     281             203 :                nRasterXSize * sizeof(double));
     282                 :         
     283             203 :         return CE_None;
     284                 :     }
     285                 :     else
     286                 :     {
     287              78 :         memset( pImage, 0, sizeof(double)*nRasterXSize );
     288                 : 
     289              78 :         if( nBlockYOff >= nGribDataYSize ) // off image?
     290              57 :             return CE_None;
     291                 : 
     292              21 :         int nCopyWords = MIN(nRasterXSize,nGribDataXSize);
     293                 : 
     294                 :         memcpy( pImage, 
     295                 :                 m_Grib_Data + nGribDataXSize*(nGribDataYSize-nBlockYOff-1),
     296              21 :                 nCopyWords * sizeof(double) );
     297                 :         
     298              21 :         return CE_None;
     299                 :     }
     300                 : }
     301                 : 
     302                 : /************************************************************************/
     303                 : /*                            ReadGribData()                            */
     304                 : /************************************************************************/
     305                 : 
     306               6 : void GRIBRasterBand::ReadGribData( DataSource & fp, sInt4 start, int subgNum, double** data, grib_MetaData** metaData)
     307                 : {
     308                 :     /* Initialisation, for calling the ReadGrib2Record function */
     309               6 :     sInt4 f_endMsg = 1;  /* 1 if we read the last grid in a GRIB message, or we haven't read any messages. */
     310                 :     // int subgNum = 0;     /* The subgrid in the message that we are interested in. */
     311               6 :     sChar f_unit = 2;        /* None = 0, English = 1, Metric = 2 */
     312               6 :     double majEarth = 0;     /* -radEarth if < 6000 ignore, otherwise use this to
     313                 :                               * override the radEarth in the GRIB1 or GRIB2
     314                 :                               * message.  Needed because NCEP uses 6371.2 but GRIB1 could only state 6367.47. */
     315               6 :     double minEarth = 0;     /* -minEarth if < 6000 ignore, otherwise use this to
     316                 :                               * override the minEarth in the GRIB1 or GRIB2 message. */
     317               6 :     sChar f_SimpleVer = 4;   /* Which version of the simple NDFD Weather table to
     318                 :                               * use. (1 is 6/2003) (2 is 1/2004) (3 is 2/2004)
     319                 :                               * (4 is 11/2004) (default 4) */
     320                 :     LatLon lwlf;         /* lower left corner (cookie slicing) -lwlf */
     321                 :     LatLon uprt;         /* upper right corner (cookie slicing) -uprt */
     322                 :     IS_dataType is;      /* Un-parsed meta data for this GRIB2 message. As well as some memory used by the unpacker. */
     323                 : 
     324               6 :     lwlf.lat = -100; // lat == -100 instructs the GRIB decoder that we don't want a subgrid
     325                 : 
     326               6 :     IS_Init (&is);
     327                 : 
     328                 : 
     329                 :     /* Read GRIB message from file position "start". */
     330               6 :     fp.DataSourceFseek(start, SEEK_SET);
     331               6 :     uInt4 grib_DataLen = 0;  /* Size of Grib_Data. */
     332               6 :     *metaData = new grib_MetaData();
     333               6 :     MetaInit (*metaData);
     334                 :     ReadGrib2Record (fp, f_unit, data, &grib_DataLen, *metaData, &is, subgNum,
     335               6 :                      majEarth, minEarth, f_SimpleVer, &f_endMsg, &lwlf, &uprt);
     336                 : 
     337               6 :     char * errMsg = errSprintf(NULL); // no intention to show errors, just swallow it and free the memory
     338               6 :     if( errMsg != NULL )
     339               0 :         CPLDebug( "GRIB", "%s", errMsg );
     340               6 :     free(errMsg);
     341               6 :     IS_Free(&is);
     342               6 : }
     343                 : 
     344                 : /************************************************************************/
     345                 : /*                           ~GRIBRasterBand()                          */
     346                 : /************************************************************************/
     347                 : 
     348              36 : GRIBRasterBand::~GRIBRasterBand()
     349                 : {
     350              18 :     CPLFree(longFstLevel);
     351              18 :     if (m_Grib_Data)
     352               6 :         free (m_Grib_Data);
     353              18 :     if (m_Grib_MetaData)
     354                 :     {
     355               6 :         MetaFree( m_Grib_MetaData );
     356               6 :         delete m_Grib_MetaData;
     357                 :     }
     358              36 : }
     359                 : 
     360                 : /************************************************************************/
     361                 : /* ==================================================================== */
     362                 : /*        GRIBDataset       */
     363                 : /* ==================================================================== */
     364                 : /************************************************************************/
     365                 : 
     366               3 : GRIBDataset::GRIBDataset()
     367                 : 
     368                 : {
     369               3 :   poTransform = NULL;
     370               3 :   pszProjection = CPLStrdup("");
     371               3 :   adfGeoTransform[0] = 0.0;
     372               3 :   adfGeoTransform[1] = 1.0;
     373               3 :   adfGeoTransform[2] = 0.0;
     374               3 :   adfGeoTransform[3] = 0.0;
     375               3 :   adfGeoTransform[4] = 0.0;
     376               3 :   adfGeoTransform[5] = 1.0;
     377               3 : }
     378                 : 
     379                 : /************************************************************************/
     380                 : /*                            ~GRIBDataset()                             */
     381                 : /************************************************************************/
     382                 : 
     383               6 : GRIBDataset::~GRIBDataset()
     384                 : 
     385                 : {
     386               3 :     FlushCache();
     387               3 :     if( fp != NULL )
     388               3 :         VSIFCloseL( fp );
     389                 :     
     390               3 :     CPLFree( pszProjection );
     391               6 : }
     392                 : 
     393                 : /************************************************************************/
     394                 : /*                          GetGeoTransform()                           */
     395                 : /************************************************************************/
     396                 : 
     397               0 : CPLErr GRIBDataset::GetGeoTransform( double * padfTransform )
     398                 : 
     399                 : {
     400               0 :     memcpy( padfTransform,  adfGeoTransform, sizeof(double) * 6 );
     401               0 :     return CE_None;
     402                 : }
     403                 : 
     404                 : /************************************************************************/
     405                 : /*                          GetProjectionRef()                          */
     406                 : /************************************************************************/
     407                 : 
     408               0 : const char *GRIBDataset::GetProjectionRef()
     409                 : 
     410                 : {
     411               0 :     return pszProjection;
     412                 : }
     413                 : 
     414                 : /************************************************************************/
     415                 : /*                            Identify()                                */
     416                 : /************************************************************************/
     417                 : 
     418            8915 : int GRIBDataset::Identify( GDALOpenInfo * poOpenInfo )
     419                 : {
     420            8915 :     if (poOpenInfo->nHeaderBytes < 8)
     421            8391 :         return FALSE;
     422                 :         
     423                 : /* -------------------------------------------------------------------- */
     424                 : /*      Does a part of what ReadSECT0() but in a thread-safe way.       */
     425                 : /* -------------------------------------------------------------------- */
     426                 :     int i;
     427          401626 :     for(i=0;i<poOpenInfo->nHeaderBytes-3;i++)
     428                 :     {
     429          401105 :         if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "GRIB", 4) ||
     430                 :             EQUALN((const char*)poOpenInfo->pabyHeader + i, "TDLP", 4))
     431               3 :             return TRUE;
     432                 :     }
     433                 :     
     434             521 :     return FALSE;
     435                 : }
     436                 : 
     437                 : /************************************************************************/
     438                 : /*                                Open()                                */
     439                 : /************************************************************************/
     440                 : 
     441            1188 : GDALDataset *GRIBDataset::Open( GDALOpenInfo * poOpenInfo )
     442                 : 
     443                 : {
     444            1188 :     if( !Identify(poOpenInfo) )
     445            1185 :         return NULL;
     446                 :         
     447                 : /* -------------------------------------------------------------------- */
     448                 : /*      A fast "probe" on the header that is partially read in memory.  */
     449                 : /* -------------------------------------------------------------------- */
     450               3 :     if( poOpenInfo->fp == NULL)
     451               0 :         return NULL;
     452                 : 
     453               3 :     char *buff = NULL;
     454               3 :     uInt4 buffLen = 0;
     455                 :     sInt4 sect0[SECT0LEN_WORD];
     456                 :     uInt4 gribLen;
     457                 :     int version;
     458                 : // grib is not thread safe, make sure not to cause problems
     459                 : // for other thread safe formats
     460                 :     static void *mutex = 0;
     461               3 :     CPLMutexHolderD(&mutex);
     462               3 :     MemoryDataSource mds (poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes);
     463               3 :     if (ReadSECT0 (mds, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) {
     464               0 :         free (buff);
     465               0 :         char * errMsg = errSprintf(NULL);
     466               0 :         if( errMsg != NULL && strstr(errMsg,"Ran out of file") == NULL )
     467               0 :             CPLDebug( "GRIB", "%s", errMsg );
     468               0 :         free(errMsg);
     469               0 :         return NULL;
     470                 :     }
     471               3 :     free(buff);
     472                 :     
     473                 : /* -------------------------------------------------------------------- */
     474                 : /*      Confirm the requested access is supported.                      */
     475                 : /* -------------------------------------------------------------------- */
     476               3 :     if( poOpenInfo->eAccess == GA_Update )
     477                 :     {
     478                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     479                 :                   "The GRIB driver does not support update access to existing"
     480               0 :                   " datasets.\n" );
     481               0 :         return NULL;
     482                 :     }
     483                 : /* -------------------------------------------------------------------- */
     484                 : /*      Create a corresponding GDALDataset.                             */
     485                 : /* -------------------------------------------------------------------- */
     486                 :     GRIBDataset   *poDS;
     487                 : 
     488               3 :     poDS = new GRIBDataset();
     489                 : 
     490               6 :     poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
     491                 :     
     492                 : /* -------------------------------------------------------------------- */
     493                 : /*      Read the header.                                                */
     494                 : /* -------------------------------------------------------------------- */
     495                 : 
     496                 : /* -------------------------------------------------------------------- */
     497                 : /*      Make an inventory of the GRIB file.                             */
     498                 : /* The inventory does not contain all the information needed for        */
     499                 : /* creating the RasterBands (especially the x and y size), therefore    */
     500                 : /* the first GRIB band is also read for some additional metadata.       */
     501                 : /* The band-data that is read is stored into the first RasterBand,      */
     502                 : /* simply so that the same portion of the file is not read twice.       */
     503                 : /* -------------------------------------------------------------------- */
     504                 :     
     505               3 :     VSIFSeekL( poDS->fp, 0, SEEK_SET );
     506                 : 
     507               3 :     FileDataSource grib_fp (poDS->fp);
     508                 : 
     509               3 :     inventoryType *Inv = NULL;  /* Contains an GRIB2 message inventory of the file */
     510               3 :     uInt4 LenInv = 0;        /* size of Inv (also # of GRIB2 messages) */
     511               3 :     int msgNum =0;          /* The messageNumber during the inventory. */
     512                 : 
     513               3 :     if (GRIB2Inventory (grib_fp, &Inv, &LenInv, 0, &msgNum) <= 0 )
     514                 :     {
     515               0 :         char * errMsg = errSprintf(NULL);
     516               0 :         if( errMsg != NULL )
     517               0 :             CPLDebug( "GRIB", "%s", errMsg );
     518               0 :         free(errMsg);
     519                 : 
     520                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     521                 :                   "%s is a grib file, but no raster dataset was successfully identified.",
     522               0 :                   poOpenInfo->pszFilename );
     523               0 :         delete poDS;
     524               0 :         return NULL;
     525                 :     }
     526                 : 
     527                 : /* -------------------------------------------------------------------- */
     528                 : /*      Create band objects.                                            */
     529                 : /* -------------------------------------------------------------------- */
     530              21 :     for (uInt4 i = 0; i < LenInv; ++i)
     531                 :     {
     532              18 :         uInt4 bandNr = i+1;
     533              18 :         if (bandNr == 1)
     534                 :         {
     535                 :             // important: set DataSet extents before creating first RasterBand in it
     536               3 :             double * data = NULL;
     537                 :             grib_MetaData* metaData;
     538               3 :             GRIBRasterBand::ReadGribData(grib_fp, 0, Inv[i].subgNum, &data, &metaData);
     539               3 :             if (metaData->gds.Nx < 1 || metaData->gds.Ny < 1 )
     540                 :             {
     541                 :                 CPLError( CE_Failure, CPLE_OpenFailed, 
     542                 :                           "%s is a grib file, but no raster dataset was successfully identified.",
     543               0 :                           poOpenInfo->pszFilename );
     544               0 :                 delete poDS;
     545               0 :                 return NULL;
     546                 :             }
     547                 : 
     548               3 :             poDS->SetGribMetaData(metaData); // set the DataSet's x,y size, georeference and projection from the first GRIB band
     549               3 :             GRIBRasterBand* gribBand = new GRIBRasterBand( poDS, bandNr, Inv+i);
     550                 : 
     551               3 :             if( Inv->GribVersion == 2 )
     552               1 :                 gribBand->FindPDSTemplate();
     553                 : 
     554               3 :             gribBand->m_Grib_Data = data;
     555               3 :             gribBand->m_Grib_MetaData = metaData;
     556               3 :             poDS->SetBand( bandNr, gribBand);
     557                 :         }
     558                 :         else
     559              15 :             poDS->SetBand( bandNr, new GRIBRasterBand( poDS, bandNr, Inv+i ));
     560              18 :         GRIB2InventoryFree (Inv + i);
     561                 :     }
     562               3 :     free (Inv);
     563                 : 
     564                 : /* -------------------------------------------------------------------- */
     565                 : /*      Initialize any PAM information.                                 */
     566                 : /* -------------------------------------------------------------------- */
     567               3 :     poDS->SetDescription( poOpenInfo->pszFilename );
     568               3 :     poDS->TryLoadXML();
     569                 : 
     570               3 :     return( poDS );
     571                 : }
     572                 : 
     573                 : /************************************************************************/
     574                 : /*                            SetMetadata()                             */
     575                 : /************************************************************************/
     576                 : 
     577               3 : void GRIBDataset::SetGribMetaData(grib_MetaData* meta)
     578                 : {
     579               3 :     nRasterXSize = meta->gds.Nx;
     580               3 :     nRasterYSize = meta->gds.Ny;
     581                 : 
     582                 : /* -------------------------------------------------------------------- */
     583                 : /*      Image projection.                                               */
     584                 : /* -------------------------------------------------------------------- */
     585               3 :     OGRSpatialReference oSRS;
     586                 : 
     587               3 :     switch(meta->gds.projType)
     588                 :     {
     589                 :       case GS3_LATLON:
     590                 :       case GS3_GAUSSIAN_LATLON:
     591                 :           // No projection, only latlon system (geographic)
     592               2 :           break;
     593                 :       case GS3_MERCATOR:
     594                 :         oSRS.SetMercator(meta->gds.meshLat, meta->gds.orientLon,
     595               1 :                          1.0, 0.0, 0.0);
     596               1 :         break;
     597                 :       case GS3_POLAR:
     598                 :         oSRS.SetPS(meta->gds.meshLat, meta->gds.orientLon,
     599                 :                    meta->gds.scaleLat1,
     600               0 :                    0.0, 0.0);
     601               0 :         break;
     602                 :       case GS3_LAMBERT:
     603                 :         oSRS.SetLCC(meta->gds.scaleLat1, meta->gds.scaleLat2,
     604                 :                     0.0, meta->gds.orientLon,
     605               0 :                     0.0, 0.0); // set projection
     606               0 :         break;
     607                 :       
     608                 : 
     609                 :       case GS3_ORTHOGRAPHIC:
     610                 : 
     611                 :         //oSRS.SetOrthographic(0.0, meta->gds.orientLon,
     612                 :         //                      meta->gds.lon2, meta->gds.lat2);
     613                 :         //oSRS.SetGEOS(meta->gds.orientLon, meta->gds.stretchFactor, meta->gds.lon2, meta->gds.lat2);
     614               0 :         oSRS.SetGEOS(  0, 35785831, 0, 0 ); // hardcoded for now, I don't know yet how to parse the meta->gds section
     615                 :         break;
     616                 :       case GS3_EQUATOR_EQUIDIST:
     617                 :         break;
     618                 :       case GS3_AZIMUTH_RANGE:
     619                 :         break;
     620                 :     }
     621                 : 
     622                 : /* -------------------------------------------------------------------- */
     623                 : /*      Earth model                                                     */
     624                 : /* -------------------------------------------------------------------- */
     625               3 :     double a = meta->gds.majEarth * 1000.0; // in meters
     626               3 :     double b = meta->gds.minEarth * 1000.0;
     627               3 :     if( a == 0 && b == 0 )
     628                 :     {
     629               0 :         a = 6377563.396;
     630               0 :         b = 6356256.910;
     631                 :     }
     632                 : 
     633               3 :     if (meta->gds.f_sphere)
     634                 :     {
     635                 :         oSRS.SetGeogCS( "Coordinate System imported from GRIB file",
     636                 :                         NULL,
     637                 :                         "Sphere",
     638               3 :                         a, 0.0 );
     639                 :     }
     640                 :     else
     641                 :     {
     642               0 :         double fInv = a/(a-b);
     643                 :         oSRS.SetGeogCS( "Coordinate System imported from GRIB file",
     644                 :                         NULL,
     645                 :                         "Spheroid imported from GRIB file",
     646               0 :                         a, fInv );
     647                 :     }
     648                 : 
     649               3 :     OGRSpatialReference oLL; // construct the "geographic" part of oSRS
     650               3 :     oLL.CopyGeogCSFrom( &oSRS );
     651                 : 
     652                 :     double rMinX;
     653                 :     double rMaxY;
     654                 :     double rPixelSizeX;
     655                 :     double rPixelSizeY;
     656               3 :     if (meta->gds.projType == GS3_ORTHOGRAPHIC)
     657                 :     {
     658                 :         //rMinX = -meta->gds.Dx * (meta->gds.Nx / 2); // This is what should work, but it doesn't .. Dx seems to have an inverse relation with pixel size
     659                 :         //rMaxY = meta->gds.Dy * (meta->gds.Ny / 2);
     660               0 :         const double geosExtentInMeters = 11137496.552; // hardcoded for now, assumption: GEOS projection, full disc (like MSG)
     661               0 :         rMinX = -(geosExtentInMeters / 2);
     662               0 :         rMaxY = geosExtentInMeters / 2;
     663               0 :         rPixelSizeX = geosExtentInMeters / meta->gds.Nx;
     664               0 :         rPixelSizeY = geosExtentInMeters / meta->gds.Ny;
     665                 :     }
     666               3 :     else if( oSRS.IsProjected() )
     667                 :     {
     668               1 :         rMinX = meta->gds.lon1; // longitude in degrees, to be transformed to meters (or degrees in case of latlon)
     669               1 :         rMaxY = meta->gds.lat1; // latitude in degrees, to be transformed to meters 
     670               1 :         OGRCoordinateTransformation *poTransformLLtoSRS = OGRCreateCoordinateTransformation( &(oLL), &(oSRS) );
     671               1 :         if ((poTransformLLtoSRS != NULL) && poTransformLLtoSRS->Transform( 1, &rMinX, &rMaxY )) // transform it to meters
     672                 :         {
     673               1 :             if (meta->gds.scan == GRIB2BIT_2) // Y is minY, GDAL wants maxY
     674               1 :                 rMaxY += (meta->gds.Ny - 1) * meta->gds.Dy; // -1 because we GDAL needs the coordinates of the centre of the pixel
     675               1 :             rPixelSizeX = meta->gds.Dx;
     676               1 :             rPixelSizeY = meta->gds.Dy;
     677                 :         }
     678                 :         else
     679                 :         {
     680               0 :             rMinX = 0.0;
     681               0 :             rMaxY = 0.0;
     682                 :             
     683               0 :             rPixelSizeX = 1.0;
     684               0 :             rPixelSizeY = -1.0;
     685                 :             
     686               0 :             oSRS.Clear();
     687                 : 
     688                 :             CPLError( CE_Warning, CPLE_AppDefined,
     689                 :                       "Unable to perform coordinate transformations, so the correct\n"
     690                 :                       "projected geotransform could not be deduced from the lat/long\n"
     691               0 :                       "control points.  Defaulting to ungeoreferenced." );
     692                 :         }
     693               1 :         delete poTransformLLtoSRS;
     694                 :     }
     695                 :     else
     696                 :     {
     697               2 :         rMinX = meta->gds.lon1; // longitude in degrees, to be transformed to meters (or degrees in case of latlon)
     698               2 :         rMaxY = meta->gds.lat1; // latitude in degrees, to be transformed to meters 
     699                 : 
     700               2 :         if (meta->gds.scan == GRIB2BIT_2) // Y is minY, GDAL wants maxY
     701               2 :             rMaxY += (meta->gds.Ny - 1) * meta->gds.Dy; // -1 because we GDAL needs the coordinates of the centre of the pixel
     702               2 :         rPixelSizeX = meta->gds.Dx;
     703               2 :         rPixelSizeY = meta->gds.Dy;
     704                 :     }
     705                 : 
     706               3 :     adfGeoTransform[0] = rMinX;
     707               3 :     adfGeoTransform[3] = rMaxY;
     708               3 :     adfGeoTransform[1] = rPixelSizeX;
     709               3 :     adfGeoTransform[5] = -rPixelSizeY;
     710                 : 
     711               3 :     CPLFree( pszProjection );
     712               3 :     pszProjection = NULL;
     713               3 :     oSRS.exportToWkt( &(pszProjection) );
     714               3 : }
     715                 : 
     716                 : /************************************************************************/
     717                 : /*                         GDALRegister_GRIB()                          */
     718                 : /************************************************************************/
     719                 : 
     720             338 : void GDALRegister_GRIB()
     721                 : 
     722                 : {
     723                 :     GDALDriver  *poDriver;
     724                 : 
     725             338 :     if( GDALGetDriverByName( "GRIB" ) == NULL )
     726                 :     {
     727             336 :         poDriver = new GDALDriver();
     728                 :         
     729             336 :         poDriver->SetDescription( "GRIB" );
     730                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     731             336 :                                    "GRIdded Binary (.grb)" );
     732                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     733             336 :                                    "frmt_grib.html" );
     734             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grb" );
     735                 : 
     736             336 :         poDriver->pfnOpen = GRIBDataset::Open;
     737             336 :         poDriver->pfnIdentify = GRIBDataset::Identify;
     738                 : 
     739             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     740                 :     }
     741             338 : }

Generated by: LCOV version 1.7