Skip to content

Commit 0671c17

Browse files
committed
gdal vector filter: add --where and --fields; add documentation
1 parent 1ba0066 commit 0671c17

9 files changed

+576
-6
lines changed

apps/gdalalg_vector_filter.cpp

+273-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
#include "gdal_priv.h"
1616
#include "ogrsf_frmts.h"
17+
#include "ogr_p.h"
18+
19+
#include <set>
1720

1821
//! @cond Doxygen_Suppress
1922

@@ -30,8 +33,239 @@ GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep)
3033
standaloneStep)
3134
{
3235
AddBBOXArg(&m_bbox);
36+
AddArg("where", 0,
37+
_("Attribute query in a restricted form of the queries used in the "
38+
"SQL WHERE statement"),
39+
&m_where)
40+
.SetReadFromFileAtSyntaxAllowed()
41+
.SetMetaVar("<WHERE>|@<filename>")
42+
.SetRemoveSQLCommentsEnabled();
43+
AddArg("fields", 0, _("Selected fields"), &m_selectedFields);
44+
AddStrictLaxArg();
3345
}
3446

47+
namespace
48+
{
49+
50+
/************************************************************************/
51+
/* GDALVectorFilterAlgorithmDataset */
52+
/************************************************************************/
53+
54+
class GDALVectorFilterAlgorithmDataset final : public GDALDataset
55+
{
56+
std::vector<std::unique_ptr<OGRLayer>> m_layers{};
57+
58+
public:
59+
GDALVectorFilterAlgorithmDataset() = default;
60+
61+
void AddLayer(std::unique_ptr<OGRLayer> poLayer)
62+
{
63+
m_layers.push_back(std::move(poLayer));
64+
}
65+
66+
int GetLayerCount() override
67+
{
68+
return static_cast<int>(m_layers.size());
69+
}
70+
71+
OGRLayer *GetLayer(int idx) override
72+
{
73+
return idx >= 0 && idx < GetLayerCount() ? m_layers[idx].get()
74+
: nullptr;
75+
}
76+
};
77+
78+
/************************************************************************/
79+
/* GDALVectorFilterAlgorithmLayer */
80+
/************************************************************************/
81+
82+
class GDALVectorFilterAlgorithmLayer final : public OGRLayer
83+
{
84+
private:
85+
bool m_bIsOK = true;
86+
OGRLayer *const m_poSrcLayer;
87+
OGRFeatureDefn *const m_poFeatureDefn = nullptr;
88+
std::vector<int> m_anMapSrcFieldsToDstFields{};
89+
std::vector<int> m_anMapDstGeomFieldsToSrcGeomFields{};
90+
91+
CPL_DISALLOW_COPY_ASSIGN(GDALVectorFilterAlgorithmLayer)
92+
93+
std::unique_ptr<OGRFeature> TranslateFeature(OGRFeature *poSrcFeature) const
94+
{
95+
auto poFeature = std::make_unique<OGRFeature>(m_poFeatureDefn);
96+
poFeature->SetFID(poSrcFeature->GetFID());
97+
const auto styleString = poSrcFeature->GetStyleString();
98+
if (styleString)
99+
poFeature->SetStyleString(styleString);
100+
poFeature->SetFieldsFrom(
101+
poSrcFeature, m_anMapSrcFieldsToDstFields.data(), false, false);
102+
int iDstGeomField = 0;
103+
for (int nSrcGeomField : m_anMapDstGeomFieldsToSrcGeomFields)
104+
{
105+
poFeature->SetGeomFieldDirectly(
106+
iDstGeomField, poSrcFeature->StealGeometry(nSrcGeomField));
107+
++iDstGeomField;
108+
}
109+
return poFeature;
110+
}
111+
112+
public:
113+
GDALVectorFilterAlgorithmLayer(
114+
OGRLayer *poSrcLayer, const std::vector<std::string> &selectedFields,
115+
bool bStrict)
116+
: m_poSrcLayer(poSrcLayer),
117+
m_poFeatureDefn(new OGRFeatureDefn(poSrcLayer->GetName()))
118+
{
119+
SetDescription(poSrcLayer->GetDescription());
120+
m_poFeatureDefn->SetGeomType(wkbNone);
121+
m_poFeatureDefn->Reference();
122+
123+
std::set<std::string> oSetSelFields;
124+
std::set<std::string> oSetSelFieldsUC;
125+
for (const std::string &osFieldName : selectedFields)
126+
{
127+
oSetSelFields.insert(osFieldName);
128+
oSetSelFieldsUC.insert(CPLString(osFieldName).toupper());
129+
}
130+
131+
std::set<std::string> oSetUsedSetFieldsUC;
132+
133+
const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
134+
for (int i = 0; i < poSrcLayerDefn->GetFieldCount(); ++i)
135+
{
136+
const auto poSrcFieldDefn = poSrcLayerDefn->GetFieldDefn(i);
137+
auto oIter = oSetSelFieldsUC.find(
138+
CPLString(poSrcFieldDefn->GetNameRef()).toupper());
139+
if (oIter != oSetSelFieldsUC.end())
140+
{
141+
m_anMapSrcFieldsToDstFields.push_back(
142+
m_poFeatureDefn->GetFieldCount());
143+
OGRFieldDefn oDstFieldDefn(*poSrcFieldDefn);
144+
m_poFeatureDefn->AddFieldDefn(&oDstFieldDefn);
145+
oSetUsedSetFieldsUC.insert(*oIter);
146+
}
147+
else
148+
{
149+
m_anMapSrcFieldsToDstFields.push_back(-1);
150+
}
151+
}
152+
153+
for (int i = 0; i < poSrcLayerDefn->GetGeomFieldCount(); ++i)
154+
{
155+
const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(i);
156+
auto oIter = oSetSelFieldsUC.find(
157+
CPLString(poSrcFieldDefn->GetNameRef()).toupper());
158+
if (oIter != oSetSelFieldsUC.end())
159+
{
160+
m_anMapDstGeomFieldsToSrcGeomFields.push_back(i);
161+
OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
162+
m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
163+
oSetUsedSetFieldsUC.insert(*oIter);
164+
}
165+
}
166+
167+
auto oIter = oSetSelFieldsUC.find(
168+
CPLString(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME).toupper());
169+
if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
170+
oIter != oSetSelFieldsUC.end() &&
171+
poSrcLayerDefn->GetGeomFieldCount() == 1)
172+
{
173+
const auto poSrcFieldDefn = poSrcLayerDefn->GetGeomFieldDefn(0);
174+
m_anMapDstGeomFieldsToSrcGeomFields.push_back(0);
175+
OGRGeomFieldDefn oDstFieldDefn(*poSrcFieldDefn);
176+
m_poFeatureDefn->AddGeomFieldDefn(&oDstFieldDefn);
177+
oSetUsedSetFieldsUC.insert(*oIter);
178+
}
179+
180+
if (oSetUsedSetFieldsUC.size() != oSetSelFields.size())
181+
{
182+
for (const std::string &osName : oSetSelFields)
183+
{
184+
if (!cpl::contains(oSetUsedSetFieldsUC,
185+
CPLString(osName).toupper()))
186+
{
187+
CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_AppDefined,
188+
"Field '%s' does not exist in layer '%s'%s",
189+
osName.c_str(), poSrcLayer->GetDescription(),
190+
bStrict ? ". Use --lax to ignore it"
191+
: ". It will be ignored");
192+
if (bStrict)
193+
m_bIsOK = false;
194+
}
195+
}
196+
}
197+
}
198+
199+
~GDALVectorFilterAlgorithmLayer() override
200+
{
201+
if (m_poFeatureDefn)
202+
m_poFeatureDefn->Dereference();
203+
}
204+
205+
bool IsOK() const
206+
{
207+
return m_bIsOK;
208+
}
209+
210+
OGRFeatureDefn *GetLayerDefn() override
211+
{
212+
return m_poFeatureDefn;
213+
}
214+
215+
GIntBig GetFeatureCount(int bForce) override
216+
{
217+
return m_poSrcLayer->GetFeatureCount(bForce);
218+
}
219+
220+
OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override
221+
{
222+
return m_poSrcLayer->GetExtent(psExtent, bForce);
223+
}
224+
225+
OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
226+
{
227+
return m_poSrcLayer->GetExtent(iGeomField, psExtent, bForce);
228+
}
229+
230+
void ResetReading() override
231+
{
232+
m_poSrcLayer->ResetReading();
233+
}
234+
235+
OGRFeature *GetNextFeature() override
236+
{
237+
auto poSrcFeature =
238+
std::unique_ptr<OGRFeature>(m_poSrcLayer->GetNextFeature());
239+
if (!poSrcFeature)
240+
return nullptr;
241+
return TranslateFeature(poSrcFeature.get()).release();
242+
}
243+
244+
OGRFeature *GetFeature(GIntBig nFID) override
245+
{
246+
auto poSrcFeature =
247+
std::unique_ptr<OGRFeature>(m_poSrcLayer->GetFeature(nFID));
248+
if (!poSrcFeature)
249+
return nullptr;
250+
return TranslateFeature(poSrcFeature.get()).release();
251+
}
252+
253+
int TestCapability(const char *pszCap) override
254+
{
255+
if (EQUAL(pszCap, OLCRandomRead) || EQUAL(pszCap, OLCCurveGeometries) ||
256+
EQUAL(pszCap, OLCMeasuredGeometries) ||
257+
EQUAL(pszCap, OLCZGeometries) ||
258+
EQUAL(pszCap, OLCFastFeatureCount) ||
259+
EQUAL(pszCap, OLCFastGetExtent) || EQUAL(pszCap, OLCStringsAsUTF8))
260+
{
261+
return m_poSrcLayer->TestCapability(pszCap);
262+
}
263+
return false;
264+
}
265+
};
266+
267+
} // namespace
268+
35269
/************************************************************************/
36270
/* GDALVectorFilterAlgorithm::RunStep() */
37271
/************************************************************************/
@@ -42,15 +276,16 @@ bool GDALVectorFilterAlgorithm::RunStep(GDALProgressFunc, void *)
42276
CPLAssert(m_outputDataset.GetName().empty());
43277
CPLAssert(!m_outputDataset.GetDatasetRef());
44278

279+
auto poSrcDS = m_inputDataset.GetDatasetRef();
280+
const int nLayerCount = poSrcDS->GetLayerCount();
281+
45282
bool ret = true;
46283
if (m_bbox.size() == 4)
47284
{
48285
const double xmin = m_bbox[0];
49286
const double ymin = m_bbox[1];
50287
const double xmax = m_bbox[2];
51288
const double ymax = m_bbox[3];
52-
auto poSrcDS = m_inputDataset.GetDatasetRef();
53-
const int nLayerCount = poSrcDS->GetLayerCount();
54289
for (int i = 0; i < nLayerCount; ++i)
55290
{
56291
auto poSrcLayer = poSrcDS->GetLayer(i);
@@ -60,7 +295,42 @@ bool GDALVectorFilterAlgorithm::RunStep(GDALProgressFunc, void *)
60295
}
61296
}
62297

63-
if (ret)
298+
if (ret && !m_where.empty())
299+
{
300+
for (int i = 0; i < nLayerCount; ++i)
301+
{
302+
auto poSrcLayer = poSrcDS->GetLayer(i);
303+
ret = ret && (poSrcLayer != nullptr);
304+
if (ret)
305+
ret = poSrcLayer->SetAttributeFilter(m_where.c_str()) ==
306+
OGRERR_NONE;
307+
}
308+
}
309+
310+
if (ret && !m_selectedFields.empty())
311+
{
312+
auto outDS = std::make_unique<GDALVectorFilterAlgorithmDataset>();
313+
outDS->SetDescription(poSrcDS->GetDescription());
314+
315+
for (int i = 0; i < nLayerCount; ++i)
316+
{
317+
auto poSrcLayer = poSrcDS->GetLayer(i);
318+
ret = ret && (poSrcLayer != nullptr);
319+
if (ret)
320+
{
321+
auto poLayer = std::make_unique<GDALVectorFilterAlgorithmLayer>(
322+
poSrcLayer, m_selectedFields, m_strictMode);
323+
ret = poLayer->IsOK();
324+
if (ret)
325+
{
326+
outDS->AddLayer(std::move(poLayer));
327+
}
328+
}
329+
}
330+
331+
m_outputDataset.Set(std::move(outDS));
332+
}
333+
else if (ret)
64334
{
65335
m_outputDataset.Set(m_inputDataset.GetDatasetRef());
66336
}

apps/gdalalg_vector_filter.h

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class GDALVectorFilterAlgorithm /* non final */
4141
bool RunStep(GDALProgressFunc pfnProgress, void *pProgressData) override;
4242

4343
std::vector<double> m_bbox{};
44+
std::string m_where{};
45+
std::vector<std::string> m_selectedFields{};
46+
bool m_strict = true;
4447
};
4548

4649
/************************************************************************/

0 commit comments

Comments
 (0)