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