LCOV - code coverage report
Current view: directory - frmts/netcdf - netcdfdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 935 755 80.7 %
Date: 2010-01-09 Functions: 23 23 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: netcdfdataset.cpp 18175 2009-12-05 00:03:36Z rouault $
       3                 :  *
       4                 :  * Project:  netCDF read/write Driver
       5                 :  * Purpose:  GDAL bindings over netCDF library.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2004, Frank Warmerdam
      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                 : #include "netcdfdataset.h"
      31                 : #include "cpl_error.h"
      32                 : CPL_CVSID("$Id: netcdfdataset.cpp 18175 2009-12-05 00:03:36Z rouault $");
      33                 : 
      34                 : 
      35                 : /************************************************************************/
      36                 : /* ==================================================================== */
      37                 : /*                         netCDFRasterBand                             */
      38                 : /* ==================================================================== */
      39                 : /************************************************************************/
      40                 : 
      41                 : class netCDFRasterBand : public GDALPamRasterBand
      42                 : {
      43                 :     nc_type nc_datatype;
      44                 :     int         nZId;
      45                 :     int         nZDim;
      46                 :     int   nLevel;
      47                 :     int         nBandXPos;
      48                 :     int         nBandYPos;
      49                 :     int         *panBandZPos;
      50                 :     int         *panBandZLev;
      51                 :     int         bNoDataSet;
      52                 :     double      dfNoDataValue;
      53                 :     CPLErr      CreateBandMetadata( ); 
      54                 :     
      55                 :   public:
      56                 : 
      57                 :     netCDFRasterBand( netCDFDataset *poDS, 
      58                 :           int nZId, 
      59                 :           int nZDim,
      60                 :           int nLevel, 
      61                 :           int *panBandZLen,
      62                 :           int *panBandPos, 
      63                 :           int nBand );
      64                 :     ~netCDFRasterBand( );
      65                 :     virtual double          GetNoDataValue( int * );
      66                 :     virtual CPLErr          SetNoDataValue( double );
      67                 :     virtual CPLErr IReadBlock( int, int, void * );
      68                 : 
      69                 : 
      70                 : };
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                            GetMetadata()                             */
      74                 : /************************************************************************/
      75              12 : char **netCDFDataset::GetMetadata( const char *pszDomain )
      76                 : {
      77              12 :     if( pszDomain != NULL && EQUALN( pszDomain, "SUBDATASETS", 11 ) )
      78               0 :         return papszSubDatasets;
      79                 :     else
      80              12 :         return GDALDataset::GetMetadata( pszDomain );
      81                 : }
      82                 : 
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                          GetProjectionRef()                          */
      86                 : /************************************************************************/
      87                 : 
      88              25 : const char * netCDFDataset::GetProjectionRef()
      89                 : {
      90              25 :     if( bGotGeoTransform )
      91              17 :   return pszProjection;
      92                 :     else
      93               8 :   return GDALPamDataset::GetProjectionRef();
      94                 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                           GetNoDataValue()                           */
      98                 : /************************************************************************/
      99                 : 
     100               1 : double netCDFRasterBand::GetNoDataValue( int * pbSuccess )
     101                 : 
     102                 : {
     103               1 :     if( pbSuccess )
     104               1 :         *pbSuccess = bNoDataSet;
     105                 : 
     106               1 :     if( bNoDataSet )
     107               1 :         return dfNoDataValue;
     108                 :     else
     109               0 :         return GDALPamRasterBand::GetNoDataValue( pbSuccess );
     110                 : }
     111                 : 
     112                 : /************************************************************************/
     113                 : /*                           SetNoDataValue()                           */
     114                 : /************************************************************************/
     115                 : 
     116              27 : CPLErr netCDFRasterBand::SetNoDataValue( double dfNoData )
     117                 : 
     118                 : {
     119              27 :     bNoDataSet = TRUE;
     120              27 :     dfNoDataValue = dfNoData;
     121                 : 
     122              27 :     return CE_None;
     123                 : }
     124                 : 
     125                 : /************************************************************************/
     126                 : /*                         ~netCDFRasterBand()                          */
     127                 : /************************************************************************/
     128                 : 
     129              54 : netCDFRasterBand::~netCDFRasterBand()
     130                 : {
     131              27 :     if( panBandZPos ) 
     132              16 :   CPLFree( panBandZPos );
     133              27 :     if( panBandZLev )
     134              16 :   CPLFree( panBandZLev );
     135              54 : }
     136                 : 
     137                 : /************************************************************************/
     138                 : /*                         CreateBandMetadata()                         */
     139                 : /************************************************************************/
     140                 : 
     141              27 : CPLErr netCDFRasterBand::CreateBandMetadata( ) 
     142                 : {
     143                 :     char     szVarName[NC_MAX_NAME];
     144                 :     char     szMetaName[NC_MAX_NAME];
     145                 :     char     szMetaTemp[8192];
     146                 :     int      nd;
     147                 :     int      i,j;
     148              27 :     int      Sum  = 1;
     149              27 :     int      Taken = 0;
     150              27 :     int      result = 0;
     151                 :     int      status;
     152              27 :     int      nVarID = -1;
     153                 :     int      nDims;
     154                 :     size_t   start[1];
     155                 :     size_t   count[1];
     156                 :     char     szTemp[NC_MAX_NAME];
     157                 :     const char *pszValue;
     158                 : 
     159                 :     nc_type nVarType;
     160                 :     netCDFDataset *poDS;
     161                 : 
     162              27 :     poDS = (netCDFDataset *) this->poDS;
     163                 : /* -------------------------------------------------------------------- */
     164                 : /*      Compute all dimensions from Band number and save in Metadata    */
     165                 : /* -------------------------------------------------------------------- */
     166              27 :     nc_inq_varname( poDS->cdfid, nZId, szVarName );
     167              27 :     nc_inq_varndims( poDS->cdfid, nZId, &nd );
     168                 : /* -------------------------------------------------------------------- */
     169                 : /*      Compute multidimention band position                            */
     170                 : /*                                                                      */
     171                 : /* BandPosition = (Total - sum(PastBandLevels) - 1)/sum(remainingLevels)*/
     172                 : /* if Data[2,3,4,x,y]                                                   */
     173                 : /*                                                                      */
     174                 : /*  BandPos0 = (nBand ) / (3*4)                                         */
     175                 : /*  BandPos1 = (nBand - BandPos0*(3*4) ) / (4)                          */
     176                 : /*  BandPos2 = (nBand - BandPos0*(3*4) ) % (4)                          */
     177                 : /* -------------------------------------------------------------------- */
     178                 : 
     179              27 :     sprintf( szMetaName,"NETCDF_VARNAME");
     180              27 :     sprintf( szMetaTemp,"%s",szVarName);
     181              27 :     SetMetadataItem( szMetaName, szMetaTemp );
     182              27 :     if( nd == 3 ) {
     183               0 :   Sum *= panBandZLev[0];
     184                 :     }
     185                 : 
     186              75 :     for( i=0; i < nd-2 ; i++ ) {
     187              48 :   if( i != nd - 2 -1 ) {
     188              32 :             Sum = 1;
     189              80 :       for( j=i+1; j < nd-2; j++ ) {
     190              48 :     Sum *= panBandZLev[j];
     191                 :       }
     192              32 :       result = (int) ( ( nLevel-Taken) / Sum );
     193                 :   }
     194                 :   else {
     195              16 :       result = (int) ( ( nLevel-Taken) % Sum );
     196                 :   }
     197                 :         
     198                 :   strcpy(szVarName, poDS->papszDimName[poDS->paDimIds[
     199              48 :         panBandZPos[i]]] );
     200                 : 
     201              48 :   sprintf( szMetaName,"NETCDF_DIMENSION_%s",  szVarName );
     202                 : 
     203                 :   status=nc_inq_varid(poDS->cdfid,  
     204                 :           szVarName,
     205              48 :           &nVarID );
     206                 : 
     207                 : /* -------------------------------------------------------------------- */
     208                 : /*      Try to uppercase the first letter of the variable               */
     209                 : /* -------------------------------------------------------------------- */
     210                 : 
     211              48 :   if( status != NC_NOERR ) {
     212              48 :       szVarName[0]=toupper(szVarName[0]);
     213                 :       status=nc_inq_varid(poDS->cdfid,  
     214                 :         szVarName,
     215              48 :         &nVarID );
     216                 :   }
     217                 : 
     218              48 :   status = nc_inq_vartype( poDS->cdfid, nVarID, &nVarType );
     219                 : 
     220              48 :   nDims = 0;
     221              48 :   status = nc_inq_varndims( poDS->cdfid, nVarID, &nDims );
     222                 : 
     223              48 :   if( nDims == 1 ) {
     224               0 :       count[0]=1;
     225               0 :       start[0]=result;
     226               0 :       switch( nVarType ) {
     227                 :       case NC_SHORT:
     228                 :     short sData;
     229                 :     status =  nc_get_vara_short( poDS->cdfid, nVarID, 
     230                 :                start,
     231               0 :                count, &sData );
     232               0 :     sprintf( szMetaTemp,"%d", sData );
     233               0 :     break;
     234                 :       case NC_INT:
     235                 :     int nData;
     236                 :     status =  nc_get_vara_int( poDS->cdfid, nVarID, 
     237                 :              start,
     238               0 :              count, &nData );
     239               0 :     sprintf( szMetaTemp,"%d", nData );
     240               0 :     break;
     241                 :       case NC_FLOAT:
     242                 :     float fData;
     243                 :     status =  nc_get_vara_float( poDS->cdfid, nVarID, 
     244                 :                start,
     245               0 :                count, &fData );
     246               0 :     sprintf( szMetaTemp,"%f", fData );
     247               0 :     break;
     248                 :       case NC_DOUBLE:
     249                 :     double dfData;
     250                 :     status =  nc_get_vara_double( poDS->cdfid, nVarID, 
     251                 :                 start,
     252               0 :                 count, &dfData);
     253               0 :     sprintf( szMetaTemp,"%g", dfData );
     254                 :     break;
     255                 :       default:
     256                 :     break;
     257                 :       }
     258                 :   }
     259                 :   else
     260              48 :       sprintf( szMetaTemp,"%d", result+1);
     261                 :   
     262              48 :         SetMetadataItem( szMetaName, szMetaTemp );
     263                 : 
     264                 : /* -------------------------------------------------------------------- */
     265                 : /*      Fetch dimension units                                           */
     266                 : /* -------------------------------------------------------------------- */
     267                 : 
     268              48 :   strcpy( szTemp, szVarName );
     269              48 :   strcat( szTemp, "#units" );
     270              48 :   pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
     271              48 :   if( pszValue != NULL ) {
     272               0 :       if( EQUAL( pszValue, "T") ) { 
     273               0 :     strcpy( szTemp, szVarName );
     274               0 :     strcat( szTemp, "#original_units" );
     275               0 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
     276               0 :     strcpy( szTemp, "NETCDF_");
     277               0 :     strcat( szTemp, szVarName );
     278               0 :     strcat( szTemp, "_original_units" );
     279               0 :     SetMetadataItem( szTemp, pszValue );
     280                 :       }
     281                 :       else {
     282               0 :     strcpy( szTemp, "NETCDF_");
     283               0 :     strcat( szTemp, szVarName  );
     284               0 :     strcat( szTemp, "_units" );
     285               0 :     SetMetadataItem( szTemp, pszValue );
     286                 :       }
     287                 :   }
     288              48 :   Taken += result * Sum;
     289                 :     }
     290                 : 
     291                 : 
     292                 : 
     293              27 :     return CE_None;
     294                 : }
     295                 : 
     296                 : /************************************************************************/
     297                 : /*                          netCDFRasterBand()                          */
     298                 : /************************************************************************/
     299                 : 
     300              27 : netCDFRasterBand::netCDFRasterBand( netCDFDataset *poDS, 
     301                 :             int nZId, 
     302                 :             int nZDim,
     303                 :             int nLevel, 
     304                 :             int *panBandZLev, 
     305                 :             int *panBandDimPos, 
     306              27 :             int nBand)
     307                 : 
     308                 : {
     309                 :     double   dfNoData;
     310              27 :     int      bNoDataSet = FALSE;
     311              27 :     nc_type  vartype=NC_NAT;
     312              27 :     nc_type  atttype=NC_NAT;
     313                 :     size_t   attlen;
     314                 :     int      status;
     315                 :     char     szNoValueName[8192];
     316                 : 
     317                 : 
     318              27 :     this->panBandZPos = NULL;
     319              27 :     this->panBandZLev = NULL;
     320              27 :     this->poDS = poDS;
     321              27 :     this->nBand = nBand;
     322              27 :     this->nZId = nZId;
     323              27 :     this->nZDim = nZDim;
     324              27 :     this->nLevel = nLevel;
     325              27 :     this->nBandXPos = panBandDimPos[0];
     326              27 :     this->nBandYPos = panBandDimPos[1];
     327                 : 
     328                 : /* -------------------------------------------------------------------- */
     329                 : /*      Take care of all other dimmensions                              */
     330                 : /* ------------------------------------------------------------------ */
     331              27 :     if( nZDim > 2 ) {
     332                 :   this->panBandZPos = 
     333              16 :       (int *) CPLCalloc( nZDim-1, sizeof( int ) );
     334                 :   this->panBandZLev = 
     335              16 :       (int *) CPLCalloc( nZDim-1, sizeof( int ) );
     336                 : 
     337              64 :   for ( int i=0; i < nZDim - 2; i++ ){
     338              48 :       this->panBandZPos[i] = panBandDimPos[i+2];
     339              48 :       this->panBandZLev[i] = panBandZLev[i];
     340                 :   }
     341                 :     }
     342              27 :     CreateBandMetadata();
     343              27 :     bNoDataSet    = FALSE;
     344              27 :     dfNoDataValue = -9999.0;
     345                 : 
     346              27 :     nBlockXSize   = poDS->GetRasterXSize( );
     347              27 :     nBlockYSize   = 1;
     348                 : 
     349                 : /* -------------------------------------------------------------------- */
     350                 : /*      Get the type of the "z" variable, our target raster array.      */
     351                 : /* -------------------------------------------------------------------- */
     352              27 :     if( nc_inq_var( poDS->cdfid, nZId, NULL, &nc_datatype, NULL, NULL,
     353                 :                    NULL ) != NC_NOERR ){
     354                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     355               0 :                   "Error in nc_var_inq() on 'z'." );
     356               0 :         return;
     357                 :     }
     358                 : 
     359              27 :     if( (nc_datatype == NC_BYTE) ) 
     360               3 :         eDataType = GDT_Byte;
     361              24 :     else if( nc_datatype == NC_SHORT )
     362               2 :         eDataType = GDT_Int16;
     363              22 :     else if( nc_datatype == NC_INT )
     364               2 :         eDataType = GDT_Int32;
     365              20 :     else if( nc_datatype == NC_FLOAT )
     366               3 :         eDataType = GDT_Float32;
     367              17 :     else if( nc_datatype == NC_DOUBLE )
     368              17 :         eDataType = GDT_Float64;
     369                 :     else
     370                 :     {
     371               0 :         if( nBand == 1 )
     372                 :             CPLError( CE_Warning, CPLE_AppDefined, 
     373                 :                       "Unsupported netCDF datatype (%d), treat as Float32.", 
     374               0 :                       (int) nc_datatype );
     375               0 :         eDataType = GDT_Float32;
     376                 :     }
     377                 : /* -------------------------------------------------------------------- */
     378                 : /*      Find out what is No Data for this variable                      */
     379                 : /* -------------------------------------------------------------------- */
     380                 : 
     381                 :     status = nc_inq_att( poDS->cdfid, nZId, 
     382              27 :        _FillValue, &atttype, &attlen);
     383                 : 
     384                 : /* -------------------------------------------------------------------- */
     385                 : /*      Look for either Missing_Value or _FillValue attributes          */
     386                 : /* -------------------------------------------------------------------- */
     387                 : 
     388              27 :     if( status == NC_NOERR ) {
     389               7 :   strcpy(szNoValueName, _FillValue );
     390                 :     }
     391                 :     else {
     392                 :   status = nc_inq_att( poDS->cdfid, nZId, 
     393              20 :            "missing_value", &atttype, &attlen );
     394              20 :   if( status == NC_NOERR ) {
     395                 : 
     396               1 :       strcpy( szNoValueName, "missing_value" );
     397                 :   }
     398                 :     }
     399                 : 
     400              27 :     nc_inq_vartype( poDS->cdfid, nZId, &vartype );
     401                 : 
     402              27 :     if( status == NC_NOERR ) {
     403               8 :   switch( atttype ) {
     404                 :   case NC_CHAR:
     405                 :       char *fillc;
     406               0 :       fillc = (char *) CPLCalloc( attlen+1, sizeof(char) );
     407                 :       status=nc_get_att_text( poDS->cdfid, nZId,
     408               0 :             szNoValueName, fillc );
     409               0 :       dfNoData = atof( fillc );
     410               0 :       CPLFree(fillc);
     411               0 :       break;
     412                 :   case NC_SHORT:
     413                 :       short sNoData;
     414                 :       status = nc_get_att_short( poDS->cdfid, nZId,
     415               2 :                szNoValueName, &sNoData );
     416               2 :       dfNoData = (double) sNoData;
     417               2 :       break;
     418                 :   case NC_INT:
     419                 :       int nNoData;
     420                 :       status = nc_get_att_int( poDS->cdfid, nZId,
     421               2 :              szNoValueName, &nNoData );
     422               2 :       dfNoData = (double) nNoData;
     423               2 :       break;
     424                 :   case NC_FLOAT:
     425                 :       float fNoData;
     426                 :       status = nc_get_att_float( poDS->cdfid, nZId,
     427               2 :                szNoValueName, &fNoData );
     428               2 :       dfNoData = (double) fNoData;
     429               2 :       break;
     430                 :   case NC_DOUBLE:
     431                 :       status = nc_get_att_double( poDS->cdfid, nZId,
     432               2 :            szNoValueName, &dfNoData );
     433                 :       break;
     434                 :   default:
     435                 :       break;
     436                 :   }
     437                 :   status = nc_get_att_double( poDS->cdfid, nZId, 
     438               8 :             szNoValueName, &dfNoData );
     439                 :   
     440                 :     } else {
     441              19 :   switch( vartype ) {
     442                 :   case NC_BYTE:
     443                 :       /* don't do default fill-values for bytes, too risky */
     444               3 :       dfNoData = 0.0;
     445               3 :       break;
     446                 :   case NC_CHAR:
     447               0 :       dfNoData = NC_FILL_CHAR;
     448               0 :       break;
     449                 :   case NC_SHORT:
     450               0 :       dfNoData = NC_FILL_SHORT;
     451               0 :       break;
     452                 :   case NC_INT:
     453               0 :       dfNoData = NC_FILL_INT;
     454               0 :       break;
     455                 :   case NC_FLOAT:
     456               0 :       dfNoData = NC_FILL_FLOAT;
     457               0 :       break;
     458                 :   case NC_DOUBLE:
     459              16 :       dfNoData = NC_FILL_DOUBLE;
     460              16 :       break;
     461                 :   default:
     462               0 :       dfNoData = 0.0;
     463                 :       break;
     464                 :   }
     465              19 :       bNoDataSet = TRUE;
     466                 :     }
     467              27 :     SetNoDataValue( dfNoData );
     468                 : 
     469                 :     
     470               0 : }
     471                 : 
     472                 : /************************************************************************/
     473                 : /*                             IReadBlock()                             */
     474                 : /************************************************************************/
     475                 : 
     476             205 : CPLErr netCDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     477                 :                                   void * pImage )
     478                 : 
     479                 : {
     480             205 :     int    nErr=-1;
     481             205 :     int    cdfid = ( ( netCDFDataset * ) poDS )->cdfid;
     482                 :     size_t start[ MAX_NC_DIMS ];
     483                 :     size_t edge[ MAX_NC_DIMS ];
     484                 :     char   pszName[ MAX_STR_LEN ];
     485                 :     int    i,j;
     486             205 :     int    Sum=-1;
     487             205 :     int    Taken=-1;
     488                 :     int    nd;
     489                 : 
     490             205 :     *pszName='\0';
     491             205 :     memset( start, 0, sizeof( start ) );
     492             205 :     memset( edge,  0, sizeof( edge )  );
     493             205 :     nc_inq_varndims ( cdfid, nZId, &nd );
     494                 : 
     495                 : /* -------------------------------------------------------------------- */
     496                 : /*      Locate X, Y and Z position in the array                         */
     497                 : /* -------------------------------------------------------------------- */
     498                 :   
     499             205 :     start[nBandXPos] = 0;          // x dim can move arround in array
     500                 :     // check y order
     501             205 :     if( ( ( netCDFDataset *) poDS )->bBottomUp ) {
     502               0 :         start[nBandYPos] = ( ( netCDFDataset * ) poDS )->ydim - 1 - nBlockYOff;
     503                 :     } else {
     504             205 :         start[nBandYPos] = nBlockYOff; // y
     505                 :     }
     506                 :         
     507             205 :     edge[nBandXPos] = nBlockXSize; 
     508             205 :     edge[nBandYPos] = 1;
     509                 : 
     510             205 :     if( nd == 3 ) {
     511               0 :         start[panBandZPos[0]]  = nLevel;     // z
     512               0 :         edge [panBandZPos[0]]  = 1;
     513                 :     }
     514                 : 
     515                 : /* -------------------------------------------------------------------- */
     516                 : /*      Compute multidimention band position                            */
     517                 : /*                                                                      */
     518                 : /* BandPosition = (Total - sum(PastBandLevels) - 1)/sum(remainingLevels)*/
     519                 : /* if Data[2,3,4,x,y]                                                   */
     520                 : /*                                                                      */
     521                 : /*  BandPos0 = (nBand ) / (3*4)                                         */
     522                 : /*  BandPos1 = (nBand - (3*4) ) / (4)                                   */
     523                 : /*  BandPos2 = (nBand - (3*4) ) % (4)                                   */
     524                 : /* -------------------------------------------------------------------- */
     525             205 :     if (nd > 3) 
     526                 :     {
     527              20 :         Taken = 0;
     528              80 :         for( i=0; i < nd-2 ; i++ ) 
     529                 :         {
     530              60 :             if( i != nd - 2 -1 ) {
     531              40 :                 Sum = 1;
     532             100 :                 for( j=i+1; j < nd-2; j++ ) {
     533              60 :                     Sum *= panBandZLev[j];
     534                 :                 }
     535              40 :                 start[panBandZPos[i]] = (int) ( ( nLevel-Taken) / Sum );
     536              40 :                 edge[panBandZPos[i]] = 1;
     537                 :             } else {
     538              20 :                 start[panBandZPos[i]] = (int) ( ( nLevel-Taken) % Sum );
     539              20 :                 edge[panBandZPos[i]] = 1;
     540                 :             }
     541              60 :             Taken += start[panBandZPos[i]] * Sum;
     542                 :         }
     543                 :     }
     544                 : 
     545             205 :     if( eDataType == GDT_Byte )
     546                 :         nErr = nc_get_vara_uchar( cdfid, nZId, start, edge, 
     547              20 :                                   (unsigned char *) pImage );
     548             185 :     else if( eDataType == GDT_Int16 )
     549                 :         nErr = nc_get_vara_short( cdfid, nZId, start, edge, 
     550               0 :                                   (short int *) pImage );
     551             185 :     else if( eDataType == GDT_Int32 )
     552                 :     {
     553                 :         if( sizeof(long) == 4 )
     554                 :             nErr = nc_get_vara_long( cdfid, nZId, start, edge, 
     555               0 :                                      (long *) pImage );
     556                 :         else
     557                 :             nErr = nc_get_vara_int( cdfid, nZId, start, edge, 
     558                 :                                     (int *) pImage );
     559                 :     }
     560             185 :     else if( eDataType == GDT_Float32 ){
     561                 :         nErr = nc_get_vara_float( cdfid, nZId, start, edge, 
     562             165 :                                   (float *) pImage );
     563           18558 :   for( i=0; i<nBlockXSize; i++ ){
     564           18393 :       if( CPLIsNan( ( (float *) pImage )[i] ) )
     565               0 :     ( (float *)pImage )[i] = dfNoDataValue;
     566                 :   }
     567                 :     }
     568              20 :     else if( eDataType == GDT_Float64 ){
     569                 :         nErr = nc_get_vara_double( cdfid, nZId, start, edge, 
     570              20 :                                    (double *) pImage );
     571             220 :   for( i=0; i<nBlockXSize; i++ ){
     572             200 :       if( CPLIsNan( ( (double *) pImage)[i] ) ) 
     573               0 :     ( (double *)pImage )[i] = dfNoDataValue;
     574                 :   }
     575                 : 
     576                 :     }
     577                 : 
     578             205 :     if( nErr != NC_NOERR )
     579                 :     {
     580                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     581                 :                   "netCDF scanline fetch failed: %s", 
     582               0 :                   nc_strerror( nErr ) );
     583               0 :         return CE_Failure;
     584                 :     }
     585                 :     else
     586             205 :         return CE_None;
     587                 : }
     588                 : 
     589                 : /************************************************************************/
     590                 : /* ==================================================================== */
     591                 : /*        netCDFDataset       */
     592                 : /* ==================================================================== */
     593                 : /************************************************************************/
     594                 : 
     595                 : /************************************************************************/
     596                 : /*                           netCDFDataset()                            */
     597                 : /************************************************************************/
     598                 : 
     599              21 : netCDFDataset::netCDFDataset()
     600                 : 
     601                 : {
     602              21 :     papszMetadata    = NULL;  
     603              21 :     papszSubDatasets = NULL;
     604              21 :     bGotGeoTransform = FALSE;
     605              21 :     pszProjection    = NULL;
     606              21 :     cdfid             = 0;
     607              21 :     bBottomUp        = FALSE;
     608              21 : }
     609                 : 
     610                 : 
     611                 : /************************************************************************/
     612                 : /*                           ~netCDFDataset()                           */
     613                 : /************************************************************************/
     614                 : 
     615              42 : netCDFDataset::~netCDFDataset()
     616                 : 
     617                 : {
     618                 : 
     619              21 :     FlushCache();
     620                 : 
     621              21 :     CSLDestroy( papszMetadata );
     622              21 :     CSLDestroy( papszSubDatasets );
     623                 : 
     624              21 :     CPLFree( pszProjection );
     625                 : 
     626              21 :     if( cdfid ) 
     627              21 :   nc_close( cdfid );
     628              42 : }
     629                 : 
     630                 : /************************************************************************/
     631                 : /*                           FetchCopyParm()                            */
     632                 : /************************************************************************/
     633                 : 
     634              10 : double netCDFDataset::FetchCopyParm( const char *pszGridMappingValue, 
     635                 :                                      const char *pszParm, double dfDefault )
     636                 : 
     637                 : {
     638                 :     char         szTemp[ MAX_NC_NAME ];
     639                 :     const char  *pszValue;
     640                 : 
     641              10 :     strcpy(szTemp,pszGridMappingValue);
     642              10 :     strcat( szTemp, "#" );
     643              10 :     strcat( szTemp, pszParm );
     644              10 :     pszValue = CSLFetchNameValue(papszMetadata, szTemp);
     645                 : 
     646              10 :     if( pszValue )
     647                 :     {
     648              10 :         return CPLAtofM(pszValue);
     649                 :     }
     650                 :     else
     651               0 :         return dfDefault;
     652                 : }
     653                 :     
     654                 : 
     655                 : /************************************************************************/
     656                 : /*                           SetProjection()                            */
     657                 : /************************************************************************/
     658              13 : void netCDFDataset::SetProjection( int var )
     659                 : {
     660                 : /* -------------------------------------------------------------------- */
     661                 : /*      Set Projection                                                  */
     662                 : /* -------------------------------------------------------------------- */
     663                 : 
     664                 :     size_t       start[2], edge[2];
     665                 :     int          status;
     666                 :     unsigned int i;
     667                 :     const char   *pszValue;
     668                 :     int          nVarProjectionID;
     669                 :     char         szVarName[ MAX_NC_NAME ];
     670                 :     char         szTemp[ MAX_NC_NAME ];
     671                 :     char         szGridMappingName[ MAX_NC_NAME ];
     672                 :     char         szGridMappingValue[ MAX_NC_NAME ];
     673                 : 
     674                 :     double       dfStdP1;
     675                 :     double       dfStdP2;
     676                 :     double       dfCenterLat;
     677                 :     double       dfCenterLon;
     678                 :     double       dfScale;
     679                 :     double       dfFalseEasting;
     680                 :     double       dfFalseNorthing;
     681                 :     double       dfCentralMeridian;
     682                 : 
     683              13 :     OGRSpatialReference oSRS;
     684              13 :     int          nVarDimXID = -1;
     685              13 :     int          nVarDimYID = -1;
     686                 :     double       *pdfXCoord;
     687                 :     double       *pdfYCoord;
     688                 :     char         szDimNameX[ MAX_NC_NAME ];
     689                 :     char         szDimNameY[ MAX_NC_NAME ];
     690                 :     int          nSpacingBegin;
     691                 :     int          nSpacingMiddle;
     692                 :     int          nSpacingLast;
     693                 : 
     694                 :     const char *pszWKT;
     695                 :     const char *pszGeoTransform;
     696              13 :     char **papszGeoTransform=NULL;
     697                 : 
     698                 : 
     699                 :     netCDFDataset * poDS;
     700              13 :     poDS = this;
     701                 : 
     702                 : /* -------------------------------------------------------------------- */
     703                 : /*      Get x/y range information.                                      */
     704                 : /* -------------------------------------------------------------------- */
     705                 : 
     706              13 :     poDS->adfGeoTransform[0] = 0.0;
     707              13 :     poDS->adfGeoTransform[1] = 1.0;
     708              13 :     poDS->adfGeoTransform[2] = 0.0;
     709              13 :     poDS->adfGeoTransform[3] = 0.0;
     710              13 :     poDS->adfGeoTransform[4] = 0.0;
     711              13 :     poDS->adfGeoTransform[5] = 1.0;
     712              13 :     poDS->pszProjection = NULL;
     713                 :     
     714                 : 
     715                 : /* -------------------------------------------------------------------- */
     716                 : /*      Look for grid_mapping metadata                                  */
     717                 : /* -------------------------------------------------------------------- */
     718                 : 
     719              13 :     strcpy( szGridMappingValue, "" );
     720              13 :     strcpy( szGridMappingName, "" );
     721                 : 
     722              13 :     nc_inq_varname(  cdfid, var, szVarName );
     723              13 :     strcpy(szTemp,szVarName);
     724              13 :     strcat(szTemp,"#grid_mapping");
     725              13 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
     726              13 :     if( pszValue ) {
     727               9 :   strcpy(szGridMappingName,szTemp);
     728               9 :   strcpy(szGridMappingValue,pszValue);
     729                 :     }
     730                 : 
     731                 : /* -------------------------------------------------------------------- */
     732                 : /*      Look for dimension: lon                                         */
     733                 : /* -------------------------------------------------------------------- */
     734                 : 
     735              32 :     for( i = 0; (i < strlen( poDS->papszDimName[ poDS->nDimXid ] )  && 
     736                 :      i < 3 ); i++ ) {
     737              19 :   szDimNameX[i] = tolower( ( poDS->papszDimName[poDS->nDimXid] )[i] );
     738                 :     }
     739              13 :     szDimNameX[3] = '\0';
     740              32 :     for( i = 0; (i < strlen( poDS->papszDimName[ poDS->nDimYid ] )  && 
     741                 :      i < 3 ); i++ ) {
     742              19 :   szDimNameY[i] = tolower( ( poDS->papszDimName[poDS->nDimYid] )[i] );
     743                 :     }
     744              13 :     szDimNameY[3] = '\0';
     745                 : 
     746                 : /* -------------------------------------------------------------------- */
     747                 : /*      Read grid_mappinginformation and set projections               */
     748                 : /* -------------------------------------------------------------------- */
     749                 : 
     750              13 :     if( !( EQUAL(szGridMappingName,"" ) ) ) {
     751               9 :   nc_inq_varid( cdfid, szGridMappingValue, &nVarProjectionID );
     752               9 :   poDS->ReadAttributes( cdfid, nVarProjectionID );
     753                 :     
     754               9 :   strcpy( szTemp, szGridMappingValue );
     755               9 :   strcat( szTemp, "#" );
     756               9 :   strcat( szTemp, GRD_MAPPING_NAME );
     757               9 :   pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
     758                 : 
     759               9 :   if( pszValue != NULL ) {
     760                 : /* -------------------------------------------------------------------- */
     761                 : /*      Transverse Mercator                                             */
     762                 : /* -------------------------------------------------------------------- */
     763                 : 
     764               9 :       if( EQUAL( pszValue, TM ) ) {
     765                 : 
     766                 :     dfScale = 
     767                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     768               2 :                                          SCALE_FACTOR, 1.0 );
     769                 : 
     770                 :     dfCenterLon = 
     771                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     772               2 :                                          LONG_CENTRAL_MERIDIAN, 0.0 );
     773                 : 
     774                 :     dfCenterLat = 
     775                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     776               2 :                                          LAT_PROJ_ORIGIN, 0.0 );
     777                 : 
     778                 :     dfFalseEasting = 
     779                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     780               2 :                                          FALSE_EASTING, 0.0 );
     781                 : 
     782                 :     dfFalseNorthing = 
     783                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     784               2 :                                          FALSE_NORTHING, 0.0 );
     785                 : 
     786                 :     oSRS.SetTM( dfCenterLat, 
     787                 :           dfCenterLon,
     788                 :           dfScale,
     789                 :           dfFalseEasting,
     790               2 :           dfFalseNorthing );
     791               2 :     oSRS.SetWellKnownGeogCS( "WGS84" );
     792                 :       }
     793                 : 
     794                 : /* -------------------------------------------------------------------- */
     795                 : /*      Cylindrical Equal Area                                          */
     796                 : /* -------------------------------------------------------------------- */
     797                 : 
     798               7 :       else if( EQUAL( pszValue, CEA ) ) {
     799                 :     dfStdP1 = 
     800                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     801               0 :                                          STD_PARALLEL_1, 0.0 );
     802                 :     dfCentralMeridian = 
     803                 :         poDS->FetchCopyParm( szGridMappingValue, 
     804               0 :            LONG_CENTRAL_MERIDIAN, 0.0 );
     805                 : 
     806                 :     dfFalseEasting = 
     807                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     808               0 :                                          FALSE_EASTING, 0.0 );
     809                 : 
     810                 :     dfFalseNorthing = 
     811                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     812               0 :                                          FALSE_NORTHING, 0.0 );
     813                 :     
     814                 :     oSRS.SetCEA( dfStdP1, dfCentralMeridian,
     815               0 :            dfFalseEasting, dfFalseNorthing );
     816                 :     
     817               0 :     oSRS.SetWellKnownGeogCS( "WGS84" );
     818                 :       }
     819                 : /* -------------------------------------------------------------------- */
     820                 : /*      lambert_azimuthal_equal_area                                    */
     821                 : /* -------------------------------------------------------------------- */
     822               7 :       else if( EQUAL( pszValue, LAEA ) ) {
     823                 :     dfCenterLon = 
     824                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     825               0 :                                          LON_PROJ_ORIGIN, 0.0 );
     826                 : 
     827                 :     dfCenterLat = 
     828                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     829               0 :                                          LAT_PROJ_ORIGIN, 0.0 );
     830                 : 
     831                 :     dfFalseEasting = 
     832                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     833               0 :                                          FALSE_EASTING, 0.0 );
     834                 : 
     835                 :     dfFalseNorthing = 
     836                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     837               0 :                                          FALSE_NORTHING, 0.0 );
     838                 : 
     839                 :     /*
     840                 :     dfLonOrig =
     841                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     842                 :                                          LON_PROJ_ORIGIN, 0.0 );
     843                 : 
     844                 :     dfLatOrig =
     845                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     846                 :                                          LAT_PROJ_ORIGIN, 0.0 );
     847                 : 
     848                 :     dfScaleFactorOrig = 
     849                 :         poDS->FetchCopyParm( szGridMappingValue,
     850                 :            SCALE_FACTOR_ORIGN, 0.0 );
     851                 : 
     852                 :     dfProjXOrig =
     853                 :         poDS->FetchCopyParm( szGridMappingValue,
     854                 :            PROJ_X_ORIGIN, 0.0 );
     855                 : 
     856                 :     dfProjYOrig =
     857                 :         poDS->FetchCopyParm( szGridMappingValue,
     858                 :            PROJ_Y_ORIGIN, 0.0 );
     859                 : 
     860                 :     dfFalseEasting = 
     861                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     862                 :                                          FALSE_EASTING, 0.0 );
     863                 : 
     864                 :     dfFalseNorthing = 
     865                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     866                 :                                          FALSE_NORTHING, 0.0 );
     867                 :     */
     868               0 :     oSRS.SetProjCS( "LAEA (WGS84) " );
     869               0 :     oSRS.SetWellKnownGeogCS( "WGS84" );
     870                 : 
     871                 :     oSRS.SetLAEA( dfCenterLat, dfCenterLon,
     872               0 :             dfFalseEasting, dfFalseNorthing );
     873                 :     
     874                 : 
     875                 :       }
     876                 : 
     877                 : 
     878                 : /* -------------------------------------------------------------------- */
     879                 : /*      Lambert conformal conic                                         */
     880                 : /* -------------------------------------------------------------------- */
     881               7 :       else if( EQUAL( pszValue, L_C_CONIC ) ) {
     882                 :     
     883                 :     dfStdP1 = 
     884                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     885               0 :                                          STD_PARALLEL_1, 0.0 );
     886                 : 
     887                 :     dfStdP2 = 
     888                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     889               0 :                                          STD_PARALLEL_2, 0.0 );
     890                 : 
     891                 :     dfCenterLon = 
     892                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     893               0 :                                          LONG_CENTRAL_MERIDIAN, 0.0 );
     894                 : 
     895                 :     dfCenterLat = 
     896                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     897               0 :                                          LAT_PROJ_ORIGIN, 0.0 );
     898                 : 
     899                 :     dfFalseEasting = 
     900                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     901               0 :                                          FALSE_EASTING, 0.0 );
     902                 : 
     903                 :     dfFalseNorthing = 
     904                 :                     poDS->FetchCopyParm( szGridMappingValue, 
     905               0 :                                          FALSE_NORTHING, 0.0 );
     906                 :     
     907               0 :     oSRS.SetWellKnownGeogCS( "WGS84" );
     908                 :     oSRS.SetLCC( dfStdP1, dfStdP2, dfCenterLat, dfCenterLon,
     909               0 :            dfFalseEasting, dfFalseNorthing );
     910                 : 
     911                 :       }
     912                 : /* -------------------------------------------------------------------- */
     913                 : /*      Is this Latitude/Longitude Grid                                 */
     914                 : /* -------------------------------------------------------------------- */
     915                 :       
     916               0 :   } else if( EQUAL( szDimNameX,"lon" ) ) {
     917               0 :       oSRS.SetWellKnownGeogCS( "WGS84" );
     918                 : 
     919                 :   } else {
     920                 :       // This would be too indiscrimant.  But we should set
     921                 :       // it if we know the data is geographic.
     922                 :       //oSRS.SetWellKnownGeogCS( "WGS84" );
     923                 :   }
     924                 :     }
     925                 : /* -------------------------------------------------------------------- */
     926                 : /*      Read projection coordinates                                     */
     927                 : /* -------------------------------------------------------------------- */
     928                 : 
     929              13 :     nc_inq_varid( cdfid, poDS->papszDimName[nDimXid], &nVarDimXID );
     930              13 :     nc_inq_varid( cdfid, poDS->papszDimName[nDimYid], &nVarDimYID );
     931                 :     
     932              13 :     if( ( nVarDimXID != -1 ) && ( nVarDimYID != -1 ) ) {
     933               2 :   pdfXCoord = (double *) CPLCalloc( xdim, sizeof(double) );
     934               2 :   pdfYCoord = (double *) CPLCalloc( ydim, sizeof(double) );
     935                 :     
     936                 : /* -------------------------------------------------------------------- */
     937                 : /*      Is pixel spacing is uniform accross the map?                    */
     938                 : /* -------------------------------------------------------------------- */
     939               2 :   start[0] = 0;
     940               2 :   edge[0]  = xdim;
     941                 :   
     942                 :   status = nc_get_vara_double( cdfid, nVarDimXID, 
     943               2 :              start, edge, pdfXCoord);
     944               2 :   edge[0]  = ydim;
     945                 :   status = nc_get_vara_double( cdfid, nVarDimYID, 
     946               2 :                                      start, edge, pdfYCoord);
     947                 : 
     948                 : /* -------------------------------------------------------------------- */
     949                 : /*      Check Longitude                                                 */
     950                 : /* -------------------------------------------------------------------- */
     951                 : 
     952               2 :   nSpacingBegin   = (int) poDS->rint((pdfXCoord[1]-pdfXCoord[0]) * 1000);
     953                 :   
     954               2 :   nSpacingMiddle  = (int) poDS->rint((pdfXCoord[xdim / 2] - 
     955               2 :                                             pdfXCoord[(xdim / 2) + 1]) * 1000);
     956                 :   
     957               2 :   nSpacingLast    = (int) poDS->rint((pdfXCoord[xdim - 2] - 
     958               2 :                                             pdfXCoord[xdim-1]) * 1000);
     959                 :   
     960               2 :   if( ( abs( nSpacingBegin )  ==  abs( nSpacingLast )     )  &&
     961                 :       ( abs( nSpacingBegin )  ==  abs( nSpacingMiddle )   ) &&
     962                 :       ( abs( nSpacingMiddle ) ==  abs( nSpacingLast )     ) ) {
     963                 : 
     964                 : /* -------------------------------------------------------------------- */
     965                 : /*      Longitude is equaly spaced, check lattitde                      */
     966                 : /* -------------------------------------------------------------------- */
     967               1 :       nSpacingBegin   = (int) poDS->rint((pdfYCoord[1]-pdfYCoord[0]) * 
     968               1 :                  1000); 
     969                 :       
     970               1 :       nSpacingMiddle  = (int) poDS->rint((pdfYCoord[ydim / 2] - 
     971               1 :             pdfYCoord[(ydim / 2) + 1]) * 
     972               1 :                  1000);
     973                 :       
     974               1 :       nSpacingLast    = (int) poDS->rint((pdfYCoord[ydim - 2] - 
     975               1 :             pdfYCoord[ydim-1]) * 
     976               1 :                  1000);
     977                 : 
     978                 :         
     979                 : /* -------------------------------------------------------------------- */
     980                 : /*   For Latitude  we allow an error of 0.1 degrees for gaussion        */
     981                 : /*   gridding                                                           */
     982                 : /* -------------------------------------------------------------------- */
     983                 : 
     984               1 :       if((( abs( abs(nSpacingBegin) - abs(nSpacingLast) ) )   < 100 ) &&
     985                 :          (( abs( abs(nSpacingBegin) -  abs(nSpacingMiddle) ) ) < 100 ) &&
     986                 :          (( abs( abs(nSpacingMiddle) - abs(nSpacingLast) ) )   < 100) ) {
     987                 : 
     988               1 :     if( ( abs( nSpacingBegin )  !=  abs( nSpacingLast )     )  ||
     989                 :         ( abs( nSpacingBegin )  !=  abs( nSpacingMiddle )   ) ||
     990                 :         ( abs( nSpacingMiddle ) !=  abs( nSpacingLast )     ) ) {
     991                 :         
     992               0 :         CPLError(CE_Warning, 1,"Latitude grid not spaced evenly.\nSeting projection for grid spacing is within 0.1 degrees threshold.\n");
     993                 : 
     994                 :     }
     995                 : /* -------------------------------------------------------------------- */
     996                 : /*      We have gridded data s we can set the Gereferencing info.       */
     997                 : /* -------------------------------------------------------------------- */
     998                 : 
     999                 : /* -------------------------------------------------------------------- */
    1000                 : /*      Enable GeoTransform                                             */
    1001                 : /* -------------------------------------------------------------------- */
    1002                 :                 /* ----------------------------------------------------------*/
    1003                 :                 /*    In the following "actual_range" and "node_offset"      */
    1004                 :                 /*    are attributes used by netCDF files created by GMT.    */
    1005                 :                 /*    If we find them we know how to proceed. Else, use      */
    1006                 :                 /*    the original algorithm.                                */
    1007                 :                 /* --------------------------------------------------------- */
    1008                 :                 double  dummy[2], xMinMax[2], yMinMax[2];
    1009               1 :                 int node_offset = 0;
    1010                 : 
    1011               1 :                 poDS->bGotGeoTransform = TRUE;
    1012                 : 
    1013               1 :                 nc_get_att_int (cdfid, NC_GLOBAL, "node_offset", &node_offset);
    1014                 : 
    1015               1 :                 if (!nc_get_att_double (cdfid, nVarDimXID, "actual_range", dummy)) {
    1016               1 :                     xMinMax[0] = dummy[0];    
    1017               1 :                     xMinMax[1] = dummy[1];
    1018                 :                 }
    1019                 :                 else {
    1020               0 :                     xMinMax[0] = pdfXCoord[0];
    1021               0 :                     xMinMax[1] = pdfXCoord[xdim-1];
    1022               0 :                     node_offset = 0;
    1023                 :                 }
    1024                 : 
    1025               1 :                 if (!nc_get_att_double (cdfid, nVarDimYID, "actual_range", dummy)) {
    1026               1 :                     yMinMax[0] = dummy[0];    
    1027               1 :                     yMinMax[1] = dummy[1];
    1028                 :                 }
    1029                 :                 else {
    1030               0 :                     yMinMax[0] = pdfYCoord[0];  
    1031               0 :                     yMinMax[1] = pdfYCoord[ydim-1];
    1032               0 :                     node_offset = 0;
    1033                 :                 }
    1034                 :                 /* for CF-1 conventions, assume bottom first */
    1035               1 :                 if( EQUAL( szDimNameY, "lat" ) && pdfYCoord[0] < pdfYCoord[1] )
    1036               0 :                     poDS->bBottomUp = TRUE;
    1037                 : 
    1038                 :                 // Check for reverse order of y-coordinate
    1039               1 :                 if ( yMinMax[0] > yMinMax[1] ) {
    1040               0 :                     dummy[0] = yMinMax[1];
    1041               0 :                     dummy[1] = yMinMax[0];
    1042               0 :                     yMinMax[0] = dummy[0];
    1043               0 :                     yMinMax[1] = dummy[1];
    1044                 :                 }
    1045                 : 
    1046               1 :                 poDS->adfGeoTransform[0] = xMinMax[0];
    1047               1 :                 poDS->adfGeoTransform[2] = 0;
    1048               1 :                 poDS->adfGeoTransform[3] = yMinMax[1];
    1049               1 :                 poDS->adfGeoTransform[4] = 0;
    1050               1 :                 poDS->adfGeoTransform[1] = ( xMinMax[1] - xMinMax[0] ) / 
    1051               1 :                     ( poDS->nRasterXSize + (node_offset - 1) );
    1052               1 :                 poDS->adfGeoTransform[5] = ( yMinMax[0] - yMinMax[1] ) / 
    1053               1 :                     ( poDS->nRasterYSize + (node_offset - 1) );
    1054                 : 
    1055                 : /* -------------------------------------------------------------------- */
    1056                 : /*     Compute the center of the pixel                                  */
    1057                 : /* -------------------------------------------------------------------- */
    1058               1 :                 if ( !node_offset ) { // Otherwise its already the pixel center
    1059               1 :                     poDS->adfGeoTransform[0] -= (poDS->adfGeoTransform[1] / 2);
    1060               1 :                     poDS->adfGeoTransform[3] -= (poDS->adfGeoTransform[5] / 2);
    1061                 :                 }
    1062                 : 
    1063               1 :                 oSRS.exportToWkt( &(poDS->pszProjection) );
    1064                 :         
    1065                 :       } 
    1066                 :   }
    1067                 : 
    1068               2 :   CPLFree( pdfXCoord );
    1069               2 :   CPLFree( pdfYCoord );
    1070                 :     }
    1071                 : 
    1072                 : 
    1073                 : /* -------------------------------------------------------------------- */
    1074                 : /*      Is this a netCDF file created by GDAL?                          */
    1075                 : /* -------------------------------------------------------------------- */
    1076              13 :     if( !EQUAL( szGridMappingValue, "" )  ) {
    1077               9 :   strcpy( szTemp,szGridMappingValue);
    1078               9 :   strcat( szTemp, "#" );
    1079               9 :   strcat( szTemp, "spatial_ref");
    1080               9 :   pszWKT = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1081                 :   
    1082               9 :   if( pszWKT != NULL ) {
    1083                 :       
    1084               9 :       pszProjection = CPLStrdup( pszWKT );
    1085                 :       
    1086               9 :       strcpy(szTemp,szGridMappingValue);
    1087               9 :       strcat( szTemp, "#" );
    1088               9 :       strcat( szTemp, "GeoTransform");
    1089                 :       
    1090               9 :       pszGeoTransform = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1091                 :       
    1092                 : /* -------------------------------------------------------------------- */
    1093                 : /*      Look for GeoTransform Array                                     */
    1094                 : /* -------------------------------------------------------------------- */
    1095                 : 
    1096               9 :       if( pszGeoTransform != NULL ) {
    1097                 :     papszGeoTransform = CSLTokenizeString2( pszGeoTransform,
    1098                 :               " ", 
    1099               9 :               CSLT_HONOURSTRINGS );
    1100               9 :     poDS->bGotGeoTransform   = TRUE;
    1101                 :     
    1102               9 :     poDS->adfGeoTransform[0] = atof( papszGeoTransform[0] );
    1103               9 :     poDS->adfGeoTransform[1] = atof( papszGeoTransform[1] );
    1104               9 :     poDS->adfGeoTransform[2] = atof( papszGeoTransform[2] );
    1105               9 :     poDS->adfGeoTransform[3] = atof( papszGeoTransform[3] );
    1106               9 :     poDS->adfGeoTransform[4] = atof( papszGeoTransform[4] );
    1107               9 :     poDS->adfGeoTransform[5] = atof( papszGeoTransform[5] );
    1108                 : /* -------------------------------------------------------------------- */
    1109                 : /*      Look for corner array values                                    */
    1110                 : /* -------------------------------------------------------------------- */
    1111                 :       } else {
    1112                 :     double dfNN, dfSN, dfEE, dfWE;
    1113               0 :     strcpy(szTemp,szGridMappingValue);
    1114               0 :     strcat( szTemp, "#" );
    1115               0 :     strcat( szTemp, "Northernmost_Northing");
    1116               0 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1117                 :     
    1118               0 :     if( pszValue != NULL ) {
    1119               0 :         dfNN = atof( pszValue );
    1120                 :     }
    1121               0 :     strcpy(szTemp,szGridMappingValue);
    1122               0 :     strcat( szTemp, "#" );
    1123               0 :     strcat( szTemp, "Southernmost_Northing");
    1124               0 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1125                 :     
    1126               0 :     if( pszValue != NULL ) {
    1127               0 :         dfSN = atof( pszValue );
    1128                 :     }
    1129                 :     
    1130               0 :     strcpy(szTemp,szGridMappingValue);
    1131               0 :     strcat( szTemp, "#" );
    1132               0 :     strcat( szTemp, "Easternmost_Easting");
    1133               0 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1134                 :     
    1135               0 :     if( pszValue != NULL ) {
    1136               0 :         dfEE = atof( pszValue );
    1137                 :     }
    1138                 :     
    1139               0 :     strcpy(szTemp,szGridMappingValue);
    1140               0 :     strcat( szTemp, "#" );
    1141               0 :     strcat( szTemp, "Westernmost_Easting");
    1142               0 :     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);
    1143                 :     
    1144               0 :     if( pszValue != NULL ) {
    1145               0 :         dfWE = atof( pszValue );
    1146                 :     }
    1147                 :     
    1148               0 :     adfGeoTransform[0] = dfWE;
    1149                 :     adfGeoTransform[1] = (dfEE - dfWE) / 
    1150               0 :         ( poDS->GetRasterXSize() - 1 );
    1151               0 :     adfGeoTransform[2] = 0.0;
    1152               0 :     adfGeoTransform[3] = dfNN;
    1153               0 :     adfGeoTransform[4] = 0.0;
    1154                 :     adfGeoTransform[5] = (dfSN - dfNN) / 
    1155               0 :         ( poDS->GetRasterYSize() - 1 );
    1156                 : /* -------------------------------------------------------------------- */
    1157                 : /*     Compute the center of the pixel                                  */
    1158                 : /* -------------------------------------------------------------------- */
    1159                 :                 adfGeoTransform[0] = dfWE
    1160               0 :                     - (adfGeoTransform[1] / 2);
    1161                 : 
    1162                 :                 adfGeoTransform[3] = dfNN
    1163               0 :                     - (adfGeoTransform[5] / 2);
    1164                 : 
    1165                 : 
    1166               0 :     bGotGeoTransform = TRUE;
    1167                 :       }
    1168               9 :       CSLDestroy( papszGeoTransform );
    1169                 :   }
    1170              13 :     }
    1171                 : 
    1172              13 : }
    1173                 : /************************************************************************/
    1174                 : /*                          GetGeoTransform()                           */
    1175                 : /************************************************************************/
    1176                 : 
    1177              12 : CPLErr netCDFDataset::GetGeoTransform( double * padfTransform )
    1178                 : 
    1179                 : {
    1180              12 :     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1181              12 :     if( bGotGeoTransform )
    1182               8 :         return CE_None;
    1183                 :     else
    1184               4 :         return GDALPamDataset::GetGeoTransform( padfTransform );;
    1185                 : }
    1186                 : 
    1187                 : /************************************************************************/
    1188                 : /*                                rint()                                */
    1189                 : /************************************************************************/
    1190                 : 
    1191               9 : double netCDFDataset::rint( double dfX)
    1192                 : {
    1193               9 :     if( dfX > 0 ) {
    1194               3 :         int nX = (int) (dfX+0.5);
    1195               3 :         if( nX % 2 ) {
    1196               0 :             double dfDiff = dfX - (double)nX;
    1197               0 :             if( dfDiff == -0.5 )
    1198               0 :                 return double( nX-1 );
    1199                 :         }
    1200               3 :         return double( nX );
    1201                 :     } else {
    1202               6 :         int nX= (int) (dfX-0.5);
    1203               6 :         if( nX % 2 ) {
    1204               1 :             double dfDiff = dfX - (double)nX;
    1205               1 :             if( dfDiff == 0.5 )
    1206               0 :                 return double(nX+1);
    1207                 :         }
    1208               6 :         return double(nX);
    1209                 :     }
    1210                 : }
    1211                 : 
    1212                 : /************************************************************************/
    1213                 : /*                        ReadAttributes()                              */
    1214                 : /************************************************************************/
    1215              67 : CPLErr netCDFDataset::SafeStrcat(char** ppszDest, char* pszSrc, size_t* nDestSize)
    1216                 : {
    1217                 :     /* Reallocate the data string until the content fits */
    1218             235 :     while(*nDestSize < (strlen(*ppszDest) + strlen(pszSrc) + 1)) {
    1219             101 :         (*nDestSize) *= 2;
    1220             101 :         *ppszDest = (char*) CPLRealloc((void*) *ppszDest, *nDestSize);
    1221                 :     }
    1222              67 :     strcat(*ppszDest, pszSrc);
    1223                 :     
    1224              67 :     return CE_None;
    1225                 : }
    1226                 : 
    1227              49 : CPLErr netCDFDataset::ReadAttributes( int cdfid, int var)
    1228                 : 
    1229                 : {
    1230                 :     char    szAttrName[ NC_MAX_NAME ];
    1231                 :     char    szVarName [ NC_MAX_NAME ];
    1232                 :     char    szMetaName[ NC_MAX_NAME * 2 ];
    1233              49 :     char    *pszMetaTemp = NULL;
    1234                 :     size_t  nMetaTempSize;
    1235                 :     nc_type nAttrType;
    1236                 :     size_t  nAttrLen, m;
    1237                 :     int     nbAttr;
    1238                 :     char    szTemp[ MAX_STR_LEN ];
    1239                 : 
    1240              49 :     nc_inq_varnatts( cdfid, var, &nbAttr );
    1241              49 :     if( var == NC_GLOBAL ) {
    1242              21 :   strcpy( szVarName,"NC_GLOBAL" );
    1243                 :     }
    1244                 :     else {
    1245              28 :   nc_inq_varname(  cdfid, var, szVarName );
    1246                 :     }
    1247                 : 
    1248             216 :     for( int l=0; l < nbAttr; l++) {
    1249                 :   
    1250             167 :   nc_inq_attname( cdfid, var, l, szAttrName);
    1251             167 :   sprintf( szMetaName, "%s#%s", szVarName, szAttrName  );
    1252             167 :   nc_inq_att( cdfid, var, szAttrName, &nAttrType, &nAttrLen );
    1253                 :   
    1254                 :         /* Allocate guaranteed minimum size */
    1255             167 :         nMetaTempSize = nAttrLen + 1;
    1256             167 :         pszMetaTemp = (char *) CPLCalloc( nMetaTempSize, sizeof( char ));
    1257             167 :         *pszMetaTemp = '\0';
    1258                 :   
    1259             167 :   switch (nAttrType) {
    1260                 :   case NC_CHAR:
    1261             103 :                 nc_get_att_text( cdfid, var, szAttrName, pszMetaTemp );
    1262             103 :                 pszMetaTemp[nAttrLen]='\0';
    1263             103 :       break;
    1264                 :   case NC_SHORT:
    1265                 :       short *psTemp;
    1266               2 :       psTemp = (short *) CPLCalloc( nAttrLen, sizeof( short ) );
    1267               2 :       nc_get_att_short( cdfid, var, szAttrName, psTemp );
    1268               2 :       for(m=0; m < nAttrLen-1; m++) {
    1269               0 :                     sprintf( szTemp, "%hd, ", psTemp[m] );
    1270               0 :                     SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1271                 :       }
    1272               2 :                 sprintf( szTemp, "%hd", psTemp[m] );
    1273               2 :                 SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1274               2 :       CPLFree(psTemp);
    1275               2 :       break;
    1276                 :   case NC_INT:
    1277                 :       int *pnTemp;
    1278               5 :       pnTemp = (int *) CPLCalloc( nAttrLen, sizeof( int ) );
    1279               5 :       nc_get_att_int( cdfid, var, szAttrName, pnTemp );
    1280               5 :       for(m=0; m < nAttrLen-1; m++) {
    1281               0 :                     sprintf( szTemp, "%d, ", pnTemp[m] );
    1282               0 :                     SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1283                 :       }
    1284               5 :               sprintf( szTemp, "%d", pnTemp[m] );
    1285               5 :               SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1286               5 :       CPLFree(pnTemp);
    1287               5 :       break;
    1288                 :   case NC_FLOAT:
    1289                 :       float *pfTemp;
    1290              13 :       pfTemp = (float *) CPLCalloc( nAttrLen, sizeof( float ) );
    1291              13 :       nc_get_att_float( cdfid, var, szAttrName, pfTemp );
    1292              14 :       for(m=0; m < nAttrLen-1; m++) {
    1293               1 :                     sprintf( szTemp, "%e, ", pfTemp[m] );
    1294               1 :                     SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1295                 :       }
    1296              13 :               sprintf( szTemp, "%e", pfTemp[m] );
    1297              13 :               SafeStrcat(&pszMetaTemp,szTemp, &nMetaTempSize);
    1298              13 :       CPLFree(pfTemp);
    1299              13 :       break;
    1300                 :   case NC_DOUBLE:
    1301                 :       double *pdfTemp;
    1302              44 :       pdfTemp = (double *) CPLCalloc(nAttrLen, sizeof(double));
    1303              44 :       nc_get_att_double( cdfid, var, szAttrName, pdfTemp );
    1304              46 :       for(m=0; m < nAttrLen-1; m++) {
    1305               2 :                     sprintf( szTemp, "%g, ", pdfTemp[m] );
    1306               2 :                     SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1307                 :       }
    1308              44 :               sprintf( szTemp, "%g", pdfTemp[m] );
    1309              44 :               SafeStrcat(&pszMetaTemp, szTemp, &nMetaTempSize);
    1310              44 :       CPLFree(pdfTemp);
    1311                 :       break;
    1312                 :   default:
    1313                 :       break;
    1314                 :   }
    1315                 : 
    1316                 :   papszMetadata = CSLSetNameValue(papszMetadata, 
    1317                 :           szMetaName, 
    1318             167 :                                         pszMetaTemp);
    1319             167 :         CPLFree(pszMetaTemp);
    1320                 :     }
    1321                 :   
    1322                 : 
    1323              49 :     return CE_None;
    1324                 : 
    1325                 : }
    1326                 : 
    1327                 : 
    1328                 : /************************************************************************/
    1329                 : /*                netCDFDataset::CreateSubDatasetList()                 */
    1330                 : /************************************************************************/
    1331               4 : void netCDFDataset::CreateSubDatasetList( )
    1332                 : {
    1333                 : 
    1334                 :     char         szDim[ MAX_NC_NAME ];
    1335                 :     char         szTemp[ MAX_NC_NAME ];
    1336                 :     char         szType[ MAX_NC_NAME ];
    1337                 :     char         szName[ MAX_NC_NAME ];
    1338                 :     char         szVarStdName[ MAX_NC_NAME ];
    1339                 :     int          nDims;
    1340                 :     int          nVar;
    1341                 :     int          nVarCount;
    1342                 :     int          i;
    1343                 :     nc_type      nVarType;
    1344                 :     int          *ponDimIds;
    1345                 :     size_t       nDimLen;
    1346                 :     int          nSub;
    1347                 :     nc_type      nAttype;
    1348                 :     size_t       nAttlen;
    1349                 : 
    1350                 :     netCDFDataset   *poDS;
    1351               4 :     poDS = this;
    1352                 : 
    1353               4 :     nSub=1;
    1354               4 :     nc_inq_nvars ( cdfid, &nVarCount );
    1355              22 :     for ( nVar = 0; nVar < nVarCount; nVar++ ) {
    1356                 : 
    1357              18 :   nc_inq_varndims ( cdfid, nVar, &nDims );
    1358              18 :   if( nDims >= 2 ) {
    1359              14 :       ponDimIds = (int *) CPLCalloc( nDims, sizeof( int ) );
    1360              14 :       nc_inq_vardimid ( cdfid, nVar, ponDimIds );
    1361                 :       
    1362                 : /* -------------------------------------------------------------------- */
    1363                 : /*      Create Sub dataset list                                         */
    1364                 : /* -------------------------------------------------------------------- */
    1365              14 :       szDim[0]='\0';
    1366              42 :       for( i = 0; i < nDims; i++ ) {
    1367              28 :     nc_inq_dimlen ( cdfid, ponDimIds[i], &nDimLen );
    1368              28 :     sprintf(szTemp, "%d", (int) nDimLen);
    1369              28 :     strcat(szTemp,  "x" );
    1370              28 :     strcat(szDim,   szTemp);
    1371                 :       }
    1372                 : 
    1373              14 :       nc_inq_vartype( cdfid, nVar, &nVarType );
    1374                 : /* -------------------------------------------------------------------- */
    1375                 : /*      Get rid of the last "x" character                               */
    1376                 : /* -------------------------------------------------------------------- */
    1377              14 :       szDim[strlen(szDim) - 1] = '\0';
    1378              14 :       switch( nVarType ) {
    1379                 :     
    1380                 :       case NC_BYTE:
    1381                 :       case NC_CHAR:
    1382              14 :     strcpy(szType, "8-bit character");
    1383              14 :     break;
    1384                 : 
    1385                 :       case NC_SHORT: 
    1386               0 :     strcpy(szType, "8-bit integer");
    1387               0 :     break;
    1388                 :       case NC_INT:
    1389               0 :     strcpy(szType, "16-bit integer");
    1390               0 :     break;
    1391                 :       case NC_FLOAT:
    1392               0 :     strcpy(szType, "32-bit floating-point");
    1393               0 :     break;
    1394                 :       case NC_DOUBLE:
    1395               0 :     strcpy(szType, "64-bit floating-point");
    1396                 :     break;
    1397                 : 
    1398                 :       default:
    1399                 :     break;
    1400                 :       }
    1401              14 :       nc_inq_varname  ( cdfid, nVar, szName);
    1402              14 :       nc_inq_att( cdfid, nVar, "standard_name", &nAttype, &nAttlen);
    1403              14 :       if( nc_get_att_text ( cdfid, nVar, "standard_name", 
    1404                 :           szVarStdName ) == NC_NOERR ) {
    1405               0 :     szVarStdName[nAttlen] = '\0';
    1406                 :       }
    1407                 :       else {
    1408              14 :     strcpy( szVarStdName, szName );
    1409                 :       }
    1410                 :     
    1411              14 :       sprintf( szTemp, "SUBDATASET_%d_NAME", nSub) ;
    1412                 :       
    1413                 :       poDS->papszSubDatasets =
    1414                 :     CSLSetNameValue( poDS->papszSubDatasets, szTemp,
    1415                 :          CPLSPrintf( "NETCDF:\"%s\":%s",
    1416                 :                poDS->osFilename.c_str(),
    1417              14 :                szName) ) ;
    1418                 :       
    1419              14 :       sprintf(  szTemp, "SUBDATASET_%d_DESC", nSub++ );
    1420                 : 
    1421                 :       poDS->papszSubDatasets =
    1422                 :     CSLSetNameValue( poDS->papszSubDatasets, szTemp,
    1423                 :          CPLSPrintf( "[%s] %s (%s)", 
    1424                 :                szDim,
    1425                 :                szVarStdName,
    1426              14 :                szType ) );
    1427              14 :       CPLFree(ponDimIds);
    1428                 :   }
    1429                 :     }
    1430                 : 
    1431               4 : }
    1432                 :     
    1433                 : /************************************************************************/
    1434                 : /*                                Open()                                */
    1435                 : /************************************************************************/
    1436                 : 
    1437            9496 : GDALDataset *netCDFDataset::Open( GDALOpenInfo * poOpenInfo )
    1438                 : 
    1439                 : {
    1440                 :     int          j;
    1441                 :     unsigned int k;
    1442                 :     int          nd;
    1443                 :     int          cdfid, dim_count, var, var_count;
    1444            9496 :     int          i = 0;
    1445                 :     size_t       lev_count;
    1446            9496 :     size_t       nTotLevCount = 1;
    1447            9496 :     int          nDim = 2;
    1448                 :     int          status;
    1449                 :     int          nDimID;
    1450                 :     char         attname[NC_MAX_NAME];
    1451                 :     int          ndims, nvars, ngatts, unlimdimid;
    1452            9496 :     int          nCount=0;
    1453            9496 :     int          nVarID=-1;
    1454                 : 
    1455                 : /* -------------------------------------------------------------------- */
    1456                 : /*      Does this appear to be a netcdf file?                           */
    1457                 : /* -------------------------------------------------------------------- */
    1458            9496 :     if( !EQUALN(poOpenInfo->pszFilename,"NETCDF:",7)
    1459                 :         && ( poOpenInfo->nHeaderBytes < 5 
    1460                 :              || !EQUALN((const char *) (poOpenInfo->pabyHeader),"CDF\001",5)))
    1461            9475 :         return NULL;
    1462                 : 
    1463                 : /* -------------------------------------------------------------------- */
    1464                 : /*       Check if filename start with NETCDF: tag                       */
    1465                 : /* -------------------------------------------------------------------- */
    1466                 :     netCDFDataset   *poDS;
    1467              21 :     poDS = new netCDFDataset();
    1468              21 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1469                 : 
    1470              21 :     if( EQUALN( poOpenInfo->pszFilename,"NETCDF:",7) )
    1471                 :     {
    1472                 :         char **papszName =
    1473                 :             CSLTokenizeString2( poOpenInfo->pszFilename,
    1474               3 :                                 ":", CSLT_HONOURSTRINGS|CSLT_PRESERVEESCAPES );
    1475                 :                    
    1476                 :     /* -------------------------------------------------------------------- */
    1477                 :     /*    Check for drive name in windows NETCDF:"D:\...                    */
    1478                 :     /* -------------------------------------------------------------------- */
    1479               3 :         if ( CSLCount(papszName) == 4 &&
    1480               0 :              strlen(papszName[1]) == 1 &&
    1481               0 :              (papszName[2][0] == '/' || papszName[2][0] == '\\') )
    1482                 :         {
    1483               0 :             poDS->osFilename = papszName[1];
    1484               0 :             poDS->osFilename += ':';
    1485               0 :             poDS->osFilename += papszName[2];
    1486               0 :             poDS->osSubdatasetName = papszName[3];
    1487               0 :             poDS->bTreatAsSubdataset = TRUE;
    1488               0 :             CSLDestroy( papszName );
    1489                 :         }
    1490               3 :         else if( CSLCount(papszName) == 3 )
    1491                 :         {
    1492               3 :             poDS->osFilename = papszName[1];
    1493               6 :             poDS->osSubdatasetName = papszName[2];
    1494               3 :             poDS->bTreatAsSubdataset = TRUE;
    1495               3 :             CSLDestroy( papszName );
    1496                 :       }
    1497                 :         else
    1498                 :         {
    1499               0 :             CSLDestroy( papszName );
    1500               0 :             delete poDS;
    1501                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1502               0 :                       "Failed to parse NETCDF: prefix string into expected three fields." );
    1503               0 :             return NULL;
    1504                 :         }
    1505                 :     }
    1506                 :     else 
    1507                 :     {
    1508              18 :   poDS->osFilename = poOpenInfo->pszFilename;
    1509              18 :         poDS->bTreatAsSubdataset = FALSE;
    1510                 :     }
    1511                 : 
    1512                 : /* -------------------------------------------------------------------- */
    1513                 : /*      Try opening the dataset.                                        */
    1514                 : /* -------------------------------------------------------------------- */
    1515              21 :     if( nc_open( poDS->osFilename, NC_NOWRITE, &cdfid ) != NC_NOERR ) {
    1516               0 :   delete poDS;
    1517               0 :         return NULL;
    1518                 :     }
    1519                 : /* -------------------------------------------------------------------- */
    1520                 : /*      Is this a real netCDF file?                                     */
    1521                 : /* -------------------------------------------------------------------- */
    1522              21 :     status = nc_inq(cdfid, &ndims, &nvars, &ngatts, &unlimdimid);
    1523              21 :     if( status != NC_NOERR ) {
    1524               0 :         delete poDS;
    1525               0 :         return NULL;
    1526                 :     }
    1527                 :     
    1528                 : /* -------------------------------------------------------------------- */
    1529                 : /*      Confirm the requested access is supported.                      */
    1530                 : /* -------------------------------------------------------------------- */
    1531              21 :     if( poOpenInfo->eAccess == GA_Update )
    1532                 :     {
    1533                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1534                 :                   "The NETCDF driver does not support update access to existing"
    1535               0 :                   " datasets.\n" );
    1536               0 :         nc_close( cdfid );
    1537               0 :         delete poDS;
    1538               0 :         return NULL;
    1539                 :     }
    1540                 :     
    1541                 : /* -------------------------------------------------------------------- */
    1542                 : /*      Does the request variable exist?                                */
    1543                 : /* -------------------------------------------------------------------- */
    1544              21 :     if( poDS->bTreatAsSubdataset )
    1545                 :     {
    1546               3 :   status = nc_inq_varid( cdfid, poDS->osSubdatasetName, &var);
    1547               3 :   if( status != NC_NOERR ) {
    1548                 :       CPLError( CE_Warning, CPLE_AppDefined, 
    1549                 :           "%s is a netCDF file, but %s is not a variable.",
    1550                 :           poOpenInfo->pszFilename, 
    1551               0 :           poDS->osSubdatasetName.c_str() );
    1552                 :       
    1553               0 :       nc_close( cdfid );
    1554               0 :             delete poDS;
    1555               0 :       return NULL;
    1556                 :   }
    1557                 :     }
    1558                 : 
    1559              21 :     if( nc_inq_ndims( cdfid, &dim_count ) != NC_NOERR || dim_count < 2 )
    1560                 :     {
    1561                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    1562                 :                   "%s is a netCDF file, but not in GMT configuration.",
    1563               0 :                   poOpenInfo->pszFilename );
    1564                 : 
    1565               0 :         nc_close( cdfid );
    1566               0 :         delete poDS;
    1567               0 :         return NULL;
    1568                 :     }
    1569                 : 
    1570              21 :     CPLDebug( "GDAL_netCDF", "dim_count = %d\n", dim_count );
    1571                 : 
    1572              21 :     if( (status = nc_get_att_text( cdfid, NC_GLOBAL, "Conventions",
    1573                 :            attname )) != NC_NOERR ) {
    1574                 :   CPLError( CE_Warning, CPLE_AppDefined, 
    1575               3 :       "No UNIDATA NC_GLOBAL:Conventions attribute");
    1576                 :         /* note that 'Conventions' is always capital 'C' in CF spec*/
    1577                 :     }
    1578                 : 
    1579                 : 
    1580                 : /* -------------------------------------------------------------------- */
    1581                 : /*      Create band information objects.                                */
    1582                 : /* -------------------------------------------------------------------- */
    1583              21 :     if ( nc_inq_nvars ( cdfid, &var_count) != NC_NOERR )
    1584                 :     {
    1585               0 :         delete poDS;
    1586               0 :   return NULL;
    1587                 :     }    
    1588                 :     
    1589              21 :     CPLDebug( "GDAL_netCDF", "var_count = %d\n", var_count );
    1590                 : 
    1591                 : /* -------------------------------------------------------------------- */
    1592                 : /*      Create a corresponding GDALDataset.                             */
    1593                 : /*      Create Netcdf Subdataset if filename as NETCDF tag              */
    1594                 : /* -------------------------------------------------------------------- */
    1595              21 :     poDS->cdfid = cdfid;
    1596                 : 
    1597              21 :     poDS->ReadAttributes( cdfid, NC_GLOBAL );  
    1598                 : 
    1599                 : /* -------------------------------------------------------------------- */
    1600                 : /*  Verify if only one variable has 2 dimensions                        */
    1601                 : /* -------------------------------------------------------------------- */
    1602              73 :     for ( j = 0; j < nvars; j++ ) {
    1603                 : 
    1604              52 :   nc_inq_varndims ( cdfid, j, &ndims );
    1605              52 :   if( ndims >= 2 ) {
    1606              29 :       nVarID=j;
    1607              29 :       nCount++;
    1608                 :   }
    1609                 :     }
    1610                 : 
    1611                 : /* -------------------------------------------------------------------- */
    1612                 : /*      We have more than one variable with 2 dimensions in the         */
    1613                 : /*      file, then treat this as a subdataset container dataset.        */
    1614                 : /* -------------------------------------------------------------------- */
    1615              21 :     if( (nCount > 1) && !poDS->bTreatAsSubdataset )
    1616                 :     {
    1617               4 :   poDS->CreateSubDatasetList();
    1618               4 :   poDS->SetMetadata( poDS->papszMetadata );
    1619               4 :         poDS->TryLoadXML();
    1620               4 :   return( poDS );
    1621                 :     }
    1622                 : 
    1623                 : /* -------------------------------------------------------------------- */
    1624                 : /*      If we are not treating things as a subdataset, then capture     */
    1625                 : /*      the name of the single available variable as the subdataset.    */
    1626                 : /* -------------------------------------------------------------------- */
    1627              17 :     if( !poDS->bTreatAsSubdataset ) // nCount must be 1!
    1628                 :     {
    1629                 :   char szVarName[NC_MAX_NAME];
    1630                 : 
    1631              14 :   nc_inq_varname( cdfid, nVarID, szVarName);
    1632              14 :         poDS->osSubdatasetName = szVarName;
    1633                 :     }
    1634                 : 
    1635                 : /* -------------------------------------------------------------------- */
    1636                 : /*      Open the NETCDF subdataset NETCDF:"filename":subdataset         */
    1637                 : /* -------------------------------------------------------------------- */
    1638                 : 
    1639              17 :     var=-1;
    1640              17 :     nc_inq_varid( cdfid, poDS->osSubdatasetName, &var);
    1641              17 :     nd = 0;
    1642              17 :     nc_inq_varndims ( cdfid, var, &nd );
    1643                 : 
    1644              17 :     poDS->paDimIds = (int *)CPLCalloc(nd, sizeof( int ) );
    1645              17 :     poDS->panBandDimPos = ( int * ) CPLCalloc( nd, sizeof( int ) );
    1646                 : 
    1647              17 :     nc_inq_vardimid( cdfid, var, poDS->paDimIds );
    1648                 : 
    1649                 :   
    1650                 : /* -------------------------------------------------------------------- */
    1651                 : /*      Check fi somebody tried to pass a variable with less than 2D    */
    1652                 : /* -------------------------------------------------------------------- */
    1653                 : 
    1654              17 :     if ( nd < 2 ) {
    1655               4 :   CPLFree( poDS->paDimIds );
    1656               4 :   CPLFree( poDS->panBandDimPos );
    1657               4 :         delete poDS;
    1658               4 :   return NULL;
    1659                 :     }
    1660                 : 
    1661                 : /* -------------------------------------------------------------------- */
    1662                 : /*      CF-1 Convention                                                 */
    1663                 : /*      dimensions to appear in the relative order T, then Z, then Y,   */
    1664                 : /*      then X  to the file. All other dimensions should, whenever      */
    1665                 : /*      possible, be placed to the left of the spatiotemporal           */
    1666                 : /*      dimensions.                                                     */
    1667                 : /* -------------------------------------------------------------------- */
    1668                 : 
    1669                 : /* -------------------------------------------------------------------- */
    1670                 : /*      Get X dimensions information                                    */
    1671                 : /* -------------------------------------------------------------------- */
    1672              13 :     poDS->nDimXid = poDS->paDimIds[nd-1];
    1673              13 :     nc_inq_dimlen ( cdfid, poDS->nDimXid, &poDS->xdim );
    1674              13 :     poDS->nRasterXSize = poDS->xdim;
    1675                 : 
    1676                 : /* -------------------------------------------------------------------- */
    1677                 : /*      Get Y dimension information                                     */
    1678                 : /* -------------------------------------------------------------------- */
    1679              13 :     poDS->nDimYid = poDS->paDimIds[nd-2];
    1680              13 :     nc_inq_dimlen ( cdfid, poDS->nDimYid, &poDS->ydim );
    1681              13 :     poDS->nRasterYSize = poDS->ydim;
    1682                 : 
    1683                 : 
    1684              45 :     for( j=0,k=0; j < nd; j++ ){
    1685              32 :   if( poDS->paDimIds[j] == poDS->nDimXid ){ 
    1686              13 :       poDS->panBandDimPos[0] = j;         // Save Position of XDim
    1687              13 :       k++;
    1688                 :   }
    1689              32 :   if( poDS->paDimIds[j] == poDS->nDimYid ){
    1690              13 :       poDS->panBandDimPos[1] = j;         // Save Position of YDim
    1691              13 :       k++;
    1692                 :   }
    1693                 :     }
    1694                 : /* -------------------------------------------------------------------- */
    1695                 : /*      X and Y Dimension Ids were not found!                           */
    1696                 : /* -------------------------------------------------------------------- */
    1697              13 :     if( k != 2 ) {
    1698               0 :   CPLFree( poDS->paDimIds );
    1699               0 :   CPLFree( poDS->panBandDimPos );
    1700               0 :   return NULL;
    1701                 :     }
    1702                 :       
    1703                 : /* -------------------------------------------------------------------- */
    1704                 : /*      Read Metadata for this variable                                 */
    1705                 : /* -------------------------------------------------------------------- */
    1706              13 :     poDS->ReadAttributes( cdfid, var );
    1707                 :   
    1708                 : /* -------------------------------------------------------------------- */
    1709                 : /*      Read Metadata for each dimension                                */
    1710                 : /* -------------------------------------------------------------------- */
    1711                 :     
    1712              45 :     for( j=0; j < dim_count; j++ ){
    1713              32 :   nc_inq_dimname( cdfid, j, poDS->papszDimName[j] );
    1714              32 :   status = nc_inq_varid( cdfid, poDS->papszDimName[j], &nDimID );
    1715              32 :   if( status == NC_NOERR ) {
    1716               6 :       poDS->ReadAttributes( cdfid, nDimID );
    1717                 :   }
    1718                 :     }
    1719                 : 
    1720              13 :     poDS->SetProjection( var );
    1721              13 :     poDS->SetMetadata( poDS->papszMetadata );
    1722                 : 
    1723                 : /* -------------------------------------------------------------------- */
    1724                 : /*      Create bands                                                    */
    1725                 : /* -------------------------------------------------------------------- */
    1726              13 :     poDS->panBandZLev = (int *)CPLCalloc( nd-2, sizeof( int ) );
    1727                 :     
    1728              13 :     nTotLevCount = 1;
    1729              13 :     if ( dim_count > 2 ) {
    1730               2 :   nDim=2;
    1731              12 :   for( j=0; j < nd; j++ ){
    1732              18 :       if( ( poDS->paDimIds[j] != poDS->nDimXid ) && 
    1733               8 :     ( poDS->paDimIds[j] != poDS->nDimYid ) ){
    1734               6 :     nc_inq_dimlen ( cdfid, poDS->paDimIds[j], &lev_count );
    1735               6 :     nTotLevCount *= lev_count;
    1736               6 :     poDS->panBandZLev[ nDim-2 ] = lev_count;
    1737               6 :     poDS->panBandDimPos[ nDim++ ] = j;  //Save Position of ZDim
    1738                 :       }
    1739                 :   }
    1740                 :     }
    1741              13 :     i=0;
    1742                 : 
    1743              80 :     for ( unsigned int lev = 0; lev < nTotLevCount ; lev++ ) {
    1744                 :   char ** papszToken;
    1745              27 :   papszToken=NULL;
    1746                 : 
    1747                 :   netCDFRasterBand *poBand =
    1748                 :             new netCDFRasterBand(poDS, var, nDim, lev,
    1749              27 :                                  poDS->panBandZLev, poDS->panBandDimPos, i+1 );
    1750                 : 
    1751              27 :   poDS->SetBand( i+1, poBand );
    1752              27 :   i++;
    1753                 :    } 
    1754                 : 
    1755              13 :     CPLFree( poDS->paDimIds );
    1756              13 :     CPLFree( poDS->panBandDimPos );
    1757              13 :     CPLFree( poDS->panBandZLev );
    1758                 :     
    1759              13 :     poDS->nBands = i;
    1760                 : 
    1761                 :     // Handle angular geographic coordinates here
    1762                 : 
    1763                 : /* -------------------------------------------------------------------- */
    1764                 : /*      Initialize any PAM information.                                 */
    1765                 : /* -------------------------------------------------------------------- */
    1766              13 :     if( poDS->bTreatAsSubdataset )
    1767                 :     {
    1768               3 :         poDS->SetPhysicalFilename( poDS->osFilename );
    1769               3 :         poDS->SetSubdatasetName( poDS->osSubdatasetName );
    1770                 :     }
    1771                 :     
    1772              13 :     poDS->TryLoadXML();
    1773                 : 
    1774              13 :     if( poDS->bTreatAsSubdataset )
    1775               3 :         poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
    1776                 :     else
    1777              10 :         poDS->oOvManager.Initialize( poDS, poDS->osFilename );
    1778                 : 
    1779              13 :     return( poDS );
    1780                 : }
    1781                 : 
    1782                 : 
    1783                 : /************************************************************************/
    1784                 : /*                            CopyMetadata()                            */
    1785                 : /*                                                                      */
    1786                 : /*      Create a copy of metadata for NC_GLOBAL or a variable           */
    1787                 : /************************************************************************/
    1788                 : 
    1789              42 : void CopyMetadata( void  *poDS, int fpImage, int CDFVarID ) {
    1790                 : 
    1791                 : /* -------------------------------------------------------------------- */
    1792                 : /*      Add CF-1.0 Conventions Global attribute                         */
    1793                 : /* -------------------------------------------------------------------- */
    1794                 :     char       **papszMetadata;
    1795                 :     char       **papszFieldData;
    1796                 :     const char *pszField;
    1797                 :     char       szMetaName[ MAX_STR_LEN ];
    1798                 :     char       szMetaValue[ MAX_STR_LEN ];
    1799                 :     int        nDataLength;
    1800                 :     int        nItems;
    1801                 : 
    1802                 : /* -------------------------------------------------------------------- */
    1803                 : /*      Global metadata are set with NC_GLOBAL as the varid             */
    1804                 : /* -------------------------------------------------------------------- */
    1805                 :     
    1806              42 :     if( CDFVarID == NC_GLOBAL ) {
    1807                 : 
    1808              16 :   papszMetadata = GDALGetMetadata( (GDALDataset *) poDS,"");
    1809                 : 
    1810                 :   nc_put_att_text( fpImage, 
    1811                 :        NC_GLOBAL, 
    1812                 :        "Conventions", 
    1813                 :        6,
    1814              16 :        "CF-1.0" );
    1815                 :     } else {
    1816                 : 
    1817              26 :   papszMetadata = GDALGetMetadata( (GDALRasterBandH) poDS, NULL );
    1818                 : 
    1819                 :     }
    1820                 : 
    1821              42 :     nItems = CSLCount( papszMetadata );             
    1822                 :     
    1823              57 :     for(int k=0; k < nItems; k++ ) {
    1824              15 :   pszField = CSLGetField( papszMetadata, k );
    1825                 :   papszFieldData = CSLTokenizeString2 (pszField, "=", 
    1826              15 :                CSLT_HONOURSTRINGS );
    1827              15 :   if( papszFieldData[1] != NULL ) {
    1828              15 :       strcpy( szMetaName,  papszFieldData[ 0 ] );
    1829              15 :       strcpy( szMetaValue, papszFieldData[ 1 ] );
    1830                 : 
    1831                 : /* -------------------------------------------------------------------- */
    1832                 : /*      netCDF attributes do not like the '#' character.                */
    1833                 : /* -------------------------------------------------------------------- */
    1834                 : 
    1835             195 :       for( unsigned int h=0; h < strlen( szMetaName ) -1 ; h++ ) {
    1836             180 :     if( szMetaName[h] == '#' ) szMetaName[h] = '-'; 
    1837                 :       }
    1838                 :       
    1839              15 :       nDataLength = strlen( szMetaValue );
    1840                 :       nc_put_att_text( fpImage, 
    1841                 :            CDFVarID, 
    1842                 :            szMetaName,
    1843                 :            nDataLength,
    1844              15 :            szMetaValue );
    1845                 : 
    1846                 :       
    1847                 :   }
    1848              15 :   CSLDestroy( papszFieldData );
    1849                 : 
    1850                 :     }
    1851              42 : }
    1852                 : /************************************************************************/
    1853                 : /*                             CreateCopy()                             */
    1854                 : /************************************************************************/
    1855                 : 
    1856                 : 
    1857                 : static GDALDataset*
    1858              17 : NCDFCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
    1859                 :                 int bStrict, char ** papszOptions, 
    1860                 :                 GDALProgressFunc pfnProgress, void * pProgressData )
    1861                 : 
    1862                 : {
    1863              17 :     int  nBands = poSrcDS->GetRasterCount();
    1864              17 :     int  nXSize = poSrcDS->GetRasterXSize();
    1865              17 :     int  nYSize = poSrcDS->GetRasterYSize();
    1866              17 :     int  bProgressive = FALSE;
    1867                 : 
    1868                 :     int  anBandDims[ NC_MAX_DIMS ];
    1869                 :     int  anBandMap[  NC_MAX_DIMS ];
    1870                 : 
    1871              17 :     int    bWriteGeoTransform = FALSE;
    1872                 :     char  pszNetcdfProjection[ NC_MAX_NAME ];
    1873                 : 
    1874              17 :     if (nBands == 0)
    1875                 :     {
    1876                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1877               1 :                   "NetCDF driver does not support source dataset with zero band.\n");
    1878               1 :         return NULL;
    1879                 :     }
    1880                 : 
    1881              16 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
    1882               0 :         return NULL;
    1883                 : 
    1884                 : 
    1885              16 :     bProgressive = CSLFetchBoolean( papszOptions, "PROGRESSIVE", FALSE );
    1886                 : 
    1887                 : /* -------------------------------------------------------------------- */
    1888                 : /*      Create the dataset.                                             */
    1889                 : /* -------------------------------------------------------------------- */
    1890                 :     int fpImage;
    1891                 :     int status;
    1892              16 :     int nXDimID = 0;
    1893              16 :     int nYDimID = 0;
    1894                 : 
    1895              16 :     status = nc_create( pszFilename, NC_CLOBBER,  &fpImage );
    1896                 : 
    1897              16 :     if( status != NC_NOERR )
    1898                 :     {
    1899                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    1900                 :                   "Unable to create netCDF file %s.\n", 
    1901               0 :                   pszFilename );
    1902               0 :         return NULL;
    1903                 :     }
    1904                 : 
    1905                 :     GDALDataType eDT;
    1906                 : 
    1907              16 :     status = nc_def_dim( fpImage, "x", nXSize, &nXDimID );
    1908              16 :     CPLDebug( "GDAL_netCDF", "status nc_def_dim X = %d\n", status );
    1909                 : 
    1910              16 :     status = nc_def_dim( fpImage, "y", nYSize, &nYDimID );
    1911              16 :     CPLDebug( "GDAL_netCDF", "status nc_def_dim Y = %d\n", status );
    1912                 : 
    1913              16 :     CPLDebug( "GDAL_netCDF", "nYDimID = %d\n", nXDimID );
    1914              16 :     CPLDebug( "GDAL_netCDF", "nXDimID = %d\n", nYDimID );
    1915              16 :     CPLDebug( "GDAL_netCDF", "nXSize = %d\n", nXSize );
    1916              16 :     CPLDebug( "GDAL_netCDF", "nYSize = %d\n", nYSize );
    1917                 : 
    1918                 : 
    1919              16 :     CopyMetadata((void *) poSrcDS, fpImage, NC_GLOBAL );
    1920                 : 
    1921                 : /* -------------------------------------------------------------------- */
    1922                 : /*      Set Projection for netCDF data CF-1 Convention                  */
    1923                 : /* -------------------------------------------------------------------- */
    1924                 : 
    1925              16 :     OGRSpatialReference oSRS;
    1926              16 :     char *pszWKT = (char *) poSrcDS->GetProjectionRef();
    1927                 : 
    1928                 : 
    1929              16 :     if( pszWKT != NULL )
    1930              16 :   oSRS.importFromWkt( &pszWKT );
    1931                 : 
    1932              16 :     if( oSRS.IsGeographic() ) {
    1933                 : 
    1934                 :   int status;
    1935                 :   int i;
    1936                 :   int NCDFVarID;
    1937                 : 
    1938              15 :   double dfNN=0.0;
    1939              15 :   double dfSN=0.0;
    1940              15 :   double dfEE=0.0;
    1941              15 :   double dfWE=0.0;
    1942                 :   double adfGeoTransform[6];
    1943                 :   char   szGeoTransform[ MAX_STR_LEN ];
    1944                 :   char   szTemp[ MAX_STR_LEN ];
    1945                 : 
    1946                 : 
    1947                 : /* -------------------------------------------------------------------- */
    1948                 : /*      Copy GeoTransform array from source                             */
    1949                 : /* -------------------------------------------------------------------- */
    1950              15 :   poSrcDS->GetGeoTransform( adfGeoTransform );
    1951              15 :         bWriteGeoTransform = TRUE;
    1952                 : 
    1953              15 :   *szGeoTransform = '\0';
    1954             105 :   for( i=0; i<6; i++ ) {
    1955                 :       sprintf( szTemp, "%g ",
    1956              90 :          adfGeoTransform[i] );
    1957              90 :       strcat( szGeoTransform, szTemp );
    1958                 :   }
    1959              15 :   CPLDebug( "GDAL_netCDF", "szGeoTranform = %s", szGeoTransform );
    1960              15 :   strcpy( pszNetcdfProjection, "GDAL_Geographics" );
    1961                 : 
    1962                 :   status = nc_def_var( fpImage, 
    1963                 :            pszNetcdfProjection, 
    1964                 :            NC_CHAR, 
    1965              15 :            0, NULL, &NCDFVarID );
    1966                 :   
    1967              15 :   dfNN = adfGeoTransform[3];
    1968              15 :   dfSN = ( adfGeoTransform[5] * nYSize ) + dfNN;
    1969              15 :   dfWE = adfGeoTransform[0];
    1970              15 :   dfEE = ( adfGeoTransform[1] * nXSize ) + dfWE;
    1971                 : 
    1972                 :         status = nc_put_att_double( fpImage,
    1973                 :             NCDFVarID, 
    1974                 :             "Northernmost_Northing",
    1975                 :             NC_DOUBLE,
    1976                 :             1,
    1977              15 :             &dfNN );
    1978                 :         status = nc_put_att_double( fpImage,
    1979                 :             NCDFVarID, 
    1980                 :             "Southernmost_Northing",
    1981                 :             NC_DOUBLE,
    1982                 :             1,
    1983              15 :             &dfSN );
    1984                 :   status = nc_put_att_double( fpImage,
    1985                 :             NCDFVarID,
    1986                 :             "Easternmost_Easting",
    1987                 :             NC_DOUBLE,
    1988                 :             1,
    1989              15 :             &dfEE );
    1990                 :   status = nc_put_att_double( fpImage,
    1991                 :             NCDFVarID,
    1992                 :             "Westernmost_Easting",
    1993                 :             NC_DOUBLE,
    1994                 :             1,
    1995              15 :             &dfWE );
    1996              15 :   pszWKT = (char *) poSrcDS->GetProjectionRef() ;
    1997                 : 
    1998                 :   nc_put_att_text( fpImage, 
    1999                 :        NCDFVarID, 
    2000                 :        "spatial_ref",
    2001                 :        strlen( pszWKT ),
    2002              15 :        pszWKT );
    2003                 : 
    2004                 :   nc_put_att_text( fpImage, 
    2005                 :        NCDFVarID, 
    2006                 :        "GeoTransform",
    2007                 :        strlen( szGeoTransform ),
    2008              15 :        szGeoTransform );
    2009                 : 
    2010                 :   nc_put_att_text( fpImage, 
    2011                 :        NCDFVarID, 
    2012                 :        GRD_MAPPING_NAME,
    2013                 :        30,
    2014              15 :        "Geographics Coordinate System" );
    2015                 :   nc_put_att_text( fpImage, 
    2016                 :        NCDFVarID, 
    2017                 :        LNG_NAME,
    2018                 :        14,
    2019              15 :        "Grid_latitude" );
    2020                 :     }
    2021                 : 
    2022              16 :     if( oSRS.IsProjected() )
    2023                 :     {
    2024                 :   const char *pszParamStr, *pszParamVal;
    2025               1 :         const OGR_SRSNode *poPROJCS = oSRS.GetAttrNode( "PROJCS" );
    2026                 :   int status;
    2027                 :   int i;
    2028                 :   int NCDFVarID;
    2029                 :   const char  *pszProjection;
    2030               1 :   double dfNN=0.0;
    2031               1 :   double dfSN=0.0;
    2032               1 :   double dfEE=0.0;
    2033               1 :   double dfWE=0.0;
    2034                 :   double adfGeoTransform[6];
    2035                 :   char   szGeoTransform[ MAX_STR_LEN ];
    2036                 :   char   szTemp[ MAX_STR_LEN ];
    2037                 : 
    2038               1 :   poSrcDS->GetGeoTransform( adfGeoTransform );
    2039                 : 
    2040               1 :   *szGeoTransform = '\0';
    2041               7 :   for( i=0; i<6; i++ ) {
    2042                 :       sprintf( szTemp, "%g ",
    2043               6 :          adfGeoTransform[i] );
    2044               6 :       strcat( szGeoTransform, szTemp );
    2045                 :   }
    2046                 : 
    2047               1 :   CPLDebug( "GDAL_netCDF", "szGeoTranform = %s", szGeoTransform );
    2048                 : 
    2049               1 :         pszProjection = oSRS.GetAttrValue( "PROJECTION" );
    2050               1 :         bWriteGeoTransform = TRUE;
    2051                 : 
    2052                 : 
    2053              32 :   for(i=0; poNetcdfSRS[i].netCDFSRS != NULL; i++ ) {
    2054              32 :       if( EQUAL( poNetcdfSRS[i].SRS, pszProjection ) ) {
    2055                 :     CPLDebug( "GDAL_netCDF", "PROJECTION = %s", 
    2056               1 :         poNetcdfSRS[i].netCDFSRS);
    2057               1 :     strcpy( pszNetcdfProjection, poNetcdfSRS[i].netCDFSRS );
    2058                 : 
    2059               1 :     break;
    2060                 :       }
    2061                 :   }
    2062                 : 
    2063                 :   status = nc_def_var( fpImage, 
    2064                 :            poNetcdfSRS[i].netCDFSRS, 
    2065                 :            NC_CHAR, 
    2066               1 :            0, NULL, &NCDFVarID );
    2067                 : 
    2068               1 :   dfNN = adfGeoTransform[3];
    2069               1 :   dfSN = ( adfGeoTransform[5] * nYSize ) + dfNN;
    2070               1 :   dfWE = adfGeoTransform[0];
    2071               1 :   dfEE = ( adfGeoTransform[1] * nXSize ) + dfWE;
    2072                 : 
    2073                 :         status = nc_put_att_double( fpImage,
    2074                 :             NCDFVarID, 
    2075                 :             "Northernmost_Northing",
    2076                 :             NC_DOUBLE,
    2077                 :             1,
    2078               1 :             &dfNN );
    2079                 :         status = nc_put_att_double( fpImage,
    2080                 :             NCDFVarID, 
    2081                 :             "Southernmost_Northing",
    2082                 :             NC_DOUBLE,
    2083                 :             1,
    2084               1 :             &dfSN );
    2085                 :   status = nc_put_att_double( fpImage,
    2086                 :             NCDFVarID,
    2087                 :             "Easternmost_Easting",
    2088                 :             NC_DOUBLE,
    2089                 :             1,
    2090               1 :             &dfEE );
    2091                 :   status = nc_put_att_double( fpImage,
    2092                 :             NCDFVarID,
    2093                 :             "Westernmost_Easting",
    2094                 :             NC_DOUBLE,
    2095                 :             1,
    2096               1 :             &dfWE );
    2097               1 :   pszWKT = (char *) poSrcDS->GetProjectionRef() ;
    2098                 : 
    2099                 :   nc_put_att_text( fpImage, 
    2100                 :        NCDFVarID, 
    2101                 :        "spatial_ref",
    2102                 :        strlen( pszWKT ),
    2103               1 :        pszWKT );
    2104                 : 
    2105                 :   nc_put_att_text( fpImage, 
    2106                 :        NCDFVarID, 
    2107                 :        "GeoTransform",
    2108                 :        strlen( szGeoTransform ),
    2109               1 :        szGeoTransform );
    2110                 : 
    2111                 :   nc_put_att_text( fpImage, 
    2112                 :        NCDFVarID, 
    2113                 :        GRD_MAPPING_NAME,
    2114                 :        strlen( pszNetcdfProjection ),
    2115               1 :        pszNetcdfProjection );
    2116                 : 
    2117                 : 
    2118              11 :         for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
    2119                 :         {
    2120                 :             const OGR_SRSNode    *poNode;
    2121                 :       float fValue;
    2122                 : 
    2123              10 :             poNode = poPROJCS->GetChild( iChild );
    2124              10 :             if( !EQUAL(poNode->GetValue(),"PARAMETER") 
    2125                 :                 || poNode->GetChildCount() != 2 )
    2126               5 :                 continue;
    2127                 : 
    2128                 : /* -------------------------------------------------------------------- */
    2129                 : /*      Look for projection attributes                                  */
    2130                 : /* -------------------------------------------------------------------- */
    2131               5 :       pszParamStr = poNode->GetChild(0)->GetValue();
    2132               5 :       pszParamVal = poNode->GetChild(1)->GetValue();
    2133                 :       
    2134                 : 
    2135             192 :       for(i=0; poNetcdfSRS[i].netCDFSRS != NULL; i++ ) {
    2136             192 :     if( EQUAL( poNetcdfSRS[i].SRS, pszParamStr ) ) {
    2137                 :         CPLDebug( "GDAL_netCDF", "%s = %s", 
    2138                 :             poNetcdfSRS[i].netCDFSRS, 
    2139               5 :             pszParamVal );
    2140               5 :         break;
    2141                 :     }
    2142                 :       }
    2143                 : /* -------------------------------------------------------------------- */
    2144                 : /*      Write Projection attribute                                      */
    2145                 : /* -------------------------------------------------------------------- */
    2146               5 :       sscanf( pszParamVal, "%f", &fValue );
    2147               5 :       if( poNetcdfSRS[i].netCDFSRS != NULL ) {
    2148                 :     nc_put_att_float( fpImage, 
    2149                 :           NCDFVarID, 
    2150                 :           poNetcdfSRS[i].netCDFSRS, 
    2151                 :           NC_FLOAT,
    2152                 :           1,
    2153               5 :           &fValue );
    2154                 : 
    2155                 :       } 
    2156                 :         }
    2157                 :     }
    2158                 : 
    2159                 : /* -------------------------------------------------------------------- */
    2160                 : /*      Initialize Band Map                                             */
    2161                 : /* -------------------------------------------------------------------- */
    2162                 : 
    2163              42 :     for(int j=1; j <= nBands; j++ ) {
    2164              26 :   anBandMap[j-1]=j;
    2165                 :     }
    2166                 :     
    2167                 : /* -------------------------------------------------------------------- */
    2168                 : /*      Create netCDF variable                                          */
    2169                 : /* -------------------------------------------------------------------- */
    2170                 : 
    2171              42 :     for( int i=1; i <= nBands; i++ ) {
    2172                 : 
    2173                 :   char      szBandName[ NC_MAX_NAME ];
    2174              26 :   GByte     *pabScanline  = NULL;
    2175              26 :   GInt16    *pasScanline  = NULL;
    2176              26 :   GInt32    *panScanline  = NULL;
    2177              26 :   float     *pafScanline  = NULL;
    2178              26 :   double    *padScanline  = NULL;
    2179                 :   int       NCDFVarID;
    2180                 :   size_t    start[ GDALNBDIM ];
    2181                 :   size_t    count[ GDALNBDIM ];
    2182                 :   size_t    nBandNameLen;
    2183                 :   double    dfNoDataValue;
    2184                 :   unsigned char      cNoDataValue;
    2185                 :   float     fNoDataValue;
    2186                 :   int       nlNoDataValue;
    2187                 :   short     nsNoDataValue;
    2188                 :   GDALRasterBandH hBand;
    2189                 : 
    2190              26 :   GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( i );
    2191              26 :         hBand = GDALGetRasterBand( poSrcDS, i );
    2192                 : 
    2193              26 :   sprintf( szBandName, "Band%d", i );
    2194                 : 
    2195              26 :   eDT = poSrcDS->GetRasterBand(i)->GetRasterDataType();
    2196              26 :   anBandDims[0] = nYDimID;
    2197              26 :   anBandDims[1] = nXDimID;
    2198              26 :   CPLErr      eErr = CE_None;
    2199                 : 
    2200              26 :   dfNoDataValue = poSrcBand->GetNoDataValue(0);
    2201                 : 
    2202              26 :   if( eDT == GDT_Byte ) {
    2203              16 :       CPLDebug( "GDAL_netCDF", "%s = GDT_Byte ", szBandName );
    2204                 : 
    2205                 :       status = nc_def_var( fpImage, szBandName, NC_BYTE, 
    2206              16 :          GDALNBDIM, anBandDims, &NCDFVarID );
    2207                 : 
    2208                 : 
    2209                 : /* -------------------------------------------------------------------- */
    2210                 : /*      Write data line per line                                        */
    2211                 : /* -------------------------------------------------------------------- */
    2212                 : 
    2213              16 :       pabScanline = (GByte *) CPLMalloc( nBands * nXSize );
    2214             186 :       for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {
    2215                 : 
    2216                 : /* -------------------------------------------------------------------- */
    2217                 : /*      Read data from band i                                           */
    2218                 : /* -------------------------------------------------------------------- */
    2219                 :     eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    2220                 :               pabScanline, nXSize, 1, GDT_Byte,
    2221             170 :               0,0);
    2222                 : 
    2223                 : /* -------------------------------------------------------------------- */
    2224                 : /*      Write Fill Value                                                */
    2225                 : /* -------------------------------------------------------------------- */
    2226                 : 
    2227             170 :       cNoDataValue=(unsigned char) dfNoDataValue;
    2228                 :       nc_put_att_uchar( fpImage,
    2229                 :              NCDFVarID,
    2230                 :              _FillValue,
    2231                 :              NC_CHAR,
    2232                 :              1,
    2233             170 :              &cNoDataValue );
    2234                 :          
    2235                 : /* -------------------------------------------------------------------- */
    2236                 : /*      Write Data from Band i                                          */
    2237                 : /* -------------------------------------------------------------------- */
    2238             170 :     start[0]=iLine;
    2239             170 :     start[1]=0;
    2240             170 :     count[0]=1;
    2241             170 :     count[1]=nXSize;
    2242                 : 
    2243                 : /* -------------------------------------------------------------------- */
    2244                 : /*      Put NetCDF file in data mode.                                   */
    2245                 : /* -------------------------------------------------------------------- */
    2246             170 :     status = nc_enddef( fpImage );
    2247                 :     status = nc_put_vara_uchar (fpImage, NCDFVarID, start,
    2248             170 :               count, pabScanline);
    2249                 : 
    2250                 : 
    2251                 : /* -------------------------------------------------------------------- */
    2252                 : /*      Put NetCDF file back in define mode.                            */
    2253                 : /* -------------------------------------------------------------------- */
    2254             170 :     status = nc_redef( fpImage );
    2255                 :     
    2256                 :       }
    2257              16 :       CPLFree( pabScanline );
    2258                 : /* -------------------------------------------------------------------- */
    2259                 : /*      Int16                                                           */
    2260                 : /* -------------------------------------------------------------------- */
    2261                 : 
    2262              12 :   } else if( ( eDT == GDT_UInt16 ) || ( eDT == GDT_Int16 ) ) {
    2263               2 :       CPLDebug( "GDAL_netCDF", "%s = GDT_Int16 ",szBandName );
    2264                 :       status = nc_def_var( fpImage, szBandName, NC_SHORT, 
    2265               2 :          GDALNBDIM, anBandDims, &NCDFVarID );
    2266                 : 
    2267                 :       pasScanline = (GInt16 *) CPLMalloc( nBands * nXSize *
    2268               2 :             sizeof( GInt16 ) );
    2269                 : /* -------------------------------------------------------------------- */
    2270                 : /*      Write Fill Value                                                */
    2271                 : /* -------------------------------------------------------------------- */
    2272               2 :       nsNoDataValue= (GInt16) dfNoDataValue;
    2273                 :       nc_put_att_short( fpImage,
    2274                 :              NCDFVarID,
    2275                 :              _FillValue,
    2276                 :              NC_SHORT,
    2277                 :              1,
    2278               2 :              &nsNoDataValue );
    2279              22 :       for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {
    2280                 : 
    2281                 :     eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    2282                 :               pasScanline, nXSize, 1, GDT_Int16,
    2283              20 :               0,0);
    2284                 : 
    2285              20 :     start[0]=iLine;
    2286              20 :     start[1]=0;
    2287              20 :     count[0]=1;
    2288              20 :     count[1]=nXSize;
    2289                 : 
    2290                 : 
    2291              20 :     status = nc_enddef( fpImage );
    2292                 :     status = nc_put_vara_short( fpImage, NCDFVarID, start,
    2293              20 :               count, pasScanline);
    2294              20 :     status = nc_redef( fpImage );
    2295                 :       }
    2296               2 :       CPLFree( pasScanline );
    2297                 : /* -------------------------------------------------------------------- */
    2298                 : /*      Int32                                                           */
    2299                 : /* -------------------------------------------------------------------- */
    2300                 : 
    2301              10 :   } else if( (eDT == GDT_UInt32) || (eDT == GDT_Int32) ) {
    2302               2 :       CPLDebug( "GDAL_netCDF", "%s = GDT_Int32 ",szBandName );
    2303                 :       status = nc_def_var( fpImage, szBandName, NC_INT, 
    2304               2 :          GDALNBDIM, anBandDims, &NCDFVarID );
    2305                 : 
    2306                 :       panScanline = (GInt32 *) CPLMalloc( nBands * nXSize *
    2307               2 :             sizeof( GInt32 ) );
    2308                 : /* -------------------------------------------------------------------- */
    2309                 : /*      Write Fill Value                                                */
    2310                 : /* -------------------------------------------------------------------- */
    2311               2 :       nlNoDataValue= (GInt32) dfNoDataValue;
    2312                 : 
    2313                 :       nc_put_att_int( fpImage,
    2314                 :              NCDFVarID,
    2315                 :              _FillValue,
    2316                 :              NC_INT,
    2317                 :              1,
    2318               2 :              &nlNoDataValue );
    2319                 : 
    2320                 : 
    2321              22 :       for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {
    2322                 : 
    2323                 :     eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    2324                 :               panScanline, nXSize, 1, GDT_Int32,
    2325              20 :               0,0);
    2326                 : 
    2327              20 :     start[0]=iLine;
    2328              20 :     start[1]=0;
    2329              20 :     count[0]=1;
    2330              20 :     count[1]=nXSize;
    2331                 : 
    2332                 : 
    2333              20 :     status = nc_enddef( fpImage );
    2334                 :     status = nc_put_vara_int( fpImage, NCDFVarID, start,
    2335              20 :               count, panScanline);
    2336              20 :     status = nc_redef( fpImage );
    2337                 :       }
    2338               2 :       CPLFree( panScanline );
    2339                 : /* -------------------------------------------------------------------- */
    2340                 : /*      float                                                           */
    2341                 : /* -------------------------------------------------------------------- */
    2342               6 :   } else if( (eDT == GDT_Float32) ) {
    2343               1 :       CPLDebug( "GDAL_netCDF", "%s = GDT_Float32 ",szBandName );
    2344                 :       status = nc_def_var( fpImage, szBandName, NC_FLOAT, 
    2345               1 :          GDALNBDIM, anBandDims, &NCDFVarID );
    2346                 : 
    2347                 :       pafScanline = (float *) CPLMalloc( nBands * nXSize *
    2348               1 :                  sizeof( float ) );
    2349                 : 
    2350                 : /* -------------------------------------------------------------------- */
    2351                 : /*      Write Fill Value                                                */
    2352                 : /* -------------------------------------------------------------------- */
    2353               1 :       fNoDataValue= (float) dfNoDataValue;
    2354                 :       nc_put_att_float( fpImage,
    2355                 :              NCDFVarID,
    2356                 :              _FillValue,
    2357                 :              NC_FLOAT,
    2358                 :              1,
    2359               1 :              &fNoDataValue );
    2360                 :          
    2361              11 :       for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {
    2362                 : 
    2363                 :     eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    2364                 :               pafScanline, nXSize, 1, 
    2365                 :               GDT_Float32,
    2366              10 :               0,0);
    2367                 : 
    2368              10 :     start[0]=iLine;
    2369              10 :     start[1]=0;
    2370              10 :     count[0]=1;
    2371              10 :     count[1]=nXSize;
    2372                 : 
    2373                 : 
    2374              10 :     status = nc_enddef( fpImage );
    2375                 :     status = nc_put_vara_float( fpImage, NCDFVarID, start,
    2376              10 :               count, pafScanline);
    2377              10 :     status = nc_redef( fpImage );
    2378                 :       }
    2379               1 :       CPLFree( pafScanline );
    2380                 : /* -------------------------------------------------------------------- */
    2381                 : /*      double                                                          */
    2382                 : /* -------------------------------------------------------------------- */
    2383               5 :   } else if( (eDT == GDT_Float64) ) {
    2384               1 :       CPLDebug( "GDAL_netCDF", "%s = GDT_Float64 ",szBandName );
    2385                 :       status = nc_def_var( fpImage, szBandName, NC_DOUBLE, 
    2386               1 :          GDALNBDIM, anBandDims, &NCDFVarID );
    2387                 : 
    2388                 :       padScanline = (double *) CPLMalloc( nBands * nXSize *
    2389               1 :             sizeof( double ) );
    2390                 : 
    2391                 : /* -------------------------------------------------------------------- */
    2392                 : /*      Write Fill Value                                                */
    2393                 : /* -------------------------------------------------------------------- */
    2394                 :     
    2395                 :       nc_put_att_double( fpImage,
    2396                 :              NCDFVarID,
    2397                 :              _FillValue,
    2398                 :              NC_DOUBLE,
    2399                 :              1,
    2400               1 :              &dfNoDataValue );
    2401                 : 
    2402              11 :       for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {
    2403                 : 
    2404                 :     eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    2405                 :               padScanline, nXSize, 1, 
    2406                 :               GDT_Float64,
    2407              10 :               0,0);
    2408                 : 
    2409              10 :     start[0]=iLine;
    2410              10 :     start[1]=0;
    2411              10 :     count[0]=1;
    2412              10 :     count[1]=nXSize;
    2413                 : 
    2414                 : 
    2415              10 :     status = nc_enddef( fpImage );
    2416                 :     status = nc_put_vara_double( fpImage, NCDFVarID, start,
    2417              10 :               count, padScanline);
    2418              10 :     status = nc_redef( fpImage );
    2419                 :       }
    2420               1 :       CPLFree( padScanline );
    2421                 :   }
    2422                 :   
    2423                 : /* -------------------------------------------------------------------- */
    2424                 : /*      Write Projection for band                                       */
    2425                 : /* -------------------------------------------------------------------- */
    2426              26 :   if( bWriteGeoTransform == TRUE ) {
    2427                 :       /*      nc_put_att_text( fpImage, NCDFVarID, 
    2428                 :            COORDINATES,
    2429                 :            7,
    2430                 :            LONLAT );
    2431                 :       */
    2432                 :       nc_put_att_text( fpImage, NCDFVarID, 
    2433                 :            GRD_MAPPING,
    2434                 :            strlen( pszNetcdfProjection ),
    2435              26 :            pszNetcdfProjection );
    2436                 :   }
    2437                 : 
    2438              26 :   sprintf( szBandName, "GDAL Band Number %d", i);
    2439              26 :   nBandNameLen = strlen( szBandName );
    2440                 :   nc_put_att_text( fpImage, 
    2441                 :        NCDFVarID, 
    2442                 :        "long_name", 
    2443                 :        nBandNameLen,
    2444              26 :        szBandName );
    2445                 : 
    2446              26 :   CopyMetadata( (void *) hBand, fpImage, NCDFVarID );
    2447                 : 
    2448                 :          
    2449                 : 
    2450                 :     }
    2451                 : 
    2452                 : 
    2453                 : 
    2454                 :     //    poDstDS->SetGeoTransform( adfGeoTransform );
    2455                 : 
    2456                 : 
    2457                 : /* -------------------------------------------------------------------- */
    2458                 : /*      Cleanup and close.                                              */
    2459                 : /* -------------------------------------------------------------------- */
    2460                 : //    CPLFree( pabScanline );
    2461                 : 
    2462              16 :     nc_close( fpImage );
    2463                 : /* -------------------------------------------------------------------- */
    2464                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    2465                 : /* -------------------------------------------------------------------- */
    2466              16 :     netCDFDataset *poDS = (netCDFDataset *) GDALOpen( pszFilename, GA_ReadOnly );
    2467                 : 
    2468              16 :     if( poDS )
    2469              12 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    2470                 : 
    2471              16 :     return poDS;
    2472                 : 
    2473                 : 
    2474                 :     }
    2475                 : 
    2476                 : /************************************************************************/
    2477                 : /*                          GDALRegister_netCDF()                       */
    2478                 : /************************************************************************/
    2479                 : 
    2480             338 : void GDALRegister_netCDF()
    2481                 : 
    2482                 : {
    2483                 :     GDALDriver  *poDriver;
    2484                 : 
    2485             338 :     if (! GDAL_CHECK_VERSION("netCDF driver"))
    2486               0 :         return;
    2487                 : 
    2488             338 :     if( GDALGetDriverByName( "netCDF" ) == NULL )
    2489                 :     {
    2490             336 :         poDriver = new GDALDriver( );
    2491                 :         
    2492             336 :         poDriver->SetDescription( "netCDF" );
    2493                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    2494             336 :                                    "Network Common Data Format" );
    2495                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2496             336 :                                    "frmt_netcdf.html" );
    2497             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "nc" );
    2498                 : 
    2499             336 :         poDriver->pfnOpen = netCDFDataset::Open;
    2500             336 :         poDriver->pfnCreateCopy = NCDFCreateCopy;
    2501                 : 
    2502                 : 
    2503             336 :         GetGDALDriverManager( )->RegisterDriver( poDriver );
    2504                 :     }
    2505                 : }
    2506                 : 
    2507                 : 
    2508                 : 
    2509                 : /* -------------------------------------------------------------------- */
    2510                 : /*      Set Lambert Conformal Conic Projection                          */
    2511                 : /* -------------------------------------------------------------------- */
    2512                 : 
    2513                 : 
    2514                 :     
    2515                 : //Albers equal area
    2516                 : //
    2517                 : //grid_mapping_name = albers_conical_equal_area
    2518                 : //
    2519                 : //Map parameters:
    2520                 : //
    2521                 : //    * standard_parallel - There may be 1 or 2 values.
    2522                 : //    * longitude_of_central_meridian
    2523                 : //    * latitude_of_projection_origin
    2524                 : //    * false_easting
    2525                 : //    * false_northing
    2526                 : //Lambert azimuthal equal area
    2527                 : //
    2528                 : //grid_mapping_name = lambert_azimuthal_equal_area
    2529                 : //
    2530                 : //Map parameters:
    2531                 : //
    2532                 : //    * longitude_of_projection_origin
    2533                 : //    * latitude_of_projection_origin
    2534                 : //    * false_easting
    2535                 : //    * false_northing
    2536                 : //Lambert conformal
    2537                 : //
    2538                 : //grid_mapping_name = lambert_conformal_conic
    2539                 : //
    2540                 : //Map parameters:
    2541                 : //
    2542                 : //    * standard_parallel - There may be 1 or 2 values.
    2543                 : //    * longitude_of_central_meridian
    2544                 : //    * latitude_of_projection_origin
    2545                 : //    * false_easting
    2546                 : //    * false_northing
    2547                 : //Polar stereographic
    2548                 : //
    2549                 : //grid_mapping_name = polar_stereographic
    2550                 : //
    2551                 : //Map parameters:
    2552                 : //
    2553                 : //    * straight_vertical_longitude_from_pole
    2554                 : //    * latitude_of_projection_origin - Either +90. or -90.
    2555                 : //    * Either standard_parallel or scale_factor_at_projection_origin
    2556                 : //    * false_easting
    2557                 : //    * false_northing
    2558                 : //Rotated pole
    2559                 : //
    2560                 : //grid_mapping_name = rotated_latitude_longitude
    2561                 : //
    2562                 : //Map parameters:
    2563                 : //
    2564                 : //    * grid_north_pole_latitude
    2565                 : //    * grid_north_pole_longitude
    2566                 : //    * north_pole_grid_longitude - This parameter is optional (default is 0.).
    2567                 : //Stereographic
    2568                 : //
    2569                 : //grid_mapping_name = stereographic
    2570                 : //
    2571                 : //Map parameters:
    2572                 : //
    2573                 : //    * longitude_of_projection_origin
    2574                 : //    * latitude_of_projection_origin
    2575                 : //    * scale_factor_at_projection_origin
    2576                 : //    * false_easting
    2577                 : //    * false_northing
    2578                 : //Transverse Mercator
    2579                 : //
    2580                 : //grid_mapping_name = transverse_mercator
    2581                 : //
    2582                 : //Map parameters:
    2583                 : //
    2584                 : //    * scale_factor_at_central_meridian
    2585                 : //    * longitude_of_central_meridian
    2586                 : //    * latitude_of_projection_origin
    2587                 : //    * false_easting
    2588                 : //    * false_northing
    2589                 : //
    2590                 : //
    2591                 : //
    2592                 : //Grid mapping attributes
    2593                 : //
    2594                 : //false_easting   
    2595                 : //false_northing  
    2596                 : //grid_mapping_name   
    2597                 : //grid_north_pole_latitude
    2598                 : //grid_north_pole_longitude
    2599                 : //latitude_of_projection_origin 
    2600                 : //longitude_of_central_meridian 
    2601                 : //longitude_of_projection_origin
    2602                 : //north_pole_grid_longitude   
    2603                 : //scale_factor_at_central_meridian 
    2604                 : //scale_factor_at_projection_origin 
    2605                 : //standard_parallel   
    2606                 : //straight_vertical_longitude_from_pole   
    2607                 : 
    2608                 : 

Generated by: LCOV version 1.7