Skip to content

Add "gdal raster index" and "gdal driver gti create" (port of gdaltindex) #12140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 15, 2025
3 changes: 2 additions & 1 deletion .github/workflows/doc_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ jobs:
-DBUILD_TESTING=ON \
-DDOXYGEN_FAIL_ON_WARNINGS=ON \
-DGDAL_BUILD_OPTIONAL_DRIVERS=OFF \
-DOGR_BUILD_OPTIONAL_DRIVERS=OFF
-DOGR_BUILD_OPTIONAL_DRIVERS=OFF \
-DGDAL_ENABLE_DRIVER_GTI=ON
cmake --build . -j$(nproc)

- name: Print versions
Expand Down
2 changes: 2 additions & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_library(
gdalalg_raster_edit.cpp
gdalalg_raster_contour.cpp
gdalalg_raster_hillshade.cpp
gdalalg_raster_index.cpp
gdalalg_raster_mosaic.cpp
gdalalg_raster_pipeline.cpp
gdalalg_raster_overview_add.cpp
Expand Down Expand Up @@ -64,6 +65,7 @@ add_library(
gdalalg_vector_grid_invdistnn.cpp
gdalalg_vector_grid_linear.cpp
gdalalg_vector_grid_nearest.cpp
gdalalg_vector_output_abstract.cpp
gdalalg_vector_reproject.cpp
gdalalg_vector_select.cpp
gdalalg_vector_sql.cpp
Expand Down
4 changes: 4 additions & 0 deletions apps/gdal_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ GDALTileIndexOptions CPL_DLL *
GDALTileIndexOptionsNew(char **papszArgv,
GDALTileIndexOptionsForBinary *psOptionsForBinary);

void CPL_DLL GDALTileIndexOptionsSetProgress(GDALTileIndexOptions *psOptions,
GDALProgressFunc pfnProgress,
void *pProgressData);

void CPL_DLL GDALTileIndexOptionsFree(GDALTileIndexOptions *psOptions);

GDALDatasetH CPL_DLL GDALTileIndex(const char *pszDest, int nSrcCount,
Expand Down
7 changes: 7 additions & 0 deletions apps/gdal_utils_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ std::string CPL_DLL GDALRasterizeAppGetParserUsage();
std::string CPL_DLL
GDALDEMAppGetParserUsage(const std::string &osProcessingMode);

GDALDatasetH GDALTileIndexInternal(const char *pszDest,
GDALDatasetH hTileIndexDS, OGRLayerH hLayer,
int nSrcCount,
const char *const *papszSrcDSNames,
const GDALTileIndexOptions *psOptionsIn,
int *pbUsageError);

#endif /* #ifndef DOXYGEN_SKIP */

#endif /* GDAL_UTILS_PRIV_H_INCLUDED */
2 changes: 2 additions & 0 deletions apps/gdalalg_raster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "gdalalg_raster_edit.h"
#include "gdalalg_raster_contour.h"
#include "gdalalg_raster_hillshade.h"
#include "gdalalg_raster_index.h"
#include "gdalalg_raster_mosaic.h"
#include "gdalalg_raster_overview.h"
#include "gdalalg_raster_pipeline.h"
Expand Down Expand Up @@ -58,6 +59,7 @@ class GDALRasterAlgorithm final : public GDALAlgorithm
RegisterSubAlgorithm<GDALRasterClipAlgorithmStandalone>();
RegisterSubAlgorithm<GDALRasterEditAlgorithmStandalone>();
RegisterSubAlgorithm<GDALRasterHillshadeAlgorithmStandalone>();
RegisterSubAlgorithm<GDALRasterIndexAlgorithm>();
RegisterSubAlgorithm<GDALRasterOverviewAlgorithm>();
RegisterSubAlgorithm<GDALRasterPipelineAlgorithm>();
RegisterSubAlgorithm<GDALRasterReprojectAlgorithmStandalone>();
Expand Down
222 changes: 222 additions & 0 deletions apps/gdalalg_raster_index.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: gdal "raster index" subcommand
* Author: Even Rouault <even dot rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/

#include "gdalalg_raster_index.h"

#include "cpl_conv.h"
#include "gdal_priv.h"
#include "gdal_utils_priv.h"
#include "ogrsf_frmts.h"

//! @cond Doxygen_Suppress

#ifndef _
#define _(x) (x)
#endif

/************************************************************************/
/* GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm() */
/************************************************************************/

GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm()
: GDALVectorOutputAbstractAlgorithm(NAME, DESCRIPTION, HELP_URL)
{
AddProgressArg();
AddInputDatasetArg(&m_inputDatasets, GDAL_OF_RASTER)
.SetAutoOpenDataset(false);
GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs();

AddCommonOptions();

AddArg("source-crs-field-name", 0,
_("Name of the field to store the CRS of each dataset"),
&m_sourceCrsName)
.SetMinCharCount(1);
AddArg("source-crs-format", 0,
_("Format in which the CRS of each dataset must be written"),
&m_sourceCrsFormat)
.SetMinCharCount(1)
.SetDefault(m_sourceCrsFormat)
.SetChoices("auto", "WKT", "EPSG", "PROJ");
}

/************************************************************************/
/* GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm() */
/************************************************************************/

GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm(
const std::string &name, const std::string &description,
const std::string &helpURL)
: GDALVectorOutputAbstractAlgorithm(name, description, helpURL)
{
}

/************************************************************************/
/* GDALRasterIndexAlgorithm::AddCommonOptions() */
/************************************************************************/

void GDALRasterIndexAlgorithm::AddCommonOptions()
{
AddArg("recursive", 0,
_("Whether input directories should be explored recursively."),
&m_recursive);
AddArg("filename-filter", 0,
_("Pattern that the filenames in input directories should follow "
"('*' and '?' wildcard)"),
&m_filenameFilter);
AddArg("min-pixel-size", 0,
_("Minimum pixel size in term of geospatial extent per pixel "
"(resolution) that a raster should have to be selected."),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone better in English than me should check, but the description feels somehow odd to me. BTW if x and y resolutions are not the same, which resolution rules?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW if x and y resolutions are not the same, which resolution rules?

a geometric mean of it

&m_minPixelSize)
.SetMinValueExcluded(0);
AddArg("max-pixel-size", 0,
_("Maximum pixel size in term of geospatial extent per pixel "
"(resolution) that a raster should have to be selected."),
&m_maxPixelSize)
.SetMinValueExcluded(0);
AddArg("location-name", 0, _("Name of the field with the raster path"),
&m_locationName)
.SetDefault(m_locationName)
.SetMinCharCount(1);
AddArg("absolute-path", 0,
_("Whether the path to the input datasets should be stored as an "
"absolute path"),
&m_writeAbsolutePaths);
AddArg("dst-crs", 0, _("Destination CRS"), &m_crs)
.SetIsCRSArg()
.AddHiddenAlias("t_srs");

{
auto &arg =
AddArg("metadata", 0, _("Add dataset metadata item"), &m_metadata)
.SetMetaVar("<KEY>=<VALUE>");
arg.AddValidationAction([this, &arg]()
{ return ValidateKeyValue(arg); });
arg.AddHiddenAlias("mo");
}
}

/************************************************************************/
/* GDALRasterIndexAlgorithm::RunImpl() */
/************************************************************************/

bool GDALRasterIndexAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
void *pProgressData)
{
CPLStringList aosSources;
for (auto &srcDS : m_inputDatasets)
{
if (srcDS.GetDatasetRef())
{
ReportError(
CE_Failure, CPLE_IllegalArg,
"Input datasets must be provided by name, not as object");
return false;
}
aosSources.push_back(srcDS.GetName());
}

auto setupRet = SetupOutputDataset();
if (!setupRet.outDS)
return false;

if (!SetDefaultOutputLayerNameIfNeeded(setupRet.outDS))
return false;

CPLStringList aosOptions;
if (m_recursive)
{
aosOptions.push_back("-recursive");
}
for (const std::string &s : m_filenameFilter)
{
aosOptions.push_back("-filename_filter");
aosOptions.push_back(s);
}
if (m_minPixelSize > 0)
{
aosOptions.push_back("-min_pixel_size");
aosOptions.push_back(CPLSPrintf("%.17g", m_minPixelSize));
}
if (m_maxPixelSize > 0)
{
aosOptions.push_back("-max_pixel_size");
aosOptions.push_back(CPLSPrintf("%.17g", m_maxPixelSize));
}

if (!m_outputLayerName.empty())
{
aosOptions.push_back("-lyr_name");
aosOptions.push_back(m_outputLayerName);
}

aosOptions.push_back("-tileindex");
aosOptions.push_back(m_locationName);

if (m_writeAbsolutePaths)
{
aosOptions.push_back("-write_absolute_path");
}
if (m_crs.empty())
{
if (m_sourceCrsName.empty())
aosOptions.push_back("-skip_different_projection");
}
else
{
aosOptions.push_back("-t_srs");
aosOptions.push_back(m_crs);
}
if (!m_sourceCrsName.empty())
{
aosOptions.push_back("-src_srs_name");
aosOptions.push_back(m_sourceCrsName);

aosOptions.push_back("-src_srs_format");
aosOptions.push_back(CPLString(m_sourceCrsFormat).toupper());
}

for (const std::string &s : m_metadata)
{
aosOptions.push_back("-mo");
aosOptions.push_back(s);
}

if (!AddExtraOptions(aosOptions))
return false;

std::unique_ptr<GDALTileIndexOptions, decltype(&GDALTileIndexOptionsFree)>
options(GDALTileIndexOptionsNew(aosOptions.List(), nullptr),
GDALTileIndexOptionsFree);

if (options)
{
GDALTileIndexOptionsSetProgress(options.get(), pfnProgress,
pProgressData);
}

const bool ret =
options && GDALTileIndexInternal(m_outputDataset.GetName().c_str(),
GDALDataset::ToHandle(setupRet.outDS),
OGRLayer::ToHandle(setupRet.layer),
aosSources.size(), aosSources.List(),
options.get(), nullptr) != nullptr;

if (ret && setupRet.newDS)
{
m_outputDataset.Set(std::move(setupRet.newDS));
}

return ret;
}

//! @endcond
68 changes: 68 additions & 0 deletions apps/gdalalg_raster_index.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: gdal "raster index" subcommand
* Author: Even Rouault <even dot rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/

#ifndef GDALALG_RASTER_INDEX_INCLUDED
#define GDALALG_RASTER_INDEX_INCLUDED

#include "gdalalg_vector_output_abstract.h"

//! @cond Doxygen_Suppress

/************************************************************************/
/* GDALRasterIndexAlgorithm */
/************************************************************************/

class CPL_DLL GDALRasterIndexAlgorithm /* non final */
: public GDALVectorOutputAbstractAlgorithm
{
public:
static constexpr const char *NAME = "index";
static constexpr const char *DESCRIPTION =
"Create a vector index of raster datasets.";
static constexpr const char *HELP_URL = "/programs/gdal_raster_index.html";

GDALRasterIndexAlgorithm();

GDALRasterIndexAlgorithm(const std::string &name,
const std::string &description,
const std::string &helpURL);

protected:
void AddCommonOptions();

// Virtual method that may be overridden by derived classes to add options
// to GDALTileIndex()
virtual bool AddExtraOptions([[maybe_unused]] CPLStringList &aosOptions)
{
return true;
}

std::vector<GDALArgDatasetValue> m_inputDatasets{};

private:
bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override;

bool m_recursive = false;
std::vector<std::string> m_filenameFilter{};
double m_minPixelSize = 0;
double m_maxPixelSize = 0;
std::string m_locationName = "location";
bool m_writeAbsolutePaths = false;
std::string m_crs{};
std::string m_sourceCrsName{};
std::string m_sourceCrsFormat = "auto";
std::vector<std::string> m_metadata{};
};

//! @endcond

#endif
Loading
Loading