You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
337 lines
11 KiB
337 lines
11 KiB
/******************************************************************************
|
|
*
|
|
* Project: GDAL
|
|
* Purpose: gdal "vector pipeline" subcommand
|
|
* 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_VECTOR_PIPELINE_INCLUDED
|
|
#define GDALALG_VECTOR_PIPELINE_INCLUDED
|
|
|
|
#include "gdalalgorithm.h"
|
|
#include "gdalalg_abstract_pipeline.h"
|
|
|
|
#include "ogrsf_frmts.h"
|
|
#include "ogrlayerwithtranslatefeature.h"
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
//! @cond Doxygen_Suppress
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelineStepRunContext */
|
|
/************************************************************************/
|
|
|
|
class GDALVectorPipelineStepAlgorithm;
|
|
|
|
class GDALVectorPipelineStepRunContext
|
|
{
|
|
public:
|
|
GDALVectorPipelineStepRunContext() = default;
|
|
|
|
// Progress callback to use during execution of the step
|
|
GDALProgressFunc m_pfnProgress = nullptr;
|
|
void *m_pProgressData = nullptr;
|
|
|
|
// If there is a step in the pipeline immediately following step to which
|
|
// this instance of GDALRasterPipelineStepRunContext is passed, and that
|
|
// this next step is usable by the current step (as determined by
|
|
// CanHandleNextStep()), then this member will point to this next step.
|
|
GDALVectorPipelineStepAlgorithm *m_poNextUsableStep = nullptr;
|
|
|
|
private:
|
|
CPL_DISALLOW_COPY_ASSIGN(GDALVectorPipelineStepRunContext)
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelineStepAlgorithm */
|
|
/************************************************************************/
|
|
|
|
class GDALVectorPipelineStepAlgorithm /* non final */ : public GDALAlgorithm
|
|
{
|
|
protected:
|
|
GDALVectorPipelineStepAlgorithm(const std::string &name,
|
|
const std::string &description,
|
|
const std::string &helpURL,
|
|
bool standaloneStep);
|
|
|
|
struct ConstructorOptions
|
|
{
|
|
bool standaloneStep = false;
|
|
bool outputDatasetRequired = true;
|
|
std::string updateMutualExclusionGroup{};
|
|
std::string outputDatasetMutualExclusionGroup{};
|
|
|
|
inline ConstructorOptions &SetStandaloneStep(bool b)
|
|
{
|
|
standaloneStep = b;
|
|
return *this;
|
|
}
|
|
|
|
inline ConstructorOptions &SetOutputDatasetRequired(bool b)
|
|
{
|
|
outputDatasetRequired = b;
|
|
return *this;
|
|
}
|
|
|
|
inline ConstructorOptions &
|
|
SetUpdateMutualExclusionGroup(const std::string &s)
|
|
{
|
|
updateMutualExclusionGroup = s;
|
|
return *this;
|
|
}
|
|
|
|
inline ConstructorOptions &
|
|
SetOutputDatasetMutualExclusionGroup(const std::string &s)
|
|
{
|
|
outputDatasetMutualExclusionGroup = s;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
GDALVectorPipelineStepAlgorithm(const std::string &name,
|
|
const std::string &description,
|
|
const std::string &helpURL,
|
|
const ConstructorOptions &options);
|
|
|
|
using StepRunContext = GDALVectorPipelineStepRunContext;
|
|
|
|
friend class GDALVectorPipelineAlgorithm;
|
|
friend class GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm>;
|
|
friend class GDALVectorConcatAlgorithm;
|
|
|
|
virtual bool IsNativelyStreamingCompatible() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
virtual bool CanHandleNextStep(GDALVectorPipelineStepAlgorithm *) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual bool RunStep(GDALVectorPipelineStepRunContext &ctxt) = 0;
|
|
|
|
void AddInputArgs(bool hiddenForCLI);
|
|
void AddOutputArgs(bool hiddenForCLI, bool shortNameOutputLayerAllowed);
|
|
|
|
bool m_standaloneStep = false;
|
|
const ConstructorOptions m_constructorOptions;
|
|
|
|
bool m_outputVRTCompatible = false;
|
|
|
|
// Input arguments
|
|
std::vector<GDALArgDatasetValue> m_inputDataset{};
|
|
std::vector<std::string> m_openOptions{};
|
|
std::vector<std::string> m_inputFormats{};
|
|
std::vector<std::string> m_inputLayerNames{};
|
|
|
|
// Output arguments
|
|
GDALArgDatasetValue m_outputDataset{};
|
|
std::string m_format{};
|
|
std::vector<std::string> m_creationOptions{};
|
|
std::vector<std::string> m_layerCreationOptions{};
|
|
bool m_overwrite = false;
|
|
bool m_update = false;
|
|
bool m_overwriteLayer = false;
|
|
bool m_appendLayer = false;
|
|
std::string m_outputLayerName{};
|
|
|
|
private:
|
|
bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override;
|
|
GDALAlgorithm::ProcessGDALGOutputRet ProcessGDALGOutput() override;
|
|
bool CheckSafeForStreamOutput() override;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelineAlgorithm */
|
|
/************************************************************************/
|
|
|
|
// This is an easter egg to pay tribute to PROJ pipeline syntax
|
|
// We accept "gdal vector +gdal=pipeline +step +gdal=read +input=poly.gpkg +step +gdal=reproject +dst-crs=EPSG:32632 +step +gdal=write +output=out.gpkg +overwrite"
|
|
// as an alternative to (recommended):
|
|
// "gdal vector pipeline ! read poly.gpkg ! reproject--dst-crs=EPSG:32632 ! write out.gpkg --overwrite"
|
|
#define GDAL_PIPELINE_PROJ_NOSTALGIA
|
|
|
|
class GDALVectorPipelineAlgorithm final
|
|
: public GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm>
|
|
{
|
|
public:
|
|
static constexpr const char *NAME = "pipeline";
|
|
static constexpr const char *DESCRIPTION = "Process a vector dataset.";
|
|
static constexpr const char *HELP_URL =
|
|
"/programs/gdal_vector_pipeline.html";
|
|
|
|
static std::vector<std::string> GetAliasesStatic()
|
|
{
|
|
return {
|
|
#ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
|
|
GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR,
|
|
"+pipeline",
|
|
"+gdal=pipeline",
|
|
#endif
|
|
};
|
|
}
|
|
|
|
GDALVectorPipelineAlgorithm();
|
|
|
|
bool
|
|
ParseCommandLineArguments(const std::vector<std::string> &args) override;
|
|
|
|
std::string GetUsageForCLI(bool shortUsage,
|
|
const UsageOptions &usageOptions) const override;
|
|
|
|
protected:
|
|
GDALArgDatasetValue &GetOutputDataset() override
|
|
{
|
|
return m_outputDataset;
|
|
}
|
|
|
|
private:
|
|
std::string m_helpDocCategory{};
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelineOutputLayer */
|
|
/************************************************************************/
|
|
|
|
/** Class that implements GetNextFeature() by forwarding to
|
|
* OGRLayerWithTranslateFeature::TranslateFeature() implementation, which
|
|
* might return several features.
|
|
*/
|
|
class GDALVectorPipelineOutputLayer /* non final */
|
|
: public OGRLayerWithTranslateFeature,
|
|
public OGRGetNextFeatureThroughRaw<GDALVectorPipelineOutputLayer>
|
|
{
|
|
protected:
|
|
explicit GDALVectorPipelineOutputLayer(OGRLayer &oSrcLayer);
|
|
~GDALVectorPipelineOutputLayer();
|
|
|
|
DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(GDALVectorPipelineOutputLayer)
|
|
|
|
OGRLayer &m_srcLayer;
|
|
|
|
public:
|
|
void ResetReading() override;
|
|
OGRFeature *GetNextRawFeature();
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{};
|
|
size_t m_idxInPendingFeatures = 0;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelinePassthroughLayer */
|
|
/************************************************************************/
|
|
|
|
/** Class that forwards GetNextFeature() calls to the source layer and
|
|
* can be added to GDALVectorPipelineOutputDataset::AddLayer()
|
|
*/
|
|
class GDALVectorPipelinePassthroughLayer /* non final */
|
|
: public GDALVectorPipelineOutputLayer
|
|
{
|
|
public:
|
|
explicit GDALVectorPipelinePassthroughLayer(OGRLayer &oSrcLayer)
|
|
: GDALVectorPipelineOutputLayer(oSrcLayer)
|
|
{
|
|
}
|
|
|
|
OGRFeatureDefn *GetLayerDefn() override;
|
|
|
|
int TestCapability(const char *pszCap) override
|
|
{
|
|
return m_srcLayer.TestCapability(pszCap);
|
|
}
|
|
|
|
void TranslateFeature(
|
|
std::unique_ptr<OGRFeature> poSrcFeature,
|
|
std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
|
|
{
|
|
apoOutFeatures.push_back(std::move(poSrcFeature));
|
|
}
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorNonStreamingAlgorithmDataset */
|
|
/************************************************************************/
|
|
|
|
class MEMDataset;
|
|
|
|
/**
|
|
* Dataset used to read all input features into memory and perform some
|
|
* processing.
|
|
*/
|
|
class GDALVectorNonStreamingAlgorithmDataset /* non final */
|
|
: public GDALDataset
|
|
{
|
|
public:
|
|
GDALVectorNonStreamingAlgorithmDataset();
|
|
~GDALVectorNonStreamingAlgorithmDataset();
|
|
|
|
virtual bool Process(OGRLayer &srcLayer, OGRLayer &dstLayer) = 0;
|
|
|
|
bool AddProcessedLayer(OGRLayer &srcLayer);
|
|
void AddPassThroughLayer(OGRLayer &oLayer);
|
|
int GetLayerCount() final override;
|
|
OGRLayer *GetLayer(int idx) final override;
|
|
int TestCapability(const char *pszCap) override;
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<OGRLayer>> m_passthrough_layers{};
|
|
std::vector<OGRLayer *> m_layers{};
|
|
std::unique_ptr<MEMDataset> m_ds{};
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALVectorPipelineOutputDataset */
|
|
/************************************************************************/
|
|
|
|
/** Class used by vector pipeline steps to create an output on-the-fly
|
|
* dataset where they can store on-the-fly layers.
|
|
*/
|
|
class GDALVectorPipelineOutputDataset final : public GDALDataset
|
|
{
|
|
GDALDataset &m_srcDS;
|
|
std::map<OGRLayer *, OGRLayerWithTranslateFeature *>
|
|
m_mapSrcLayerToNewLayer{};
|
|
std::vector<std::unique_ptr<OGRLayerWithTranslateFeature>>
|
|
m_layersToDestroy{};
|
|
std::vector<OGRLayerWithTranslateFeature *> m_layers{};
|
|
|
|
OGRLayerWithTranslateFeature *m_belongingLayer = nullptr;
|
|
std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{};
|
|
size_t m_idxInPendingFeatures = 0;
|
|
|
|
CPL_DISALLOW_COPY_ASSIGN(GDALVectorPipelineOutputDataset)
|
|
|
|
public:
|
|
explicit GDALVectorPipelineOutputDataset(GDALDataset &oSrcDS);
|
|
~GDALVectorPipelineOutputDataset();
|
|
|
|
void AddLayer(OGRLayer &oSrcLayer,
|
|
std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer);
|
|
|
|
int GetLayerCount() override;
|
|
|
|
OGRLayer *GetLayer(int idx) override;
|
|
|
|
int TestCapability(const char *pszCap) override;
|
|
|
|
void ResetReading() override;
|
|
|
|
OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
|
|
double *pdfProgressPct,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData) override;
|
|
};
|
|
|
|
//! @endcond
|
|
|
|
#endif
|