OGRSpatialReference* OGRGetGeomediaSRS(OGRFeature* poFeature)
{
    if (poFeature == NULL)
        return NULL;

    int nGeodeticDatum = poFeature->GetFieldAsInteger("GeodeticDatum");
    int nEllipsoid = poFeature->GetFieldAsInteger("Ellipsoid");
    int nProjAlgorithm = poFeature->GetFieldAsInteger("ProjAlgorithm");

    if (nGeodeticDatum == 17 && nEllipsoid == 22)
    {
        if (nProjAlgorithm == 12)
        {
            OGRSpatialReference* poSRS = new OGRSpatialReference();

            const char* pszDescription = poFeature->GetFieldAsString("Description");
            if (pszDescription && pszDescription[0] != 0)
                poSRS->SetNode( "PROJCS", pszDescription );
            poSRS->SetWellKnownGeogCS("WGS84");

            double dfStdP1 = poFeature->GetFieldAsDouble("StandPar1");
            double dfStdP2 = poFeature->GetFieldAsDouble("StandPar2");
            double dfCenterLat = poFeature->GetFieldAsDouble("LatOfOrigin");
            double dfCenterLong = poFeature->GetFieldAsDouble("LonOfOrigin");
            double dfFalseEasting = poFeature->GetFieldAsDouble("FalseX");
            double dfFalseNorthing = poFeature->GetFieldAsDouble("FalseY");
            poSRS->SetACEA( dfStdP1, dfStdP2,
                            dfCenterLat, dfCenterLong,
                            dfFalseEasting, dfFalseNorthing );
            return poSRS;
        }
    }

    return NULL;
}
Beispiel #2
0
void IDADataset::ProcessGeoref()

{
    OGRSpatialReference oSRS;

    if( nProjection == 3 ) 
    {
        oSRS.SetWellKnownGeogCS( "WGS84" );
    }
    else if( nProjection == 4 ) 
    {
        oSRS.SetLCC( dfParallel1, dfParallel2, 
                     dfLatCenter, dfLongCenter, 
                     0.0, 0.0 );
        oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866", 
                        6378206.4, 293.97869821389662 );
    }
    else if( nProjection == 6 ) 
    {
        oSRS.SetLAEA( dfLatCenter, dfLongCenter, 0.0, 0.0 );
        oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere", 
                        6370997.0, 0.0 );
    }
    else if( nProjection == 8 )
    {
        oSRS.SetACEA( dfParallel1, dfParallel2, 
                      dfLatCenter, dfLongCenter, 
                      0.0, 0.0 );
        oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866", 
                        6378206.4, 293.97869821389662 );
    }
    else if( nProjection == 9 ) 
    {
        oSRS.SetGH( dfLongCenter, 0.0, 0.0 );
        oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere", 
                        6370997.0, 0.0 );
    }

    if( oSRS.GetRoot() != NULL )
    {
        CPLFree( pszProjection );
        pszProjection = NULL;

        oSRS.exportToWkt( &pszProjection );
    }

    adfGeoTransform[0] = 0 - dfDX * dfXCenter;
    adfGeoTransform[1] = dfDX;
    adfGeoTransform[2] = 0.0;
    adfGeoTransform[3] =  dfDY * dfYCenter;
    adfGeoTransform[4] = 0.0;
    adfGeoTransform[5] = -dfDY;

    if( nProjection == 3 )
    {
        adfGeoTransform[0] += dfLongCenter;
        adfGeoTransform[3] += dfLatCenter;
    }
}
std::string AlbersConEqArea::wkt()
{
	OGRSpatialReference sr;
	int epsg = DATUM2EPSG[datum()];
	char **wkt = 0;
	std::string output = "";
	OGRErr err;

	sr.SetProjCS("Albers Conic Equal Area");
	if (epsg != -1) {
		sr.importFromEPSG(epsg);
		sr.SetACEA(param(2), param(3), param(5), param(4), param(6), param(7));
		err = sr.exportToPrettyWkt(wkt);
	} else {
		return output;
	}

	if (err == OGRERR_NONE) {
		output = *wkt;
		OGRFree(wkt);
	}

	return output;
}
Beispiel #4
0
void clsRasterData::outputGTiff(map<string,float> header,int nValidCells,float** position, float* value,string filename)
{
	float noDataValue = header["NODATA_VALUE"];

	int nCols = header["NCOLS"];
	int nRows = header["NROWS"];
	float xll = header["XLLCENTER"];
	float yll = header["YLLCENTER"];
	float dx = header["CELLSIZE"];

	int n = nRows * nCols;
	float *data = new float[n];

	int index = 0;
	for (int i = 0; i < nRows; ++i)
	{
		for (int j = 0; j < nCols; ++j)
		{
			if(index < nValidCells)
			{
				if(position[index][0] == i && position[index][1] == j) 
				{
					data[i*nCols+j] = value[index];	
					index++;
				}
				else 
					data[i*nCols+j] = noDataValue;
			}
			else 
				data[i*nCols+j] = noDataValue;				
		}
	}

	const char *pszFormat = "GTiff";
	GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);

	char **papszOptions = poDriver->GetMetadata();
	GDALDataset *poDstDS = poDriver->Create(filename.c_str(), nCols, nRows, 1, GDT_Float32, papszOptions );
	
	//write the data to new file
	GDALRasterBand  *poDstBand= poDstDS->GetRasterBand(1);
	poDstBand->RasterIO(GF_Write, 0, 0,  nCols, nRows, data,  nCols, nRows, GDT_Float32, 0, 0);
	poDstBand->SetNoDataValue(noDataValue);

	double geoTrans[6];
	geoTrans[0] = xll;
	geoTrans[1] = dx;
	geoTrans[2] = 0;
	geoTrans[3] = yll + nRows*dx;
	geoTrans[4] = 0;
	geoTrans[5] = -dx;
	poDstDS->SetGeoTransform(geoTrans);

	OGRSpatialReference srs;
	srs.SetACEA(25, 47, 0, 105, 0, 0);
	srs.SetWellKnownGeogCS("WGS84");
	
	char *pSrsWkt = NULL;
	srs.exportToWkt(&pSrsWkt);
	poDstDS->SetProjection(pSrsWkt);
	CPLFree(pSrsWkt);

	GDALClose(poDstDS);

	delete[] data;
}
Beispiel #5
0
void PDSDataset::ParseSRS()

{
    const char *pszFilename = GetDescription();

/* ==================================================================== */
/*      Get the geotransform.                                           */
/* ==================================================================== */
    /***********   Grab Cellsize ************/
    //example:
    //MAP_SCALE   = 14.818 <KM/PIXEL>
    //added search for unit (only checks for CM, KM - defaults to Meters)
    const char *value;
    //Georef parameters
    double dfULXMap=0.5;
    double dfULYMap = 0.5;
    double dfXDim = 1.0;
    double dfYDim = 1.0;
    double xulcenter = 0.0;
    double yulcenter = 0.0;

    value = GetKeyword("IMAGE_MAP_PROJECTION.MAP_SCALE");
    if (strlen(value) > 0 ) {
        dfXDim = atof(value);
        dfYDim = atof(value) * -1;
        
        CPLString unit = GetKeywordUnit("IMAGE_MAP_PROJECTION.MAP_SCALE",2); //KM
        //value = GetKeywordUnit("IMAGE_MAP_PROJECTION.MAP_SCALE",3); //PIXEL
        if((EQUAL(unit,"M"))  || (EQUAL(unit,"METER")) || (EQUAL(unit,"METERS"))) {
            // do nothing
        }
        else if (EQUAL(unit,"CM")) {
            // convert from cm to m
            dfXDim = dfXDim / 100.0;
            dfYDim = dfYDim / 100.0;
        } else {
            //defaults to convert km to m
            dfXDim = dfXDim * 1000.0;
            dfYDim = dfYDim * 1000.0;
        }            
    }
    
/* -------------------------------------------------------------------- */
/*      Calculate upper left corner of pixel in meters from the         */
/*      upper  left center pixel sample/line offsets.  It doesn't       */
/*      mean the defaults will work for every PDS image, as these       */
/*      values are used inconsistantly.  Thus we have included          */
/*      conversion options to allow the user to override the            */
/*      documented PDS3 default. Jan. 2011, for known mapping issues    */
/*      see GDAL PDS page or mapping within ISIS3 source (USGS)         */
/*      $ISIS3DATA/base/translations/pdsProjectionLineSampToXY.def      */
/* -------------------------------------------------------------------- */
   
    // defaults should be correct for what is documented in the PDS3 standard
    double   dfSampleOffset_Shift;
    double   dfLineOffset_Shift;
    double   dfSampleOffset_Mult;
    double   dfLineOffset_Mult;

    dfSampleOffset_Shift = 
        atof(CPLGetConfigOption( "PDS_SampleProjOffset_Shift", "-0.5" ));
    
    dfLineOffset_Shift = 
        atof(CPLGetConfigOption( "PDS_LineProjOffset_Shift", "-0.5" ));

    dfSampleOffset_Mult =
        atof(CPLGetConfigOption( "PDS_SampleProjOffset_Mult", "-1.0") );

    dfLineOffset_Mult = 
        atof( CPLGetConfigOption( "PDS_LineProjOffset_Mult", "1.0") );

    /***********   Grab LINE_PROJECTION_OFFSET ************/
    value = GetKeyword("IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
    if (strlen(value) > 0) {
        yulcenter = atof(value);
        dfULYMap = ((yulcenter + dfLineOffset_Shift) * -dfYDim * dfLineOffset_Mult);
        //notice dfYDim is negative here which is why it is again negated here
    }
    /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
    value = GetKeyword("IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
    if( strlen(value) > 0 ) {
        xulcenter = atof(value);
        dfULXMap = ((xulcenter + dfSampleOffset_Shift) * dfXDim * dfSampleOffset_Mult);
    }

/* ==================================================================== */
/*      Get the coordinate system.                                      */
/* ==================================================================== */
    int	bProjectionSet = TRUE;
    double semi_major = 0.0;
    double semi_minor = 0.0;
    double iflattening = 0.0;
    double center_lat = 0.0;
    double center_lon = 0.0;
    double first_std_parallel = 0.0;
    double second_std_parallel = 0.0;
    OGRSpatialReference oSRS;

    /***********  Grab TARGET_NAME  ************/
    /**** This is the planets name i.e. MARS ***/
    CPLString target_name = GetKeyword("TARGET_NAME");
    CleanString( target_name );
     
    /**********   Grab MAP_PROJECTION_TYPE *****/
    CPLString map_proj_name = 
        GetKeyword( "IMAGE_MAP_PROJECTION.MAP_PROJECTION_TYPE");
    CleanString( map_proj_name );
     
    /******  Grab semi_major & convert to KM ******/
    semi_major = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
    
    /******  Grab semi-minor & convert to KM ******/
    semi_minor = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;

    /***********   Grab CENTER_LAT ************/
    center_lat = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));

    /***********   Grab CENTER_LON ************/
    center_lon = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));

    /**********   Grab 1st std parallel *******/
    first_std_parallel = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));

    /**********   Grab 2nd std parallel *******/
    second_std_parallel = 
        atof(GetKeyword( "IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
     
    /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
    // Need to further study how ocentric/ographic will effect the gdal library.
    // So far we will use this fact to define a sphere or ellipse for some projections
    // Frank - may need to talk this over
    char bIsGeographic = TRUE;
    value = GetKeyword("IMAGE_MAP_PROJECTION.COORDINATE_SYSTEM_NAME");
    if (EQUAL( value, "PLANETOCENTRIC" ))
        bIsGeographic = FALSE; 

/**   Set oSRS projection and parameters --- all PDS supported types added if apparently supported in oSRS
      "AITOFF",  ** Not supported in GDAL??
      "ALBERS", 
      "BONNE",
      "BRIESEMEISTER",   ** Not supported in GDAL??
      "CYLINDRICAL EQUAL AREA",
      "EQUIDISTANT",
      "EQUIRECTANGULAR",
      "GNOMONIC",
      "HAMMER",    ** Not supported in GDAL??
      "HENDU",     ** Not supported in GDAL??
      "LAMBERT AZIMUTHAL EQUAL AREA",
      "LAMBERT CONFORMAL",
      "MERCATOR",
      "MOLLWEIDE",
      "OBLIQUE CYLINDRICAL",
      "ORTHOGRAPHIC",
      "SIMPLE CYLINDRICAL",
      "SINUSOIDAL",
      "STEREOGRAPHIC",
      "TRANSVERSE MERCATOR",
      "VAN DER GRINTEN",     ** Not supported in GDAL??
      "WERNER"     ** Not supported in GDAL?? 
**/ 
    CPLDebug( "PDS","using projection %s\n\n", map_proj_name.c_str());

    if ((EQUAL( map_proj_name, "EQUIRECTANGULAR" )) ||
        (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) ||
        (EQUAL( map_proj_name, "EQUIDISTANT" )) )  {
        oSRS.SetEquirectangular2 ( 0.0, center_lon, center_lat, 0, 0 );
    } else if (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) {
        oSRS.SetOrthographic ( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "SINUSOIDAL" )) {
        oSRS.SetSinusoidal ( center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "MERCATOR" )) {
        oSRS.SetMercator ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "STEREOGRAPHIC" )) {
        oSRS.SetStereographic ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC")) {
        oSRS.SetPS ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "TRANSVERSE_MERCATOR" )) {
        oSRS.SetTM ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "LAMBERT_CONFORMAL_CONIC" )) {
        oSRS.SetLCC ( first_std_parallel, second_std_parallel, 
                      center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "LAMBERT_AZIMUTHAL_EQUAL_AREA" )) {
        oSRS.SetLAEA( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "CYLINDRICAL_EQUAL_AREA" )) {
        oSRS.SetCEA  ( first_std_parallel, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "MOLLWEIDE" )) {
        oSRS.SetMollweide ( center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "ALBERS" )) {
        oSRS.SetACEA ( first_std_parallel, second_std_parallel, 
                       center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "BONNE" )) {
        oSRS.SetBonne ( first_std_parallel, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "GNOMONIC" )) {
        oSRS.SetGnomonic ( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "OBLIQUE_CYLINDRICAL" )) { 
        // hope Swiss Oblique Cylindrical is the same
        oSRS.SetSOC ( center_lat, center_lon, 0, 0 );
    } else {
        CPLDebug( "PDS",
                  "Dataset projection %s is not supported. Continuing...",
                  map_proj_name.c_str() );
        bProjectionSet = FALSE;
    }

    if (bProjectionSet) {
        //Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
        CPLString proj_target_name = map_proj_name + " " + target_name;
        oSRS.SetProjCS(proj_target_name); //set ProjCS keyword
     
        //The geographic/geocentric name will be the same basic name as the body name
        //'GCS' = Geographic/Geocentric Coordinate System
        CPLString geog_name = "GCS_" + target_name;
        
        //The datum and sphere names will be the same basic name aas the planet
        CPLString datum_name = "D_" + target_name;
        CPLString sphere_name = target_name; // + "_IAU_IAG");  //Might not be IAU defined so don't add
          
        //calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
        if ((semi_major - semi_minor) < 0.0000001) 
            iflattening = 0;
        else
            iflattening = semi_major / (semi_major - semi_minor);
     
        //Set the body size but take into consideration which proj is being used to help w/ compatibility
        //Notice that most PDS projections are spherical based on the fact that ISIS/PICS are spherical 
        //Set the body size but take into consideration which proj is being used to help w/ proj4 compatibility
        //The use of a Sphere, polar radius or ellipse here is based on how ISIS does it internally
        if ( ( (EQUAL( map_proj_name, "STEREOGRAPHIC" ) && (fabs(center_lat) == 90)) ) || 
             (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC" )))  
        {
            if (bIsGeographic) { 
                //Geograpraphic, so set an ellipse
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, iflattening, 
                                "Reference_Meridian", 0.0 );
            } else {
                //Geocentric, so force a sphere using the semi-minor axis. I hope... 
                sphere_name += "_polarRadius";
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_minor, 0.0, 
                                "Reference_Meridian", 0.0 );
            }
        }
        else if ( (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) || 
                  (EQUAL( map_proj_name, "EQUIDISTANT" )) || 
                  (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) || 
                  (EQUAL( map_proj_name, "STEREOGRAPHIC" )) || 
                  (EQUAL( map_proj_name, "SINUSOIDAL" )) ) {
            //isis uses the spherical equation for these projections so force a sphere
            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                            semi_major, 0.0, 
                            "Reference_Meridian", 0.0 );
        } 
        else if (EQUAL( map_proj_name, "EQUIRECTANGULAR" )) { 
            //isis uses local radius as a sphere, which is pre-calculated in the PDS label as the semi-major
            sphere_name += "_localRadius";
            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                            semi_major, 0.0, 
                            "Reference_Meridian", 0.0 );
        } 
        else { 
            //All other projections: Mercator, Transverse Mercator, Lambert Conformal, etc.
            //Geographic, so set an ellipse
            if (bIsGeographic) {
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, iflattening, 
                                "Reference_Meridian", 0.0 );
            } else { 
                //Geocentric, so force a sphere. I hope... 
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, 0.0, 
                                "Reference_Meridian", 0.0 );
            }
        }

        // translate back into a projection string.
        char *pszResult = NULL;
        oSRS.exportToWkt( &pszResult );
        osProjection = pszResult;
        CPLFree( pszResult );
    }

/* ==================================================================== */
/*      Check for a .prj and world file to override the georeferencing. */
/* ==================================================================== */
    {
        CPLString osPath, osName;
        VSILFILE *fp;

        osPath = CPLGetPath( pszFilename );
        osName = CPLGetBasename(pszFilename);
        const char  *pszPrjFile = CPLFormCIFilename( osPath, osName, "prj" );

        fp = VSIFOpenL( pszPrjFile, "r" );
        if( fp != NULL )
        {
            char	**papszLines;
            OGRSpatialReference oSRS;

            VSIFCloseL( fp );
        
            papszLines = CSLLoad( pszPrjFile );

            if( oSRS.importFromESRI( papszLines ) == OGRERR_NONE )
            {
                char *pszResult = NULL;
                oSRS.exportToWkt( &pszResult );
                osProjection = pszResult;
                CPLFree( pszResult );
            }

            CSLDestroy( papszLines );
        }
    }
    
    if( dfULYMap != 0.5 || dfULYMap != 0.5 || dfXDim != 1.0 || dfYDim != 1.0 )
    {
        bGotTransform = TRUE;
        adfGeoTransform[0] = dfULXMap;
        adfGeoTransform[1] = dfXDim;
        adfGeoTransform[2] = 0.0;
        adfGeoTransform[3] = dfULYMap;
        adfGeoTransform[4] = 0.0;
        adfGeoTransform[5] = dfYDim;
    }
    
    if( !bGotTransform )
        bGotTransform = 
            GDALReadWorldFile( pszFilename, "psw", 
                               adfGeoTransform );

    if( !bGotTransform )
        bGotTransform = 
            GDALReadWorldFile( pszFilename, "wld", 
                               adfGeoTransform );

}
Beispiel #6
0
GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo )
{
/* -------------------------------------------------------------------- */
/*      Does this look like a VICAR dataset?                             */
/* -------------------------------------------------------------------- */
    if( !Identify( poOpenInfo ) )
        return NULL;

/* -------------------------------------------------------------------- */
/*      Open the file using the large file API.                         */
/* -------------------------------------------------------------------- */
    VSILFILE *fpQube = VSIFOpenL( poOpenInfo->pszFilename, "rb" );

    if( fpQube == NULL )
        return NULL;

    VICARDataset *poDS = new VICARDataset();
    if( ! poDS->oKeywords.Ingest( fpQube, poOpenInfo->pabyHeader ) ) {
        VSIFCloseL( fpQube );
        delete poDS;
        return NULL;
    }

    VSIFCloseL( fpQube );

    /***** CHECK ENDIANNESS **************/

    const char *value = poDS->GetKeyword( "INTFMT" );
    if (!EQUAL(value,"LOW") ) {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "%s layout not supported. Abort\n\n", value);
        delete poDS;
        return FALSE;
    }
    value = poDS->GetKeyword( "REALFMT" );
    if (!EQUAL(value,"RIEEE") ) {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "%s layout not supported. Abort\n\n", value);
        delete poDS;
        return FALSE;
    }

    char chByteOrder = 'M';
    value = poDS->GetKeyword( "BREALFMT" );
    if (EQUAL(value,"VAX") ) {
        chByteOrder = 'I';
    }

    /************ CHECK INSTRUMENT *****************/
    /************ ONLY HRSC TESTED *****************/

    bool bIsDTM = false;
    value = poDS->GetKeyword( "DTM.DTM_OFFSET" );
    if (!EQUAL(value,"") ) {
        bIsDTM = true;
    }

    value = poDS->GetKeyword( "BLTYPE" );
    if (!EQUAL(value,"M94_HRSC") && !bIsDTM ) {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "%s instrument not tested. Continue with caution!\n\n", value);
    }

    /***********   Grab layout type (BSQ, BIP, BIL) ************/

    char szLayout[10] = "BSQ"; //default to band seq.
    value = poDS->GetKeyword( "ORG" );
    if (!EQUAL(value,"BSQ") )
    {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "%s layout not supported. Abort\n\n", value);
        delete poDS;
        return FALSE;
    }

    strcpy(szLayout,"BSQ");
    const int nCols = atoi(poDS->GetKeyword("NS"));
    const int nRows = atoi(poDS->GetKeyword("NL"));
    const int nBands = atoi(poDS->GetKeyword("NB"));

    /***********   Grab record bytes  **********/
    int nSkipBytes = atoi(poDS->GetKeyword("NBB"));

    GDALDataType eDataType = GDT_Byte;
    double dfNoData = 0.0;
    if (EQUAL( poDS->GetKeyword( "FORMAT" ), "BYTE" )) {
        eDataType = GDT_Byte;
        dfNoData = NULL1;
    }
    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "HALF" )) {
        eDataType = GDT_Int16;
        dfNoData = NULL2;
        chByteOrder = 'I';
    }
    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "FULL" )) {
        eDataType = GDT_UInt32;
        dfNoData = 0;
    }
    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "REAL" )) {
        eDataType = GDT_Float32;
        dfNoData = NULL3;
        chByteOrder = 'I';
    }
    else {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "Could not find known VICAR label entries!\n");
        delete poDS;
        return NULL;
    }

    if( nRows < 1 || nCols < 1 || nBands < 1 )
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "File %s appears to be a VICAR file, but failed to find some "
                  "required keywords.",
                  poDS->GetDescription() );
        return FALSE;
    }
/* -------------------------------------------------------------------- */
/*      Capture some information from the file that is of interest.     */
/* -------------------------------------------------------------------- */
    poDS->nRasterXSize = nCols;
    poDS->nRasterYSize = nRows;

    double dfULXMap=0.5;
    double dfULYMap = 0.5;
    double dfXDim = 1.0;
    double dfYDim = 1.0;
    double xulcenter = 0.0;
    double yulcenter = 0.0;

    value = poDS->GetKeyword("MAP.MAP_SCALE");
    if (strlen(value) > 0 ) {
        dfXDim = CPLAtof(value);
        dfYDim = CPLAtof(value) * -1;
        dfXDim = dfXDim * 1000.0;
        dfYDim = dfYDim * 1000.0;
    }

    double dfSampleOffset_Shift =
        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Shift", "-0.5" ));

    double dfLineOffset_Shift =
        CPLAtof(CPLGetConfigOption( "PDS_LineProjOffset_Shift", "-0.5" ));

    double dfSampleOffset_Mult =
        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Mult", "-1.0") );

    double dfLineOffset_Mult =
        CPLAtof( CPLGetConfigOption( "PDS_LineProjOffset_Mult", "1.0") );

    /***********   Grab LINE_PROJECTION_OFFSET ************/
    value = poDS->GetKeyword("MAP.LINE_PROJECTION_OFFSET");
    if (strlen(value) > 0) {
        yulcenter = CPLAtof(value);
        dfULYMap = ((yulcenter + dfLineOffset_Shift) * -dfYDim * dfLineOffset_Mult);
    }
    /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
    value = poDS->GetKeyword("MAP.SAMPLE_PROJECTION_OFFSET");
    if( strlen(value) > 0 ) {
        xulcenter = CPLAtof(value);
        dfULXMap = ((xulcenter + dfSampleOffset_Shift) * dfXDim * dfSampleOffset_Mult);
    }

/* ==================================================================== */
/*      Get the coordinate system.                                      */
/* ==================================================================== */
    bool bProjectionSet = true;

    /***********  Grab TARGET_NAME  ************/
    /**** This is the planets name i.e. MARS ***/
    const CPLString target_name = poDS->GetKeyword("MAP.TARGET_NAME");

    /**********   Grab MAP_PROJECTION_TYPE *****/
    const CPLString map_proj_name
        = poDS->GetKeyword( "MAP.MAP_PROJECTION_TYPE");

    /******  Grab semi_major & convert to KM ******/
    const double semi_major
        = CPLAtof(poDS->GetKeyword( "MAP.A_AXIS_RADIUS")) * 1000.0;

    /******  Grab semi-minor & convert to KM ******/
    const double semi_minor
        = CPLAtof(poDS->GetKeyword( "MAP.C_AXIS_RADIUS")) * 1000.0;

    /***********   Grab CENTER_LAT ************/
    const double center_lat =
        CPLAtof(poDS->GetKeyword( "MAP.CENTER_LATITUDE"));

    /***********   Grab CENTER_LON ************/
    const double center_lon
        = CPLAtof(poDS->GetKeyword( "MAP.CENTER_LONGITUDE"));

    /**********   Grab 1st std parallel *******/
    const double first_std_parallel =
        CPLAtof(poDS->GetKeyword( "MAP.FIRST_STANDARD_PARALLEL"));

    /**********   Grab 2nd std parallel *******/
    const double second_std_parallel =
        CPLAtof(poDS->GetKeyword( "MAP.SECOND_STANDARD_PARALLEL"));

    /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
    // Need to further study how ocentric/ographic will effect the gdal library.
    // So far we will use this fact to define a sphere or ellipse for some projections
    // Frank - may need to talk this over
    bool bIsGeographic = true;
    value = poDS->GetKeyword("MAP.COORDINATE_SYSTEM_NAME");
    if (EQUAL( value, "PLANETOCENTRIC" ))
        bIsGeographic = false;

/**   Set oSRS projection and parameters --- all PDS supported types added if apparently supported in oSRS
      "AITOFF",  ** Not supported in GDAL??
      "ALBERS",
      "BONNE",
      "BRIESEMEISTER",   ** Not supported in GDAL??
      "CYLINDRICAL EQUAL AREA",
      "EQUIDISTANT",
      "EQUIRECTANGULAR",
      "GNOMONIC",
      "HAMMER",    ** Not supported in GDAL??
      "HENDU",     ** Not supported in GDAL??
      "LAMBERT AZIMUTHAL EQUAL AREA",
      "LAMBERT CONFORMAL",
      "MERCATOR",
      "MOLLWEIDE",
      "OBLIQUE CYLINDRICAL",
      "ORTHOGRAPHIC",
      "SIMPLE CYLINDRICAL",
      "SINUSOIDAL",
      "STEREOGRAPHIC",
      "TRANSVERSE MERCATOR",
      "VAN DER GRINTEN",     ** Not supported in GDAL??
      "WERNER"     ** Not supported in GDAL??
**/
    CPLDebug( "PDS", "using projection %s\n\n", map_proj_name.c_str());

    OGRSpatialReference oSRS;

    if ((EQUAL( map_proj_name, "EQUIRECTANGULAR" )) ||
        (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) ||
        (EQUAL( map_proj_name, "EQUIDISTANT" )) )  {
        oSRS.SetEquirectangular2 ( 0.0, center_lon, center_lat, 0, 0 );
    } else if (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) {
        oSRS.SetOrthographic ( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "SINUSOIDAL" )) {
        oSRS.SetSinusoidal ( center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "MERCATOR" )) {
        oSRS.SetMercator ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "STEREOGRAPHIC" )) {
        oSRS.SetStereographic ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC")) {
        oSRS.SetPS ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "TRANSVERSE_MERCATOR" )) {
        oSRS.SetTM ( center_lat, center_lon, 1, 0, 0 );
    } else if (EQUAL( map_proj_name, "LAMBERT_CONFORMAL_CONIC" )) {
        oSRS.SetLCC ( first_std_parallel, second_std_parallel,
                      center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "LAMBERT_AZIMUTHAL_EQUAL_AREA" )) {
        oSRS.SetLAEA( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "CYLINDRICAL_EQUAL_AREA" )) {
        oSRS.SetCEA  ( first_std_parallel, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "MOLLWEIDE" )) {
        oSRS.SetMollweide ( center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "ALBERS" )) {
        oSRS.SetACEA ( first_std_parallel, second_std_parallel,
                       center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "BONNE" )) {
        oSRS.SetBonne ( first_std_parallel, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "GNOMONIC" )) {
        oSRS.SetGnomonic ( center_lat, center_lon, 0, 0 );
    } else if (EQUAL( map_proj_name, "OBLIQUE_CYLINDRICAL" )) { 
        // hope Swiss Oblique Cylindrical is the same
        oSRS.SetSOC ( center_lat, center_lon, 0, 0 );
    } else {
        CPLDebug( "VICAR",
                  "Dataset projection %s is not supported. Continuing...",
                  map_proj_name.c_str() );
        bProjectionSet = false;
    }

    if (bProjectionSet) {
        //Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
        CPLString proj_target_name = map_proj_name + " " + target_name;
        oSRS.SetProjCS(proj_target_name); //set ProjCS keyword

        //The geographic/geocentric name will be the same basic name as the body name
        //'GCS' = Geographic/Geocentric Coordinate System
        CPLString geog_name = "GCS_" + target_name;

        //The datum and sphere names will be the same basic name aas the planet
        CPLString datum_name = "D_" + target_name;
        CPLString sphere_name = target_name; // + "_IAU_IAG");  //Might not be IAU defined so don't add

        //calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
        double iflattening = 0.0;
        if ((semi_major - semi_minor) < 0.0000001)
            iflattening = 0;
        else
            iflattening = semi_major / (semi_major - semi_minor);

        //Set the body size but take into consideration which proj is being used to help w/ compatibility
        //Notice that most PDS projections are spherical based on the fact that ISIS/PICS are spherical
        //Set the body size but take into consideration which proj is being used to help w/ proj4 compatibility
        //The use of a Sphere, polar radius or ellipse here is based on how ISIS does it internally
        if ( ( (EQUAL( map_proj_name, "STEREOGRAPHIC" ) && (fabs(center_lat) == 90)) ) ||
             (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC" )))
        {
            if (bIsGeographic) {
                //Geograpraphic, so set an ellipse
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, iflattening, 
                                "Reference_Meridian", 0.0 );
            } else {
                //Geocentric, so force a sphere using the semi-minor axis. I hope...
                sphere_name += "_polarRadius";
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_minor, 0.0, 
                                "Reference_Meridian", 0.0 );
            }
        }
        else if ( (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) || 
                  (EQUAL( map_proj_name, "EQUIDISTANT" )) || 
                  (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) || 
                  (EQUAL( map_proj_name, "STEREOGRAPHIC" )) || 
                  (EQUAL( map_proj_name, "SINUSOIDAL" )) ) {
            //isis uses the spherical equation for these projections so force a sphere
            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                            semi_major, 0.0, 
                            "Reference_Meridian", 0.0 );
        }
        else if (EQUAL( map_proj_name, "EQUIRECTANGULAR" )) {
            //isis uses local radius as a sphere, which is pre-calculated in the PDS label as the semi-major
            sphere_name += "_localRadius";
            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                            semi_major, 0.0, 
                            "Reference_Meridian", 0.0 );
        }
        else
        {
            //All other projections: Mercator, Transverse Mercator, Lambert Conformal, etc.
            //Geographic, so set an ellipse
            if (bIsGeographic) {
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, iflattening,
                                "Reference_Meridian", 0.0 );
            }
            else
            {
                //Geocentric, so force a sphere. I hope...
                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
                                semi_major, 0.0,
                                "Reference_Meridian", 0.0 );
            }
        }

        // translate back into a projection string.
        char *pszResult = NULL;
        oSRS.exportToWkt( &pszResult );
        poDS->osProjection = pszResult;
        CPLFree( pszResult );
    }
    {
        poDS->bGotTransform = TRUE;
        poDS->adfGeoTransform[0] = dfULXMap;
        poDS->adfGeoTransform[1] = dfXDim;
        poDS->adfGeoTransform[2] = 0.0;
        poDS->adfGeoTransform[3] = dfULYMap;
        poDS->adfGeoTransform[4] = 0.0;
        poDS->adfGeoTransform[5] = dfYDim;
    }

    CPLString osQubeFile = poOpenInfo->pszFilename;
    if( !poDS->bGotTransform )
        poDS->bGotTransform =
            GDALReadWorldFile( osQubeFile, "psw",
                               poDS->adfGeoTransform );

    if( !poDS->bGotTransform )
        poDS->bGotTransform =
            GDALReadWorldFile( osQubeFile, "wld",
                               poDS->adfGeoTransform );

/* -------------------------------------------------------------------- */
/*      Open target binary file.                                        */
/* -------------------------------------------------------------------- */
    if( poOpenInfo->eAccess == GA_ReadOnly )
        poDS->fpImage = VSIFOpenL( osQubeFile, "r" );
    else
        poDS->fpImage = VSIFOpenL( osQubeFile, "r+" );

    if( poDS->fpImage == NULL )
    {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "Failed to open %s with write permission.\n%s",
                  osQubeFile.c_str(),
                  VSIStrerror( errno ) );
        delete poDS;
        return NULL;
    }

    poDS->eAccess = poOpenInfo->eAccess;

/* -------------------------------------------------------------------- */
/*      Compute the line offsets.                                        */
/* -------------------------------------------------------------------- */

    const long int nItemSize = GDALGetDataTypeSize(eDataType)/8;
    const long int nPixelOffset = nItemSize;
    const long int nLineOffset = nPixelOffset * nCols + atoi(poDS->GetKeyword("NBB")) ;
    const long int nBandOffset = nLineOffset * nRows;

    nSkipBytes = atoi(poDS->GetKeyword("LBLSIZE"));

/* -------------------------------------------------------------------- */
/*      Create band information objects.                                */
/* -------------------------------------------------------------------- */
    for( int i = 0; i < nBands; i++ )
    {
        GDALRasterBand	*poBand
            = new RawRasterBand( poDS, i+1, poDS->fpImage, nSkipBytes + nBandOffset * i,
                                 nPixelOffset, nLineOffset, eDataType,
#ifdef CPL_LSB
                                   chByteOrder == 'I' || chByteOrder == 'L',
#else
                                   chByteOrder == 'M',
#endif
                                   TRUE );

        poDS->SetBand( i+1, poBand );
        poBand->SetNoDataValue( dfNoData );
        if (bIsDTM) {
            poBand->SetScale( (double) CPLAtof(poDS->GetKeyword( "DTM.DTM_SCALING_FACTOR") ) );
            poBand->SetOffset( (double) CPLAtof(poDS->GetKeyword( "DTM.DTM_OFFSET") ) );
            const char* pszMin = poDS->GetKeyword( "DTM.DTM_MINIMUM_DN", NULL );
            const char* pszMax = poDS->GetKeyword( "DTM.DTM_MAXIMUM_DN", NULL );
            if (pszMin != NULL && pszMax != NULL )
                poBand->SetStatistics(CPLAtofM(pszMin),CPLAtofM(pszMax),0,0);
            const char* pszNoData = poDS->GetKeyword( "DTM.DTM_MISSING_DN", NULL );
            if (pszNoData != NULL )
                poBand->SetNoDataValue( CPLAtofM(pszNoData) );
        } else if (EQUAL( poDS->GetKeyword( "BLTYPE"), "M94_HRSC" )) {
            float scale=CPLAtof(poDS->GetKeyword("DLRTO8.REFLECTANCE_SCALING_FACTOR","-1."));
            if (scale < 0.) {
                scale = CPLAtof(poDS->GetKeyword( "HRCAL.REFLECTANCE_SCALING_FACTOR","1."));
            }
            poBand->SetScale( scale );
            float offset=CPLAtof(poDS->GetKeyword("DLRTO8.REFLECTANCE_OFFSET","-1."));
            if (offset < 0.) {
                offset = CPLAtof(poDS->GetKeyword( "HRCAL.REFLECTANCE_OFFSET","0."));
            }
            poBand->SetOffset( offset );
        }
        const char* pszMin = poDS->GetKeyword( "STATISTICS.MINIMUM", NULL );
        const char* pszMax = poDS->GetKeyword( "STATISTICS.MAXIMUM", NULL );
        const char* pszMean = poDS->GetKeyword( "STATISTICS.MEAN", NULL );
        const char* pszStdDev = poDS->GetKeyword( "STATISTICS.STANDARD_DEVIATION", NULL );
        if (pszMin != NULL && pszMax != NULL && pszMean != NULL && pszStdDev != NULL )
                poBand->SetStatistics(CPLAtofM(pszMin),CPLAtofM(pszMax),CPLAtofM(pszMean),CPLAtofM(pszStdDev));
    }


/* -------------------------------------------------------------------- */
/*      Instrument-specific keywords as metadata.                       */
/* -------------------------------------------------------------------- */

/******************   HRSC    ******************************/

    if (EQUAL( poDS->GetKeyword( "BLTYPE"), "M94_HRSC" ) ) {
        poDS->SetMetadataItem( "SPACECRAFT_NAME", poDS->GetKeyword( "M94_INSTRUMENT.INSTRUMENT_HOST_NAME") );
        poDS->SetMetadataItem( "PRODUCT_TYPE", poDS->GetKeyword( "TYPE"));

        if (EQUAL( poDS->GetKeyword( "M94_INSTRUMENT.DETECTOR_ID"), "MEX_HRSC_SRC" )) {
            static const char *apszKeywords[] =  {
                        "M94_ORBIT.IMAGE_TIME",
                        "FILE.EVENT_TYPE",
                        "FILE.PROCESSING_LEVEL_ID",
                        "M94_INSTRUMENT.DETECTOR_ID", 
                        "M94_CAMERAS.EXPOSURE_DURATION",
                        "HRCONVER.INSTRUMENT_TEMPERATURE", NULL
                    };
            for( int i = 0; apszKeywords[i] != NULL; i++ ) {
                const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
                if( pszKeywordValue != NULL )
                    poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
            }
        } else {
            static const char *apszKeywords[] =  {
                "M94_ORBIT.START_TIME", "M94_ORBIT.STOP_TIME",
                "M94_INSTRUMENT.DETECTOR_ID",
                "M94_CAMERAS.MACROPIXEL_SIZE",
                "FILE.EVENT_TYPE",
                "M94_INSTRUMENT.MISSION_PHASE_NAME",
                "HRORTHO.SPICE_FILE_NAME",
                "HRCONVER.MISSING_FRAMES", "HRCONVER.OVERFLOW_FRAMES", "HRCONVER.ERROR_FRAMES",
                "HRFOOT.BEST_GROUND_SAMPLING_DISTANCE",
                "DLRTO8.RADIANCE_SCALING_FACTOR", "DLRTO8.RADIANCE_OFFSET",
                "DLRTO8.REFLECTANCE_SCALING_FACTOR", "DLRTO8.REFLECTANCE_OFFSET",
                "HRCAL.RADIANCE_SCALING_FACTOR", "HRCAL.RADIANCE_OFFSET",
                "HRCAL.REFLECTANCE_SCALING_FACTOR", "HRCAL.REFLECTANCE_OFFSET",
                "HRORTHO.DTM_NAME", "HRORTHO.EXTORI_FILE_NAME", "HRORTHO.GEOMETRIC_CALIB_FILE_NAME",
                NULL
            };
            for( int i = 0; apszKeywords[i] != NULL; i++ ) {
                const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i], NULL );
                if( pszKeywordValue != NULL )
                    poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
            }
        }
    }
    if (bIsDTM && EQUAL( poDS->GetKeyword( "MAP.TARGET_NAME"), "MARS" )) {
        poDS->SetMetadataItem( "SPACECRAFT_NAME", "MARS_EXPRESS" );
        poDS->SetMetadataItem( "PRODUCT_TYPE", "DTM");
        static const char *apszKeywords[] = {
            "DTM.DTM_MISSING_DN", "DTM.DTM_OFFSET", "DTM.DTM_SCALING_FACTOR", "DTM.DTM_A_AXIS_RADIUS", 
            "DTM.DTM_B_AXIS_RADIUS", "DTM.DTM_C_AXIS_RADIUS", "DTM.DTM_DESC", "DTM.DTM_MINIMUM_DN",
            "DTM.DTM_MAXIMUM_DN", NULL };
        for( int i = 0; apszKeywords[i] != NULL; i++ ) {
            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
            if( pszKeywordValue != NULL )
                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
        }
    }


/******************   DAWN   ******************************/
    else if (EQUAL( poDS->GetKeyword( "INSTRUMENT_ID"), "FC2" )) {
        poDS->SetMetadataItem( "SPACECRAFT_NAME", "DAWN" );
        static const char *apszKeywords[] =  {"ORBIT_NUMBER","FILTER_NUMBER",
        "FRONT_DOOR_STATUS",
        "FIRST_LINE",
        "FIRST_LINE_SAMPLE",
        "PRODUCER_INSTITUTION_NAME",
        "SOURCE_FILE_NAME",
        "PROCESSING_LEVEL_ID",
        "TARGET_NAME",
        "LIMB_IN_IMAGE",
        "POLE_IN_IMAGE",
        "REFLECTANCE_SCALING_FACTOR",
        "SPICE_FILE_NAME",
        "SPACECRAFT_CENTRIC_LATITUDE",
        "SPACECRAFT_EASTERN_LONGITUDE",
        "FOOTPRINT_POSITIVE_LONGITUDE",
            NULL };
        for( int i = 0; apszKeywords[i] != NULL; i++ ) {
            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
            if( pszKeywordValue != NULL )
                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
        }

    }
    else if (bIsDTM && EQUAL( poDS->GetKeyword( "TARGET_NAME"), "VESTA" )) {
        poDS->SetMetadataItem( "SPACECRAFT_NAME", "DAWN" );
        poDS->SetMetadataItem( "PRODUCT_TYPE", "DTM");
        static const char *apszKeywords[] = {
            "DTM_MISSING_DN", "DTM_OFFSET", "DTM_SCALING_FACTOR", "DTM_A_AXIS_RADIUS", 
            "DTM_B_AXIS_RADIUS", "DTM_C_AXIS_RADIUS", "DTM_MINIMUM_DN",
            "DTM_MAXIMUM_DN", "MAP_PROJECTION_TYPE", "COORDINATE_SYSTEM_NAME",
            "POSITIVE_LONGITUDE_DIRECTION", "MAP_SCALE",
            "CENTER_LONGITUDE", "LINE_PROJECTION_OFFSET", "SAMPLE_PROJECTION_OFFSET",
            NULL };
        for( int i = 0; apszKeywords[i] != NULL; i++ ) {
            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
            if( pszKeywordValue != NULL )
                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
        }
    }


/* -------------------------------------------------------------------- */
/*      END Instrument-specific keywords as metadata.                   */
/* -------------------------------------------------------------------- */

    if (EQUAL(poDS->GetKeyword( "EOL"), "1" ))
        poDS->SetMetadataItem( "END-OF-DATASET_LABEL", "PRESENT" );
    poDS->SetMetadataItem( "CONVERSION_DETAILS", "http://www.lpi.usra.edu/meetings/lpsc2014/pdf/1088.pdf" );

/* -------------------------------------------------------------------- */
/*      Initialize any PAM information.                                 */
/* -------------------------------------------------------------------- */
    poDS->TryLoadXML();

/* -------------------------------------------------------------------- */
/*      Check for overviews.                                            */
/* -------------------------------------------------------------------- */
    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );

    return( poDS );
}
IRaster* ingestGDALRaster()
{
    GDALDataset* ds = gdalDataset;
    cout << "Reading raster metadata...";

    GDALRasterBand* band = ds->GetRasterBand(bandNum);
    int xSize = band->GetXSize();
    int ySize = band->GetYSize();
    int hasNoDataValue;
    double noDataValue = band->GetNoDataValue(&hasNoDataValue);
    if (hasNoDataValue != 0)
        noDataValue = NULL_DOUBLE_;
    double xForm[6];
    ds->GetGeoTransform(xForm);
    double minX = xForm[0];
    double cellSizeX = xForm[1];
    double skewX = xForm[2];
    double minY = xForm[3];
    double skewY = xForm[4];
    double cellSizeY = xForm[5];
    string* spatialRef = new string(ds->GetProjectionRef());

    if( ds->GetMetadataItem("NC_GLOBAL#IOAPI_VERSION", "") != NULL) {
        // Get georeference from IOAPI metadata
        // See: http://www.baronams.com/products/ioapi/GRIDS.html#horiz

        // Build the affine transform from metadata
        minX = atof(ds->GetMetadataItem("NC_GLOBAL#XORIG", ""));
        minY = atof(ds->GetMetadataItem("NC_GLOBAL#YORIG", ""));
        cellSizeX = atof(ds->GetMetadataItem("NC_GLOBAL#XCELL", ""));
        cellSizeY = atof(ds->GetMetadataItem("NC_GLOBAL#YCELL", ""));
        skewX = 0;
        skewY = 0;

        // Build the SpatialReference
        double xcent, ycent, p_alp, p_bet, p_gam;
        char *gdnam;
        OGRSpatialReference* sref = new OGRSpatialReference("");
        // Assume datum is WGS84 (may not be, but IO/API files don't (can't?) say...)
        sref->SetWellKnownGeogCS("WGS84");

        int gdtyp = atoi(ds->GetMetadataItem("NC_GLOBAL#GDTYP", ""));
        switch(gdtyp) {
            case 0:
                // Unknown projection (we assume lat-lon)
                break;

            case 1:
                // LATGRD3 -- Latitude/longitude
                break;

            case 2:
                // LAMGRD3 -- Lambert Conformal Conic (two standard parallels)
                xcent = atof(ds->GetMetadataItem("NC_GLOBAL#XCENT", ""));
                ycent = atof(ds->GetMetadataItem("NC_GLOBAL#YCENT", ""));
                p_alp = atof(ds->GetMetadataItem("NC_GLOBAL#P_ALP", ""));
                p_bet = atof(ds->GetMetadataItem("NC_GLOBAL#P_BET", ""));
                sref->SetLCC(p_alp, p_bet, ycent, xcent, 0, 0);
                gdnam = (char *)ds->GetMetadataItem("NC_GLOBAL#GDNAM", "");
                sref->SetProjCS(gdnam);
                break;
                
            case 9:
                // ALBGRD3 -- Albers Equal-Area Conic
                xcent = atof(ds->GetMetadataItem("NC_GLOBAL#XCENT", ""));
                ycent = atof(ds->GetMetadataItem("NC_GLOBAL#YCENT", ""));
                p_alp = atof(ds->GetMetadataItem("NC_GLOBAL#P_ALP", ""));
                p_bet = atof(ds->GetMetadataItem("NC_GLOBAL#P_BET", ""));
                sref->SetACEA(p_alp, p_bet, ycent, xcent, 0, 0);
                gdnam = (char *)ds->GetMetadataItem("NC_GLOBAL#GDNAM", "");
                sref->SetProjCS(gdnam);
                break;
                
            case 10:
                // LEQGRID3 -- Lambert Azimuthal Equal-Area
                p_alp = atof(ds->GetMetadataItem("NC_GLOBAL#P_ALP", ""));
                // Correct for bad metadata on some files
                if(p_alp == 0.0) {
                    xcent = atof(ds->GetMetadataItem("NC_GLOBAL#XCENT", ""));
                    ycent = atof(ds->GetMetadataItem("NC_GLOBAL#YCENT", ""));
                    p_alp = ycent;
                    p_gam = xcent;
                } else {
                    p_gam = atof(ds->GetMetadataItem("NC_GLOBAL#P_GAM", ""));
                }
                sref->SetLAEA(p_alp, p_gam, 0, 0);
                gdnam = (char *)ds->GetMetadataItem("NC_GLOBAL#GDNAM", "");
                sref->SetProjCS(gdnam);
                break;

            default:
                throw new runtime_error("ERROR: Unable to parse IO/API GDTYP variable");
        }

        char* wktSrStr = new char[spatialRef->length()];
        strcpy((char *)spatialRef->c_str(), wktSrStr);
        sref->exportToWkt(&wktSrStr);
        //CPLFree(sref);
        spatialRef->assign(wktSrStr);
    }

    cout << "...Done.\nReading raster band " << bandNum << "...";

    IRaster* result = NULL;
    CPLErr retval;

    switch (band->GetRasterDataType()) {

        //retval = band->RasterIO(GF_Read, 0, 0, band->XSize, band->YSize, floatArray, band->XSize, band->YSize, 0, 0);


        case GDT_Float32: {
            float* floatArray = new float[xSize * ySize];
            retval = band->RasterIO(GF_Read, 0, 0, xSize, ySize, floatArray, xSize, ySize, band->GetRasterDataType(), 0, 0);
            if (retval != CE_None)
                throw new runtime_error("GDALRasterBand::ReadBlock() returned error");
            result = new Raster<float>(floatArray, xSize, ySize, cellSizeX, cellSizeY, minX, minY, skewX, skewY, spatialRef, noDataValue);
            cout << " -- Pixel type: Float32 -- ...Done\n";
        } break;

        case GDT_Float64: {
            double* doubleArray = new double[xSize * ySize];
            retval = band->RasterIO(GF_Read, 0, 0, xSize, ySize, doubleArray, xSize, ySize, band->GetRasterDataType(), 0, 0);
            if (retval != CE_None)
                throw new runtime_error("GDALRasterBand::ReadBlock() returned error");
            result = new Raster<double>(doubleArray, xSize, ySize, cellSizeX, cellSizeY, minX, minY, skewX, skewY, spatialRef, noDataValue);
            cout << " -- Pixel type: Float64 -- ...Done\n";
        } break;

        case GDT_Int32: {
            int* intArray = new int[xSize * ySize];
            retval = band->RasterIO(GF_Read, 0, 0, xSize, ySize, intArray, xSize, ySize, band->GetRasterDataType(), 0, 0);
            if (retval != CE_None)
                throw new runtime_error("GDALRasterBand::ReadBlock() returned error");
            result = new Raster<int>(intArray, xSize, ySize, cellSizeX, cellSizeY, minX, minY, skewX, skewY, spatialRef, noDataValue);
            cout << " -- Pixel type: Int32 -- ...Done\n";
        } break;

        case GDT_Int16: {
            short* shortArray = new short[xSize * ySize];
            retval = band->RasterIO(GF_Read, 0, 0, xSize, ySize, shortArray, xSize, ySize, band->GetRasterDataType(), 0, 0);
            if (retval != CE_None)
                throw new runtime_error("GDALRasterBand::ReadBlock() returned error");
            result = new Raster<short>(shortArray, xSize, ySize, cellSizeX, cellSizeY, minX, minY, skewX, skewY, spatialRef, noDataValue);
            cout << " -- Pixel type: Int32 -- ...Done\n";
        } break;

        case GDT_Byte: {
            char* byteArray = new char[xSize * ySize];
            retval = band->RasterIO(GF_Read, 0, 0, xSize, ySize, byteArray, xSize, ySize, band->GetRasterDataType(), 0, 0);
            if (retval != CE_None)
                throw new runtime_error("GDALRasterBand::ReadBlock() returned error");
            result = new Raster<char>(byteArray, xSize, ySize, cellSizeX, cellSizeY, minX, minY, skewX, skewY, spatialRef, noDataValue);
            cout << " -- Pixel type: Byte -- ...Done\n";
        } break;

        default:
            throw new runtime_error("Unsupported pixel type");
    }

    return result;
}
rspfString rspfOgcWktTranslator::fromOssimKwl(const rspfKeywordlist &kwl,
                                                const char *prefix)const
{
   rspfString projType = kwl.find(rspfKeywordNames::TYPE_KW);
   rspfString datumType = kwl.find(rspfKeywordNames::DATUM_KW);
   
   rspfString wktString;
   OGRSpatialReference oSRS;
   
   if(projType == "")
   {
      return wktString;
   }
   
   rspfString zone = kwl.find(prefix, rspfKeywordNames::ZONE_KW);
   rspfString hemisphere = kwl.find(prefix, rspfKeywordNames::HEMISPHERE_KW);
   rspfString parallel1  = kwl.find(prefix, rspfKeywordNames::STD_PARALLEL_1_KW);
   rspfString parallel2  = kwl.find(prefix, rspfKeywordNames::STD_PARALLEL_2_KW);
   rspfString originLat  = kwl.find(prefix, rspfKeywordNames::ORIGIN_LATITUDE_KW);
   rspfString centralMeridian = kwl.find(prefix, rspfKeywordNames::CENTRAL_MERIDIAN_KW);
   rspfString scale = kwl.find(prefix, rspfKeywordNames::SCALE_FACTOR_KW);
   rspfString pcsCode = kwl.find(prefix, rspfKeywordNames::PCS_CODE_KW);
   rspfDpt falseEastingNorthing;
   falseEastingNorthing.x = 0.0;
   falseEastingNorthing.y = 0.0;
   const char *lookup =
      kwl.find(prefix, rspfKeywordNames::FALSE_EASTING_NORTHING_UNITS_KW);
   if (lookup)
   {
      rspfUnitType units =
         static_cast<rspfUnitType>(rspfUnitTypeLut::instance()->
                                    getEntryNumber(lookup));
      
      lookup = kwl.find(prefix, rspfKeywordNames::FALSE_EASTING_NORTHING_KW);
      if (lookup)
      {
         rspfDpt eastingNorthing;
         eastingNorthing.toPoint(std::string(lookup));
         
         switch (units)
         {
            case RSPF_METERS:
            {
               falseEastingNorthing = eastingNorthing;
               break;
            }
            case RSPF_FEET:
            case RSPF_US_SURVEY_FEET:
            {
               rspfUnitConversionTool ut;
               ut.setValue(eastingNorthing.x, units);
               falseEastingNorthing.x = ut.getValue(RSPF_METERS);
               ut.setValue(eastingNorthing.y, units);
               falseEastingNorthing.y = ut.getValue(RSPF_METERS);
               break;
            }
            default:
            {
               rspfNotify(rspfNotifyLevel_WARN)
                  << "rspfOgcWktTranslator::fromOssimKwl WARNING!"
                  << "Unhandled unit type for "
                  << rspfKeywordNames::FALSE_EASTING_NORTHING_UNITS_KW
                  << ":  " 
                  << ( rspfUnitTypeLut::instance()->
                       getEntryString(units).c_str() )
                  << endl;
               break;
            }
         } // End of switch (units)
         
      }  // End of if (FALSE_EASTING_NORTHING_KW)
   } // End of if (FALSE_EASTING_NORTHING_UNITS_KW)
   else
   {
      lookup =  kwl.find(prefix, rspfKeywordNames::FALSE_EASTING_KW);
      if(lookup)
      {
         falseEastingNorthing.x = fabs(rspfString(lookup).toFloat64());
      }
      
      lookup =  kwl.find(prefix, rspfKeywordNames::FALSE_NORTHING_KW);
      if(lookup)
      {
         falseEastingNorthing.y = fabs(rspfString(lookup).toFloat64());
      }
   }
   oSRS.SetLinearUnits("Meter", 1.0);
   int pcsCodeVal = (pcsCode.empty() == false) ? pcsCode.toInt() : EPSG_CODE_MAX;
   if(pcsCodeVal < EPSG_CODE_MAX)
   {
      rspfEpsgProjectionDatabase* proj_db = rspfEpsgProjectionDatabase::instance();
      rspfString pcsCodeName = proj_db->findProjectionName(pcsCodeVal);
      if ( pcsCodeName.contains("HARN") && pcsCodeName.contains("_Feet") )
      {
         rspfString feetStr("_Feet");
         rspfString newPcsCodeName( pcsCodeName.before(feetStr).c_str() );
         rspfString epsg_spec = proj_db->findProjectionCode(newPcsCodeName);
         rspf_uint32 new_code = epsg_spec.after(":").toUInt32();
         if (new_code)
          pcsCodeVal = new_code;
      }
      oSRS.importFromEPSG( pcsCodeVal );
   }
   else if(projType == "rspfUtmProjection")
   {
#if 0
      hemisphere = hemisphere.trim().upcase();
      
      if(hemisphere != "")
      {
         oSRS.SetUTM(zone.toLong(), hemisphere != "S");
      }
      else
      {
         oSRS.SetUTM(zone.toLong(), true);
      }
#else
      short gcs = USER_DEFINED;
      if (datumType == "WGE") gcs = GCS_WGS_84;
      else if (datumType == "WGD") gcs = GCS_WGS_72;
      else if (datumType == "NAR-C") gcs = GCS_NAD83;
      else if (datumType == "NAR") gcs = GCS_NAD83;
      else if (datumType == "NAS-C") gcs = GCS_NAD27;
      else if (datumType == "NAS") gcs = GCS_NAD27;
      else if (datumType == "ADI-M") gcs = GCS_Adindan;
      else if (datumType == "ARF-M") gcs = GCS_Arc_1950;
      else if (datumType == "ARS-M") gcs = GCS_Arc_1960;
      else if (datumType == "EUR-7" || datumType == "EUR-M") gcs = GCS_ED50;
      else if ((datumType == "OGB-7") ||
               (datumType == "OGB-M") ||
               (datumType == "OGB-A") ||
               (datumType == "OGB-B") ||
               (datumType == "OGB-C") ||
               (datumType == "OGB-D")) gcs = GCS_OSGB_1936;
      else if  (datumType == "TOY-M")  gcs = GCS_Tokyo;
      else
      {
         if(traceDebug())
         {
            rspfNotify(rspfNotifyLevel_DEBUG)
               << "DATUM = " << datumType << " tag not written " << std::endl
               << "Please let us know so we can add it"          << std::endl;
         }
      }
      int mapZone = zone.toInt();
      hemisphere = hemisphere.trim().upcase();
      bool bDoImportFromEPSG = false;
      switch ( gcs )
      {
         case GCS_WGS_84:
         {
            if (hemisphere == "N") // Northern hemisphere.
            {
               pcsCodeVal = 32600 + mapZone;
            }
            else // Southern hemisphere.
            {
               pcsCodeVal = 32700 + mapZone;
            }
            bDoImportFromEPSG = true;
            break;
         }
         case GCS_WGS_72:
         {
            if (hemisphere == "N") // Northern hemisphere.
            {
               pcsCodeVal = 32200 + mapZone;
            }
            else // Southern hemisphere.
            {
               pcsCodeVal = 32300 + mapZone;
            }
            bDoImportFromEPSG = true;
            break;
         }
         case GCS_NAD27:
         {
            if (hemisphere == "N") // Northern hemisphere.
            {
               pcsCodeVal = 26700 + mapZone;
            }
            else // Southern hemisphere.
            {
               pcsCodeVal = 32000 + mapZone;
            }
            bDoImportFromEPSG = true;
            break;
         }
         case GCS_NAD83:
         {
            if (hemisphere == "N") // Northern hemisphere.
            {
               pcsCodeVal = 26900 + mapZone;
            }
            else // Southern hemisphere.
            {
               pcsCodeVal = 32100 + mapZone;
            }
            bDoImportFromEPSG = true;
            break;
         }
         default:
         {
            if (mapZone > 0) // Northern hemisphere.
            {
               pcsCodeVal = 16000 + mapZone;
            }
            else if (mapZone < 0) // Southern hemisphere.
            {
               hemisphere = "S";
               pcsCodeVal = 16100 + abs(mapZone);
            }
            break;
         }
      } // End of "switch ( gcs )"
      if ( bDoImportFromEPSG == true )
         oSRS.importFromEPSG( pcsCodeVal );
      else
      {
         if(hemisphere != "")
         {
            oSRS.SetUTM(zone.toLong(), hemisphere != "S");
         }
         else
         {
            oSRS.SetUTM(zone.toLong(), true);
         }
      }
#endif
   }
   else if(projType == "rspfLlxyProjection")
   {
      OGRSpatialReference oGeogCS;
      
      oGeogCS.SetEquirectangular(0.0,
                                 0.0,
                                 0.0,
                                 0.0);
      oGeogCS.SetAngularUnits(SRS_UA_DEGREE, atof(SRS_UA_DEGREE_CONV));
      
      oSRS.CopyGeogCSFrom( &oGeogCS );  
   }
   else if(projType == "rspfEquDistCylProjection")
   {
      OGRSpatialReference oGeogCS;
      
      oGeogCS.SetEquirectangular(originLat.toDouble(),
                                 centralMeridian.toDouble(),
                                 falseEastingNorthing.x,
                                 falseEastingNorthing.y);
      oGeogCS.SetAngularUnits(SRS_UA_DEGREE, atof(SRS_UA_DEGREE_CONV));
      
      oSRS.CopyGeogCSFrom( &oGeogCS );  
   }
   else if(projType == "rspfSinusoidalProjection")
   {
      oSRS.SetSinusoidal(centralMeridian.toDouble(),
                         falseEastingNorthing.x,
                         falseEastingNorthing.y);
   }
   else if(projType == "rspfCylEquAreaProjection")
   {
      oSRS.SetCEA(originLat.toDouble(),
                  centralMeridian.toDouble(),
                  falseEastingNorthing.x,
                  falseEastingNorthing.y);
   }
   else if(projType == "rspfCassiniProjection")
   {
      oSRS.SetCS(originLat.toDouble(),
                 centralMeridian.toDouble(),
                 falseEastingNorthing.x,
                 falseEastingNorthing.y);
   }
   else if(projType == "rspfAlbersProjection")
   {
      oSRS.SetACEA(parallel1.toDouble(),
                   parallel2.toDouble(),
                   originLat.toDouble(),
                   centralMeridian.toDouble(),
                   falseEastingNorthing.x,
                   falseEastingNorthing.y);
   }
   else if(projType == "rspfAzimEquDistProjection")
   {
      oSRS.SetAE(originLat.toDouble(),
                 centralMeridian.toDouble(),
                 falseEastingNorthing.x,
                 falseEastingNorthing.y);
   }
   else if(projType == "rspfEckert4Projection")
   {
      oSRS.SetEckertIV(centralMeridian.toDouble(),
                       falseEastingNorthing.x,
                       falseEastingNorthing.y);
   }
   else if(projType == "rspfEckert6Projection")
   {
      oSRS.SetEckertVI(centralMeridian.toDouble(),
                       falseEastingNorthing.x,
                       falseEastingNorthing.y);
   }
   else if(projType == "rspfGnomonicProjection")
   {
      oSRS.SetGnomonic(originLat.toDouble(),
                       centralMeridian.toDouble(),
                       falseEastingNorthing.x,
                       falseEastingNorthing.y);
   }
   else if(projType == "rspfLambertConformalConicProjection")
   {
      oSRS.SetLCC(parallel1.toDouble(),
                  parallel2.toDouble(),
                  originLat.toDouble(),
                  centralMeridian.toDouble(),
                  falseEastingNorthing.x,
                  falseEastingNorthing.y);
   }
   else if(projType == "rspfVanDerGrintenProjection")
   {
      oSRS.SetVDG(centralMeridian.toDouble(),
                  falseEastingNorthing.x,
                  falseEastingNorthing.y);
   }
   else if(projType == "rspfMillerProjection")
   {
      oSRS.SetMC(originLat.toDouble(),
                 centralMeridian.toDouble(),
                 falseEastingNorthing.x,
                 falseEastingNorthing.y);
   }
   else if(projType == "rspfMercatorProjection")
   {
      oSRS.SetMercator(originLat.toDouble(),
                       centralMeridian.toDouble(),
                       scale.toDouble(),
                       falseEastingNorthing.x,
                       falseEastingNorthing.y);
   }
   else if(projType == "rspfMollweidProjection")
   {
      oSRS.SetMollweide(centralMeridian.toDouble(),
                        falseEastingNorthing.x,
                        falseEastingNorthing.y);
   }
   else if(projType == "rspfNewZealandMapGridProjection")
   {
      oSRS.SetNZMG(originLat.toDouble(),
                   centralMeridian.toDouble(),
                   falseEastingNorthing.x,
                   falseEastingNorthing.y);
   }
   else if(projType == "rspfOrthoGraphicProjection")
   {
      oSRS.SetOrthographic(originLat.toDouble(),
                           centralMeridian.toDouble(),
                           falseEastingNorthing.x,
                           falseEastingNorthing.y);
   }
   else if(projType == "rspfPolarStereoProjection")
   {
      oSRS.SetPS(originLat.toDouble(),
                 centralMeridian.toDouble(),
                 scale.toDouble(),
                 falseEastingNorthing.x,
                 falseEastingNorthing.y);
   }
   else if(projType == "rspfPolyconicProjectio")
   {
      oSRS.SetPolyconic(originLat.toDouble(),
                        centralMeridian.toDouble(),
                        falseEastingNorthing.x,
                        falseEastingNorthing.y);
   }
   else if(projType == "rspfStereographicProjection")
   {
      oSRS.SetStereographic(originLat.toDouble(),
                            centralMeridian.toDouble(),
                            scale.toDouble(),
                            falseEastingNorthing.x,
                            falseEastingNorthing.y);
   }
   else if(projType == "rspfTransMercatorProjection")
   {
      oSRS.SetTM(originLat.toDouble(),
                 centralMeridian.toDouble(),
                 scale.toDouble(),
                 falseEastingNorthing.x,
                 falseEastingNorthing.y);
   }
   else 
   {
      cerr << "rspfOgcWktTranslator::fromOssimKwl:\n"
           << "Projection translation for "
           << projType
           << " not supported "
           << endl;
   }
   
   if(pcsCodeVal >= EPSG_CODE_MAX)
   {
      datumType =  datumType.upcase();
      
      if(datumType == "WGE")
      {
         oSRS.SetWellKnownGeogCS("WGS84");
      }
      else if(datumType == "WGD")
      {
         oSRS.SetWellKnownGeogCS("WGS72");      
      }
      else if(datumType == "NAS-C") //1927
      {
         oSRS.SetWellKnownGeogCS("NAD27");      
      }
      else if(datumType == "NAS") //1927
      {
         oSRS.SetWellKnownGeogCS("NAD27");      
      }
      else if(datumType == "NAR-C") // 1983
      {
         oSRS.SetWellKnownGeogCS("NAD83");
      }
      else if(datumType == "NAR") // 1983
      {
         oSRS.SetWellKnownGeogCS("NAD83");
      }
      else if(datumType == "NTF")
      {
        oSRS.SetWellKnownGeogCS("EPSG:4275");
      }
      else
      {
         cerr << "rspfOgcWktTranslator::fromOssimKwl: Datum translation for "
              << datumType
              <<" not supported"
              << endl;
      }
   }
   char* exportString = NULL;
   oSRS.exportToWkt(&exportString);
   
   if(exportString)
   {
      wktString = exportString;
      OGRFree(exportString);
   }
   return wktString;
   
}