Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "explode" step of "vector pipeline"
5 : * Author: Daniel Baston
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2026, ISciences LLC
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_vector_explode.h"
14 :
15 : #include "cpl_conv.h"
16 : #include "cpl_string.h"
17 : #include "gdal_priv.h"
18 : #include "ogr_p.h"
19 : #include "ogrsf_frmts.h"
20 :
21 : #include <algorithm>
22 : #include <cinttypes>
23 : #include <list>
24 : #include <memory>
25 : #include <numeric>
26 : #include <vector>
27 :
28 : //! @cond Doxygen_Suppress
29 :
30 : #ifndef _
31 : #define _(x) (x)
32 : #endif
33 :
34 : /************************************************************************/
35 : /* GDALVectorExplodeAlgorithm::GDALVectorExplodeAlgorithm() */
36 : /************************************************************************/
37 :
38 108 : GDALVectorExplodeAlgorithm::GDALVectorExplodeAlgorithm(bool standaloneStep)
39 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
40 108 : standaloneStep)
41 : {
42 108 : AddActiveLayerArg(&m_activeLayer);
43 :
44 : {
45 : auto &arg =
46 216 : AddArg("field", 0, _("Attribute fields(s) to explode"), &m_fields)
47 108 : .SetDuplicateValuesAllowed(false)
48 108 : .SetMetaVar("FIELD");
49 :
50 324 : SetAutoCompleteFunctionForFieldName(
51 108 : arg, nullptr, true, false, m_inputDataset, {"ALL"},
52 2 : [](const OGRFieldDefn *defn)
53 110 : { return OGR_GetFieldTypeIsList(defn->GetType()); });
54 : }
55 :
56 108 : AddArg("geometry", 0, _("Explode default geometry field"), &m_defaultGeom);
57 :
58 : {
59 : auto &arg = AddArg("geometry-field", 0,
60 216 : _("Geometry field(s) to explode"), &m_geomFields)
61 108 : .SetDuplicateValuesAllowed(false)
62 108 : .SetMetaVar("GEOMETRY-FIELD");
63 324 : SetAutoCompleteFunctionForFieldName(arg, nullptr, false, true,
64 216 : m_inputDataset, {"ALL"});
65 : }
66 :
67 : AddArg("index-field", 0, _("Name of the output index field"),
68 216 : &m_indexFieldName)
69 108 : .SetDefault(m_indexFieldName);
70 108 : }
71 :
72 : GDALVectorExplodeAlgorithmStandalone::~GDALVectorExplodeAlgorithmStandalone() =
73 : default;
74 :
75 : namespace
76 : {
77 :
78 : class GDALVectorExplodeLayer final : public GDALVectorPipelineOutputLayer
79 : {
80 : public:
81 24 : GDALVectorExplodeLayer(OGRLayer &srcLayer,
82 : const std::vector<std::string> &fieldsToExplode,
83 : const std::vector<std::string> &geomFieldsToExplode,
84 : const std::string &indexFieldName)
85 24 : : GDALVectorPipelineOutputLayer(srcLayer),
86 : m_fieldsToExplode(fieldsToExplode),
87 : m_geomFieldsToExplode(geomFieldsToExplode),
88 24 : m_indexFieldName(indexFieldName)
89 : {
90 24 : if (!PrepareFeatureDefn())
91 : {
92 1 : m_setupError = true;
93 : }
94 24 : }
95 :
96 24 : bool PrepareFeatureDefn()
97 : {
98 24 : m_poFeatureDefn.reset(
99 24 : OGRFeatureDefn::CreateFeatureDefn(m_srcLayer.GetName()));
100 :
101 : // Avoid creating geometry field with null SRS
102 : // We'll copy it in later from the source layer
103 24 : m_poFeatureDefn->DeleteGeomFieldDefn(0);
104 :
105 24 : const bool addIndexField = !m_indexFieldName.empty();
106 :
107 24 : if (addIndexField)
108 : {
109 : auto poIdxField = std::make_unique<OGRFieldDefn>(
110 6 : m_indexFieldName.c_str(), OFTInteger);
111 3 : m_poFeatureDefn->AddFieldDefn(std::move(poIdxField));
112 : }
113 :
114 24 : const OGRFeatureDefn *poSrcDefn = m_srcLayer.GetLayerDefn();
115 :
116 : // By default, all fields copied as-is.
117 24 : m_unnestedFieldSrcToDstMap.resize(poSrcDefn->GetFieldCount(), -1);
118 24 : m_passThroughFieldSrcToDstMap.resize(poSrcDefn->GetFieldCount());
119 24 : std::iota(m_passThroughFieldSrcToDstMap.begin(),
120 : m_passThroughFieldSrcToDstMap.end(), addIndexField ? 1 : 0);
121 :
122 24 : m_geomFieldExploded.resize(poSrcDefn->GetGeomFieldCount(), false);
123 :
124 47 : for (const auto &fieldName : m_fieldsToExplode)
125 : {
126 24 : const int iSrcField = poSrcDefn->GetFieldIndex(fieldName.c_str());
127 24 : if (iSrcField < 0)
128 : {
129 1 : CPLError(CE_Failure, CPLE_AppDefined,
130 : "Field '%s' not found in source layer.",
131 : fieldName.c_str());
132 1 : return false;
133 : }
134 :
135 : const OGRFieldDefn *poSrcFieldDefn =
136 23 : poSrcDefn->GetFieldDefn(iSrcField);
137 23 : const auto eSrcType = poSrcFieldDefn->GetType();
138 23 : if (OGR_GetFieldTypeIsList(eSrcType))
139 : {
140 20 : m_passThroughFieldSrcToDstMap[iSrcField] = -1;
141 20 : m_unnestedFieldSrcToDstMap[iSrcField] =
142 20 : iSrcField + addIndexField;
143 : }
144 : }
145 :
146 41 : for (const auto &fieldName : m_geomFieldsToExplode)
147 : {
148 : // Is it a geometry field?
149 18 : int iSrcGeomField = poSrcDefn->GetGeomFieldIndex(fieldName.c_str());
150 :
151 : // Interpret --geometry-field _OGR_GEOMETRY_ as the first geometry
152 : // field, regardless of what it is actually named
153 18 : if (iSrcGeomField < 0)
154 : {
155 22 : if (poSrcDefn->GetGeomFieldCount() > 0 &&
156 11 : EQUAL(fieldName.c_str(),
157 : OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME))
158 : {
159 9 : iSrcGeomField = 0;
160 : }
161 : }
162 :
163 : // Didn't find anything by name. Check by index.
164 20 : if (iSrcGeomField < 0 &&
165 2 : std::all_of(
166 2 : fieldName.begin(), fieldName.end(), [](char c)
167 2 : { return std::isdigit(static_cast<unsigned char>(c)); }))
168 : {
169 2 : const int iGeomField = std::atoi(fieldName.c_str());
170 :
171 2 : if (iGeomField < poSrcDefn->GetGeomFieldCount())
172 : {
173 2 : iSrcGeomField = iGeomField;
174 : }
175 : }
176 :
177 18 : if (iSrcGeomField < 0)
178 : {
179 0 : CPLError(
180 : CE_Failure, CPLE_AppDefined,
181 : "Could not find geometry field '%s' in source layer '%s'",
182 0 : fieldName.c_str(), m_srcLayer.GetName());
183 0 : return false;
184 : }
185 :
186 18 : m_geomFieldExploded[iSrcGeomField] = true;
187 : }
188 :
189 : // Create attribute fields
190 64 : for (int iSrcField = 0; iSrcField < poSrcDefn->GetFieldCount();
191 : iSrcField++)
192 : {
193 41 : const auto *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iSrcField);
194 41 : std::unique_ptr<OGRFieldDefn> poDstFieldDefn;
195 :
196 41 : if (m_passThroughFieldSrcToDstMap[iSrcField] != -1)
197 : {
198 : poDstFieldDefn =
199 21 : std::make_unique<OGRFieldDefn>(*poSrcFieldDefn);
200 : }
201 : else
202 : {
203 : const auto eScalarType =
204 20 : OGR_GetFieldTypeAsScalar(poSrcFieldDefn->GetType());
205 20 : poDstFieldDefn = std::make_unique<OGRFieldDefn>(
206 40 : poSrcFieldDefn->GetNameRef(), eScalarType);
207 : }
208 :
209 41 : m_poFeatureDefn->AddFieldDefn(std::move(poDstFieldDefn));
210 : }
211 :
212 : // Create geometry fields
213 48 : for (int iSrcGeomField = 0;
214 48 : iSrcGeomField < poSrcDefn->GetGeomFieldCount(); iSrcGeomField++)
215 : {
216 : const OGRGeomFieldDefn *poSrcGeomFieldDefn =
217 25 : poSrcDefn->GetGeomFieldDefn(iSrcGeomField);
218 25 : std::unique_ptr<OGRGeomFieldDefn> poDstGeomFieldDefn;
219 :
220 25 : if (m_geomFieldExploded[iSrcGeomField])
221 : {
222 : const auto eDstType =
223 18 : OGR_GT_GetSingle(poSrcGeomFieldDefn->GetType());
224 18 : poDstGeomFieldDefn = std::make_unique<OGRGeomFieldDefn>(
225 18 : poSrcGeomFieldDefn->GetNameRef(), eDstType);
226 36 : poDstGeomFieldDefn->SetSpatialRef(
227 18 : poSrcGeomFieldDefn->GetSpatialRef());
228 : }
229 : else
230 : {
231 : poDstGeomFieldDefn =
232 7 : std::make_unique<OGRGeomFieldDefn>(*poSrcGeomFieldDefn);
233 : }
234 :
235 25 : m_poFeatureDefn->AddGeomFieldDefn(std::move(poDstGeomFieldDefn));
236 : }
237 :
238 23 : return true;
239 : }
240 :
241 3 : const char *GetDescription() const override
242 : {
243 3 : return m_poFeatureDefn->GetName();
244 : }
245 :
246 379 : const OGRFeatureDefn *GetLayerDefn() const override
247 : {
248 379 : return m_poFeatureDefn.get();
249 : }
250 :
251 137 : void ResetReading() override
252 : {
253 137 : m_nextFID = 1;
254 137 : GDALVectorPipelineOutputLayer::ResetReading();
255 137 : }
256 :
257 57 : bool TestCapability(const char *pszCap) const override
258 : {
259 57 : if (EQUAL(pszCap, OLCFastGetExtent) ||
260 55 : EQUAL(pszCap, OLCFastGetExtent3D) ||
261 55 : EQUAL(pszCap, OLCStringsAsUTF8) ||
262 39 : EQUAL(pszCap, OLCCurveGeometries) ||
263 35 : EQUAL(pszCap, OLCMeasuredGeometries) ||
264 31 : EQUAL(pszCap, OLCZGeometries))
265 : {
266 29 : return m_srcLayer.TestCapability(pszCap);
267 : }
268 :
269 28 : return false;
270 : }
271 :
272 165 : bool TranslateFeature(
273 : std::unique_ptr<OGRFeature> poSrcFeature,
274 : std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
275 : {
276 165 : if (m_setupError)
277 : {
278 1 : CPLError(CE_Failure, CPLE_AppDefined,
279 : "Failed to prepare output layer.");
280 1 : return false;
281 : }
282 :
283 164 : int nDstFeatures = 1;
284 :
285 635 : for (int iDstFeature = 0; iDstFeature < nDstFeatures; iDstFeature++)
286 : {
287 : auto poDstFeature =
288 478 : std::make_unique<OGRFeature>(m_poFeatureDefn.get());
289 478 : if (!m_indexFieldName.empty())
290 : {
291 14 : poDstFeature->SetField(0, iDstFeature);
292 : }
293 :
294 956 : if (poDstFeature->SetFieldsFrom(
295 478 : poSrcFeature.get(), m_passThroughFieldSrcToDstMap.data(),
296 478 : true) != OGRERR_NONE)
297 : {
298 0 : CPLError(CE_Failure, CPLE_AppDefined,
299 : "Failed to set fields of output feature");
300 0 : return false;
301 : }
302 :
303 2589 : for (int iSrcArrayField = 0;
304 2589 : iSrcArrayField <
305 2589 : static_cast<int>(m_unnestedFieldSrcToDstMap.size());
306 : iSrcArrayField++)
307 : {
308 : const int iDstField =
309 2115 : m_unnestedFieldSrcToDstMap[iSrcArrayField];
310 2115 : if (iDstField < 0)
311 : {
312 1622 : continue;
313 : }
314 :
315 : const auto poSrcFieldDefn =
316 493 : poSrcFeature->GetFieldDefnRef(iSrcArrayField);
317 493 : const auto eSrcType = poSrcFieldDefn->GetType();
318 493 : int nArrayLength = -1;
319 493 : if (eSrcType == OFTIntegerList)
320 : {
321 430 : const int *pnArray = poSrcFeature->GetFieldAsIntegerList(
322 : iSrcArrayField, &nArrayLength);
323 430 : if (iDstFeature >= nArrayLength)
324 : {
325 1 : CPLError(CE_Failure, CPLE_AppDefined,
326 : "Field '%s' of source feature %" PRId64
327 : " does not have enough elements.",
328 : poSrcFieldDefn->GetNameRef(),
329 1 : static_cast<int64_t>(poSrcFeature->GetFID()));
330 4 : return false;
331 : }
332 429 : poDstFeature->SetField(iDstField, pnArray[iDstFeature]);
333 : }
334 63 : else if (eSrcType == OFTInteger64List)
335 : {
336 : const GIntBig *pnArray =
337 21 : poSrcFeature->GetFieldAsInteger64List(iSrcArrayField,
338 : &nArrayLength);
339 21 : if (iDstFeature >= nArrayLength)
340 : {
341 1 : CPLError(CE_Failure, CPLE_AppDefined,
342 : "Field '%s' of source feature %" PRId64
343 : " does not have enough elements.",
344 : poSrcFieldDefn->GetNameRef(),
345 1 : static_cast<int64_t>(poSrcFeature->GetFID()));
346 1 : return false;
347 : }
348 20 : poDstFeature->SetField(iDstField, pnArray[iDstFeature]);
349 : }
350 42 : else if (eSrcType == OFTRealList)
351 : {
352 : const double *padfArray =
353 21 : poSrcFeature->GetFieldAsDoubleList(iSrcArrayField,
354 : &nArrayLength);
355 21 : if (iDstFeature >= nArrayLength)
356 : {
357 1 : CPLError(CE_Failure, CPLE_AppDefined,
358 : "Field '%s' of source feature %" PRId64
359 : " does not have enough elements.",
360 : poSrcFieldDefn->GetNameRef(),
361 1 : static_cast<int64_t>(poSrcFeature->GetFID()));
362 1 : return false;
363 : }
364 20 : poDstFeature->SetField(iDstField, padfArray[iDstFeature]);
365 : }
366 21 : else if (eSrcType == OFTStringList)
367 : {
368 : CSLConstList papszArray =
369 21 : poSrcFeature->GetFieldAsStringList(iSrcArrayField);
370 21 : nArrayLength = CSLCount(papszArray);
371 21 : if (iDstFeature >= nArrayLength)
372 : {
373 1 : CPLError(CE_Failure, CPLE_AppDefined,
374 : "Field '%s' of source feature %" PRId64
375 : " does not have enough elements.",
376 : poSrcFieldDefn->GetNameRef(),
377 1 : static_cast<int64_t>(poSrcFeature->GetFID()));
378 1 : return false;
379 : }
380 20 : poDstFeature->SetField(iDstField, papszArray[iDstFeature]);
381 : }
382 489 : nDstFeatures = std::max(nDstFeatures, nArrayLength);
383 : }
384 :
385 945 : for (int iGeomField = 0;
386 945 : iGeomField < poSrcFeature->GetGeomFieldCount(); iGeomField++)
387 : {
388 474 : if (m_geomFieldExploded[iGeomField])
389 : {
390 0 : std::unique_ptr<OGRGeometry> poDstGeom;
391 :
392 : OGRGeometry *poSrcGeom(
393 55 : poSrcFeature->GetGeomFieldRef(iGeomField));
394 :
395 : const bool bSrcIsCollection =
396 105 : poSrcGeom != nullptr &&
397 50 : OGR_GT_IsSubClassOf(
398 50 : wkbFlatten(poSrcGeom->getGeometryType()),
399 55 : wkbGeometryCollection);
400 :
401 55 : if (bSrcIsCollection)
402 : {
403 : OGRGeometryCollection *poColl =
404 43 : poSrcGeom->toGeometryCollection();
405 :
406 43 : auto nGeoms = poColl->getNumGeometries();
407 43 : nDstFeatures = std::max(nDstFeatures, nGeoms);
408 :
409 43 : if (nGeoms == 0)
410 : {
411 1 : CPLError(
412 : CE_Failure, CPLE_AppDefined,
413 : "Geometry field '%s' of source feature %" PRId64
414 : " has %d elements (expected %d)",
415 1 : poSrcFeature->GetDefnRef()
416 1 : ->GetGeomFieldDefn(iGeomField)
417 : ->GetNameRef(),
418 1 : static_cast<int64_t>(poSrcFeature->GetFID()),
419 : nGeoms + iDstFeature, nDstFeatures);
420 1 : return false;
421 : }
422 :
423 42 : poDstGeom = poColl->stealGeometry(0);
424 : }
425 : else
426 : {
427 : const OGRGeometry *poSrcSingleGeom =
428 12 : poSrcFeature->GetGeomFieldRef(iGeomField);
429 12 : if (iDstFeature > 0 && poSrcSingleGeom != nullptr)
430 : {
431 2 : CPLError(
432 : CE_Failure, CPLE_AppDefined,
433 : "Geometry field '%s' of source feature %" PRId64
434 : " is not a collection.",
435 2 : poSrcFeature->GetDefnRef()
436 2 : ->GetGeomFieldDefn(iGeomField)
437 : ->GetNameRef(),
438 2 : static_cast<int64_t>(poSrcFeature->GetFID()));
439 2 : return false;
440 : }
441 :
442 10 : if (poSrcSingleGeom)
443 5 : poDstGeom.reset(poSrcSingleGeom->clone());
444 : }
445 :
446 104 : poDstFeature->SetGeomField(iGeomField,
447 52 : std::move(poDstGeom));
448 : }
449 : else
450 : {
451 419 : poDstFeature->SetGeomField(
452 419 : iGeomField, poSrcFeature->GetGeomFieldRef(iGeomField));
453 : }
454 : }
455 :
456 471 : poDstFeature->SetFID(m_nextFID++);
457 471 : if (PassesFilters(poDstFeature.get()))
458 356 : apoOutFeatures.push_back(std::move(poDstFeature));
459 : }
460 :
461 157 : return true;
462 : }
463 :
464 : protected:
465 4 : OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
466 : bool bForce) override
467 : {
468 4 : return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
469 : }
470 :
471 0 : OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
472 : bool bForce) override
473 : {
474 0 : return m_srcLayer.GetExtent3D(iGeomField, psExtent3D, bForce);
475 : }
476 :
477 : private:
478 : std::vector<int> m_passThroughFieldSrcToDstMap{};
479 : std::vector<int> m_unnestedFieldSrcToDstMap{};
480 : std::vector<bool> m_geomFieldExploded{};
481 : std::vector<std::string> m_fieldsToExplode{};
482 : std::vector<std::string> m_geomFieldsToExplode{};
483 : std::string m_indexFieldName{};
484 : bool m_setupError{false};
485 : OGRFeatureDefnRefCountedPtr m_poFeatureDefn{nullptr};
486 : GIntBig m_nextFID{1};
487 :
488 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorExplodeLayer)
489 : };
490 :
491 : } // namespace
492 :
493 : /************************************************************************/
494 : /* GDALVectorExplodeAlgorithm::RunStep() */
495 : /************************************************************************/
496 :
497 24 : bool GDALVectorExplodeAlgorithm::RunStep(GDALPipelineStepRunContext &)
498 : {
499 24 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
500 24 : CPLAssert(poSrcDS);
501 :
502 48 : auto poOutDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
503 :
504 24 : if (m_defaultGeom)
505 : {
506 4 : m_geomFields.emplace_back(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
507 : }
508 :
509 24 : if (m_fields.empty() && m_geomFields.empty())
510 : {
511 0 : ReportError(CE_Failure, CPLE_IllegalArg,
512 : "At least one field or geometry field must be specified");
513 0 : return false;
514 : }
515 :
516 49 : for (OGRLayer *poSrcLayer : poSrcDS->GetLayers())
517 : {
518 25 : if (!poSrcLayer)
519 1 : continue;
520 :
521 27 : if (!m_activeLayer.empty() &&
522 2 : poSrcLayer->GetDescription() != m_activeLayer)
523 : {
524 2 : poOutDS->AddLayer(
525 : *poSrcLayer,
526 2 : std::make_unique<GDALVectorPipelinePassthroughLayer>(
527 : *poSrcLayer));
528 1 : continue;
529 : }
530 :
531 24 : const auto *poLayerDefn = poSrcLayer->GetLayerDefn();
532 :
533 48 : auto fieldsForLayer = m_fields;
534 48 : auto geomFieldsForLayer = m_geomFields;
535 :
536 24 : if (geomFieldsForLayer.size() == 1 && geomFieldsForLayer[0] == "ALL")
537 : {
538 3 : geomFieldsForLayer.clear();
539 3 : for (int iGeomField = 0;
540 6 : iGeomField < poLayerDefn->GetGeomFieldCount(); iGeomField++)
541 : {
542 : geomFieldsForLayer.emplace_back(
543 3 : poLayerDefn->GetGeomFieldDefn(iGeomField)->GetNameRef());
544 : }
545 : }
546 :
547 24 : if (fieldsForLayer.size() == 1 && fieldsForLayer[0] == "ALL")
548 : {
549 3 : fieldsForLayer.clear();
550 6 : for (int iField = 0; iField < poLayerDefn->GetFieldCount();
551 : iField++)
552 : {
553 : fieldsForLayer.emplace_back(
554 3 : poLayerDefn->GetFieldDefn(iField)->GetNameRef());
555 : }
556 : }
557 :
558 : auto poOutLayer = std::make_unique<GDALVectorExplodeLayer>(
559 24 : *poSrcLayer, fieldsForLayer, geomFieldsForLayer, m_indexFieldName);
560 24 : poOutDS->AddLayer(*poSrcLayer, std::move(poOutLayer));
561 : }
562 :
563 24 : m_outputDataset.Set(std::move(poOutDS));
564 24 : return true;
565 : }
566 :
567 : //! @endcond
|