Skip to content

Commit c51f7a1

Browse files
authored
Merge pull request OSGeo#13429 from dbaston/gdal-vector-check-geometry-include-field
gdal vector check-geometry: add include-field option
2 parents a5ddce6 + b62944f commit c51f7a1

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

apps/gdalalg_vector_check_geometry.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ GDALVectorCheckGeometryAlgorithm::GDALVectorCheckGeometryAlgorithm(
3131
: GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
3232
standaloneStep)
3333
{
34+
AddArg("include-field", 0,
35+
_("Fields from input layer to include in output"), &m_includeFields);
36+
3437
AddArg("include-valid", 0,
3538
_("Include valid inputs in output, with empty geometry"),
3639
&m_includeValid);
@@ -47,8 +50,10 @@ class GDALInvalidLocationLayer final : public GDALVectorPipelineOutputLayer
4750
static constexpr const char *ERROR_DESCRIPTION_FIELD = "error";
4851

4952
public:
50-
GDALInvalidLocationLayer(OGRLayer &layer, bool bSingleLayerOutput,
51-
int srcGeomField, bool skipValid)
53+
GDALInvalidLocationLayer(OGRLayer &layer,
54+
const std::vector<int> &srcFieldIndices,
55+
bool bSingleLayerOutput, int srcGeomField,
56+
bool skipValid)
5257
: GDALVectorPipelineOutputLayer(layer),
5358
m_defn(OGRFeatureDefn::CreateFeatureDefn(
5459
bSingleLayerOutput ? "error_location"
@@ -60,6 +65,18 @@ class GDALInvalidLocationLayer final : public GDALVectorPipelineOutputLayer
6065
{
6166
m_defn->Reference();
6267

68+
if (!srcFieldIndices.empty())
69+
{
70+
const OGRFeatureDefn &srcDefn = *layer.GetLayerDefn();
71+
m_srcFieldMap.resize(srcDefn.GetFieldCount(), -1);
72+
int iDstField = 0;
73+
for (int iSrcField : srcFieldIndices)
74+
{
75+
m_defn->AddFieldDefn(srcDefn.GetFieldDefn(iSrcField));
76+
m_srcFieldMap[iSrcField] = iDstField++;
77+
}
78+
}
79+
6380
auto poDescriptionFieldDefn =
6481
std::make_unique<OGRFieldDefn>(ERROR_DESCRIPTION_FIELD, OFTString);
6582
m_defn->AddFieldDefn(std::move(poDescriptionFieldDefn));
@@ -82,7 +99,7 @@ class GDALInvalidLocationLayer final : public GDALVectorPipelineOutputLayer
8299
return m_defn;
83100
}
84101

85-
std::unique_ptr<OGRFeature> CreateFeatureFromLastError()
102+
std::unique_ptr<OGRFeature> CreateFeatureFromLastError() const
86103
{
87104
auto poErrorFeature = std::make_unique<OGRFeature>(m_defn);
88105

@@ -244,6 +261,11 @@ class GDALInvalidLocationLayer final : public GDALVectorPipelineOutputLayer
244261

245262
if (poErrorFeature)
246263
{
264+
if (!m_srcFieldMap.empty())
265+
{
266+
poErrorFeature->SetFieldsFrom(
267+
poSrcFeature.get(), m_srcFieldMap.data(), false, false);
268+
}
247269
poErrorFeature->SetFID(poSrcFeature->GetFID());
248270
apoOutputFeatures.push_back(std::move(poErrorFeature));
249271
}
@@ -252,6 +274,7 @@ class GDALInvalidLocationLayer final : public GDALVectorPipelineOutputLayer
252274
CPL_DISALLOW_COPY_ASSIGN(GDALInvalidLocationLayer)
253275

254276
private:
277+
std::vector<int> m_srcFieldMap{};
255278
OGRFeatureDefn *const m_defn;
256279
const GEOSContextHandle_t m_geosContext;
257280
const int m_srcGeomField;
@@ -310,9 +333,26 @@ bool GDALVectorCheckGeometryAlgorithm::RunStep(GDALPipelineStepRunContext &)
310333
return false;
311334
}
312335

336+
std::vector<int> includeFieldIndices;
337+
for (const auto &fieldName : m_includeFields)
338+
{
339+
auto iSrcField =
340+
poSrcLayerDefn->GetFieldIndex(fieldName.c_str());
341+
if (iSrcField == -1)
342+
{
343+
ReportError(
344+
CE_Failure, CPLE_AppDefined,
345+
"Specified field '%s' does not exist in layer '%s'",
346+
fieldName.c_str(), poSrcLayer->GetDescription());
347+
return false;
348+
}
349+
includeFieldIndices.push_back(iSrcField);
350+
}
351+
313352
outDS->AddLayer(*poSrcLayer,
314353
std::make_unique<GDALInvalidLocationLayer>(
315-
*poSrcLayer, bSingleLayerOutput, geomFieldIndex,
354+
*poSrcLayer, includeFieldIndices,
355+
bSingleLayerOutput, geomFieldIndex,
316356
!m_includeValid));
317357
}
318358
}

apps/gdalalg_vector_check_geometry.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class GDALVectorCheckGeometryAlgorithm : public GDALVectorPipelineStepAlgorithm
3838
private:
3939
bool RunStep(GDALPipelineStepRunContext &ctxt) override;
4040

41+
std::vector<std::string> m_includeFields{};
4142
std::string m_geomField{};
4243
bool m_includeValid{false};
4344
};

autotest/utilities/test_gdalalg_vector_check_geometry.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,3 +495,32 @@ def test_gdalalg_vector_check_geometry_no_geometry_field(alg):
495495
Exception, match="Specified layer 'source' has no geometry field"
496496
):
497497
alg.Run()
498+
499+
500+
def test_gdalalg_vector_check_geometry_include_field(alg):
501+
502+
alg["input"] = "../ogr/data/poly.shp"
503+
alg["include-field"] = ["EAS_ID", "AREA"]
504+
alg["output-format"] = "stream"
505+
alg["include-valid"] = True
506+
507+
assert alg.Run()
508+
dst_ds = alg["output"].GetDataset()
509+
dst_lyr = dst_ds.GetLayer(0)
510+
dst_defn = dst_lyr.GetLayerDefn()
511+
assert dst_defn.GetFieldDefn(0).GetName() == "EAS_ID"
512+
assert dst_defn.GetFieldDefn(1).GetName() == "AREA"
513+
514+
f = dst_lyr.GetNextFeature()
515+
assert f["EAS_ID"] == 168
516+
assert f["AREA"] == 215229.266
517+
518+
519+
def test_gdalalg_vector_check_geometry_include_field_error(alg):
520+
521+
alg["input"] = "../ogr/data/poly.shp"
522+
alg["include-field"] = "does_not_exist"
523+
alg["output-format"] = "stream"
524+
525+
with pytest.raises(Exception, match="Specified field .* does not exist"):
526+
alg.Run()

doc/source/programs/gdal_vector_check_coverage.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ Standard options
5151

5252
Include features for valid geometries in the output, maintaining 1:1 correspondence between input and output features.
5353

54+
.. option:: --include-field
55+
56+
.. versionadded:: 3.12.1
57+
58+
Optional field(s) to copy from the input features to the output.
59+
5460
.. option:: --maximum-gap-width <MAXIMUM-GAP-WIDTH>
5561

5662
Defines the largest area that should be considered a gap.

0 commit comments

Comments
 (0)