Coverage Report

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