gdal/apps/gdalalg_raster_edit.cpp

210 lines
6.8 KiB
C++

/******************************************************************************
*
* Project: GDAL
* Purpose: "edit" step of "raster pipeline"
* Author: Even Rouault <even dot rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/
#include "gdalalg_raster_edit.h"
#include "gdal_priv.h"
#include "gdal_utils.h"
//! @cond Doxygen_Suppress
#ifndef _
#define _(x) (x)
#endif
/************************************************************************/
/* GDALRasterEditAlgorithm::GDALRasterEditAlgorithm() */
/************************************************************************/
GDALRasterEditAlgorithm::GDALRasterEditAlgorithm(bool standaloneStep)
: GDALRasterPipelineStepAlgorithm(
NAME, DESCRIPTION, HELP_URL,
// Avoid automatic addition of input/output arguments
/*standaloneStep = */ false)
{
if (standaloneStep)
{
AddArg("dataset", 0, _("Dataset (in-place updated)"), &m_dataset,
GDAL_OF_RASTER | GDAL_OF_UPDATE)
.SetPositional()
.SetRequired();
m_standaloneStep = true;
}
AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
.AddHiddenAlias("a_srs")
.SetIsCRSArg(/*noneAllowed=*/true);
AddBBOXArg(&m_bbox);
{
auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
&m_metadata)
.SetMetaVar("<KEY>=<VALUE>");
arg.AddValidationAction([this, &arg]()
{ return ValidateKeyValue(arg); });
arg.AddHiddenAlias("mo");
}
AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
&m_unsetMetadata)
.SetMetaVar("<KEY>");
}
/************************************************************************/
/* GDALRasterEditAlgorithm::RunImpl() */
/************************************************************************/
bool GDALRasterEditAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
void *pProgressData)
{
if (m_standaloneStep)
{
auto poDS = m_dataset.GetDatasetRef();
CPLAssert(poDS);
if (poDS->GetAccess() != GA_Update)
{
ReportError(CE_Failure, CPLE_AppDefined,
"Dataset should be opened in update mode");
return false;
}
if (m_overrideCrs == "null" || m_overrideCrs == "none")
{
if (poDS->SetSpatialRef(nullptr) != CE_None)
{
ReportError(CE_Failure, CPLE_AppDefined,
"SetSpatialRef(%s) failed", m_overrideCrs.c_str());
return false;
}
}
else if (!m_overrideCrs.empty())
{
OGRSpatialReference oSRS;
oSRS.SetFromUserInput(m_overrideCrs.c_str());
oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
if (poDS->SetSpatialRef(&oSRS) != CE_None)
{
ReportError(CE_Failure, CPLE_AppDefined,
"SetSpatialRef(%s) failed", m_overrideCrs.c_str());
return false;
}
}
if (!m_bbox.empty())
{
if (poDS->GetRasterXSize() == 0 || poDS->GetRasterYSize() == 0)
{
ReportError(
CE_Failure, CPLE_AppDefined,
"Cannot set extent because dataset has 0x0 dimension");
return false;
}
double adfGT[6];
adfGT[0] = m_bbox[0];
adfGT[1] = (m_bbox[2] - m_bbox[0]) / poDS->GetRasterXSize();
adfGT[2] = 0;
adfGT[3] = m_bbox[3];
adfGT[4] = 0;
adfGT[5] = -(m_bbox[3] - m_bbox[1]) / poDS->GetRasterYSize();
if (poDS->SetGeoTransform(adfGT) != CE_None)
{
ReportError(CE_Failure, CPLE_AppDefined,
"Setting extent failed");
return false;
}
}
const CPLStringList aosMD(m_metadata);
for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
{
if (poDS->SetMetadataItem(key, value) != CE_None)
{
ReportError(CE_Failure, CPLE_AppDefined,
"SetMetadataItem('%s', '%s') failed", key, value);
return false;
}
}
for (const std::string &key : m_unsetMetadata)
{
if (poDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
{
ReportError(CE_Failure, CPLE_AppDefined,
"SetMetadataItem('%s', NULL) failed", key.c_str());
return false;
}
}
return true;
}
else
{
return RunStep(pfnProgress, pProgressData);
}
}
/************************************************************************/
/* GDALRasterEditAlgorithm::RunStep() */
/************************************************************************/
bool GDALRasterEditAlgorithm::RunStep(GDALProgressFunc, void *)
{
CPLAssert(m_inputDataset.GetDatasetRef());
CPLAssert(m_outputDataset.GetName().empty());
CPLAssert(!m_outputDataset.GetDatasetRef());
CPLStringList aosOptions;
aosOptions.AddString("-of");
aosOptions.AddString("VRT");
if (!m_overrideCrs.empty())
{
aosOptions.AddString("-a_srs");
aosOptions.AddString(m_overrideCrs.c_str());
}
if (!m_bbox.empty())
{
aosOptions.AddString("-a_ullr");
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[0])); // upper-left X
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[3])); // upper-left Y
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[2])); // lower-right X
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[1])); // lower-right Y
}
for (const auto &val : m_metadata)
{
aosOptions.AddString("-mo");
aosOptions.AddString(val.c_str());
}
for (const std::string &key : m_unsetMetadata)
{
aosOptions.AddString("-mo");
aosOptions.AddString((key + "=").c_str());
}
GDALTranslateOptions *psOptions =
GDALTranslateOptionsNew(aosOptions.List(), nullptr);
GDALDatasetH hSrcDS = GDALDataset::ToHandle(m_inputDataset.GetDatasetRef());
auto poRetDS =
GDALDataset::FromHandle(GDALTranslate("", hSrcDS, psOptions, nullptr));
GDALTranslateOptionsFree(psOptions);
const bool ok = poRetDS != nullptr;
if (ok)
m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
return ok;
}
//! @endcond