/****************************************************************************** * $Id: dteddataset.cpp 10646 2007-01-18 02:38:10Z warmerdam $ * * Project: DTED Translator * Purpose: GDALDataset driver for DTED translator. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "dted_api.h" #include "gdal_pam.h" CPL_CVSID("$Id: dteddataset.cpp 10646 2007-01-18 02:38:10Z warmerdam $"); CPL_C_START void GDALRegister_DTED(void); CPL_C_END /************************************************************************/ /* ==================================================================== */ /* DTEDDataset */ /* ==================================================================== */ /************************************************************************/ class DTEDRasterBand; class DTEDDataset : public GDALPamDataset { friend class DTEDRasterBand; DTEDInfo *psDTED; public: virtual ~DTEDDataset(); virtual const char *GetProjectionRef(void); virtual CPLErr GetGeoTransform( double * ); static GDALDataset *Open( GDALOpenInfo * ); }; /************************************************************************/ /* ==================================================================== */ /* DTEDRasterBand */ /* ==================================================================== */ /************************************************************************/ class DTEDRasterBand : public GDALPamRasterBand { friend class DTEDDataset; int bNoDataSet; double dfNoDataValue; public: DTEDRasterBand( DTEDDataset *, int ); virtual CPLErr IReadBlock( int, int, void * ); virtual double GetNoDataValue( int *pbSuccess = NULL ); virtual const char* GetUnitType() { return "m"; } }; /************************************************************************/ /* DTEDRasterBand() */ /************************************************************************/ DTEDRasterBand::DTEDRasterBand( DTEDDataset *poDS, int nBand ) { this->poDS = poDS; this->nBand = nBand; eDataType = GDT_Int16; bNoDataSet = TRUE; dfNoDataValue = (double) DTED_NODATA_VALUE; nBlockXSize = 1; nBlockYSize = poDS->GetRasterYSize();; } /************************************************************************/ /* IReadBlock() */ /************************************************************************/ CPLErr DTEDRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage ) { DTEDDataset *poDTED_DS = (DTEDDataset *) poDS; int nYSize = poDTED_DS->psDTED->nYSize; GInt16 *panData; (void) nBlockXOff; CPLAssert( nBlockYOff == 0 ); /* -------------------------------------------------------------------- */ /* Read the data. */ /* -------------------------------------------------------------------- */ panData = (GInt16 *) pImage; if( !DTEDReadProfile( poDTED_DS->psDTED, nBlockXOff, panData ) ) return CE_Failure; /* -------------------------------------------------------------------- */ /* Flip line to orient it top to bottom instead of bottom to */ /* top. */ /* -------------------------------------------------------------------- */ for( int i = nYSize/2; i >= 0; i-- ) { GInt16 nTemp; nTemp = panData[i]; panData[i] = panData[nYSize - i - 1]; panData[nYSize - i - 1] = nTemp; } return CE_None; } /************************************************************************/ /* GetNoDataValue() */ /************************************************************************/ double DTEDRasterBand::GetNoDataValue( int * pbSuccess ) { if( pbSuccess ) *pbSuccess = bNoDataSet; return dfNoDataValue; } /************************************************************************/ /* ~DTEDDataset() */ /************************************************************************/ DTEDDataset::~DTEDDataset() { FlushCache(); if( psDTED != NULL ) DTEDClose( psDTED ); } /************************************************************************/ /* Open() */ /************************************************************************/ GDALDataset *DTEDDataset::Open( GDALOpenInfo * poOpenInfo ) { int i; DTEDInfo *psDTED; /* -------------------------------------------------------------------- */ /* Try opening the dataset. */ /* -------------------------------------------------------------------- */ psDTED = DTEDOpen( poOpenInfo->pszFilename, "rb", TRUE ); if( psDTED == NULL ) return( NULL ); /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ DTEDDataset *poDS; poDS = new DTEDDataset(); poDS->psDTED = psDTED; /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ poDS->nRasterXSize = psDTED->nXSize; poDS->nRasterYSize = psDTED->nYSize; /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->nBands = 1;; for( i = 0; i < poDS->nBands; i++ ) poDS->SetBand( i+1, new DTEDRasterBand( poDS, i+1 ) ); /* -------------------------------------------------------------------- */ /* Collect any metadata available. */ /* -------------------------------------------------------------------- */ char *pszValue; pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTACCURACY_UHL ); poDS->SetMetadataItem( "DTED_VerticalAccuracy_UHL", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTACCURACY_ACC ); poDS->SetMetadataItem( "DTED_VerticalAccuracy_ACC", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_SECURITYCODE_UHL ); poDS->SetMetadataItem( "DTED_SecurityCode_UHL", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_SECURITYCODE_DSI ); poDS->SetMetadataItem( "DTED_SecurityCode_DSI", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_UNIQUEREF_UHL ); poDS->SetMetadataItem( "DTED_UniqueRef_UHL", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_UNIQUEREF_DSI ); poDS->SetMetadataItem( "DTED_UniqueRef_DSI", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_DATA_EDITION ); poDS->SetMetadataItem( "DTED_DataEdition", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_MATCHMERGE_VERSION ); poDS->SetMetadataItem( "DTED_MatchMergeVersion", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_MAINT_DATE ); poDS->SetMetadataItem( "DTED_MaintenanceDate", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_MATCHMERGE_DATE ); poDS->SetMetadataItem( "DTED_MatchMergeDate", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_MAINT_DESCRIPTION ); poDS->SetMetadataItem( "DTED_MaintenanceDescription", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_PRODUCER ); poDS->SetMetadataItem( "DTED_Producer", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTDATUM ); poDS->SetMetadataItem( "DTED_VerticalDatum", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_DIGITIZING_SYS ); poDS->SetMetadataItem( "DTED_DigitizingSystem", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_COMPILATION_DATE ); poDS->SetMetadataItem( "DTED_CompilationDate", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_HORIZACCURACY ); poDS->SetMetadataItem( "DTED_HorizontalAccuracy", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_REL_HORIZACCURACY ); poDS->SetMetadataItem( "DTED_RelHorizontalAccuracy", pszValue ); CPLFree( pszValue ); pszValue = DTEDGetMetadata( psDTED, DTEDMD_REL_VERTACCURACY ); poDS->SetMetadataItem( "DTED_RelVerticalAccuracy", pszValue ); CPLFree( pszValue ); poDS->SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT ); /* -------------------------------------------------------------------- */ /* Support overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); return( poDS ); } /************************************************************************/ /* GetGeoTransform() */ /************************************************************************/ CPLErr DTEDDataset::GetGeoTransform( double * padfTransform ) { padfTransform[0] = psDTED->dfULCornerX; padfTransform[1] = psDTED->dfPixelSizeX; padfTransform[2] = 0.0; padfTransform[3] = psDTED->dfULCornerY; padfTransform[4] = 0.0; padfTransform[5] = psDTED->dfPixelSizeY * -1; return( CE_None ); } /************************************************************************/ /* GetProjectionRef() */ /************************************************************************/ const char *DTEDDataset::GetProjectionRef() { return( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]" ); } /************************************************************************/ /* DTEDCreateCopy() */ /* */ /* For now we will assume the input is exactly one proper */ /* cell. */ /************************************************************************/ static GDALDataset * DTEDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData ) { (void) pProgressData; (void) pfnProgress; (void) papszOptions; (void) bStrict; /* -------------------------------------------------------------------- */ /* Work out the level. */ /* -------------------------------------------------------------------- */ int nLevel; if( poSrcDS->GetRasterYSize() == 121 ) nLevel = 0; else if( poSrcDS->GetRasterYSize() == 1201 ) nLevel = 1; else if( poSrcDS->GetRasterYSize() == 3601 ) nLevel = 2; else { CPLError( CE_Warning, CPLE_AppDefined, "The source does not appear to be a properly formatted cell." ); nLevel = 1; } /* -------------------------------------------------------------------- */ /* Work out the LL origin. */ /* -------------------------------------------------------------------- */ int nLLOriginLat, nLLOriginLong; double adfGeoTransform[6]; poSrcDS->GetGeoTransform( adfGeoTransform ); nLLOriginLat = (int) floor(adfGeoTransform[3] + poSrcDS->GetRasterYSize() * adfGeoTransform[5] + 0.5); nLLOriginLong = (int) floor(adfGeoTransform[0] + 0.5); /* -------------------------------------------------------------------- */ /* Create the output dted file. */ /* -------------------------------------------------------------------- */ const char *pszError; pszError = DTEDCreate( pszFilename, nLevel, nLLOriginLat, nLLOriginLong ); if( pszError != NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", pszError ); return NULL; } /* -------------------------------------------------------------------- */ /* Open the DTED file so we can output the data to it. */ /* -------------------------------------------------------------------- */ DTEDInfo *psDTED; psDTED = DTEDOpen( pszFilename, "rb+", FALSE ); if( psDTED == NULL ) return NULL; /* -------------------------------------------------------------------- */ /* Read all the data in one dollup. */ /* -------------------------------------------------------------------- */ GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 ); GInt16 *panData; panData = (GInt16 *) CPLMalloc(sizeof(GInt16) * psDTED->nXSize * psDTED->nYSize); poSrcBand->RasterIO( GF_Read, 0, 0, psDTED->nXSize, psDTED->nYSize, (void *) panData, psDTED->nXSize, psDTED->nYSize, GDT_Int16, 0, 0 ); /* -------------------------------------------------------------------- */ /* Write all the profiles. */ /* -------------------------------------------------------------------- */ GInt16 anProfData[3601]; double dfNodataCount=0.0; GByte iPartialCell; for( int iProfile = 0; iProfile < psDTED->nXSize; iProfile++ ) { for( int iY = 0; iY < psDTED->nYSize; iY++ ) { anProfData[iY] = panData[iProfile + iY * psDTED->nXSize]; if ( anProfData[iY] == DTED_NODATA_VALUE ) dfNodataCount = dfNodataCount+1.0; } DTEDWriteProfile( psDTED, iProfile, anProfData ); } CPLFree( panData ); /* -------------------------------------------------------------------- */ /* Partial cell indicator: 0 for complete coverage; 1-99 for incomplete */ /* -------------------------------------------------------------------- */ char pszPartialCell[2]; if ( dfNodataCount < 0.5 ) iPartialCell = 0; else { iPartialCell = int(floor(100.0 - (dfNodataCount*100.0/(psDTED->nXSize * psDTED->nYSize)))); if (iPartialCell < 1) iPartialCell=1; } sprintf(pszPartialCell,"%02d",iPartialCell); strncpy((char *) (psDTED->pachDSIRecord+289), pszPartialCell, 2 ); /* -------------------------------------------------------------------- */ /* Try to copy any matching available metadata. */ /* -------------------------------------------------------------------- */ if( poSrcDS->GetMetadataItem( "DTED_VerticalAccuracy_UHL" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_VERTACCURACY_UHL, poSrcDS->GetMetadataItem( "DTED_VerticalAccuracy_UHL" ) ); if( poSrcDS->GetMetadataItem( "DTED_VerticalAccuracy_ACC" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_VERTACCURACY_ACC, poSrcDS->GetMetadataItem( "DTED_VerticalAccuracy_ACC" ) ); if( poSrcDS->GetMetadataItem( "DTED_SecurityCode_UHL" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_SECURITYCODE_UHL, poSrcDS->GetMetadataItem( "DTED_SecurityCode_UHL" ) ); if( poSrcDS->GetMetadataItem( "DTED_SecurityCode_DSI" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_SECURITYCODE_DSI, poSrcDS->GetMetadataItem( "DTED_SecurityCode_DSI" ) ); if( poSrcDS->GetMetadataItem( "DTED_UniqueRef_UHL" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_UNIQUEREF_UHL, poSrcDS->GetMetadataItem( "DTED_UniqueRef_UHL" ) ); if( poSrcDS->GetMetadataItem( "DTED_UniqueRef_DSI" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_UNIQUEREF_DSI, poSrcDS->GetMetadataItem( "DTED_UniqueRef_DSI" ) ); if( poSrcDS->GetMetadataItem( "DTED_DataEdition" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_DATA_EDITION, poSrcDS->GetMetadataItem( "DTED_DataEdition" ) ); if( poSrcDS->GetMetadataItem( "DTED_MatchMergeVersion" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_MATCHMERGE_VERSION, poSrcDS->GetMetadataItem( "DTED_MatchMergeVersion" ) ); if( poSrcDS->GetMetadataItem( "DTED_MaintenanceDate" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_MAINT_DATE, poSrcDS->GetMetadataItem( "DTED_MaintenanceDate" ) ); if( poSrcDS->GetMetadataItem( "DTED_MatchMergeDate" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_MATCHMERGE_DATE, poSrcDS->GetMetadataItem( "DTED_MatchMergeDate" ) ); if( poSrcDS->GetMetadataItem( "DTED_MaintenanceDescription" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_MAINT_DESCRIPTION, poSrcDS->GetMetadataItem( "DTED_MaintenanceDescription" ) ); if( poSrcDS->GetMetadataItem( "DTED_Producer" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_PRODUCER, poSrcDS->GetMetadataItem( "DTED_Producer" ) ); if( poSrcDS->GetMetadataItem( "DTED_VerticalDatum" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_VERTDATUM, poSrcDS->GetMetadataItem( "DTED_VerticalDatum" ) ); if( poSrcDS->GetMetadataItem( "DTED_DigitizingSystem" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_DIGITIZING_SYS, poSrcDS->GetMetadataItem( "DTED_DigitizingSystem" ) ); if( poSrcDS->GetMetadataItem( "DTED_CompilationDate" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_COMPILATION_DATE, poSrcDS->GetMetadataItem( "DTED_CompilationDate" ) ); if( poSrcDS->GetMetadataItem( "DTED_HorizontalAccuracy" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_HORIZACCURACY, poSrcDS->GetMetadataItem( "DTED_HorizontalAccuracy" ) ); if( poSrcDS->GetMetadataItem( "DTED_RelHorizontalAccuracy" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_REL_HORIZACCURACY, poSrcDS->GetMetadataItem( "DTED_RelHorizontalAccuracy" ) ); if( poSrcDS->GetMetadataItem( "DTED_RelVerticalAccuracy" ) != NULL ) DTEDSetMetadata( psDTED, DTEDMD_REL_VERTACCURACY, poSrcDS->GetMetadataItem( "DTED_RelVerticalAccuracy" ) ); /* -------------------------------------------------------------------- */ /* Try to open the resulting DTED file. */ /* -------------------------------------------------------------------- */ DTEDClose( psDTED ); /* -------------------------------------------------------------------- */ /* Reopen and copy missing information into a PAM file. */ /* -------------------------------------------------------------------- */ GDALPamDataset *poDS = (GDALPamDataset *) GDALOpen( pszFilename, GA_ReadOnly ); if( poDS ) poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); return poDS; } /************************************************************************/ /* GDALRegister_DTED() */ /************************************************************************/ void GDALRegister_DTED() { GDALDriver *poDriver; if( GDALGetDriverByName( "DTED" ) == NULL ) { poDriver = new GDALDriver(); poDriver->SetDescription( "DTED" ); poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "DTED Elevation Raster" ); poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_various.html#DTED" ); poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte Int16 UInt16" ); poDriver->pfnOpen = DTEDDataset::Open; poDriver->pfnCreateCopy = DTEDCreateCopy; GetGDALDriverManager()->RegisterDriver( poDriver ); } }