Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "gdal vector simplify-coverage" subcommand 5 : * Author: Daniel Baston 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2025, ISciences LLC 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_vector_simplify_coverage.h" 14 : 15 : #include "cpl_error.h" 16 : #include "gdal_priv.h" 17 : #include "gdalalg_vector_geom.h" 18 : #include "ogr_geometry.h" 19 : #include "ogr_geos.h" 20 : #include "ogrsf_frmts.h" 21 : 22 : #include <cinttypes> 23 : 24 : #ifndef _ 25 : #define _(x) (x) 26 : #endif 27 : 28 : //! @cond Doxygen_Suppress 29 : 30 48 : GDALVectorSimplifyCoverageAlgorithm::GDALVectorSimplifyCoverageAlgorithm( 31 48 : bool standaloneStep) 32 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 33 48 : standaloneStep) 34 : { 35 48 : AddActiveLayerArg(&m_activeLayer); 36 : AddArg("tolerance", 0, _("Distance tolerance for simplification."), 37 96 : &m_opts.tolerance) 38 48 : .SetPositional() 39 48 : .SetRequired() 40 48 : .SetMinValueIncluded(0); 41 : AddArg("preserve-boundary", 0, 42 : _("Whether the exterior boundary should be preserved."), 43 48 : &m_opts.preserveBoundary); 44 48 : } 45 : 46 : #if defined HAVE_GEOS && \ 47 : (GEOS_VERSION_MAJOR > 3 || \ 48 : (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 12)) 49 : 50 16 : class GDALVectorSimplifyCoverageOutputDataset final 51 : : public GDALGeosNonStreamingAlgorithmDataset 52 : { 53 : public: 54 8 : GDALVectorSimplifyCoverageOutputDataset( 55 : const GDALVectorSimplifyCoverageAlgorithm::Options &opts) 56 8 : : m_opts(opts) 57 : { 58 8 : } 59 : 60 : ~GDALVectorSimplifyCoverageOutputDataset() override; 61 : 62 43 : bool PolygonsOnly() const override 63 : { 64 43 : return true; 65 : } 66 : 67 40 : bool SkipEmpty() const override 68 : { 69 40 : return false; 70 : } 71 : 72 4 : bool ProcessGeos() override 73 : { 74 : // Perform coverage simplification 75 4 : GEOSGeometry *coll = GEOSGeom_createCollection_r( 76 : m_poGeosContext, GEOS_GEOMETRYCOLLECTION, m_apoGeosInputs.data(), 77 4 : static_cast<unsigned int>(m_apoGeosInputs.size())); 78 : 79 4 : if (coll == nullptr) 80 : { 81 0 : return false; 82 : } 83 : 84 4 : m_apoGeosInputs.clear(); 85 : 86 8 : m_poGeosResultAsCollection = GEOSCoverageSimplifyVW_r( 87 4 : m_poGeosContext, coll, m_opts.tolerance, m_opts.preserveBoundary); 88 4 : GEOSGeom_destroy_r(m_poGeosContext, coll); 89 : 90 4 : return m_poGeosResultAsCollection != nullptr; 91 : } 92 : 93 : private: 94 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorSimplifyCoverageOutputDataset) 95 : 96 : const GDALVectorSimplifyCoverageAlgorithm::Options &m_opts; 97 : }; 98 : 99 : GDALVectorSimplifyCoverageOutputDataset:: 100 : ~GDALVectorSimplifyCoverageOutputDataset() = default; 101 : 102 8 : bool GDALVectorSimplifyCoverageAlgorithm::RunStep( 103 : GDALPipelineStepRunContext &ctxt) 104 : { 105 8 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 106 : auto poDstDS = 107 16 : std::make_unique<GDALVectorSimplifyCoverageOutputDataset>(m_opts); 108 : 109 16 : GDALVectorAlgorithmLayerProgressHelper progressHelper(ctxt); 110 : 111 18 : for (auto &&poSrcLayer : poSrcDS->GetLayers()) 112 : { 113 14 : if (m_activeLayer.empty() || 114 4 : m_activeLayer == poSrcLayer->GetDescription()) 115 : { 116 7 : progressHelper.AddProcessedLayer(*poSrcLayer); 117 : } 118 : else 119 : { 120 3 : progressHelper.AddPassThroughLayer(*poSrcLayer); 121 : } 122 : } 123 : 124 8 : if (!progressHelper.HasProcessedLayers()) 125 : { 126 1 : ReportError(CE_Failure, CPLE_AppDefined, 127 : "Specified layer '%s' was not found", 128 : m_activeLayer.c_str()); 129 1 : return false; 130 : } 131 : 132 13 : for (auto [poSrcLayer, bProcessed, layerProgressFunc, layerProgressData] : 133 17 : progressHelper) 134 : { 135 8 : if (bProcessed) 136 : { 137 7 : if (!poDstDS->AddProcessedLayer(*poSrcLayer, layerProgressFunc, 138 : layerProgressData.get())) 139 : { 140 3 : return false; 141 : } 142 : } 143 : else 144 : { 145 1 : poDstDS->AddPassThroughLayer(*poSrcLayer); 146 : } 147 : } 148 : 149 4 : m_outputDataset.Set(std::move(poDstDS)); 150 : 151 4 : return true; 152 : } 153 : 154 : #else 155 : 156 : bool GDALVectorSimplifyCoverageAlgorithm::RunStep(GDALPipelineStepRunContext &) 157 : { 158 : ReportError(CE_Failure, CPLE_AppDefined, 159 : "%s requires GDAL to be built against version 3.12 or later of " 160 : "the GEOS library.", 161 : NAME); 162 : return false; 163 : } 164 : #endif // HAVE_GEOS 165 : 166 : GDALVectorSimplifyCoverageAlgorithmStandalone:: 167 : ~GDALVectorSimplifyCoverageAlgorithmStandalone() = default; 168 : 169 : //! @endcond