int SDTSRasterReader::Open( SDTS_CATD * poCATD, SDTS_IREF * poIREF, const char * pszModule ) { strncpy( szModule, pszModule, sizeof(szModule) ); szModule[sizeof(szModule) - 1] = '\0'; /* ==================================================================== */ /* Search the LDEF module for the requested cell module. */ /* ==================================================================== */ DDFModule oLDEF; DDFRecord *poRecord; /* -------------------------------------------------------------------- */ /* Open the LDEF module, and report failure if it is missing. */ /* -------------------------------------------------------------------- */ if( poCATD->GetModuleFilePath("LDEF") == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find LDEF entry in CATD module ... " "can't treat as raster.\n" ); return FALSE; } if( !oLDEF.Open( poCATD->GetModuleFilePath("LDEF") ) ) return FALSE; /* -------------------------------------------------------------------- */ /* Read each record, till we find what we want. */ /* -------------------------------------------------------------------- */ while( (poRecord = oLDEF.ReadRecord() ) != NULL ) { if( EQUAL(poRecord->GetStringSubfield("LDEF",0,"CMNM",0), pszModule) ) break; } if( poRecord == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find module `%s' in LDEF file.\n", pszModule ); return FALSE; } /* -------------------------------------------------------------------- */ /* Extract raster dimensions, and origin offset (0/1). */ /* -------------------------------------------------------------------- */ nXSize = poRecord->GetIntSubfield( "LDEF", 0, "NCOL", 0 ); nYSize = poRecord->GetIntSubfield( "LDEF", 0, "NROW", 0 ); nXStart = poRecord->GetIntSubfield( "LDEF", 0, "SOCI", 0 ); nYStart = poRecord->GetIntSubfield( "LDEF", 0, "SORI", 0 ); /* -------------------------------------------------------------------- */ /* Get the point in the pixel that the origin defines. We only */ /* support top left and center. */ /* -------------------------------------------------------------------- */ strcpy( szINTR, poRecord->GetStringSubfield( "LDEF", 0, "INTR", 0 ) ); if( EQUAL(szINTR,"") ) strcpy( szINTR, "CE" ); if( !EQUAL(szINTR,"CE") && !EQUAL(szINTR,"TL") ) { CPLError( CE_Warning, CPLE_AppDefined, "Unsupported INTR value of `%s', assume CE.\n" "Positions may be off by one pixel.\n", szINTR ); strcpy( szINTR, "CE" ); } /* -------------------------------------------------------------------- */ /* Record the LDEF record number we used so we can find the */ /* corresponding RSDF record. */ /* -------------------------------------------------------------------- */ int nLDEF_RCID; nLDEF_RCID = poRecord->GetIntSubfield( "LDEF", 0, "RCID", 0 ); oLDEF.Close(); /* ==================================================================== */ /* Search the RSDF module for the requested cell module. */ /* ==================================================================== */ DDFModule oRSDF; /* -------------------------------------------------------------------- */ /* Open the RSDF module, and report failure if it is missing. */ /* -------------------------------------------------------------------- */ if( poCATD->GetModuleFilePath("RSDF") == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find RSDF entry in CATD module ... " "can't treat as raster.\n" ); return FALSE; } if( !oRSDF.Open( poCATD->GetModuleFilePath("RSDF") ) ) return FALSE; /* -------------------------------------------------------------------- */ /* Read each record, till we find what we want. */ /* -------------------------------------------------------------------- */ while( (poRecord = oRSDF.ReadRecord() ) != NULL ) { if( poRecord->GetIntSubfield("LYID",0,"RCID",0) == nLDEF_RCID ) break; } if( poRecord == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find LDEF:%d record in RSDF file.\n", nLDEF_RCID ); return FALSE; } /* -------------------------------------------------------------------- */ /* Establish the raster pixel/line to georef transformation. */ /* -------------------------------------------------------------------- */ double dfZ; if( poRecord->FindField( "SADR" ) == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find SADR field in RSDF record.\n" ); return FALSE; } poIREF->GetSADR( poRecord->FindField( "SADR" ), 1, adfTransform + 0, adfTransform + 3, &dfZ ); adfTransform[1] = poIREF->dfXRes; adfTransform[2] = 0.0; adfTransform[4] = 0.0; adfTransform[5] = -1 * poIREF->dfYRes; /* -------------------------------------------------------------------- */ /* If the origin is the center of the pixel, then shift it back */ /* half a pixel to the top left of the top left. */ /* -------------------------------------------------------------------- */ if( EQUAL(szINTR,"CE") ) { adfTransform[0] -= adfTransform[1] * 0.5; adfTransform[3] -= adfTransform[5] * 0.5; } /* -------------------------------------------------------------------- */ /* Verify some other assumptions. */ /* -------------------------------------------------------------------- */ const char *pszString; pszString = poRecord->GetStringSubfield( "RSDF", 0, "OBRP", 0); if( !EQUAL(pszString,"G2") ) { CPLError( CE_Failure, CPLE_AppDefined, "OBRP value of `%s' not expected 2D raster code (G2).\n", pszString ); return FALSE; } pszString = poRecord->GetStringSubfield( "RSDF", 0, "SCOR", 0); if( !EQUAL(pszString,"TL") ) { CPLError( CE_Warning, CPLE_AppDefined, "SCOR (origin) is `%s' instead of expected top left.\n" "Georef coordinates will likely be incorrect.\n", pszString ); } oRSDF.Close(); /* -------------------------------------------------------------------- */ /* For now we will assume that the block size is one scanline. */ /* We will blow a gasket later while reading the cell file if */ /* this isn't the case. */ /* */ /* This isn't a very flexible raster implementation! */ /* -------------------------------------------------------------------- */ nXBlockSize = nXSize; nYBlockSize = 1; /* ==================================================================== */ /* Fetch the data type used for the raster, and the units from */ /* the data dictionary/schema record (DDSH). */ /* ==================================================================== */ DDFModule oDDSH; /* -------------------------------------------------------------------- */ /* Open the DDSH module, and report failure if it is missing. */ /* -------------------------------------------------------------------- */ if( poCATD->GetModuleFilePath("DDSH") == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find DDSH entry in CATD module ... " "can't treat as raster.\n" ); return FALSE; } if( !oDDSH.Open( poCATD->GetModuleFilePath("DDSH") ) ) return FALSE; /* -------------------------------------------------------------------- */ /* Read each record, till we find what we want. */ /* -------------------------------------------------------------------- */ while( (poRecord = oDDSH.ReadRecord() ) != NULL ) { if( EQUAL(poRecord->GetStringSubfield("DDSH",0,"NAME",0),pszModule) ) break; } if( poRecord == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find DDSH record for %s.\n", pszModule ); return FALSE; } /* -------------------------------------------------------------------- */ /* Get some values we are interested in. */ /* -------------------------------------------------------------------- */ if( poRecord->GetStringSubfield("DDSH",0,"FMT",0) != NULL ) strcpy( szFMT, poRecord->GetStringSubfield("DDSH",0,"FMT",0) ); else strcpy( szFMT, "BUI16" ); if( poRecord->GetStringSubfield("DDSH",0,"UNIT",0) != NULL ) strcpy( szUNITS, poRecord->GetStringSubfield("DDSH",0,"UNIT",0) ); else strcpy( szUNITS, "METERS" ); if( poRecord->GetStringSubfield("DDSH",0,"ATLB",0) != NULL ) strcpy( szLabel, poRecord->GetStringSubfield("DDSH",0,"ATLB",0) ); else strcpy( szLabel, "" ); /* -------------------------------------------------------------------- */ /* Open the cell file. */ /* -------------------------------------------------------------------- */ return( oDDFModule.Open( poCATD->GetModuleFilePath(pszModule) ) ); }
GDALDataset *SDTSDataset::Open( GDALOpenInfo * poOpenInfo ) { /* -------------------------------------------------------------------- */ /* Before trying SDTSOpen() we first verify that the first */ /* record is in fact a SDTS file descriptor record. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes < 24 ) return NULL; char *pachLeader = reinterpret_cast<char *>( poOpenInfo->pabyHeader ); if( pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3' ) return NULL; if( pachLeader[6] != 'L' ) return NULL; if( pachLeader[8] != '1' && pachLeader[8] != ' ' ) return NULL; /* -------------------------------------------------------------------- */ /* Try opening the dataset. */ /* -------------------------------------------------------------------- */ SDTSTransfer *poTransfer = new SDTSTransfer; if( !poTransfer->Open( poOpenInfo->pszFilename ) ) { delete poTransfer; return NULL; } /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { delete poTransfer; CPLError( CE_Failure, CPLE_NotSupported, "The SDTS driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Find the first raster layer. If there are none, abort */ /* returning an error. */ /* -------------------------------------------------------------------- */ SDTSRasterReader *poRL = NULL; for( int i = 0; i < poTransfer->GetLayerCount(); i++ ) { if( poTransfer->GetLayerType( i ) == SLTRaster ) { poRL = poTransfer->GetLayerRasterReader( i ); break; } } if( poRL == NULL ) { delete poTransfer; CPLError( CE_Warning, CPLE_AppDefined, "%s is an SDTS transfer, but has no raster cell layers.\n" "Perhaps it is a vector transfer?\n", poOpenInfo->pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Initialize a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ SDTSDataset *poDS = new SDTSDataset(); poDS->poTransfer = poTransfer; poDS->poRL = poRL; /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ poDS->nRasterXSize = poRL->GetXSize(); poDS->nRasterYSize = poRL->GetYSize(); /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->nBands = 1; poDS->papoBands = reinterpret_cast<GDALRasterBand **>( VSICalloc( sizeof(GDALRasterBand *), poDS->nBands ) ); for( int i = 0; i < poDS->nBands; i++ ) poDS->SetBand( i+1, new SDTSRasterBand( poDS, i+1, poRL ) ); /* -------------------------------------------------------------------- */ /* Try to establish the projection string. For now we only */ /* support UTM and GEO. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; SDTS_XREF *poXREF = poTransfer->GetXREF(); if( EQUAL(poXREF->pszSystemName,"UTM") ) { oSRS.SetUTM( poXREF->nZone ); } else if( EQUAL(poXREF->pszSystemName,"GEO") ) { /* we set datum later */ } else oSRS.SetLocalCS( poXREF->pszSystemName ); if( oSRS.IsLocal() ) /* don't try to set datum. */; else if( EQUAL(poXREF->pszDatum,"NAS") ) oSRS.SetWellKnownGeogCS( "NAD27" ); else if( EQUAL(poXREF->pszDatum, "NAX") ) oSRS.SetWellKnownGeogCS( "NAD83" ); else if( EQUAL(poXREF->pszDatum, "WGC") ) oSRS.SetWellKnownGeogCS( "WGS72" ); else if( EQUAL(poXREF->pszDatum, "WGE") ) oSRS.SetWellKnownGeogCS( "WGS84" ); else oSRS.SetWellKnownGeogCS( "WGS84" ); oSRS.Fixup(); poDS->pszProjection = NULL; if( oSRS.exportToWkt( &poDS->pszProjection ) != OGRERR_NONE ) poDS->pszProjection = CPLStrdup(""); /* -------------------------------------------------------------------- */ /* Get metadata from the IDEN file. */ /* -------------------------------------------------------------------- */ const char* pszIDENFilePath = poTransfer->GetCATD()->GetModuleFilePath("IDEN"); if (pszIDENFilePath) { DDFModule oIDENFile; if( oIDENFile.Open( pszIDENFilePath ) ) { DDFRecord* poRecord; while( (poRecord = oIDENFile.ReadRecord()) != NULL ) { if( poRecord->GetStringSubfield( "IDEN", 0, "MODN", 0 ) == NULL ) continue; static const char* const fields[][2] = { { "TITL", "TITLE" }, { "DAID", "DATASET_ID" }, { "DAST", "DATA_STRUCTURE" }, { "MPDT", "MAP_DATE" }, { "DCDT", "DATASET_CREATION_DATE" } }; for ( int i = 0; i < static_cast<int>( sizeof(fields) ) / static_cast<int>( sizeof(fields[0] ) ); i++) { const char* pszFieldValue = poRecord->GetStringSubfield( "IDEN", 0, fields[i][0], 0 ); if ( pszFieldValue ) poDS->SetMetadataItem(fields[i][1], pszFieldValue); } break; } } } /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for external overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() ); return poDS; }