Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "geom" step of "vector pipeline", or "gdal vector geom" standalone 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #ifndef GDALALG_VECTOR_GEOM_INCLUDED 14 : #define GDALALG_VECTOR_GEOM_INCLUDED 15 : 16 : #include "gdalalg_vector_pipeline.h" 17 : #include "ogr_geos.h" 18 : 19 : //! @cond Doxygen_Suppress 20 : 21 : /************************************************************************/ 22 : /* GDALVectorGeomAlgorithm */ 23 : /************************************************************************/ 24 : 25 : class GDALVectorGeomAlgorithm /* non final */ 26 : : public GDALVectorPipelineStepAlgorithm 27 : { 28 : public: 29 : static constexpr const char *NAME = "geom"; 30 : static constexpr const char *DESCRIPTION = 31 : "Geometry operations on a vector dataset."; 32 : static constexpr const char *HELP_URL = "/programs/gdal_vector_geom.html"; 33 : 34 : explicit GDALVectorGeomAlgorithm(bool standaloneStep = false); 35 : 36 : private: 37 : bool RunStep(GDALPipelineStepRunContext &ctxt) override; 38 : 39 : void WarnIfDeprecated() override; 40 : 41 : /** Register the sub-algorithm of type MyAlgorithm. 42 : */ 43 357 : template <class MyAlgorithm> bool RegisterSubAlgorithm(bool standalone) 44 : { 45 714 : GDALAlgorithmRegistry::AlgInfo info; 46 357 : info.m_name = MyAlgorithm::NAME; 47 357 : info.m_aliases = MyAlgorithm::GetAliasesStatic(); 48 360 : info.m_creationFunc = [standalone]() -> std::unique_ptr<GDALAlgorithm> 49 3 : { return std::make_unique<MyAlgorithm>(standalone); }; 50 714 : return GDALAlgorithm::RegisterSubAlgorithm(info); 51 : } 52 : }; 53 : 54 : /************************************************************************/ 55 : /* GDALVectorGeomAlgorithmStandalone */ 56 : /************************************************************************/ 57 : 58 6 : class GDALVectorGeomAlgorithmStandalone final : public GDALVectorGeomAlgorithm 59 : { 60 : public: 61 3 : GDALVectorGeomAlgorithmStandalone() 62 3 : : GDALVectorGeomAlgorithm(/* standaloneStep = */ true) 63 : { 64 3 : } 65 : 66 : ~GDALVectorGeomAlgorithmStandalone() override; 67 : }; 68 : 69 : /************************************************************************/ 70 : /* GDALVectorGeomAbstractAlgorithm */ 71 : /************************************************************************/ 72 : 73 : class GDALVectorGeomAbstractAlgorithm /* non final */ 74 : : public GDALVectorPipelineStepAlgorithm 75 : { 76 : protected: 77 : struct OptionsBase 78 : { 79 : std::string m_activeLayer{}; 80 : std::string m_geomField{}; 81 : }; 82 : 83 : virtual std::unique_ptr<OGRLayerWithTranslateFeature> 84 : CreateAlgLayer(OGRLayer &srcLayer) = 0; 85 : 86 : GDALVectorGeomAbstractAlgorithm(const std::string &name, 87 : const std::string &description, 88 : const std::string &helpURL, 89 : bool standaloneStep, OptionsBase &opts); 90 : 91 : bool RunStep(GDALPipelineStepRunContext &ctxt) override; 92 : 93 : private: 94 : std::string &m_activeLayer; 95 : }; 96 : 97 : /************************************************************************/ 98 : /* GDALVectorGeomOneToOneAlgorithmLayer */ 99 : /************************************************************************/ 100 : 101 : template <class T> 102 : class GDALVectorGeomOneToOneAlgorithmLayer /* non final */ 103 : : public GDALVectorPipelineOutputLayer 104 : { 105 : public: 106 220 : const OGRFeatureDefn *GetLayerDefn() const override 107 : { 108 220 : return m_srcLayer.GetLayerDefn(); 109 : } 110 : 111 21 : GIntBig GetFeatureCount(int bForce) override 112 : { 113 21 : if (!m_poAttrQuery && !m_poFilterGeom) 114 11 : return m_srcLayer.GetFeatureCount(bForce); 115 10 : return OGRLayer::GetFeatureCount(bForce); 116 : } 117 : 118 12 : OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent, 119 : bool bForce) override 120 : { 121 12 : return m_srcLayer.GetExtent(iGeomField, psExtent, bForce); 122 : } 123 : 124 26 : OGRFeature *GetFeature(GIntBig nFID) override 125 : { 126 52 : auto poSrcFeature = 127 26 : std::unique_ptr<OGRFeature>(m_srcLayer.GetFeature(nFID)); 128 26 : if (!poSrcFeature) 129 11 : return nullptr; 130 15 : return TranslateFeature(std::move(poSrcFeature)).release(); 131 : } 132 : 133 48 : int TestCapability(const char *pszCap) const override 134 : { 135 48 : if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) || 136 44 : EQUAL(pszCap, OLCMeasuredGeometries) || 137 40 : EQUAL(pszCap, OLCZGeometries) || EQUAL(pszCap, OLCFastGetExtent) || 138 35 : (EQUAL(pszCap, OLCFastFeatureCount) && !m_poAttrQuery && 139 4 : !m_poFilterGeom) || 140 31 : EQUAL(pszCap, OLCStringsAsUTF8)) 141 : { 142 33 : return m_srcLayer.TestCapability(pszCap); 143 : } 144 15 : return false; 145 : } 146 : 147 : protected: 148 : const typename T::Options m_opts; 149 : 150 42 : GDALVectorGeomOneToOneAlgorithmLayer(OGRLayer &oSrcLayer, 151 : const typename T::Options &opts) 152 42 : : GDALVectorPipelineOutputLayer(oSrcLayer), m_opts(opts) 153 : { 154 42 : SetDescription(oSrcLayer.GetDescription()); 155 42 : SetMetadata(oSrcLayer.GetMetadata()); 156 42 : if (!m_opts.m_geomField.empty()) 157 : { 158 2 : const int nIdx = oSrcLayer.GetLayerDefn()->GetGeomFieldIndex( 159 : m_opts.m_geomField.c_str()); 160 2 : if (nIdx >= 0) 161 2 : m_iGeomIdx = nIdx; 162 : else 163 0 : m_iGeomIdx = INT_MAX; 164 : } 165 42 : } 166 : 167 678 : bool IsSelectedGeomField(int idx) const 168 : { 169 678 : return m_iGeomIdx < 0 || idx == m_iGeomIdx; 170 : } 171 : 172 : virtual std::unique_ptr<OGRFeature> 173 : TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature) const = 0; 174 : 175 640 : void TranslateFeature( 176 : std::unique_ptr<OGRFeature> poSrcFeature, 177 : std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override 178 : { 179 1280 : auto poDstFeature = TranslateFeature(std::move(poSrcFeature)); 180 640 : if (poDstFeature) 181 638 : apoOutFeatures.push_back(std::move(poDstFeature)); 182 640 : } 183 : 184 : private: 185 : int m_iGeomIdx = -1; 186 : }; 187 : 188 : #ifdef HAVE_GEOS 189 : 190 : /************************************************************************/ 191 : /* GDALGeosNonStreamingAlgorithmDataset */ 192 : /************************************************************************/ 193 : 194 : /** A GDALGeosNonStreamingAlgorithmDataset manages the work of reading features 195 : * from an input layer, converting OGR geometries into GEOS geometries, 196 : * applying a GEOS function, and writing result to an output layer. It is 197 : * appropriate only for GEOS algorithms that operate on all input geometries 198 : * at a single time. 199 : */ 200 : class GDALGeosNonStreamingAlgorithmDataset 201 : : public GDALVectorNonStreamingAlgorithmDataset 202 : { 203 : public: 204 : GDALGeosNonStreamingAlgorithmDataset(); 205 : 206 : ~GDALGeosNonStreamingAlgorithmDataset() override; 207 : 208 : CPL_DISALLOW_COPY_ASSIGN(GDALGeosNonStreamingAlgorithmDataset) 209 : 210 : bool ConvertInputsToGeos(OGRLayer &srcLayer, OGRLayer &dstLayer, 211 : bool sameDefn); 212 : 213 : bool ConvertOutputsFromGeos(OGRLayer &dstLayer); 214 : 215 : bool Process(OGRLayer &srcLayer, OGRLayer &dstLayer) override; 216 : 217 : virtual bool ProcessGeos() = 0; 218 : 219 : /// Whether the operation should fail if non-polygonal geometries are present 220 : virtual bool PolygonsOnly() const = 0; 221 : 222 : /// Whether empty result features should be excluded from the output 223 : virtual bool SkipEmpty() const = 0; 224 : 225 6 : void SetSourceGeometryField(int i) 226 : { 227 6 : m_sourceGeometryField = i; 228 6 : } 229 : 230 : protected: 231 : GEOSContextHandle_t m_poGeosContext{nullptr}; 232 : std::vector<GEOSGeometry *> m_apoGeosInputs{}; 233 : GEOSGeometry *m_poGeosResultAsCollection{nullptr}; 234 : GEOSGeometry **m_papoGeosResults{nullptr}; 235 : 236 : private: 237 : std::vector<std::unique_ptr<OGRFeature>> m_apoFeatures{}; 238 : unsigned int m_nGeosResultSize{0}; 239 : int m_sourceGeometryField{0}; 240 : }; 241 : 242 : #endif 243 : 244 : //! @endcond 245 : 246 : #endif /* GDALALG_VECTOR_GEOM_INCLUDED */