Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: gdal "vector pipeline" subcommand 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #ifndef GDALALG_VECTOR_PIPELINE_INCLUDED 14 : #define GDALALG_VECTOR_PIPELINE_INCLUDED 15 : 16 : #include "gdalalgorithm.h" 17 : #include "gdalalg_abstract_pipeline.h" 18 : 19 : #include "ogrsf_frmts.h" 20 : #include "ogrlayerwithtranslatefeature.h" 21 : 22 : #include <map> 23 : #include <vector> 24 : 25 : //! @cond Doxygen_Suppress 26 : 27 : /************************************************************************/ 28 : /* GDALVectorPipelineStepAlgorithm */ 29 : /************************************************************************/ 30 : 31 : class GDALVectorPipelineStepAlgorithm /* non final */ : public GDALAlgorithm 32 : { 33 : protected: 34 : GDALVectorPipelineStepAlgorithm(const std::string &name, 35 : const std::string &description, 36 : const std::string &helpURL, 37 : bool standaloneStep); 38 : 39 : friend class GDALVectorPipelineAlgorithm; 40 : friend class GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm>; 41 : 42 : virtual bool RunStep(GDALProgressFunc pfnProgress, void *pProgressData) = 0; 43 : 44 : void AddInputArgs(bool hiddenForCLI); 45 : void AddOutputArgs(bool hiddenForCLI, bool shortNameOutputLayerAllowed); 46 : 47 : bool m_standaloneStep = false; 48 : 49 : // Input arguments 50 : GDALArgDatasetValue m_inputDataset{}; 51 : std::vector<std::string> m_openOptions{}; 52 : std::vector<std::string> m_inputFormats{}; 53 : std::vector<std::string> m_inputLayerNames{}; 54 : 55 : // Output arguments 56 : GDALArgDatasetValue m_outputDataset{}; 57 : std::string m_format{}; 58 : std::vector<std::string> m_creationOptions{}; 59 : std::vector<std::string> m_layerCreationOptions{}; 60 : bool m_overwrite = false; 61 : bool m_update = false; 62 : bool m_overwriteLayer = false; 63 : bool m_appendLayer = false; 64 : std::string m_outputLayerName{}; 65 : 66 : private: 67 : bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override; 68 : GDALAlgorithm::ProcessGDALGOutputRet ProcessGDALGOutput() override; 69 : bool CheckSafeForStreamOutput() override; 70 : }; 71 : 72 : /************************************************************************/ 73 : /* GDALVectorPipelineAlgorithm */ 74 : /************************************************************************/ 75 : 76 : // This is an easter egg to pay tribute to PROJ pipeline syntax 77 : // 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" 78 : // as an alternative to (recommended): 79 : // "gdal vector pipeline ! read poly.gpkg ! reproject--dst-crs=EPSG:32632 ! write out.gpkg --overwrite" 80 : #define GDAL_PIPELINE_PROJ_NOSTALGIA 81 : 82 : class GDALVectorPipelineAlgorithm final 83 : : public GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm> 84 : { 85 : public: 86 : static constexpr const char *NAME = "pipeline"; 87 : static constexpr const char *DESCRIPTION = "Process a vector dataset."; 88 : static constexpr const char *HELP_URL = 89 : "/programs/gdal_vector_pipeline.html"; 90 : 91 242 : static std::vector<std::string> GetAliases() 92 : { 93 : return { 94 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA 95 : GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR, 96 : "+pipeline", 97 : "+gdal=pipeline", 98 : #endif 99 968 : }; 100 : } 101 : 102 : GDALVectorPipelineAlgorithm(); 103 : 104 : bool 105 : ParseCommandLineArguments(const std::vector<std::string> &args) override; 106 : 107 : std::string GetUsageForCLI(bool shortUsage, 108 : const UsageOptions &usageOptions) const override; 109 : 110 : protected: 111 58 : GDALArgDatasetValue &GetOutputDataset() override 112 : { 113 58 : return m_outputDataset; 114 : } 115 : 116 : private: 117 : std::string m_helpDocCategory{}; 118 : }; 119 : 120 : /************************************************************************/ 121 : /* GDALVectorPipelineOutputLayer */ 122 : /************************************************************************/ 123 : 124 : /** Class that implements GetNextFeature() by forwarding to 125 : * OGRLayerWithTranslateFeature::TranslateFeature() implementation, which 126 : * might return several features. 127 : */ 128 : class GDALVectorPipelineOutputLayer /* non final */ 129 : : public OGRLayerWithTranslateFeature, 130 : public OGRGetNextFeatureThroughRaw<GDALVectorPipelineOutputLayer> 131 : { 132 : protected: 133 : explicit GDALVectorPipelineOutputLayer(OGRLayer &oSrcLayer); 134 : 135 232 : DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(GDALVectorPipelineOutputLayer) 136 : 137 : OGRLayer &m_srcLayer; 138 : 139 : public: 140 : void ResetReading() override; 141 : OGRFeature *GetNextRawFeature(); 142 : 143 : private: 144 : std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{}; 145 : size_t m_idxInPendingFeatures = 0; 146 : }; 147 : 148 : /************************************************************************/ 149 : /* GDALVectorPipelinePassthroughLayer */ 150 : /************************************************************************/ 151 : 152 : /** Class that forwards GetNextFeature() calls to the source layer and 153 : * can be aded to GDALVectorPipelineOutputDataset::AddLayer() 154 : */ 155 : class GDALVectorPipelinePassthroughLayer /* non final */ 156 : : public GDALVectorPipelineOutputLayer 157 : { 158 : public: 159 5 : explicit GDALVectorPipelinePassthroughLayer(OGRLayer &oSrcLayer) 160 5 : : GDALVectorPipelineOutputLayer(oSrcLayer) 161 : { 162 5 : } 163 : 164 42 : OGRFeatureDefn *GetLayerDefn() override 165 : { 166 42 : return m_srcLayer.GetLayerDefn(); 167 : } 168 : 169 3 : int TestCapability(const char *pszCap) override 170 : { 171 3 : return m_srcLayer.TestCapability(pszCap); 172 : } 173 : 174 4 : void TranslateFeature( 175 : std::unique_ptr<OGRFeature> poSrcFeature, 176 : std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override 177 : { 178 4 : apoOutFeatures.push_back(std::move(poSrcFeature)); 179 4 : } 180 : }; 181 : 182 : /************************************************************************/ 183 : /* GDALVectorPipelineOutputDataset */ 184 : /************************************************************************/ 185 : 186 : /** Class used by vector pipeline steps to create an output on-the-fly 187 : * dataset where they can store on-the-fly layers. 188 : */ 189 : class GDALVectorPipelineOutputDataset final : public GDALDataset 190 : { 191 : GDALDataset &m_srcDS; 192 : std::map<OGRLayer *, OGRLayerWithTranslateFeature *> 193 : m_mapSrcLayerToNewLayer{}; 194 : std::vector<std::unique_ptr<OGRLayerWithTranslateFeature>> 195 : m_layersToDestroy{}; 196 : std::vector<OGRLayerWithTranslateFeature *> m_layers{}; 197 : 198 : OGRLayerWithTranslateFeature *m_belongingLayer = nullptr; 199 : std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{}; 200 : size_t m_idxInPendingFeatures = 0; 201 : 202 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorPipelineOutputDataset) 203 : 204 : public: 205 : explicit GDALVectorPipelineOutputDataset(GDALDataset &oSrcDS); 206 : 207 : void AddLayer(OGRLayer &oSrcLayer, 208 : std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer); 209 : 210 : int GetLayerCount() override; 211 : 212 : OGRLayer *GetLayer(int idx) override; 213 : 214 : int TestCapability(const char *pszCap) override; 215 : 216 : void ResetReading() override; 217 : 218 : OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer, 219 : double *pdfProgressPct, 220 : GDALProgressFunc pfnProgress, 221 : void *pProgressData) override; 222 : }; 223 : 224 : //! @endcond 225 : 226 : #endif