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