Line data Source code
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_vector_read.h"
15 : #include "gdalalg_vector_buffer.h"
16 : #include "gdalalg_vector_clip.h"
17 : #include "gdalalg_vector_concat.h"
18 : #include "gdalalg_vector_edit.h"
19 : #include "gdalalg_vector_explode_collections.h"
20 : #include "gdalalg_vector_filter.h"
21 : #include "gdalalg_vector_geom.h"
22 : #include "gdalalg_vector_make_valid.h"
23 : #include "gdalalg_vector_reproject.h"
24 : #include "gdalalg_vector_segmentize.h"
25 : #include "gdalalg_vector_select.h"
26 : #include "gdalalg_vector_set_geom_type.h"
27 : #include "gdalalg_vector_simplify.h"
28 : #include "gdalalg_vector_simplify_coverage.h"
29 : #include "gdalalg_vector_sql.h"
30 : #include "gdalalg_vector_swap_xy.h"
31 : #include "gdalalg_vector_write.h"
32 :
33 : #include "../frmts/mem/memdataset.h"
34 :
35 : #include "cpl_conv.h"
36 : #include "cpl_string.h"
37 :
38 : #include <algorithm>
39 : #include <cassert>
40 :
41 : //! @cond Doxygen_Suppress
42 :
43 : #ifndef _
44 : #define _(x) (x)
45 : #endif
46 :
47 : /************************************************************************/
48 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
49 : /************************************************************************/
50 :
51 894 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
52 : const std::string &name, const std::string &description,
53 894 : const std::string &helpURL, bool standaloneStep)
54 : : GDALVectorPipelineStepAlgorithm(
55 : name, description, helpURL,
56 894 : ConstructorOptions().SetStandaloneStep(standaloneStep))
57 : {
58 894 : }
59 :
60 : /************************************************************************/
61 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
62 : /************************************************************************/
63 :
64 1051 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
65 : const std::string &name, const std::string &description,
66 1051 : const std::string &helpURL, const ConstructorOptions &options)
67 1051 : : GDALPipelineStepAlgorithm(name, description, helpURL, options)
68 : {
69 1051 : if (m_standaloneStep)
70 : {
71 190 : m_supportsStreamedOutput = true;
72 :
73 190 : AddVectorInputArgs(false);
74 190 : AddProgressArg();
75 190 : AddVectorOutputArgs(false, false);
76 : }
77 1051 : }
78 :
79 : GDALVectorPipelineStepAlgorithm::~GDALVectorPipelineStepAlgorithm() = default;
80 :
81 : /************************************************************************/
82 : /* GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm() */
83 : /************************************************************************/
84 :
85 78 : GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
86 : : GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm>(
87 : NAME, DESCRIPTION, HELP_URL,
88 78 : ConstructorOptions().SetInputDatasetMaxCount(INT_MAX))
89 : {
90 78 : m_supportsStreamedOutput = true;
91 :
92 78 : AddVectorInputArgs(/* hiddenForCLI = */ true);
93 78 : AddProgressArg();
94 156 : AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
95 78 : .SetHiddenForCLI()
96 78 : .SetPositional();
97 78 : AddVectorOutputArgs(/* hiddenForCLI = */ true,
98 : /* shortNameOutputLayerAllowed=*/false);
99 :
100 78 : RegisterAlgorithms(m_stepRegistry, false);
101 78 : }
102 :
103 : /************************************************************************/
104 : /* GDALVectorPipelineAlgorithm::RegisterAlgorithms() */
105 : /************************************************************************/
106 :
107 : /* static */
108 127 : void GDALVectorPipelineAlgorithm::RegisterAlgorithms(
109 : GDALAlgorithmRegistry ®istry, bool forMixedPipeline)
110 : {
111 254 : GDALAlgorithmRegistry::AlgInfo algInfo;
112 :
113 : const auto addSuffixIfNeeded =
114 762 : [forMixedPipeline](const char *name) -> std::string
115 : {
116 1056 : return forMixedPipeline ? std::string(name).append(VECTOR_SUFFIX)
117 1818 : : std::string(name);
118 127 : };
119 :
120 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorReadAlgorithm::NAME);
121 82 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
122 209 : { return std::make_unique<GDALVectorReadAlgorithm>(); };
123 127 : registry.Register(algInfo);
124 :
125 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorWriteAlgorithm::NAME);
126 82 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
127 209 : { return std::make_unique<GDALVectorWriteAlgorithm>(); };
128 127 : registry.Register(algInfo);
129 :
130 127 : registry.Register<GDALVectorBufferAlgorithm>();
131 127 : registry.Register<GDALVectorConcatAlgorithm>();
132 :
133 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorClipAlgorithm::NAME);
134 18 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
135 145 : { return std::make_unique<GDALVectorClipAlgorithm>(); };
136 127 : registry.Register(algInfo);
137 :
138 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorEditAlgorithm::NAME);
139 21 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
140 148 : { return std::make_unique<GDALVectorEditAlgorithm>(); };
141 127 : registry.Register(algInfo);
142 :
143 127 : registry.Register<GDALVectorExplodeCollectionsAlgorithm>();
144 :
145 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorReprojectAlgorithm::NAME);
146 26 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
147 153 : { return std::make_unique<GDALVectorReprojectAlgorithm>(); };
148 127 : registry.Register(algInfo);
149 :
150 127 : registry.Register<GDALVectorFilterAlgorithm>();
151 127 : registry.Register<GDALVectorGeomAlgorithm>();
152 127 : registry.Register<GDALVectorMakeValidAlgorithm>();
153 127 : registry.Register<GDALVectorSegmentizeAlgorithm>();
154 :
155 127 : algInfo.m_name = addSuffixIfNeeded(GDALVectorSelectAlgorithm::NAME);
156 19 : algInfo.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
157 146 : { return std::make_unique<GDALVectorSelectAlgorithm>(); };
158 127 : registry.Register(algInfo);
159 :
160 127 : registry.Register<GDALVectorSetGeomTypeAlgorithm>();
161 127 : registry.Register<GDALVectorSimplifyAlgorithm>();
162 127 : registry.Register<GDALVectorSimplifyCoverageAlgorithm>();
163 127 : registry.Register<GDALVectorSQLAlgorithm>();
164 127 : registry.Register<GDALVectorSwapXYAlgorithm>();
165 127 : }
166 :
167 : /************************************************************************/
168 : /* GDALVectorPipelineAlgorithm::ParseCommandLineArguments() */
169 : /************************************************************************/
170 :
171 68 : bool GDALVectorPipelineAlgorithm::ParseCommandLineArguments(
172 : const std::vector<std::string> &args)
173 : {
174 80 : if (args.size() == 1 && (args[0] == "-h" || args[0] == "--help" ||
175 12 : args[0] == "help" || args[0] == "--json-usage"))
176 : {
177 2 : return GDALAlgorithm::ParseCommandLineArguments(args);
178 : }
179 66 : else if (args.size() == 1 && STARTS_WITH(args[0].c_str(), "--help-doc="))
180 : {
181 3 : m_helpDocCategory = args[0].substr(strlen("--help-doc="));
182 6 : return GDALAlgorithm::ParseCommandLineArguments({"--help-doc"});
183 : }
184 :
185 427 : for (const auto &arg : args)
186 : {
187 366 : if (arg.find("--pipeline") == 0)
188 2 : return GDALAlgorithm::ParseCommandLineArguments(args);
189 :
190 : // gdal vector pipeline [--progress] "read poly.gpkg ..."
191 365 : if (arg.find("read ") == 0)
192 1 : return GDALAlgorithm::ParseCommandLineArguments(args);
193 : }
194 :
195 61 : if (!m_steps.empty())
196 : {
197 1 : ReportError(CE_Failure, CPLE_AppDefined,
198 : "ParseCommandLineArguments() can only be called once per "
199 : "instance.");
200 1 : return false;
201 : }
202 :
203 : struct Step
204 : {
205 : std::unique_ptr<GDALVectorPipelineStepAlgorithm> alg{};
206 : std::vector<std::string> args{};
207 : };
208 :
209 120 : std::vector<Step> steps;
210 60 : steps.resize(1);
211 :
212 405 : for (const auto &arg : args)
213 : {
214 351 : if (arg == "--progress")
215 : {
216 2 : m_progressBarRequested = true;
217 2 : continue;
218 : }
219 :
220 349 : if (IsCalledFromCommandLine() && (arg == "-h" || arg == "--help"))
221 : {
222 3 : if (!steps.back().alg)
223 1 : steps.pop_back();
224 3 : if (steps.empty())
225 : {
226 6 : return GDALAlgorithm::ParseCommandLineArguments(args);
227 : }
228 : else
229 : {
230 2 : m_stepOnWhichHelpIsRequested = std::move(steps.back().alg);
231 2 : return true;
232 : }
233 : }
234 :
235 346 : auto &curStep = steps.back();
236 :
237 346 : if (arg == "!" || arg == "|")
238 : {
239 75 : if (curStep.alg)
240 : {
241 70 : steps.resize(steps.size() + 1);
242 : }
243 : }
244 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
245 271 : else if (arg == "+step")
246 : {
247 4 : if (curStep.alg)
248 : {
249 2 : steps.resize(steps.size() + 1);
250 : }
251 : }
252 267 : else if (arg.find("+gdal=") == 0)
253 : {
254 3 : const std::string stepName = arg.substr(strlen("+gdal="));
255 3 : curStep.alg = GetStepAlg(stepName);
256 3 : if (!curStep.alg)
257 : {
258 1 : ReportError(CE_Failure, CPLE_AppDefined,
259 : "unknown step name: %s", stepName.c_str());
260 1 : return false;
261 : }
262 : }
263 : #endif
264 264 : else if (!curStep.alg)
265 : {
266 126 : std::string algName = arg;
267 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
268 126 : if (!algName.empty() && algName[0] == '+')
269 1 : algName = algName.substr(1);
270 : #endif
271 126 : curStep.alg = GetStepAlg(algName);
272 126 : if (!curStep.alg)
273 : {
274 1 : ReportError(CE_Failure, CPLE_AppDefined,
275 : "unknown step name: %s", algName.c_str());
276 1 : return false;
277 : }
278 250 : curStep.alg->SetCallPath({std::move(algName)});
279 : }
280 : else
281 : {
282 138 : if (curStep.alg->HasSubAlgorithms())
283 : {
284 : auto subAlg = std::unique_ptr<GDALVectorPipelineStepAlgorithm>(
285 : cpl::down_cast<GDALVectorPipelineStepAlgorithm *>(
286 3 : curStep.alg->InstantiateSubAlgorithm(arg).release()));
287 3 : if (!subAlg)
288 : {
289 1 : ReportError(CE_Failure, CPLE_AppDefined,
290 : "'%s' is a unknown sub-algorithm of '%s'",
291 1 : arg.c_str(), curStep.alg->GetName().c_str());
292 1 : return false;
293 : }
294 2 : curStep.alg = std::move(subAlg);
295 2 : continue;
296 : }
297 :
298 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
299 139 : if (!arg.empty() && arg[0] == '+' &&
300 4 : arg.find(' ') == std::string::npos)
301 : {
302 3 : curStep.args.push_back("--" + arg.substr(1));
303 3 : continue;
304 : }
305 : #endif
306 :
307 : // #define GDAL_PIPELINE_NATURAL_LANGUAGE
308 : #ifdef GDAL_PIPELINE_NATURAL_LANGUAGE
309 : std::string &value = arg;
310 : // gdal vector pipeline "read [from] poly.gpkg, reproject [from EPSG:4326] to EPSG:32632 and write to out.gpkg with overwriting"
311 : if (value == "and")
312 : {
313 : steps.resize(steps.size() + 1);
314 : }
315 : else if (value == "from" &&
316 : curStep.alg->GetName() == GDALVectorReadAlgorithm::NAME)
317 : {
318 : // do nothing
319 : }
320 : else if (value == "from" && curStep.alg->GetName() == "reproject")
321 : {
322 : curStep.args.push_back("--src-crs");
323 : }
324 : else if (value == "to" && curStep.alg->GetName() == "reproject")
325 : {
326 : curStep.args.push_back("--dst-crs");
327 : }
328 : else if (value == "to" &&
329 : curStep.alg->GetName() == GDALVectorWriteAlgorithm::NAME)
330 : {
331 : // do nothing
332 : }
333 : else if (value == "with" &&
334 : curStep.alg->GetName() == GDALVectorWriteAlgorithm::NAME)
335 : {
336 : // do nothing
337 : }
338 : else if (value == "overwriting" &&
339 : curStep.alg->GetName() == GDALVectorWriteAlgorithm::NAME)
340 : {
341 : curStep.args.push_back("--overwrite");
342 : }
343 : else if (!value.empty() && value.back() == ',')
344 : {
345 : curStep.args.push_back(value.substr(0, value.size() - 1));
346 : steps.resize(steps.size() + 1);
347 : }
348 : else
349 : #endif
350 :
351 : {
352 132 : curStep.args.push_back(arg);
353 : }
354 : }
355 : }
356 :
357 : // As we initially added a step without alg to bootstrap things, make
358 : // sure to remove it if it hasn't been filled, or the user has terminated
359 : // the pipeline with a '!' separator.
360 54 : if (!steps.back().alg)
361 2 : steps.pop_back();
362 :
363 : // Automatically add a final write step if none in m_executionForStreamOutput
364 : // mode
365 57 : if (m_executionForStreamOutput && !steps.empty() &&
366 3 : steps.back().alg->GetName() != GDALVectorWriteAlgorithm::NAME)
367 : {
368 2 : steps.resize(steps.size() + 1);
369 2 : steps.back().alg = GetStepAlg(GDALVectorWriteAlgorithm::NAME);
370 2 : steps.back().args.push_back("--output-format");
371 2 : steps.back().args.push_back("stream");
372 2 : steps.back().args.push_back("streamed_dataset");
373 : }
374 :
375 54 : bool helpRequested = false;
376 54 : if (IsCalledFromCommandLine())
377 : {
378 8 : for (auto &step : steps)
379 5 : step.alg->SetCalledFromCommandLine();
380 :
381 18 : for (const std::string &v : args)
382 : {
383 15 : if (cpl::ends_with(v, "=?"))
384 1 : helpRequested = true;
385 : }
386 : }
387 :
388 54 : if (steps.size() < 2)
389 : {
390 3 : if (!steps.empty() && helpRequested)
391 : {
392 1 : steps.back().alg->ParseCommandLineArguments(steps.back().args);
393 1 : return false;
394 : }
395 :
396 2 : ReportError(CE_Failure, CPLE_AppDefined,
397 : "At least 2 steps must be provided");
398 2 : return false;
399 : }
400 :
401 102 : std::vector<GDALVectorPipelineStepAlgorithm *> stepAlgs;
402 171 : for (const auto &step : steps)
403 120 : stepAlgs.push_back(step.alg.get());
404 51 : if (!CheckFirstStep(stepAlgs))
405 2 : return false;
406 :
407 49 : if (steps.back().alg->GetName() != GDALVectorWriteAlgorithm::NAME)
408 : {
409 1 : if (helpRequested)
410 : {
411 0 : steps.back().alg->ParseCommandLineArguments(steps.back().args);
412 0 : return false;
413 : }
414 1 : ReportError(CE_Failure, CPLE_AppDefined, "Last step should be '%s'",
415 : GDALVectorWriteAlgorithm::NAME);
416 1 : return false;
417 : }
418 112 : for (size_t i = 0; i < steps.size() - 1; ++i)
419 : {
420 65 : if (steps[i].alg->GetName() == GDALVectorWriteAlgorithm::NAME)
421 : {
422 1 : ReportError(CE_Failure, CPLE_AppDefined,
423 : "Only last step can be '%s'",
424 : GDALVectorWriteAlgorithm::NAME);
425 1 : return false;
426 : }
427 : }
428 :
429 157 : for (auto &step : steps)
430 : {
431 110 : step.alg->SetReferencePathForRelativePaths(
432 : GetReferencePathForRelativePaths());
433 : }
434 :
435 : // Propagate input parameters set at the pipeline level to the
436 : // "read" step
437 : {
438 47 : auto &step = steps.front();
439 430 : for (auto &arg : step.alg->GetArgs())
440 : {
441 383 : auto pipelineArg = GetArg(arg->GetName());
442 383 : if (pipelineArg && pipelineArg->IsExplicitlySet())
443 : {
444 8 : arg->SetSkipIfAlreadySet(true);
445 8 : arg->SetFrom(*pipelineArg);
446 : }
447 : }
448 : }
449 :
450 : // Same with "write" step
451 : {
452 47 : auto &step = steps.back();
453 658 : for (auto &arg : step.alg->GetArgs())
454 : {
455 611 : auto pipelineArg = GetArg(arg->GetName());
456 611 : if (pipelineArg && pipelineArg->IsExplicitlySet())
457 : {
458 10 : arg->SetSkipIfAlreadySet(true);
459 10 : arg->SetFrom(*pipelineArg);
460 : }
461 : }
462 : }
463 :
464 : // Parse each step, but without running the validation
465 144 : for (const auto &step : steps)
466 : {
467 104 : step.alg->m_skipValidationInParseCommandLine = true;
468 104 : if (!step.alg->ParseCommandLineArguments(step.args))
469 7 : return false;
470 : }
471 :
472 : // Evaluate "input" argument of "read" step, together with the "output"
473 : // argument of the "write" step, in case they point to the same dataset.
474 40 : auto inputArg = steps.front().alg->GetArg(GDAL_ARG_NAME_INPUT);
475 80 : if (inputArg && inputArg->IsExplicitlySet() &&
476 120 : inputArg->GetType() == GAAT_DATASET_LIST &&
477 40 : inputArg->Get<std::vector<GDALArgDatasetValue>>().size() == 1)
478 : {
479 38 : steps.front().alg->ProcessDatasetArg(inputArg, steps.back().alg.get());
480 : }
481 :
482 127 : for (const auto &step : steps)
483 : {
484 90 : if (!step.alg->ValidateArguments())
485 3 : return false;
486 : }
487 :
488 122 : for (auto &step : steps)
489 85 : m_steps.push_back(std::move(step.alg));
490 :
491 37 : return true;
492 : }
493 :
494 : /************************************************************************/
495 : /* GDALVectorPipelineAlgorithm::GetUsageForCLI() */
496 : /************************************************************************/
497 :
498 8 : std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
499 : bool shortUsage, const UsageOptions &usageOptions) const
500 : {
501 8 : UsageOptions stepUsageOptions;
502 8 : stepUsageOptions.isPipelineStep = true;
503 :
504 8 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
505 : {
506 4 : auto alg = GetStepAlg(m_helpDocCategory);
507 4 : std::string ret;
508 2 : if (alg)
509 : {
510 2 : alg->SetCallPath({m_helpDocCategory});
511 1 : alg->GetArg("help-doc")->Set(true);
512 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
513 : }
514 : else
515 : {
516 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
517 : m_helpDocCategory.c_str());
518 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
519 1 : m_helpDocCategory.c_str());
520 : }
521 : }
522 :
523 6 : UsageOptions usageOptionsMain(usageOptions);
524 6 : usageOptionsMain.isPipelineMain = true;
525 : std::string ret =
526 12 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
527 6 : if (shortUsage)
528 2 : return ret;
529 :
530 : ret += "\n<PIPELINE> is of the form: read|concat [READ-OPTIONS] "
531 4 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write [WRITE-OPTIONS]\n";
532 :
533 4 : if (m_helpDocCategory == "main")
534 : {
535 1 : return ret;
536 : }
537 :
538 3 : ret += '\n';
539 3 : ret += "Example: 'gdal vector pipeline --progress ! read in.gpkg ! \\\n";
540 3 : ret += " reproject --dst-crs=EPSG:32632 ! ";
541 3 : ret += "write out.gpkg --overwrite'\n";
542 3 : ret += '\n';
543 3 : ret += "Potential steps are:\n";
544 :
545 57 : for (const std::string &name : m_stepRegistry.GetNames())
546 : {
547 108 : auto alg = GetStepAlg(name);
548 54 : assert(alg);
549 54 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
550 54 : stepUsageOptions.maxOptLen =
551 54 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
552 : }
553 :
554 : {
555 3 : const auto name = GDALVectorReadAlgorithm::NAME;
556 3 : ret += '\n';
557 6 : auto alg = GetStepAlg(name);
558 3 : assert(alg);
559 6 : alg->SetCallPath({name});
560 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
561 : }
562 57 : for (const std::string &name : m_stepRegistry.GetNames())
563 : {
564 108 : auto alg = GetStepAlg(name);
565 54 : assert(alg);
566 60 : if (alg->CanBeFirstStep() && !alg->IsHidden() &&
567 6 : name != GDALVectorReadAlgorithm::NAME)
568 : {
569 3 : ret += '\n';
570 6 : alg->SetCallPath({name});
571 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
572 : }
573 : }
574 57 : for (const std::string &name : m_stepRegistry.GetNames())
575 : {
576 108 : auto alg = GetStepAlg(name);
577 54 : assert(alg);
578 99 : if (!alg->CanBeFirstStep() && !alg->IsHidden() &&
579 45 : name != GDALVectorWriteAlgorithm::NAME)
580 : {
581 42 : ret += '\n';
582 84 : alg->SetCallPath({name});
583 42 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
584 : }
585 : }
586 : {
587 3 : const auto name = GDALVectorWriteAlgorithm::NAME;
588 3 : ret += '\n';
589 6 : auto alg = GetStepAlg(name);
590 3 : assert(alg);
591 6 : alg->SetCallPath({name});
592 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
593 : }
594 :
595 3 : ret += GetUsageForCLIEnd();
596 :
597 3 : return ret;
598 : }
599 :
600 : /************************************************************************/
601 : /* GDALVectorPipelineOutputLayer */
602 : /************************************************************************/
603 :
604 : /************************************************************************/
605 : /* GDALVectorPipelineOutputLayer() */
606 : /************************************************************************/
607 :
608 106 : GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
609 106 : : m_srcLayer(srcLayer)
610 : {
611 106 : }
612 :
613 : /************************************************************************/
614 : /* ~GDALVectorPipelineOutputLayer() */
615 : /************************************************************************/
616 :
617 : GDALVectorPipelineOutputLayer::~GDALVectorPipelineOutputLayer() = default;
618 :
619 : /************************************************************************/
620 : /* GDALVectorPipelineOutputLayer::ResetReading() */
621 : /************************************************************************/
622 :
623 484 : void GDALVectorPipelineOutputLayer::ResetReading()
624 : {
625 484 : m_srcLayer.ResetReading();
626 484 : m_pendingFeatures.clear();
627 484 : m_idxInPendingFeatures = 0;
628 484 : }
629 :
630 : /************************************************************************/
631 : /* GDALVectorPipelineOutputLayer::GetNextRawFeature() */
632 : /************************************************************************/
633 :
634 1831 : OGRFeature *GDALVectorPipelineOutputLayer::GetNextRawFeature()
635 : {
636 1831 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
637 : {
638 : OGRFeature *poFeature =
639 14 : m_pendingFeatures[m_idxInPendingFeatures].release();
640 14 : ++m_idxInPendingFeatures;
641 14 : return poFeature;
642 : }
643 1817 : m_pendingFeatures.clear();
644 1817 : m_idxInPendingFeatures = 0;
645 : while (true)
646 : {
647 : auto poSrcFeature =
648 1820 : std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
649 1820 : if (!poSrcFeature)
650 183 : return nullptr;
651 1637 : TranslateFeature(std::move(poSrcFeature), m_pendingFeatures);
652 1637 : if (!m_pendingFeatures.empty())
653 1634 : break;
654 3 : }
655 1634 : OGRFeature *poFeature = m_pendingFeatures[0].release();
656 1634 : m_idxInPendingFeatures = 1;
657 1634 : return poFeature;
658 : }
659 :
660 : /************************************************************************/
661 : /* GDALVectorPipelineOutputDataset */
662 : /************************************************************************/
663 :
664 : /************************************************************************/
665 : /* GDALVectorPipelineOutputDataset() */
666 : /************************************************************************/
667 :
668 99 : GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
669 99 : GDALDataset &srcDS)
670 99 : : m_srcDS(srcDS)
671 : {
672 99 : SetDescription(m_srcDS.GetDescription());
673 99 : SetMetadata(m_srcDS.GetMetadata());
674 99 : }
675 :
676 : /************************************************************************/
677 : /* ~GDALVectorPipelineOutputDataset() */
678 : /************************************************************************/
679 :
680 : GDALVectorPipelineOutputDataset::~GDALVectorPipelineOutputDataset() = default;
681 :
682 : /************************************************************************/
683 : /* GDALVectorPipelineOutputDataset::AddLayer() */
684 : /************************************************************************/
685 :
686 111 : void GDALVectorPipelineOutputDataset::AddLayer(
687 : OGRLayer &oSrcLayer,
688 : std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
689 : {
690 111 : m_layersToDestroy.push_back(std::move(poNewLayer));
691 : OGRLayerWithTranslateFeature *poNewLayerRaw =
692 111 : m_layersToDestroy.back().get();
693 111 : m_layers.push_back(poNewLayerRaw);
694 111 : m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
695 111 : }
696 :
697 : /************************************************************************/
698 : /* GDALVectorPipelineOutputDataset::GetLayerCount() */
699 : /************************************************************************/
700 :
701 368 : int GDALVectorPipelineOutputDataset::GetLayerCount()
702 : {
703 368 : return static_cast<int>(m_layers.size());
704 : }
705 :
706 : /************************************************************************/
707 : /* GDALVectorPipelineOutputDataset::GetLayer() */
708 : /************************************************************************/
709 :
710 193 : OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx)
711 : {
712 193 : return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
713 : }
714 :
715 : /************************************************************************/
716 : /* GDALVectorPipelineOutputDataset::TestCapability() */
717 : /************************************************************************/
718 :
719 75 : int GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap)
720 : {
721 75 : if (EQUAL(pszCap, ODsCRandomLayerRead) ||
722 31 : EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
723 : {
724 59 : return m_srcDS.TestCapability(pszCap);
725 : }
726 16 : return false;
727 : }
728 :
729 : /************************************************************************/
730 : /* GDALVectorPipelineOutputDataset::ResetReading() */
731 : /************************************************************************/
732 :
733 3 : void GDALVectorPipelineOutputDataset::ResetReading()
734 : {
735 3 : m_srcDS.ResetReading();
736 3 : m_pendingFeatures.clear();
737 3 : m_idxInPendingFeatures = 0;
738 3 : }
739 :
740 : /************************************************************************/
741 : /* GDALVectorPipelineOutputDataset::GetNextFeature() */
742 : /************************************************************************/
743 :
744 23 : OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
745 : OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
746 : GDALProgressFunc pfnProgress, void *pProgressData)
747 : {
748 23 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
749 : {
750 : OGRFeature *poFeature =
751 3 : m_pendingFeatures[m_idxInPendingFeatures].release();
752 3 : if (ppoBelongingLayer)
753 3 : *ppoBelongingLayer = m_belongingLayer;
754 3 : ++m_idxInPendingFeatures;
755 3 : return poFeature;
756 : }
757 :
758 20 : m_pendingFeatures.clear();
759 20 : m_idxInPendingFeatures = 0;
760 :
761 : while (true)
762 : {
763 20 : OGRLayer *poSrcBelongingLayer = nullptr;
764 20 : auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
765 20 : &poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
766 20 : if (!poSrcFeature)
767 3 : return nullptr;
768 17 : auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
769 17 : if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
770 : {
771 17 : m_belongingLayer = iterToDstLayer->second;
772 17 : m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
773 17 : m_pendingFeatures);
774 17 : if (!m_pendingFeatures.empty())
775 17 : break;
776 : }
777 0 : }
778 17 : OGRFeature *poFeature = m_pendingFeatures[0].release();
779 17 : if (ppoBelongingLayer)
780 17 : *ppoBelongingLayer = m_belongingLayer;
781 17 : m_idxInPendingFeatures = 1;
782 17 : return poFeature;
783 : }
784 :
785 : /************************************************************************/
786 : /* GDALVectorPipelinePassthroughLayer::GetLayerDefn() */
787 : /************************************************************************/
788 :
789 47 : OGRFeatureDefn *GDALVectorPipelinePassthroughLayer::GetLayerDefn()
790 : {
791 47 : return m_srcLayer.GetLayerDefn();
792 : }
793 :
794 : /************************************************************************/
795 : /* GDALVectorNonStreamingAlgorithmDataset() */
796 : /************************************************************************/
797 :
798 8 : GDALVectorNonStreamingAlgorithmDataset::GDALVectorNonStreamingAlgorithmDataset()
799 8 : : m_ds(MEMDataset::Create("", 0, 0, 0, GDT_Unknown, nullptr))
800 : {
801 8 : }
802 :
803 : /************************************************************************/
804 : /* ~GDALVectorNonStreamingAlgorithmDataset() */
805 : /************************************************************************/
806 :
807 : GDALVectorNonStreamingAlgorithmDataset::
808 : ~GDALVectorNonStreamingAlgorithmDataset() = default;
809 :
810 : /************************************************************************/
811 : /* GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer() */
812 : /************************************************************************/
813 :
814 7 : bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
815 : OGRLayer &srcLayer)
816 : {
817 7 : CPLStringList aosOptions;
818 7 : if (srcLayer.TestCapability(OLCStringsAsUTF8))
819 : {
820 1 : aosOptions.AddNameValue("ADVERTIZE_UTF8", "TRUE");
821 : }
822 :
823 : OGRMemLayer *poDstLayer =
824 7 : m_ds->CreateLayer(*srcLayer.GetLayerDefn(), aosOptions.List());
825 7 : m_layers.push_back(poDstLayer);
826 :
827 7 : const bool bRet = Process(srcLayer, *poDstLayer);
828 7 : poDstLayer->SetUpdatable(false);
829 14 : return bRet;
830 : }
831 :
832 : /************************************************************************/
833 : /* GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer() */
834 : /************************************************************************/
835 :
836 3 : void GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer(
837 : OGRLayer &oLayer)
838 : {
839 3 : m_passthrough_layers.push_back(
840 6 : std::make_unique<GDALVectorPipelinePassthroughLayer>(oLayer));
841 3 : m_layers.push_back(m_passthrough_layers.back().get());
842 3 : }
843 :
844 : /************************************************************************/
845 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() */
846 : /************************************************************************/
847 :
848 40 : int GDALVectorNonStreamingAlgorithmDataset::GetLayerCount()
849 : {
850 40 : return static_cast<int>(m_layers.size());
851 : }
852 :
853 : /************************************************************************/
854 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayer() */
855 : /************************************************************************/
856 :
857 33 : OGRLayer *GDALVectorNonStreamingAlgorithmDataset::GetLayer(int idx)
858 : {
859 33 : if (idx < 0 || idx >= static_cast<int>(m_layers.size()))
860 : {
861 2 : return nullptr;
862 : }
863 31 : return m_layers[idx];
864 : }
865 :
866 : /************************************************************************/
867 : /* GDALVectorNonStreamingAlgorithmDataset::TestCapability() */
868 : /************************************************************************/
869 :
870 9 : int GDALVectorNonStreamingAlgorithmDataset::TestCapability(const char *pszCap)
871 : {
872 9 : if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer))
873 : {
874 2 : return false;
875 : }
876 :
877 7 : return m_ds->TestCapability(pszCap);
878 : }
879 :
880 : //! @endcond
|