gdal/frmts/sdts/sdtsdataset.cpp

395 строки
14 KiB
C++

/******************************************************************************
*
* Project: SDTS Translator
* Purpose: GDALDataset driver for SDTS Raster translator.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
* Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
*
* 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 "gdal_frmts.h"
#include "gdal_pam.h"
#include "ogr_spatialref.h"
#include "sdts_al.h"
/**
\file sdtsdataset.cpp
exclude
*/
/************************************************************************/
/* ==================================================================== */
/* SDTSDataset */
/* ==================================================================== */
/************************************************************************/
class SDTSRasterBand;
class SDTSDataset final : public GDALPamDataset
{
friend class SDTSRasterBand;
SDTSTransfer *poTransfer;
SDTSRasterReader *poRL;
OGRSpatialReference m_oSRS{};
public:
SDTSDataset();
virtual ~SDTSDataset();
static GDALDataset *Open(GDALOpenInfo *);
const OGRSpatialReference *GetSpatialRef() const override
{
return &m_oSRS;
}
virtual CPLErr GetGeoTransform(double *) override;
};
class SDTSRasterBand final : public GDALPamRasterBand
{
friend class SDTSDataset;
SDTSRasterReader *poRL;
public:
SDTSRasterBand(SDTSDataset *, int, SDTSRasterReader *);
virtual CPLErr IReadBlock(int, int, void *) override;
virtual double GetNoDataValue(int *pbSuccess) override;
virtual const char *GetUnitType() override;
};
/************************************************************************/
/* SDTSDataset() */
/************************************************************************/
SDTSDataset::SDTSDataset() : poTransfer(nullptr), poRL(nullptr)
{
m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
}
/************************************************************************/
/* ~SDTSDataset() */
/************************************************************************/
SDTSDataset::~SDTSDataset()
{
FlushCache(true);
if (poTransfer != nullptr)
delete poTransfer;
if (poRL != nullptr)
delete poRL;
}
/************************************************************************/
/* Open() */
/************************************************************************/
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 nullptr;
char *pachLeader = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
if (pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3')
return nullptr;
if (pachLeader[6] != 'L')
return nullptr;
if (pachLeader[8] != '1' && pachLeader[8] != ' ')
return nullptr;
/* -------------------------------------------------------------------- */
/* Try opening the dataset. */
/* -------------------------------------------------------------------- */
SDTSTransfer *poTransfer = new SDTSTransfer;
if (!poTransfer->Open(poOpenInfo->pszFilename))
{
delete poTransfer;
return nullptr;
}
/* -------------------------------------------------------------------- */
/* 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 nullptr;
}
/* -------------------------------------------------------------------- */
/* Find the first raster layer. If there are none, abort */
/* returning an error. */
/* -------------------------------------------------------------------- */
SDTSRasterReader *poRL = nullptr;
for (int i = 0; i < poTransfer->GetLayerCount(); i++)
{
if (poTransfer->GetLayerType(i) == SLTRaster)
{
poRL = poTransfer->GetLayerRasterReader(i);
break;
}
}
if (poRL == nullptr)
{
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 nullptr;
}
/* -------------------------------------------------------------------- */
/* 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. */
/* -------------------------------------------------------------------- */
SDTS_XREF *poXREF = poTransfer->GetXREF();
if (EQUAL(poXREF->pszSystemName, "UTM"))
{
poDS->m_oSRS.SetUTM(poXREF->nZone);
}
else if (EQUAL(poXREF->pszSystemName, "GEO"))
{
/* we set datum later */
}
else
poDS->m_oSRS.SetLocalCS(poXREF->pszSystemName);
if (poDS->m_oSRS.IsLocal())
/* don't try to set datum. */;
else if (EQUAL(poXREF->pszDatum, "NAS"))
poDS->m_oSRS.SetWellKnownGeogCS("NAD27");
else if (EQUAL(poXREF->pszDatum, "NAX"))
poDS->m_oSRS.SetWellKnownGeogCS("NAD83");
else if (EQUAL(poXREF->pszDatum, "WGC"))
poDS->m_oSRS.SetWellKnownGeogCS("WGS72");
else /* if( EQUAL(poXREF->pszDatum, "WGE") ) or default */
poDS->m_oSRS.SetWellKnownGeogCS("WGS84");
/* -------------------------------------------------------------------- */
/* Get metadata from the IDEN file. */
/* -------------------------------------------------------------------- */
const char *pszIDENFilePath =
poTransfer->GetCATD()->GetModuleFilePath("IDEN");
if (pszIDENFilePath)
{
DDFModule oIDENFile;
if (oIDENFile.Open(pszIDENFilePath))
{
DDFRecord *poRecord = nullptr;
while ((poRecord = oIDENFile.ReadRecord()) != nullptr)
{
if (poRecord->GetStringSubfield("IDEN", 0, "MODN", 0) ==
nullptr)
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;
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr SDTSDataset::GetGeoTransform(double *padfTransform)
{
if (poRL->GetTransform(padfTransform))
return CE_None;
return CE_Failure;
}
/************************************************************************/
/* ==================================================================== */
/* SDTSRasterBand */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* SDTSRasterBand() */
/************************************************************************/
SDTSRasterBand::SDTSRasterBand(SDTSDataset *poDSIn, int nBandIn,
SDTSRasterReader *poRLIn)
: poRL(poRLIn)
{
poDS = poDSIn;
nBand = nBandIn;
if (poRL->GetRasterType() == SDTS_RT_INT16)
eDataType = GDT_Int16;
else
eDataType = GDT_Float32;
nBlockXSize = poRL->GetBlockXSize();
nBlockYSize = poRL->GetBlockYSize();
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr SDTSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
{
if (poRL->GetBlock(nBlockXOff, nBlockYOff, pImage))
return CE_None;
return CE_Failure;
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
double SDTSRasterBand::GetNoDataValue(int *pbSuccess)
{
if (pbSuccess != nullptr)
*pbSuccess = TRUE;
return -32766.0;
}
/************************************************************************/
/* GetUnitType() */
/************************************************************************/
const char *SDTSRasterBand::GetUnitType()
{
if (EQUAL(poRL->szUNITS, "FEET"))
return "ft";
else if (STARTS_WITH_CI(poRL->szUNITS, "MET"))
return "m";
return poRL->szUNITS;
}
/************************************************************************/
/* GDALRegister_SDTS() */
/************************************************************************/
void GDALRegister_SDTS()
{
if (GDALGetDriverByName("SDTS") != nullptr)
return;
GDALDriver *poDriver = new GDALDriver();
poDriver->SetDescription("SDTS");
poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS Raster");
poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sdts.html");
poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ddf");
poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
poDriver->pfnOpen = SDTSDataset::Open;
GetGDALDriverManager()->RegisterDriver(poDriver);
}