Coverage Report

Created: 2026-09-14 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_vector_pipeline.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "vector pipeline" subcommand
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_pipeline.h"
14
#include "gdalalg_external.h"
15
#include "gdalalg_materialize.h"
16
#include "gdalalg_vector_read.h"
17
#include "gdalalg_vector_buffer.h"
18
#include "gdalalg_vector_check_coverage.h"
19
#include "gdalalg_vector_check_geometry.h"
20
#include "gdalalg_vector_clean_coverage.h"
21
#include "gdalalg_vector_clip.h"
22
#include "gdalalg_vector_combine.h"
23
#include "gdalalg_vector_compare.h"
24
#include "gdalalg_vector_concat.h"
25
#include "gdalalg_vector_concave_hull.h"
26
#include "gdalalg_vector_convex_hull.h"
27
#include "gdalalg_vector_create.h"
28
#include "gdalalg_vector_dissolve.h"
29
#include "gdalalg_vector_edit.h"
30
#include "gdalalg_vector_explode.h"
31
#include "gdalalg_vector_explode_collections.h"
32
#include "gdalalg_vector_export_schema.h"
33
#include "gdalalg_vector_filter.h"
34
#include "gdalalg_vector_info.h"
35
#include "gdalalg_vector_layer_algebra.h"
36
#include "gdalalg_vector_limit.h"
37
#include "gdalalg_vector_make_point.h"
38
#include "gdalalg_vector_make_valid.h"
39
#include "gdalalg_vector_partition.h"
40
#include "gdalalg_vector_rename_layer.h"
41
#include "gdalalg_vector_reproject.h"
42
#include "gdalalg_vector_segmentize.h"
43
#include "gdalalg_vector_select.h"
44
#include "gdalalg_vector_set_field_type.h"
45
#include "gdalalg_vector_set_geom_type.h"
46
#include "gdalalg_vector_simplify.h"
47
#include "gdalalg_vector_simplify_coverage.h"
48
#include "gdalalg_vector_sort.h"
49
#include "gdalalg_vector_sql.h"
50
#include "gdalalg_vector_swap_xy.h"
51
#include "gdalalg_vector_update.h"
52
#include "gdalalg_vector_write.h"
53
#include "gdalalg_tee.h"
54
55
#include "../frmts/mem/memdataset.h"
56
57
#include "cpl_conv.h"
58
#include "cpl_string.h"
59
60
#include <algorithm>
61
#include <cassert>
62
63
//! @cond Doxygen_Suppress
64
65
#ifndef _
66
#define _(x) (x)
67
#endif
68
69
0
GDALVectorAlgorithmStepRegistry::~GDALVectorAlgorithmStepRegistry() = default;
70
71
/************************************************************************/
72
/*  GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm()  */
73
/************************************************************************/
74
75
GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
76
    const std::string &name, const std::string &description,
77
    const std::string &helpURL, bool standaloneStep)
78
0
    : GDALVectorPipelineStepAlgorithm(
79
0
          name, description, helpURL,
80
0
          ConstructorOptions().SetStandaloneStep(standaloneStep))
81
0
{
82
0
}
83
84
/************************************************************************/
85
/*  GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm()  */
86
/************************************************************************/
87
88
GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
89
    const std::string &name, const std::string &description,
90
    const std::string &helpURL, const ConstructorOptions &options)
91
0
    : GDALPipelineStepAlgorithm(name, description, helpURL, options)
92
0
{
93
0
    if (m_standaloneStep)
94
0
    {
95
0
        m_supportsStreamedOutput = true;
96
97
0
        if (m_constructorOptions.addDefaultArguments)
98
0
        {
99
0
            AddVectorInputArgs(false);
100
0
            AddProgressArg();
101
0
            AddVectorOutputArgs(false, false);
102
0
        }
103
0
    }
104
0
    else
105
0
    {
106
0
        if (m_constructorOptions.addDefaultArguments)
107
0
        {
108
0
            AddVectorHiddenInputDatasetArg();
109
0
        }
110
0
    }
111
0
}
112
113
0
GDALVectorPipelineStepAlgorithm::~GDALVectorPipelineStepAlgorithm() = default;
114
115
/************************************************************************/
116
/*      GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()      */
117
/************************************************************************/
118
119
GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
120
0
    : GDALAbstractPipelineAlgorithm(
121
0
          NAME, DESCRIPTION, HELP_URL,
122
0
          ConstructorOptions().SetInputDatasetMaxCount(INT_MAX))
123
0
{
124
0
    m_supportsStreamedOutput = true;
125
126
0
    AddVectorInputArgs(/* hiddenForCLI = */ true);
127
0
    AddProgressArg();
128
0
    AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
129
0
        .SetHiddenForCLI()
130
0
        .SetPositional();
131
0
    AddVectorOutputArgs(/* hiddenForCLI = */ true,
132
0
                        /* shortNameOutputLayerAllowed=*/false);
133
134
0
    AddOutputStringArg(&m_output).SetHiddenForCLI();
135
0
    AddStdoutArg(&m_stdout);
136
137
0
    RegisterAlgorithms(m_stepRegistry, false);
138
0
}
139
140
/************************************************************************/
141
/*          GDALVectorPipelineAlgorithm::RegisterAlgorithms()           */
142
/************************************************************************/
143
144
/* static */
145
void GDALVectorPipelineAlgorithm::RegisterAlgorithms(
146
    GDALVectorAlgorithmStepRegistry &registry, bool forMixedPipeline)
147
0
{
148
0
    GDALAlgorithmRegistry::AlgInfo algInfo;
149
150
0
    const auto addSuffixIfNeeded =
151
0
        [forMixedPipeline](const char *name) -> std::string
152
0
    {
153
0
        return forMixedPipeline ? std::string(name).append(VECTOR_SUFFIX)
154
0
                                : std::string(name);
155
0
    };
156
157
0
    registry.Register<GDALVectorReadAlgorithm>(
158
0
        addSuffixIfNeeded(GDALVectorReadAlgorithm::NAME));
159
160
0
    registry.Register<GDALVectorWriteAlgorithm>(
161
0
        addSuffixIfNeeded(GDALVectorWriteAlgorithm::NAME));
162
163
0
    registry.Register<GDALVectorInfoAlgorithm>(
164
0
        addSuffixIfNeeded(GDALVectorInfoAlgorithm::NAME));
165
166
0
    registry.Register<GDALVectorBufferAlgorithm>();
167
0
    registry.Register<GDALVectorCheckCoverageAlgorithm>();
168
0
    registry.Register<GDALVectorCheckGeometryAlgorithm>();
169
0
    registry.Register<GDALVectorCombineAlgorithm>();
170
171
0
    registry.Register<GDALVectorCompareAlgorithm>(
172
0
        addSuffixIfNeeded(GDALVectorCompareAlgorithm::NAME));
173
174
0
    registry.Register<GDALVectorConcatAlgorithm>();
175
0
    registry.Register<GDALVectorConcaveHullAlgorithm>();
176
0
    registry.Register<GDALVectorConvexHullAlgorithm>();
177
0
    registry.Register<GDALVectorCleanCoverageAlgorithm>();
178
179
0
    registry.Register<GDALVectorClipAlgorithm>(
180
0
        addSuffixIfNeeded(GDALVectorClipAlgorithm::NAME));
181
0
    registry.Register<GDALVectorDissolveAlgorithm>();
182
183
0
    registry.Register<GDALVectorCreateAlgorithm>(
184
0
        addSuffixIfNeeded(GDALVectorCreateAlgorithm::NAME));
185
186
0
    registry.Register<GDALVectorEditAlgorithm>(
187
0
        addSuffixIfNeeded(GDALVectorEditAlgorithm::NAME));
188
189
0
    registry.Register<GDALVectorExplodeAlgorithm>();
190
0
    registry.Register<GDALVectorExplodeCollectionsAlgorithm>();
191
0
    registry.Register<GDALVectorExportSchemaAlgorithm>();
192
193
0
    registry.Register<GDALMaterializeVectorAlgorithm>(
194
0
        addSuffixIfNeeded(GDALMaterializeVectorAlgorithm::NAME));
195
196
0
    registry.Register<GDALVectorReprojectAlgorithm>(
197
0
        addSuffixIfNeeded(GDALVectorReprojectAlgorithm::NAME));
198
199
0
    registry.Register<GDALVectorFilterAlgorithm>();
200
0
    registry.Register<GDALVectorLayerAlgebraAlgorithm>();
201
0
    registry.Register<GDALVectorLimitAlgorithm>();
202
0
    registry.Register<GDALVectorMakePointAlgorithm>();
203
0
    registry.Register<GDALVectorMakeValidAlgorithm>();
204
0
    registry.Register<GDALVectorPartitionAlgorithm>();
205
0
    registry.Register<GDALVectorRenameLayerAlgorithm>();
206
0
    registry.Register<GDALVectorSegmentizeAlgorithm>();
207
208
0
    registry.Register<GDALVectorSelectAlgorithm>(
209
0
        addSuffixIfNeeded(GDALVectorSelectAlgorithm::NAME));
210
211
0
    registry.Register<GDALVectorSetFieldTypeAlgorithm>();
212
0
    registry.Register<GDALVectorSetGeomTypeAlgorithm>();
213
0
    registry.Register<GDALVectorSimplifyAlgorithm>();
214
0
    registry.Register<GDALVectorSimplifyCoverageAlgorithm>();
215
0
    registry.Register<GDALVectorSortAlgorithm>();
216
0
    registry.Register<GDALVectorSQLAlgorithm>();
217
0
    registry.Register<GDALVectorUpdateAlgorithm>(
218
0
        addSuffixIfNeeded(GDALVectorUpdateAlgorithm::NAME));
219
0
    registry.Register<GDALVectorSwapXYAlgorithm>();
220
221
0
    registry.Register<GDALTeeVectorAlgorithm>(
222
0
        addSuffixIfNeeded(GDALTeeVectorAlgorithm::NAME));
223
224
0
    if (!forMixedPipeline)
225
0
    {
226
0
        registry.Register<GDALExternalVectorAlgorithm>();
227
0
    }
228
0
}
229
230
/************************************************************************/
231
/*            GDALVectorPipelineAlgorithm::GetUsageForCLI()             */
232
/************************************************************************/
233
234
std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
235
    bool shortUsage, const UsageOptions &usageOptions) const
236
0
{
237
0
    UsageOptions stepUsageOptions;
238
0
    stepUsageOptions.isPipelineStep = true;
239
240
0
    if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
241
0
    {
242
0
        auto alg = GetStepAlg(m_helpDocCategory);
243
0
        if (alg)
244
0
        {
245
0
            alg->SetCallPath({m_helpDocCategory});
246
0
            alg->GetArg("help-doc")->Set(true);
247
0
            return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
248
0
        }
249
0
        else
250
0
        {
251
0
            fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
252
0
                    m_helpDocCategory.c_str());
253
0
            return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
254
0
                              m_helpDocCategory.c_str());
255
0
        }
256
0
    }
257
258
0
    UsageOptions usageOptionsMain(usageOptions);
259
0
    usageOptionsMain.isPipelineMain = true;
260
0
    std::string ret =
261
0
        GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
262
0
    if (shortUsage)
263
0
        return ret;
264
265
0
    ret += "\n<PIPELINE> is of the form: read|concat [READ-OPTIONS] "
266
0
           "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write|info [WRITE-OPTIONS]\n";
267
268
0
    if (m_helpDocCategory == "main")
269
0
    {
270
0
        return ret;
271
0
    }
272
273
0
    ret += '\n';
274
0
    ret += "Example: 'gdal vector pipeline --progress ! read in.gpkg ! \\\n";
275
0
    ret += "               reproject --output-crs=EPSG:32632 ! ";
276
0
    ret += "write out.gpkg --overwrite'\n";
277
0
    ret += '\n';
278
0
    ret += "Potential steps are:\n";
279
280
0
    for (const std::string &name : m_stepRegistry.GetNames())
281
0
    {
282
0
        auto alg = GetStepAlg(name);
283
0
        assert(alg);
284
0
        auto [options, maxOptLen] = alg->GetArgNamesForCLI();
285
0
        stepUsageOptions.maxOptLen =
286
0
            std::max(stepUsageOptions.maxOptLen, maxOptLen);
287
0
    }
288
289
0
    {
290
0
        const auto name = GDALVectorReadAlgorithm::NAME;
291
0
        ret += '\n';
292
0
        auto alg = GetStepAlg(name);
293
0
        alg->SetCallPath({name});
294
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
295
0
    }
296
0
    for (const std::string &name : m_stepRegistry.GetNames())
297
0
    {
298
0
        auto alg = GetStepAlg(name);
299
0
        assert(alg);
300
0
        if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
301
0
            !alg->IsHidden() && name != GDALVectorReadAlgorithm::NAME)
302
0
        {
303
0
            ret += '\n';
304
0
            alg->SetCallPath({name});
305
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
306
0
        }
307
0
    }
308
0
    for (const std::string &name : m_stepRegistry.GetNames())
309
0
    {
310
0
        auto alg = GetStepAlg(name);
311
0
        assert(alg);
312
0
        if (alg->CanBeMiddleStep() && !alg->IsHidden())
313
0
        {
314
0
            ret += '\n';
315
0
            alg->SetCallPath({name});
316
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
317
0
        }
318
0
    }
319
0
    for (const std::string &name : m_stepRegistry.GetNames())
320
0
    {
321
0
        auto alg = GetStepAlg(name);
322
0
        assert(alg);
323
0
        if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
324
0
            !alg->IsHidden() && name != GDALVectorWriteAlgorithm::NAME)
325
0
        {
326
0
            ret += '\n';
327
0
            alg->SetCallPath({name});
328
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
329
0
        }
330
0
    }
331
0
    {
332
0
        const auto name = GDALVectorWriteAlgorithm::NAME;
333
0
        ret += '\n';
334
0
        auto alg = GetStepAlg(name);
335
0
        alg->SetCallPath({name});
336
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
337
0
    }
338
339
0
    ret += GetUsageForCLIEnd();
340
341
0
    return ret;
342
0
}
343
344
/************************************************************************/
345
/*                      GDALVectorDecoratedDataset                      */
346
/************************************************************************/
347
348
namespace
349
{
350
class DummyDataset final : public GDALDataset
351
{
352
  public:
353
0
    DummyDataset() = default;
354
};
355
}  // namespace
356
357
/************************************************************************/
358
/*                     GDALVectorDecoratedDataset()                     */
359
/************************************************************************/
360
361
GDALVectorDecoratedDataset::GDALVectorDecoratedDataset(GDALDataset *poSrcDS)
362
0
    : m_dummySrcDS(poSrcDS ? nullptr : std::make_unique<DummyDataset>()),
363
0
      m_srcDS(poSrcDS ? *poSrcDS : *(m_dummySrcDS.get()))
364
0
{
365
0
    m_srcDS.Reference();
366
0
    SetDescription(m_srcDS.GetDescription());
367
0
}
368
369
/************************************************************************/
370
/*                    ~GDALVectorDecoratedDataset()                     */
371
/************************************************************************/
372
373
GDALVectorDecoratedDataset::~GDALVectorDecoratedDataset()
374
0
{
375
0
    m_srcDS.ReleaseRef();
376
0
}
377
378
/************************************************************************/
379
/*                    GDALVectorPipelineOutputLayer                     */
380
/************************************************************************/
381
382
/************************************************************************/
383
/*                   GDALVectorPipelineOutputLayer()                    */
384
/************************************************************************/
385
386
GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
387
0
    : m_srcLayer(srcLayer)
388
0
{
389
0
}
390
391
/************************************************************************/
392
/*                   ~GDALVectorPipelineOutputLayer()                   */
393
/************************************************************************/
394
395
0
GDALVectorPipelineOutputLayer::~GDALVectorPipelineOutputLayer() = default;
396
397
/************************************************************************/
398
/*            GDALVectorPipelineOutputLayer::ResetReading()             */
399
/************************************************************************/
400
401
void GDALVectorPipelineOutputLayer::ResetReading()
402
0
{
403
0
    m_srcLayer.ResetReading();
404
0
    m_pendingFeatures.clear();
405
0
    m_idxInPendingFeatures = 0;
406
0
}
407
408
/************************************************************************/
409
/*           GDALVectorPipelineOutputLayer::GetNextFeature()            */
410
/************************************************************************/
411
412
OGRFeature *GDALVectorPipelineOutputLayer::GetNextFeature()
413
0
{
414
0
    if (m_idxInPendingFeatures < m_pendingFeatures.size())
415
0
    {
416
0
        OGRFeature *poFeature =
417
0
            m_pendingFeatures[m_idxInPendingFeatures].release();
418
0
        ++m_idxInPendingFeatures;
419
0
        return poFeature;
420
0
    }
421
0
    m_pendingFeatures.clear();
422
0
    m_idxInPendingFeatures = 0;
423
0
    while (true)
424
0
    {
425
0
        auto poSrcFeature =
426
0
            std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
427
0
        if (!poSrcFeature)
428
0
            return nullptr;
429
        // It is the job of TranslateFeature() to apply layer filters
430
0
        if (!TranslateFeature(std::move(poSrcFeature), m_pendingFeatures))
431
0
        {
432
0
            return nullptr;
433
0
        }
434
0
        if (!m_pendingFeatures.empty())
435
0
            break;
436
0
    }
437
0
    OGRFeature *poFeature = m_pendingFeatures[0].release();
438
0
    m_idxInPendingFeatures = 1;
439
0
    return poFeature;
440
0
}
441
442
/************************************************************************/
443
/*            GDALVectorPipelineOutputLayer::PassesFilters()            */
444
/************************************************************************/
445
446
bool GDALVectorPipelineOutputLayer::PassesFilters(const OGRFeature *poFeature)
447
0
{
448
0
    return (!m_poFilterGeom || FilterGeometry(poFeature->GetGeometryRef())) &&
449
0
           (!m_poAttrQuery || m_poAttrQuery->Evaluate(poFeature));
450
0
}
451
452
/************************************************************************/
453
/*                       GDALVectorOutputDataset                        */
454
/************************************************************************/
455
456
/************************************************************************/
457
/*                      GDALVectorOutputDataset()                       */
458
/************************************************************************/
459
460
GDALVectorOutputDataset::GDALVectorOutputDataset(GDALDataset *poSrcDS)
461
0
    : GDALVectorDecoratedDataset(poSrcDS)
462
0
{
463
0
}
464
465
/************************************************************************/
466
/*                           TestCapability()                           */
467
/************************************************************************/
468
469
bool GDALVectorOutputDataset::TestCapability(const char *) const
470
0
{
471
0
    return 0;
472
0
}
473
474
/************************************************************************/
475
/*                   GDALVectorPipelineOutputDataset                    */
476
/************************************************************************/
477
478
/************************************************************************/
479
/*                  GDALVectorPipelineOutputDataset()                   */
480
/************************************************************************/
481
482
GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
483
    GDALDataset &srcDS)
484
0
    : GDALVectorDecoratedDataset(&srcDS)
485
0
{
486
0
}
487
488
/************************************************************************/
489
/*             GDALVectorPipelineOutputDataset::AddLayer()              */
490
/************************************************************************/
491
492
void GDALVectorPipelineOutputDataset::AddLayer(
493
    OGRLayer &oSrcLayer,
494
    std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
495
0
{
496
0
    m_layersToDestroy.push_back(std::move(poNewLayer));
497
0
    OGRLayerWithTranslateFeature *poNewLayerRaw =
498
0
        m_layersToDestroy.back().get();
499
0
    m_layers.push_back(poNewLayerRaw);
500
0
    m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
501
0
}
502
503
/************************************************************************/
504
/*           GDALVectorPipelineOutputDataset::GetLayerCount()           */
505
/************************************************************************/
506
507
int GDALVectorPipelineOutputDataset::GetLayerCount() const
508
0
{
509
0
    return static_cast<int>(m_layers.size());
510
0
}
511
512
/************************************************************************/
513
/*             GDALVectorPipelineOutputDataset::GetLayer()              */
514
/************************************************************************/
515
516
OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx) const
517
0
{
518
0
    return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
519
0
}
520
521
/************************************************************************/
522
/*          GDALVectorPipelineOutputDataset::TestCapability()           */
523
/************************************************************************/
524
525
bool GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap) const
526
0
{
527
0
    if (EQUAL(pszCap, ODsCRandomLayerRead) ||
528
0
        EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
529
0
    {
530
0
        return m_srcDS.TestCapability(pszCap);
531
0
    }
532
0
    return false;
533
0
}
534
535
/************************************************************************/
536
/*           GDALVectorPipelineOutputDataset::ResetReading()            */
537
/************************************************************************/
538
539
void GDALVectorPipelineOutputDataset::ResetReading()
540
0
{
541
0
    m_srcDS.ResetReading();
542
0
    m_pendingFeatures.clear();
543
0
    m_idxInPendingFeatures = 0;
544
0
}
545
546
/************************************************************************/
547
/*          GDALVectorPipelineOutputDataset::GetNextFeature()           */
548
/************************************************************************/
549
550
OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
551
    OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
552
    GDALProgressFunc pfnProgress, void *pProgressData)
553
0
{
554
0
    if (m_idxInPendingFeatures < m_pendingFeatures.size())
555
0
    {
556
0
        OGRFeature *poFeature =
557
0
            m_pendingFeatures[m_idxInPendingFeatures].release();
558
0
        if (ppoBelongingLayer)
559
0
            *ppoBelongingLayer = m_belongingLayer;
560
0
        ++m_idxInPendingFeatures;
561
0
        return poFeature;
562
0
    }
563
564
0
    m_pendingFeatures.clear();
565
0
    m_idxInPendingFeatures = 0;
566
567
0
    while (true)
568
0
    {
569
0
        OGRLayer *poSrcBelongingLayer = nullptr;
570
0
        auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
571
0
            &poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
572
0
        if (!poSrcFeature)
573
0
            return nullptr;
574
0
        auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
575
0
        if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
576
0
        {
577
0
            m_belongingLayer = iterToDstLayer->second;
578
579
0
            if (!m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
580
0
                                                    m_pendingFeatures))
581
0
            {
582
0
                return nullptr;
583
0
            }
584
585
0
            if (!m_pendingFeatures.empty())
586
0
                break;
587
0
        }
588
0
    }
589
0
    OGRFeature *poFeature = m_pendingFeatures[0].release();
590
0
    if (ppoBelongingLayer)
591
0
        *ppoBelongingLayer = m_belongingLayer;
592
0
    m_idxInPendingFeatures = 1;
593
0
    return poFeature;
594
0
}
595
596
/************************************************************************/
597
/*          GDALVectorPipelinePassthroughLayer::GetLayerDefn()          */
598
/************************************************************************/
599
600
const OGRFeatureDefn *GDALVectorPipelinePassthroughLayer::GetLayerDefn() const
601
0
{
602
0
    return m_srcLayer.GetLayerDefn();
603
0
}
604
605
/************************************************************************/
606
/*          GDALVectorPipelinePassthroughLayer::GetLayerDefn()          */
607
/************************************************************************/
608
609
bool GDALVectorPipelinePassthroughLayer::TranslateFeature(
610
    std::unique_ptr<OGRFeature> poSrcFeature,
611
    std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures)
612
0
{
613
0
    if (PassesFilters(poSrcFeature.get()))
614
0
    {
615
0
        apoOutFeatures.push_back(std::move(poSrcFeature));
616
0
    }
617
618
0
    return true;
619
0
}
620
621
/************************************************************************/
622
/*               GDALVectorNonStreamingAlgorithmDataset()               */
623
/************************************************************************/
624
625
GDALVectorNonStreamingAlgorithmDataset::GDALVectorNonStreamingAlgorithmDataset(
626
    GDALDataset &oSrcDS)
627
0
    : GDALVectorDecoratedDataset(&oSrcDS)
628
0
{
629
0
}
630
631
/************************************************************************/
632
/*              ~GDALVectorNonStreamingAlgorithmDataset()               */
633
/************************************************************************/
634
635
GDALVectorNonStreamingAlgorithmDataset::
636
0
    ~GDALVectorNonStreamingAlgorithmDataset() = default;
637
638
/************************************************************************/
639
/*     GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer()      */
640
/************************************************************************/
641
642
bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
643
    std::unique_ptr<GDALVectorNonStreamingAlgorithmLayer> layer,
644
    GDALProgressFunc progressFn, void *progressData)
645
0
{
646
0
    if (!layer->Process(progressFn, progressData))
647
0
    {
648
0
        return false;
649
0
    }
650
651
0
    m_owned_layers.emplace_back(std::move(layer));
652
0
    m_layers.push_back(m_owned_layers.back().get());
653
654
0
    return true;
655
0
}
656
657
/************************************************************************/
658
/*    GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer()     */
659
/************************************************************************/
660
661
void GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer(
662
    OGRLayer &oLayer)
663
0
{
664
0
    m_owned_layers.push_back(
665
0
        std::make_unique<GDALVectorPipelinePassthroughLayer>(oLayer));
666
0
    m_layers.push_back(m_owned_layers.back().get());
667
0
}
668
669
/************************************************************************/
670
/*       GDALVectorNonStreamingAlgorithmDataset::GetLayerCount()        */
671
/************************************************************************/
672
673
int GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() const
674
0
{
675
0
    return static_cast<int>(m_layers.size());
676
0
}
677
678
/************************************************************************/
679
/*          GDALVectorNonStreamingAlgorithmDataset::GetLayer()          */
680
/************************************************************************/
681
682
OGRLayer *GDALVectorNonStreamingAlgorithmDataset::GetLayer(int idx) const
683
0
{
684
0
    if (idx < 0 || idx >= static_cast<int>(m_layers.size()))
685
0
    {
686
0
        return nullptr;
687
0
    }
688
0
    return m_layers[idx];
689
0
}
690
691
/************************************************************************/
692
/*       GDALVectorNonStreamingAlgorithmDataset::TestCapability()       */
693
/************************************************************************/
694
695
bool GDALVectorNonStreamingAlgorithmDataset::TestCapability(
696
    const char *pszCap) const
697
0
{
698
0
    if (EQUAL(pszCap, ODsCCurveGeometries) ||
699
0
        EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
700
0
    {
701
0
        return true;
702
0
    }
703
704
0
    return false;
705
0
}
706
707
/************************************************************************/
708
/*               GDALVectorAlgorithmLayerProgressHelper()               */
709
/************************************************************************/
710
711
GDALVectorAlgorithmLayerProgressHelper::GDALVectorAlgorithmLayerProgressHelper(
712
    GDALProgressFunc pfnProgress, void *pProgressData)
713
0
    : m_pfnProgress(pfnProgress), m_pProgressData(pProgressData)
714
0
{
715
0
}
716
717
/************************************************************************/
718
/*               GDALVectorAlgorithmLayerProgressHelper()               */
719
/************************************************************************/
720
721
GDALVectorAlgorithmLayerProgressHelper::GDALVectorAlgorithmLayerProgressHelper(
722
    const GDALPipelineStepRunContext &ctxt)
723
0
    : GDALVectorAlgorithmLayerProgressHelper(ctxt.m_pfnProgress,
724
0
                                             ctxt.m_pProgressData)
725
0
{
726
0
}
727
728
/************************************************************************/
729
/*     GDALVectorAlgorithmLayerProgressHelper::AddProcessedLayer()      */
730
/************************************************************************/
731
732
void GDALVectorAlgorithmLayerProgressHelper::AddProcessedLayer(
733
    OGRLayer &srcLayer)
734
0
{
735
0
    m_apoSrcLayers.emplace_back(&srcLayer, true);
736
0
    if (m_pfnProgress && m_nTotalFeatures >= 0 &&
737
0
        srcLayer.TestCapability(OLCFastFeatureCount))
738
0
    {
739
0
        const auto nLayerFeatures = srcLayer.GetFeatureCount(false);
740
0
        if (nLayerFeatures < 0)
741
0
            m_nTotalFeatures = -1;
742
0
        else
743
0
            m_nTotalFeatures += nLayerFeatures;
744
0
        m_anFeatures.push_back(nLayerFeatures);
745
0
    }
746
0
    else
747
0
    {
748
0
        m_anFeatures.push_back(-1);
749
0
        m_nTotalFeatures = -1;
750
0
    }
751
0
}
752
753
/************************************************************************/
754
/*    GDALVectorAlgorithmLayerProgressHelper::AddPassThroughLayer()     */
755
/************************************************************************/
756
757
void GDALVectorAlgorithmLayerProgressHelper::AddPassThroughLayer(
758
    OGRLayer &srcLayer)
759
0
{
760
0
    m_apoSrcLayers.emplace_back(&srcLayer, false);
761
0
}
762
763
/************************************************************************/
764
/*                GDALVectorNonStreamingAlgorithmLayer()                */
765
/************************************************************************/
766
767
GDALVectorNonStreamingAlgorithmLayer::GDALVectorNonStreamingAlgorithmLayer(
768
    OGRLayer &srcLayer, int geomFieldIndex)
769
0
    : m_srcLayer(srcLayer), m_geomFieldIndex(geomFieldIndex)
770
0
{
771
0
}
772
773
/************************************************************************/
774
/*               ~GDALVectorNonStreamingAlgorithmLayer()                */
775
/************************************************************************/
776
777
0
GDALVectorNonStreamingAlgorithmLayer::~GDALVectorNonStreamingAlgorithmLayer() =
778
    default;
779
780
/************************************************************************/
781
/*      GDALVectorNonStreamingAlgorithmLayer::GetNextRawFeature()       */
782
/************************************************************************/
783
784
OGRFeature *GDALVectorNonStreamingAlgorithmLayer::GetNextRawFeature()
785
0
{
786
0
    return GetNextProcessedFeature().release();
787
0
}
788
789
/************************************************************************/
790
/*    GDALVectorAlgorithmLayerProgressHelper::iterator::operator*()     */
791
/************************************************************************/
792
793
GDALVectorAlgorithmLayerProgressHelper::iterator::value_type
794
GDALVectorAlgorithmLayerProgressHelper::iterator::operator*() const
795
0
{
796
0
    const double dfProgressStart =
797
0
        m_helper.m_anFeatures.empty() ? 0
798
0
        : m_helper.m_nTotalFeatures > 0
799
0
            ? static_cast<double>(m_nFeatureIdx) /
800
0
                  static_cast<double>(m_helper.m_nTotalFeatures)
801
0
            : static_cast<double>(m_nProcessedLayerIdx) /
802
0
                  std::max(1.0,
803
0
                           static_cast<double>(m_helper.m_anFeatures.size()));
804
0
    const double dfProgressEnd =
805
0
        m_helper.m_anFeatures.empty() ? 0
806
0
        : m_helper.m_nTotalFeatures > 0
807
0
            ? static_cast<double>(m_nFeatureIdx +
808
0
                                  m_helper.m_anFeatures[m_nProcessedLayerIdx]) /
809
0
                  static_cast<double>(m_helper.m_nTotalFeatures)
810
0
            : static_cast<double>(m_nProcessedLayerIdx + 1) /
811
0
                  std::max(1.0,
812
0
                           static_cast<double>(m_helper.m_anFeatures.size()));
813
814
0
    progress_data_unique_ptr pScaledProgressData(nullptr,
815
0
                                                 GDALDestroyScaledProgress);
816
0
    if (m_helper.m_pfnProgress && m_helper.m_apoSrcLayers[m_nLayerIdx].second)
817
0
    {
818
0
        pScaledProgressData.reset(GDALCreateScaledProgress(
819
0
            dfProgressStart, dfProgressEnd, m_helper.m_pfnProgress,
820
0
            m_helper.m_pProgressData));
821
0
    }
822
823
0
    return value_type(m_helper.m_apoSrcLayers[m_nLayerIdx].first,
824
0
                      m_helper.m_apoSrcLayers[m_nLayerIdx].second,
825
0
                      m_helper.m_pfnProgress ? GDALScaledProgress : nullptr,
826
0
                      std::move(pScaledProgressData));
827
0
}
828
829
//! @endcond