-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a 'gdal raster edit' command to override SRS, extent and metadata
- Loading branch information
Showing
18 changed files
with
999 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/****************************************************************************** | ||
* | ||
* 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); | ||
|
||
{ | ||
auto &arg = | ||
AddArg("extent", 0, _("Extent as xmin,ymin,xmax,ymax"), &m_extent) | ||
.SetRepeatedArgAllowed(false) | ||
.SetMinCount(4) | ||
.SetMaxCount(4) | ||
.SetDisplayHintAboutRepetition(false); | ||
arg.AddValidationAction( | ||
[&arg]() | ||
{ | ||
const auto &val = arg.Get<std::vector<double>>(); | ||
CPLAssert(val.size() == 4); | ||
if (!(val[0] <= val[2]) || !(val[1] <= val[3])) | ||
{ | ||
CPLError( | ||
CE_Failure, CPLE_AppDefined, | ||
"Value of 'extent' should be xmin,ymin,xmax,ymax with " | ||
"xmin <= xmax and ymin <= ymax"); | ||
return false; | ||
} | ||
return true; | ||
}); | ||
} | ||
|
||
{ | ||
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_extent.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_extent[0]; | ||
adfGT[1] = (m_extent[2] - m_extent[0]) / poDS->GetRasterXSize(); | ||
adfGT[2] = 0; | ||
adfGT[3] = m_extent[3]; | ||
adfGT[4] = 0; | ||
adfGT[5] = -(m_extent[3] - m_extent[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_extent.empty()) | ||
{ | ||
aosOptions.AddString("-a_ullr"); | ||
aosOptions.AddString(CPLSPrintf("%.17g", m_extent[0])); // upper-left X | ||
aosOptions.AddString(CPLSPrintf("%.17g", m_extent[3])); // upper-left Y | ||
aosOptions.AddString( | ||
CPLSPrintf("%.17g", m_extent[2])); // lower-right X | ||
aosOptions.AddString( | ||
CPLSPrintf("%.17g", m_extent[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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/****************************************************************************** | ||
* | ||
* 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 | ||
****************************************************************************/ | ||
|
||
#ifndef GDALALG_RASTER_EDIT_INCLUDED | ||
#define GDALALG_RASTER_EDIT_INCLUDED | ||
|
||
#include "gdalalg_raster_pipeline.h" | ||
|
||
//! @cond Doxygen_Suppress | ||
|
||
/************************************************************************/ | ||
/* GDALRasterEditAlgorithm */ | ||
/************************************************************************/ | ||
|
||
class GDALRasterEditAlgorithm /* non final */ | ||
: public GDALRasterPipelineStepAlgorithm | ||
{ | ||
public: | ||
static constexpr const char *NAME = "edit"; | ||
static constexpr const char *DESCRIPTION = "Edit a raster dataset."; | ||
static constexpr const char *HELP_URL = "/programs/gdal_raster_edit.html"; | ||
|
||
static std::vector<std::string> GetAliases() | ||
{ | ||
return {}; | ||
} | ||
|
||
explicit GDALRasterEditAlgorithm(bool standaloneStep = false); | ||
|
||
private: | ||
bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override; | ||
bool RunStep(GDALProgressFunc pfnProgress, void *pProgressData) override; | ||
|
||
GDALArgDatasetValue m_dataset{}; // standalone mode only | ||
std::string m_overrideCrs{}; | ||
std::vector<double> m_extent{}; | ||
std::vector<std::string> m_metadata{}; | ||
std::vector<std::string> m_unsetMetadata{}; | ||
}; | ||
|
||
/************************************************************************/ | ||
/* GDALRasterEditAlgorithmStandalone */ | ||
/************************************************************************/ | ||
|
||
class GDALRasterEditAlgorithmStandalone final : public GDALRasterEditAlgorithm | ||
{ | ||
public: | ||
GDALRasterEditAlgorithmStandalone() | ||
: GDALRasterEditAlgorithm(/* standaloneStep = */ true) | ||
{ | ||
} | ||
}; | ||
|
||
//! @endcond | ||
|
||
#endif /* GDALALG_RASTER_EDIT_INCLUDED */ |
Oops, something went wrong.