void GRIBDataset::SetGribMetaData(grib_MetaData* meta) { nRasterXSize = meta->gds.Nx; nRasterYSize = meta->gds.Ny; /* -------------------------------------------------------------------- */ /* Image projection. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; switch(meta->gds.projType) { case GS3_LATLON: case GS3_GAUSSIAN_LATLON: // No projection, only latlon system (geographic) break; case GS3_MERCATOR: oSRS.SetMercator(meta->gds.meshLat, meta->gds.orientLon, 1.0, 0.0, 0.0); break; case GS3_POLAR: oSRS.SetPS(meta->gds.meshLat, meta->gds.orientLon, meta->gds.scaleLat1, 0.0, 0.0); break; case GS3_LAMBERT: oSRS.SetLCC(meta->gds.scaleLat1, meta->gds.scaleLat2, 0.0, meta->gds.orientLon, 0.0, 0.0); // set projection break; case GS3_ORTHOGRAPHIC: //oSRS.SetOrthographic(0.0, meta->gds.orientLon, // meta->gds.lon2, meta->gds.lat2); //oSRS.SetGEOS(meta->gds.orientLon, meta->gds.stretchFactor, meta->gds.lon2, meta->gds.lat2); oSRS.SetGEOS( 0, 35785831, 0, 0 ); // hardcoded for now, I don't know yet how to parse the meta->gds section break; case GS3_EQUATOR_EQUIDIST: break; case GS3_AZIMUTH_RANGE: break; } /* -------------------------------------------------------------------- */ /* Earth model */ /* -------------------------------------------------------------------- */ double a = meta->gds.majEarth * 1000.0; // in meters double b = meta->gds.minEarth * 1000.0; if( a == 0 && b == 0 ) { a = 6377563.396; b = 6356256.910; } if (meta->gds.f_sphere) { oSRS.SetGeogCS( "Coordinate System imported from GRIB file", NULL, "Sphere", a, 0.0 ); } else { double fInv = a/(a-b); oSRS.SetGeogCS( "Coordinate System imported from GRIB file", NULL, "Spheroid imported from GRIB file", a, fInv ); } OGRSpatialReference oLL; // construct the "geographic" part of oSRS oLL.CopyGeogCSFrom( &oSRS ); double rMinX; double rMaxY; double rPixelSizeX; double rPixelSizeY; if (meta->gds.projType == GS3_ORTHOGRAPHIC) { //rMinX = -meta->gds.Dx * (meta->gds.Nx / 2); // This is what should work, but it doesn't .. Dx seems to have an inverse relation with pixel size //rMaxY = meta->gds.Dy * (meta->gds.Ny / 2); const double geosExtentInMeters = 11137496.552; // hardcoded for now, assumption: GEOS projection, full disc (like MSG) rMinX = -(geosExtentInMeters / 2); rMaxY = geosExtentInMeters / 2; rPixelSizeX = geosExtentInMeters / meta->gds.Nx; rPixelSizeY = geosExtentInMeters / meta->gds.Ny; } else if( oSRS.IsProjected() ) { rMinX = meta->gds.lon1; // longitude in degrees, to be transformed to meters (or degrees in case of latlon) rMaxY = meta->gds.lat1; // latitude in degrees, to be transformed to meters OGRCoordinateTransformation *poTransformLLtoSRS = OGRCreateCoordinateTransformation( &(oLL), &(oSRS) ); if ((poTransformLLtoSRS != NULL) && poTransformLLtoSRS->Transform( 1, &rMinX, &rMaxY )) // transform it to meters { if (meta->gds.scan == GRIB2BIT_2) // Y is minY, GDAL wants maxY rMaxY += (meta->gds.Ny - 1) * meta->gds.Dy; // -1 because we GDAL needs the coordinates of the centre of the pixel rPixelSizeX = meta->gds.Dx; rPixelSizeY = meta->gds.Dy; } else { rMinX = 0.0; rMaxY = 0.0; rPixelSizeX = 1.0; rPixelSizeY = -1.0; oSRS.Clear(); CPLError( CE_Warning, CPLE_AppDefined, "Unable to perform coordinate transformations, so the correct\n" "projected geotransform could not be deduced from the lat/long\n" "control points. Defaulting to ungeoreferenced." ); } delete poTransformLLtoSRS; } else { rMinX = meta->gds.lon1; // longitude in degrees, to be transformed to meters (or degrees in case of latlon) rMaxY = meta->gds.lat1; // latitude in degrees, to be transformed to meters if (meta->gds.lat2 > rMaxY) rMaxY = meta->gds.lat2; rPixelSizeX = meta->gds.Dx; rPixelSizeY = meta->gds.Dy; } adfGeoTransform[0] = rMinX; adfGeoTransform[3] = rMaxY; adfGeoTransform[1] = rPixelSizeX; adfGeoTransform[5] = -rPixelSizeY; CPLFree( pszProjection ); pszProjection = NULL; oSRS.exportToWkt( &(pszProjection) ); }
GDALDataset *MSGNDataset::Open( GDALOpenInfo * poOpenInfo ) { open_mode_type open_mode = MODE_VISIR; GDALOpenInfo* open_info = poOpenInfo; if (!poOpenInfo->bStatOK) { if ( EQUALN(poOpenInfo->pszFilename, "HRV:", 4) ) { open_info = new GDALOpenInfo(&poOpenInfo->pszFilename[4], poOpenInfo->eAccess); open_mode = MODE_HRV; } else if ( EQUALN(poOpenInfo->pszFilename, "RAD:", 4 ) ) { open_info = new GDALOpenInfo(&poOpenInfo->pszFilename[4], poOpenInfo->eAccess); open_mode = MODE_RAD; } } /* -------------------------------------------------------------------- */ /* Before trying MSGNOpen() we first verify that there is at */ /* least one "\n#keyword" type signature in the first chunk of */ /* the file. */ /* -------------------------------------------------------------------- */ if( open_info->fp == NULL || open_info->nHeaderBytes < 50 ) return NULL; /* check if this is a "NATIVE" MSG format image */ if( !EQUALN((char *)open_info->pabyHeader, "FormatName : NATIVE", 36) ) { return NULL; } /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { CPLError( CE_Failure, CPLE_NotSupported, "The MSGN driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ MSGNDataset *poDS; poDS = new MSGNDataset(); poDS->fp = open_info->fp; open_info->fp = NULL; /* -------------------------------------------------------------------- */ /* Read the header. */ /* -------------------------------------------------------------------- */ // first reset the file pointer, then hand over to the msg_reader_core VSIFSeek( poDS->fp, 0, SEEK_SET ); poDS->msg_reader_core = new Msg_reader_core(poDS->fp); if (!poDS->msg_reader_core->get_open_success()) { delete poDS; return NULL; } poDS->nRasterXSize = poDS->msg_reader_core->get_columns(); poDS->nRasterYSize = poDS->msg_reader_core->get_lines(); if (open_mode == MODE_HRV) { poDS->nRasterXSize *= 3; poDS->nRasterYSize *= 3; } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ unsigned int i; unsigned int band_count = 1; unsigned int missing_band_count = 0; unsigned char* bands = poDS->msg_reader_core->get_band_map(); unsigned char band_map[MSG_NUM_CHANNELS+1]; // map GDAL band numbers to MSG channels for (i=0; i < MSG_NUM_CHANNELS; i++) { if (bands[i]) { bool ok_to_add = false; switch (open_mode) { case MODE_VISIR: ok_to_add = i < MSG_NUM_CHANNELS - 1; break; case MODE_RAD: ok_to_add = (i <= 2) || (Msg_reader_core::Blackbody_LUT[i+1].B != 0); break; case MODE_HRV: ok_to_add = i == MSG_NUM_CHANNELS - 1; break; } if (ok_to_add) { poDS->SetBand( band_count, new MSGNRasterBand( poDS, band_count, open_mode, i+1, i+1 - missing_band_count)); band_map[band_count] = i+1; band_count++; } } else { missing_band_count++; } } double pixel_gsd_x; double pixel_gsd_y; double origin_x; double origin_y; if (open_mode != MODE_HRV) { pixel_gsd_x = 1000 * poDS->msg_reader_core->get_col_dir_step(); // convert from km to m pixel_gsd_y = 1000 * poDS->msg_reader_core->get_line_dir_step(); // convert from km to m origin_x = -pixel_gsd_x * (-(Conversions::nlines / 2.0) + poDS->msg_reader_core->get_col_start()); origin_y = -pixel_gsd_y * ((Conversions::nlines / 2.0) - poDS->msg_reader_core->get_line_start()); } else { pixel_gsd_x = 1000 * poDS->msg_reader_core->get_col_dir_step() / 3.0; // convert from km to m, approximate for HRV pixel_gsd_y = 1000 * poDS->msg_reader_core->get_line_dir_step() / 3.0; // convert from km to m, approximate for HRV origin_x = -pixel_gsd_x * (-(3*Conversions::nlines / 2.0) + 3*poDS->msg_reader_core->get_col_start()); origin_y = -pixel_gsd_y * ((3*Conversions::nlines / 2.0) - 3*poDS->msg_reader_core->get_line_start()); } poDS->adfGeoTransform[0] = origin_x; poDS->adfGeoTransform[1] = pixel_gsd_x; poDS->adfGeoTransform[2] = 0.0; poDS->adfGeoTransform[3] = origin_y; poDS->adfGeoTransform[4] = 0.0; poDS->adfGeoTransform[5] = -pixel_gsd_y; OGRSpatialReference oSRS; oSRS.SetProjCS("Geostationary projection (MSG)"); oSRS.SetGEOS( 0, 35785831, 0, 0 ); oSRS.SetGeogCS( "MSG Ellipsoid", "MSG_DATUM", "MSG_SPHEROID", Conversions::rpol * 1000.0, 1 / ( 1 - Conversions::rpol/Conversions::req) ); oSRS.exportToWkt( &(poDS->pszProjection) ); CALIBRATION* cal = poDS->msg_reader_core->get_calibration_parameters(); char tagname[30]; char field[300]; poDS->SetMetadataItem("Radiometric parameters format", "offset slope"); for (i=1; i < band_count; i++) { sprintf(tagname, "ch%02d_cal", band_map[i]); sprintf(field, "%.12e %.12e", cal[band_map[i]-1].cal_offset, cal[band_map[i]-1].cal_slope); poDS->SetMetadataItem(tagname, field); } sprintf(field, "%04d%02d%02d/%02d:%02d", poDS->msg_reader_core->get_year(), poDS->msg_reader_core->get_month(), poDS->msg_reader_core->get_day(), poDS->msg_reader_core->get_hour(), poDS->msg_reader_core->get_minute() ); poDS->SetMetadataItem("Date/Time", field); sprintf(field, "%d %d", poDS->msg_reader_core->get_line_start(), poDS->msg_reader_core->get_col_start() ); poDS->SetMetadataItem("Origin", field); if (open_info != poOpenInfo) { delete open_info; } return( poDS ); }