Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_raster_fill_nodata.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  "gdal raster fillnodata" standalone command
5
 * Author:   Alessandro Pasotti <elpaso at itopen dot it>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2025, Alessandro Pasotti <elpaso at itopen dot it>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "gdalalg_raster_fill_nodata.h"
14
15
#include "cpl_progress.h"
16
#include "gdal_priv.h"
17
#include "gdal_alg.h"
18
#include "commonutils.h"
19
20
#include <algorithm>
21
22
//! @cond Doxygen_Suppress
23
24
#ifndef _
25
0
#define _(x) (x)
26
#endif
27
28
/************************************************************************/
29
/*    GDALRasterFillNodataAlgorithm::GDALRasterFillNodataAlgorithm()    */
30
/************************************************************************/
31
32
GDALRasterFillNodataAlgorithm::GDALRasterFillNodataAlgorithm(
33
    bool standalone) noexcept
34
0
    : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION,
35
0
                                                      HELP_URL, standalone)
36
0
{
37
0
    AddBandArg(&m_band).SetDefault(m_band);
38
39
0
    AddArg("max-distance", 'd',
40
0
           _("The maximum distance (in pixels) that the algorithm will search "
41
0
             "out for values to interpolate."),
42
0
           &m_maxDistance)
43
0
        .SetDefault(m_maxDistance)
44
0
        .SetMetaVar("MAX_DISTANCE");
45
46
0
    AddArg("smoothing-iterations", 's',
47
0
           _("The number of 3x3 average filter smoothing iterations to run "
48
0
             "after the interpolation to dampen artifacts. The default is zero "
49
0
             "smoothing iterations."),
50
0
           &m_smoothingIterations)
51
0
        .SetDefault(m_smoothingIterations)
52
0
        .SetMetaVar("SMOOTHING_ITERATIONS");
53
54
0
    auto &mask{AddArg("mask", 0,
55
0
                      _("Use the first band of the specified file as a "
56
0
                        "validity mask (zero is invalid, non-zero is valid)."),
57
0
                      &m_maskDataset)};
58
59
0
    SetAutoCompleteFunctionForFilename(mask, GDAL_OF_RASTER);
60
61
0
    AddArg("strategy", 0,
62
0
           _("By default, pixels are interpolated using an inverse distance "
63
0
             "weighting (invdist). It is also possible to choose a nearest "
64
0
             "neighbour (nearest) strategy."),
65
0
           &m_strategy)
66
0
        .SetDefault(m_strategy)
67
0
        .SetChoices("invdist", "nearest");
68
0
}
69
70
/************************************************************************/
71
/*               GDALRasterFillNodataAlgorithm::RunStep()               */
72
/************************************************************************/
73
74
bool GDALRasterFillNodataAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
75
0
{
76
0
    auto pfnProgress = ctxt.m_pfnProgress;
77
0
    auto pProgressData = ctxt.m_pProgressData;
78
79
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
80
0
    std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)> pScaledData(
81
0
        GDALCreateScaledProgress(0.0, 0.5, pfnProgress, pProgressData),
82
0
        GDALDestroyScaledProgress);
83
0
    auto poTmpDS = CreateTemporaryCopy(
84
0
        this, poSrcDS, m_band, true, pScaledData ? GDALScaledProgress : nullptr,
85
0
        pScaledData.get());
86
0
    if (!poTmpDS)
87
0
        return false;
88
89
0
    GDALRasterBand *maskBand{nullptr};
90
0
    if (m_maskDataset.GetDatasetRef())
91
0
    {
92
0
        maskBand = m_maskDataset.GetDatasetRef()->GetRasterBand(1);
93
0
        if (!maskBand)
94
0
        {
95
0
            ReportError(CE_Failure, CPLE_AppDefined, "Cannot get mask band.");
96
0
            return false;
97
0
        }
98
0
    }
99
100
    // Get the output band
101
0
    GDALRasterBand *dstBand{poTmpDS->GetRasterBand(1)};
102
0
    CPLAssert(dstBand);
103
104
    // Prepare options to pass to GDALFillNodata
105
0
    CPLStringList aosFillOptions;
106
107
0
    if (EQUAL(m_strategy.c_str(), "nearest"))
108
0
        aosFillOptions.AddNameValue("INTERPOLATION", "NEAREST");
109
0
    else
110
0
        aosFillOptions.AddNameValue("INTERPOLATION",
111
0
                                    "INV_DIST");  // default strategy
112
113
0
    pScaledData.reset(
114
0
        GDALCreateScaledProgress(0.5, 1.0, pfnProgress, pProgressData));
115
0
    const auto retVal = GDALFillNodata(
116
0
        dstBand, maskBand, m_maxDistance, 0, m_smoothingIterations,
117
0
        aosFillOptions.List(), pScaledData ? GDALScaledProgress : nullptr,
118
0
        pScaledData.get());
119
120
0
    if (retVal == CE_None)
121
0
    {
122
0
        if (pfnProgress)
123
0
            pfnProgress(1.0, "", pProgressData);
124
0
        m_outputDataset.Set(std::move(poTmpDS));
125
0
    }
126
127
0
    return retVal == CE_None;
128
0
}
129
130
GDALRasterFillNodataAlgorithmStandalone::
131
0
    ~GDALRasterFillNodataAlgorithmStandalone() = default;
132
133
//! @endcond