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 59 : GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep) 32 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 33 59 : standaloneStep) 34 : { 35 59 : AddActiveLayerArg(&m_activeLayer); 36 59 : 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 118 : &m_where) 41 59 : .SetReadFromFileAtSyntaxAllowed() 42 118 : .SetMetaVar("<WHERE>|@<filename>") 43 59 : .SetRemoveSQLCommentsEnabled(); 44 : AddArg("update-extent", 0, 45 : _("Update layer extent to take into account the filter"), 46 59 : &m_updateExtent); 47 59 : } 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 13 : bool GDALVectorFilterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt) 112 : { 113 13 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 114 13 : CPLAssert(poSrcDS); 115 : 116 13 : CPLAssert(m_outputDataset.GetName().empty()); 117 13 : CPLAssert(!m_outputDataset.GetDatasetRef()); 118 : 119 13 : const int nLayerCount = poSrcDS->GetLayerCount(); 120 : 121 13 : bool ret = true; 122 13 : 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 13 : if (ret && !m_where.empty()) 139 : { 140 17 : for (int i = 0; i < nLayerCount; ++i) 141 : { 142 10 : auto poSrcLayer = poSrcDS->GetLayer(i); 143 10 : ret = ret && (poSrcLayer != nullptr); 144 14 : if (ret && (m_activeLayer.empty() || 145 4 : m_activeLayer == poSrcLayer->GetDescription())) 146 : { 147 8 : ret = poSrcLayer->SetAttributeFilter(m_where.c_str()) == 148 : OGRERR_NONE; 149 : } 150 : } 151 : } 152 : 153 13 : if (ret && m_updateExtent) 154 : { 155 : auto outDS = 156 1 : std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS); 157 : 158 1 : int64_t nTotalFeatures = 0; 159 1 : if (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 1 : int64_t nFeatureCounter = 0; 186 3 : for (int i = 0; ret && i < nLayerCount; ++i) 187 : { 188 2 : auto poSrcLayer = poSrcDS->GetLayer(i); 189 2 : ret = (poSrcLayer != nullptr); 190 2 : if (ret) 191 : { 192 4 : if (m_activeLayer.empty() || 193 2 : m_activeLayer == poSrcLayer->GetDescription()) 194 : { 195 1 : OGREnvelope3D sLayerEnvelope, sFeatureEnvelope; 196 2 : for (auto &&poFeature : poSrcLayer) 197 : { 198 1 : const auto poGeom = poFeature->GetGeometryRef(); 199 1 : if (poGeom && !poGeom->IsEmpty()) 200 : { 201 1 : poGeom->getEnvelope(&sFeatureEnvelope); 202 1 : sLayerEnvelope.Merge(sFeatureEnvelope); 203 : } 204 : 205 1 : ++nFeatureCounter; 206 1 : if (nTotalFeatures > 0 && ctxt.m_pfnProgress && 207 0 : !ctxt.m_pfnProgress( 208 0 : static_cast<double>(nFeatureCounter) / 209 0 : static_cast<double>(nTotalFeatures), 210 : "", ctxt.m_pProgressData)) 211 : { 212 0 : ReportError(CE_Failure, CPLE_UserInterrupt, 213 : "Interrupted by user"); 214 0 : return false; 215 : } 216 : } 217 2 : outDS->AddLayer( 218 : *poSrcLayer, 219 : std::make_unique< 220 2 : GDALVectorFilterAlgorithmLayerChangeExtent>( 221 : *poSrcLayer, sLayerEnvelope)); 222 : } 223 : else 224 : { 225 2 : outDS->AddLayer( 226 : *poSrcLayer, 227 2 : std::make_unique<GDALVectorPipelinePassthroughLayer>( 228 : *poSrcLayer)); 229 : } 230 : } 231 : } 232 : 233 1 : if (ret) 234 2 : m_outputDataset.Set(std::move(outDS)); 235 : } 236 12 : else if (ret) 237 : { 238 11 : m_outputDataset.Set(poSrcDS); 239 : } 240 : 241 13 : return ret; 242 : } 243 : 244 : GDALVectorFilterAlgorithmStandalone::~GDALVectorFilterAlgorithmStandalone() = 245 : default; 246 : 247 : //! @endcond