Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "filter" step of "vector pipeline" 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 : #include "gdalalg_vector_filter.h" 14 : 15 : #include "gdal_priv.h" 16 : #include "ogrsf_frmts.h" 17 : #include "ogr_p.h" 18 : 19 : #include <set> 20 : 21 : //! @cond Doxygen_Suppress 22 : 23 : #ifndef _ 24 : #define _(x) (x) 25 : #endif 26 : 27 : /************************************************************************/ 28 : /* GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm() */ 29 : /************************************************************************/ 30 : 31 101 : GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep) 32 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 33 101 : standaloneStep) 34 : { 35 101 : AddActiveLayerArg(&m_activeLayer); 36 101 : AddBBOXArg(&m_bbox); 37 : AddArg("where", 0, 38 : _("Attribute query in a restricted form of the queries used in the " 39 : "SQL WHERE statement"), 40 202 : &m_where) 41 101 : .SetReadFromFileAtSyntaxAllowed() 42 202 : .SetMetaVar("<WHERE>|@<filename>") 43 101 : .SetRemoveSQLCommentsEnabled(); 44 : AddArg("update-extent", 0, 45 : _("Update layer extent to take into account the filter"), 46 101 : &m_updateExtent); 47 101 : } 48 : 49 : /************************************************************************/ 50 : /* GDALVectorFilterAlgorithmLayerChangeExtent */ 51 : /************************************************************************/ 52 : 53 : namespace 54 : { 55 : class GDALVectorFilterAlgorithmLayerChangeExtent final 56 : : public GDALVectorPipelinePassthroughLayer 57 : { 58 : public: 59 1 : GDALVectorFilterAlgorithmLayerChangeExtent( 60 : OGRLayer &oSrcLayer, const OGREnvelope3D &sLayerEnvelope) 61 1 : : GDALVectorPipelinePassthroughLayer(oSrcLayer), 62 1 : m_sLayerEnvelope(sLayerEnvelope) 63 : { 64 1 : } 65 : 66 1 : OGRErr IGetExtent(int /*iGeomField*/, OGREnvelope *psExtent, 67 : bool /* bForce */) override 68 : { 69 1 : if (m_sLayerEnvelope.IsInit()) 70 : { 71 1 : *psExtent = m_sLayerEnvelope; 72 1 : return OGRERR_NONE; 73 : } 74 : else 75 : { 76 0 : return OGRERR_FAILURE; 77 : } 78 : } 79 : 80 1 : OGRErr IGetExtent3D(int /*iGeomField*/, OGREnvelope3D *psExtent, 81 : bool /* bForce */) override 82 : { 83 1 : if (m_sLayerEnvelope.IsInit()) 84 : { 85 1 : *psExtent = m_sLayerEnvelope; 86 1 : return OGRERR_NONE; 87 : } 88 : else 89 : { 90 0 : return OGRERR_FAILURE; 91 : } 92 : } 93 : 94 0 : int TestCapability(const char *pszCap) const override 95 : { 96 0 : if (EQUAL(pszCap, OLCFastGetExtent)) 97 0 : return true; 98 0 : return m_srcLayer.TestCapability(pszCap); 99 : } 100 : 101 : private: 102 : const OGREnvelope3D m_sLayerEnvelope; 103 : }; 104 : 105 : } // namespace 106 : 107 : /************************************************************************/ 108 : /* GDALVectorFilterAlgorithm::RunStep() */ 109 : /************************************************************************/ 110 : 111 18 : bool GDALVectorFilterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt) 112 : { 113 18 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 114 18 : CPLAssert(poSrcDS); 115 : 116 18 : CPLAssert(m_outputDataset.GetName().empty()); 117 18 : CPLAssert(!m_outputDataset.GetDatasetRef()); 118 : 119 18 : const int nLayerCount = poSrcDS->GetLayerCount(); 120 : 121 18 : bool ret = true; 122 18 : if (m_bbox.size() == 4) 123 : { 124 4 : const double xmin = m_bbox[0]; 125 4 : const double ymin = m_bbox[1]; 126 4 : const double xmax = m_bbox[2]; 127 4 : const double ymax = m_bbox[3]; 128 8 : for (int i = 0; i < nLayerCount; ++i) 129 : { 130 4 : auto poSrcLayer = poSrcDS->GetLayer(i); 131 4 : ret = ret && (poSrcLayer != nullptr); 132 4 : if (poSrcLayer && (m_activeLayer.empty() || 133 0 : m_activeLayer == poSrcLayer->GetDescription())) 134 4 : poSrcLayer->SetSpatialFilterRect(xmin, ymin, xmax, ymax); 135 : } 136 : } 137 : 138 18 : if (ret && !m_where.empty()) 139 : { 140 28 : for (int i = 0; i < nLayerCount; ++i) 141 : { 142 16 : auto poSrcLayer = poSrcDS->GetLayer(i); 143 16 : ret = ret && (poSrcLayer != nullptr); 144 22 : if (ret && (m_activeLayer.empty() || 145 6 : m_activeLayer == poSrcLayer->GetDescription())) 146 : { 147 13 : ret = poSrcLayer->SetAttributeFilter(m_where.c_str()) == 148 : OGRERR_NONE; 149 : } 150 : } 151 : } 152 : 153 18 : if (ret) 154 : { 155 : auto outDS = 156 17 : std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS); 157 : 158 17 : int64_t nTotalFeatures = 0; 159 17 : if (m_updateExtent && ctxt.m_pfnProgress) 160 : { 161 0 : for (int i = 0; ret && i < nLayerCount; ++i) 162 : { 163 0 : auto poSrcLayer = poSrcDS->GetLayer(i); 164 0 : ret = (poSrcLayer != nullptr); 165 0 : if (ret) 166 : { 167 0 : if (m_activeLayer.empty() || 168 0 : m_activeLayer == poSrcLayer->GetDescription()) 169 : { 170 0 : if (poSrcLayer->TestCapability(OLCFastFeatureCount)) 171 : { 172 0 : const auto nFC = poSrcLayer->GetFeatureCount(false); 173 0 : if (nFC < 0) 174 : { 175 0 : nTotalFeatures = 0; 176 0 : break; 177 : } 178 0 : nTotalFeatures += nFC; 179 : } 180 : } 181 : } 182 : } 183 : } 184 : 185 17 : int64_t nFeatureCounter = 0; 186 38 : for (int i = 0; ret && i < nLayerCount; ++i) 187 : { 188 21 : auto poSrcLayer = poSrcDS->GetLayer(i); 189 21 : ret = (poSrcLayer != nullptr); 190 21 : if (ret) 191 : { 192 25 : if (m_updateExtent && 193 4 : (m_activeLayer.empty() || 194 2 : m_activeLayer == poSrcLayer->GetDescription())) 195 : { 196 1 : OGREnvelope3D sLayerEnvelope, sFeatureEnvelope; 197 2 : for (auto &&poFeature : poSrcLayer) 198 : { 199 1 : const auto poGeom = poFeature->GetGeometryRef(); 200 1 : if (poGeom && !poGeom->IsEmpty()) 201 : { 202 1 : poGeom->getEnvelope(&sFeatureEnvelope); 203 1 : sLayerEnvelope.Merge(sFeatureEnvelope); 204 : } 205 : 206 1 : ++nFeatureCounter; 207 1 : if (nTotalFeatures > 0 && ctxt.m_pfnProgress && 208 0 : !ctxt.m_pfnProgress( 209 0 : static_cast<double>(nFeatureCounter) / 210 0 : static_cast<double>(nTotalFeatures), 211 : "", ctxt.m_pProgressData)) 212 : { 213 0 : ReportError(CE_Failure, CPLE_UserInterrupt, 214 : "Interrupted by user"); 215 0 : return false; 216 : } 217 : } 218 2 : outDS->AddLayer( 219 : *poSrcLayer, 220 : std::make_unique< 221 2 : GDALVectorFilterAlgorithmLayerChangeExtent>( 222 : *poSrcLayer, sLayerEnvelope)); 223 : } 224 : else 225 : { 226 40 : outDS->AddLayer( 227 : *poSrcLayer, 228 40 : std::make_unique<GDALVectorPipelinePassthroughLayer>( 229 : *poSrcLayer)); 230 : } 231 : } 232 : } 233 : 234 17 : if (ret) 235 17 : m_outputDataset.Set(std::move(outDS)); 236 : } 237 : 238 18 : return ret; 239 : } 240 : 241 : GDALVectorFilterAlgorithmStandalone::~GDALVectorFilterAlgorithmStandalone() = 242 : default; 243 : 244 : //! @endcond