• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 16038479760

03 Jul 2025 12:12AM UTC coverage: 71.106% (-0.004%) from 71.11%
16038479760

Pull #12692

github

web-flow
Merge efeee3602 into b5d2a80d4
Pull Request #12692: C/C++/Python band algebra: add gdal.abs(), sqrt(), log(), log10() and pow()

80 of 87 new or added lines in 3 files covered. (91.95%)

8848 existing lines in 54 files now uncovered.

574863 of 808463 relevant lines covered (71.11%)

255001.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.13
/gcore/gdalcomputedrasterband.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  GDALComputedDataset and GDALComputedRasterBand
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "gdal_priv.h"
14
#include "vrtdataset.h"
15

16
#include <cmath>
17
#include <limits>
18

19
/************************************************************************/
20
/*                        GDALComputedDataset                           */
21
/************************************************************************/
22

23
class GDALComputedDataset final : public GDALDataset
1,588✔
24
{
25
    friend class GDALComputedRasterBand;
26

27
    const GDALComputedRasterBand::Operation m_op;
28
    CPLStringList m_aosOptions{};
29
    std::vector<std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>>
30
        m_bandDS{};
31
    std::vector<GDALRasterBand *> m_poBands{};
32
    VRTDataset m_oVRTDS;
33

34
    void AddSources(GDALComputedRasterBand *poBand);
35

36
    static const char *
37
    OperationToFunctionName(GDALComputedRasterBand::Operation op);
38

39
    GDALComputedDataset &operator=(const GDALComputedDataset &) = delete;
40
    GDALComputedDataset(GDALComputedDataset &&) = delete;
41
    GDALComputedDataset &operator=(GDALComputedDataset &&) = delete;
42

43
  public:
44
    GDALComputedDataset(const GDALComputedDataset &other);
45

46
    GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
47
                        GDALDataType eDT, int nBlockXSize, int nBlockYSize,
48
                        GDALComputedRasterBand::Operation op,
49
                        const GDALRasterBand *firstBand, double *pFirstConstant,
50
                        const GDALRasterBand *secondBand,
51
                        double *pSecondConstant);
52

53
    GDALComputedDataset(GDALComputedRasterBand *poBand, int nXSize, int nYSize,
54
                        GDALDataType eDT, int nBlockXSize, int nBlockYSize,
55
                        GDALComputedRasterBand::Operation op,
56
                        const std::vector<const GDALRasterBand *> &bands,
57
                        double constant);
58

59
    ~GDALComputedDataset() override;
60

61
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override
91✔
62
    {
63
        return m_oVRTDS.GetGeoTransform(gt);
91✔
64
    }
65

66
    const OGRSpatialReference *GetSpatialRef() const override
91✔
67
    {
68
        return m_oVRTDS.GetSpatialRef();
91✔
69
    }
70

71
    char **GetMetadata(const char *pszDomain) override
1✔
72
    {
73
        return m_oVRTDS.GetMetadata(pszDomain);
1✔
74
    }
75

76
    const char *GetMetadataItem(const char *pszName,
169✔
77
                                const char *pszDomain) override
78
    {
79
        return m_oVRTDS.GetMetadataItem(pszName, pszDomain);
169✔
80
    }
81

82
    void *GetInternalHandle(const char *pszHandleName) override
84✔
83
    {
84
        if (pszHandleName && EQUAL(pszHandleName, "VRT_DATASET"))
84✔
85
            return &m_oVRTDS;
42✔
86
        return nullptr;
42✔
87
    }
88
};
89

90
/************************************************************************/
91
/*                        IsComparisonOperator()                        */
92
/************************************************************************/
93

94
static bool IsComparisonOperator(GDALComputedRasterBand::Operation op)
508✔
95
{
96
    switch (op)
508✔
97
    {
98
        case GDALComputedRasterBand::Operation::OP_GT:
288✔
99
        case GDALComputedRasterBand::Operation::OP_GE:
100
        case GDALComputedRasterBand::Operation::OP_LT:
101
        case GDALComputedRasterBand::Operation::OP_LE:
102
        case GDALComputedRasterBand::Operation::OP_EQ:
103
        case GDALComputedRasterBand::Operation::OP_NE:
104
        case GDALComputedRasterBand::Operation::OP_LOGICAL_AND:
105
        case GDALComputedRasterBand::Operation::OP_LOGICAL_OR:
106
            return true;
288✔
107
        default:
220✔
108
            break;
220✔
109
    }
110
    return false;
220✔
111
}
112

113
/************************************************************************/
114
/*                        GDALComputedDataset()                         */
115
/************************************************************************/
116

117
GDALComputedDataset::GDALComputedDataset(const GDALComputedDataset &other)
483✔
118
    : GDALDataset(), m_op(other.m_op), m_aosOptions(other.m_aosOptions),
483✔
119
      m_poBands(other.m_poBands),
483✔
120
      m_oVRTDS(other.GetRasterXSize(), other.GetRasterYSize(),
121
               other.m_oVRTDS.GetBlockXSize(), other.m_oVRTDS.GetBlockYSize())
483✔
122
{
123
    nRasterXSize = other.nRasterXSize;
483✔
124
    nRasterYSize = other.nRasterYSize;
483✔
125

126
    auto poBand = new GDALComputedRasterBand(
127
        const_cast<const GDALComputedRasterBand &>(
128
            *cpl::down_cast<GDALComputedRasterBand *>(
483✔
129
                const_cast<GDALComputedDataset &>(other).GetRasterBand(1))),
130
        true);
483✔
131
    SetBand(1, poBand);
483✔
132

133
    GDALGeoTransform gt;
483✔
134
    if (const_cast<VRTDataset &>(other.m_oVRTDS).GetGeoTransform(gt) == CE_None)
483✔
135
    {
136
        m_oVRTDS.SetGeoTransform(gt);
430✔
137
    }
138

139
    if (const auto *poSRS =
483✔
140
            const_cast<VRTDataset &>(other.m_oVRTDS).GetSpatialRef())
483✔
141
    {
142
        m_oVRTDS.SetSpatialRef(poSRS);
430✔
143
    }
144

145
    m_oVRTDS.AddBand(other.m_oVRTDS.GetRasterBand(1)->GetRasterDataType(),
483✔
146
                     m_aosOptions.List());
147

148
    AddSources(poBand);
483✔
149
}
483✔
150

151
/************************************************************************/
152
/*                        GDALComputedDataset()                         */
153
/************************************************************************/
154

155
GDALComputedDataset::GDALComputedDataset(
274✔
156
    GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
157
    int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
158
    const GDALRasterBand *firstBand, double *pFirstConstant,
159
    const GDALRasterBand *secondBand, double *pSecondConstant)
274✔
160
    : m_op(op), m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
274✔
161
{
162
    CPLAssert(firstBand != nullptr || secondBand != nullptr);
274✔
163
    if (firstBand)
274✔
164
        m_poBands.push_back(const_cast<GDALRasterBand *>(firstBand));
252✔
165
    if (secondBand)
274✔
166
        m_poBands.push_back(const_cast<GDALRasterBand *>(secondBand));
100✔
167

168
    nRasterXSize = nXSize;
274✔
169
    nRasterYSize = nYSize;
274✔
170

171
    if (auto poSrcDS = m_poBands.front()->GetDataset())
274✔
172
    {
173
        GDALGeoTransform gt;
274✔
174
        if (poSrcDS->GetGeoTransform(gt) == CE_None)
274✔
175
        {
176
            m_oVRTDS.SetGeoTransform(gt);
140✔
177
        }
178

179
        if (const auto *poSRS = poSrcDS->GetSpatialRef())
274✔
180
        {
181
            m_oVRTDS.SetSpatialRef(poSRS);
140✔
182
        }
183
    }
184

185
    if (op == GDALComputedRasterBand::Operation::OP_CAST)
274✔
186
    {
187
#ifdef DEBUG
188
        // Just for code coverage...
189
        CPL_IGNORE_RET_VAL(GDALComputedDataset::OperationToFunctionName(op));
24✔
190
#endif
191
        m_aosOptions.SetNameValue("subclass", "VRTSourcedRasterBand");
24✔
192
    }
193
    else
194
    {
195
        m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
250✔
196
        if (IsComparisonOperator(op))
250✔
197
        {
198
            m_aosOptions.SetNameValue("PixelFunctionType", "expression");
135✔
199
            if (firstBand && secondBand)
135✔
200
            {
201
                m_aosOptions.SetNameValue(
43✔
202
                    "_PIXELFN_ARG_expression",
203
                    CPLSPrintf(
204
                        "source1 %s source2",
205
                        GDALComputedDataset::OperationToFunctionName(op)));
43✔
206
            }
207
            else if (firstBand && pSecondConstant)
92✔
208
            {
209
                m_aosOptions.SetNameValue(
74✔
210
                    "_PIXELFN_ARG_expression",
211
                    CPLSPrintf("source1 %s %.17g",
212
                               GDALComputedDataset::OperationToFunctionName(op),
213
                               *pSecondConstant));
74✔
214
            }
215
            else if (pFirstConstant && secondBand)
18✔
216
            {
217
                m_aosOptions.SetNameValue(
18✔
218
                    "_PIXELFN_ARG_expression",
219
                    CPLSPrintf(
220
                        "%.17g %s source1", *pFirstConstant,
221
                        GDALComputedDataset::OperationToFunctionName(op)));
18✔
222
            }
223
            else
224
            {
225
                CPLAssert(false);
×
226
            }
227
        }
228
        else if (op == GDALComputedRasterBand::Operation::OP_SUBTRACT &&
115✔
229
                 pSecondConstant)
230
        {
231
            m_aosOptions.SetNameValue("PixelFunctionType", "sum");
2✔
232
            m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
2✔
233
                                      CPLSPrintf("%.17g", -(*pSecondConstant)));
2✔
234
        }
235
        else if (op == GDALComputedRasterBand::Operation::OP_DIVIDE)
113✔
236
        {
237
            if (pSecondConstant)
6✔
238
            {
239
                m_aosOptions.SetNameValue("PixelFunctionType", "mul");
1✔
240
                m_aosOptions.SetNameValue(
241
                    "_PIXELFN_ARG_k",
242
                    CPLSPrintf("%.17g", 1.0 / (*pSecondConstant)));
1✔
243
            }
244
            else if (pFirstConstant)
5✔
245
            {
246
                m_aosOptions.SetNameValue("PixelFunctionType", "inv");
2✔
247
                m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
248
                                          CPLSPrintf("%.17g", *pFirstConstant));
2✔
249
            }
250
            else
251
            {
252
                m_aosOptions.SetNameValue("PixelFunctionType", "div");
3✔
253
            }
254
        }
255
        else if (op == GDALComputedRasterBand::Operation::OP_LOG)
107✔
256
        {
257
            CPLAssert(firstBand);
2✔
258
            CPLAssert(!secondBand);
2✔
259
            CPLAssert(!pFirstConstant);
2✔
260
            CPLAssert(!pSecondConstant);
2✔
261
            m_aosOptions.SetNameValue("PixelFunctionType", "expression");
2✔
262
            m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
263
                                      "log(source1)");
2✔
264
        }
265
        else if (op == GDALComputedRasterBand::Operation::OP_POW)
105✔
266
        {
267
            if (firstBand && secondBand)
6✔
268
            {
269
                m_aosOptions.SetNameValue("PixelFunctionType", "expression");
2✔
270
                m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
2✔
271
                                          "source1 ^ source2");
2✔
272
            }
273
            else if (firstBand && pSecondConstant)
4✔
274
            {
275
                m_aosOptions.SetNameValue("PixelFunctionType", "pow");
2✔
276
                m_aosOptions.SetNameValue(
2✔
277
                    "_PIXELFN_ARG_power",
278
                    CPLSPrintf("%.17g", *pSecondConstant));
2✔
279
            }
280
            else if (pFirstConstant && secondBand)
2✔
281
            {
282
                m_aosOptions.SetNameValue("PixelFunctionType", "exp");
2✔
283
                m_aosOptions.SetNameValue("_PIXELFN_ARG_base",
2✔
284
                                          CPLSPrintf("%.17g", *pFirstConstant));
2✔
285
            }
286
            else
287
            {
NEW
288
                CPLAssert(false);
×
289
            }
290
        }
291
        else
292
        {
293
            m_aosOptions.SetNameValue("PixelFunctionType",
294
                                      OperationToFunctionName(op));
99✔
295
            if (pSecondConstant)
99✔
296
                m_aosOptions.SetNameValue(
297
                    "_PIXELFN_ARG_k", CPLSPrintf("%.17g", *pSecondConstant));
62✔
298
        }
299
    }
300
    m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
274✔
301
    m_oVRTDS.AddBand(eDT, m_aosOptions.List());
274✔
302

303
    SetBand(1, poBand);
274✔
304

305
    AddSources(poBand);
274✔
306
}
274✔
307

308
/************************************************************************/
309
/*                        GDALComputedDataset()                         */
310
/************************************************************************/
311

312
GDALComputedDataset::GDALComputedDataset(
37✔
313
    GDALComputedRasterBand *poBand, int nXSize, int nYSize, GDALDataType eDT,
314
    int nBlockXSize, int nBlockYSize, GDALComputedRasterBand::Operation op,
315
    const std::vector<const GDALRasterBand *> &bands, double constant)
37✔
316
    : m_op(op), m_oVRTDS(nXSize, nYSize, nBlockXSize, nBlockYSize)
37✔
317
{
318
    for (const GDALRasterBand *poIterBand : bands)
132✔
319
        m_poBands.push_back(const_cast<GDALRasterBand *>(poIterBand));
95✔
320

321
    nRasterXSize = nXSize;
37✔
322
    nRasterYSize = nYSize;
37✔
323

324
    if (auto poSrcDS = m_poBands.front()->GetDataset())
37✔
325
    {
326
        GDALGeoTransform gt;
37✔
327
        if (poSrcDS->GetGeoTransform(gt) == CE_None)
37✔
328
        {
329
            m_oVRTDS.SetGeoTransform(gt);
16✔
330
        }
331

332
        if (const auto *poSRS = poSrcDS->GetSpatialRef())
37✔
333
        {
334
            m_oVRTDS.SetSpatialRef(poSRS);
16✔
335
        }
336
    }
337

338
    m_aosOptions.SetNameValue("subclass", "VRTDerivedRasterBand");
37✔
339
    if (op == GDALComputedRasterBand::Operation::OP_TERNARY)
37✔
340
    {
341
        m_aosOptions.SetNameValue("PixelFunctionType", "expression");
18✔
342
        m_aosOptions.SetNameValue("_PIXELFN_ARG_expression",
343
                                  "source1 ? source2 : source3");
18✔
344
    }
345
    else
346
    {
347
        m_aosOptions.SetNameValue("PixelFunctionType",
348
                                  OperationToFunctionName(op));
19✔
349
        if (!std::isnan(constant))
19✔
350
        {
351
            m_aosOptions.SetNameValue("_PIXELFN_ARG_k",
352
                                      CPLSPrintf("%.17g", constant));
8✔
353
        }
354
        m_aosOptions.SetNameValue("_PIXELFN_ARG_propagateNoData", "true");
19✔
355
    }
356
    m_oVRTDS.AddBand(eDT, m_aosOptions.List());
37✔
357

358
    SetBand(1, poBand);
37✔
359

360
    AddSources(poBand);
37✔
361
}
37✔
362

363
/************************************************************************/
364
/*                       ~GDALComputedDataset()                         */
365
/************************************************************************/
366

367
GDALComputedDataset::~GDALComputedDataset() = default;
368

369
/************************************************************************/
370
/*                       HaveAllBandsSameNoDataValue()                  */
371
/************************************************************************/
372

373
static bool HaveAllBandsSameNoDataValue(GDALRasterBand **apoBands,
909✔
374
                                        size_t nBands, bool &hasAtLeastOneNDV,
375
                                        double &singleNDV)
376
{
377
    hasAtLeastOneNDV = false;
909✔
378
    singleNDV = 0;
909✔
379

380
    int bFirstBandHasNoData = false;
909✔
381
    for (size_t i = 0; i < nBands; ++i)
2,221✔
382
    {
383
        int bHasNoData = false;
1,318✔
384
        const double dfNoData = apoBands[i]->GetNoDataValue(&bHasNoData);
1,318✔
385
        if (bHasNoData)
1,318✔
386
            hasAtLeastOneNDV = true;
18✔
387
        if (i == 0)
1,318✔
388
        {
389
            bFirstBandHasNoData = bHasNoData;
909✔
390
            singleNDV = dfNoData;
909✔
391
        }
392
        else if (bHasNoData != bFirstBandHasNoData)
409✔
393
        {
394
            return false;
6✔
395
        }
396
        else if (bFirstBandHasNoData &&
415✔
397
                 !((std::isnan(singleNDV) && std::isnan(dfNoData)) ||
8✔
398
                   (singleNDV == dfNoData)))
6✔
399
        {
400
            return false;
4✔
401
        }
402
    }
403
    return true;
903✔
404
}
405

406
/************************************************************************/
407
/*                  GDALComputedDataset::AddSources()                   */
408
/************************************************************************/
409

410
void GDALComputedDataset::AddSources(GDALComputedRasterBand *poBand)
794✔
411
{
412
    auto poSourcedRasterBand =
413
        cpl::down_cast<VRTSourcedRasterBand *>(m_oVRTDS.GetRasterBand(1));
794✔
414

415
    bool hasAtLeastOneNDV = false;
794✔
416
    double singleNDV = 0;
794✔
417
    const bool bSameNDV = HaveAllBandsSameNoDataValue(
794✔
418
        m_poBands.data(), m_poBands.size(), hasAtLeastOneNDV, singleNDV);
419

420
    // For inputs that are instances of GDALComputedDataset, clone them
421
    // to make sure we do not depend on temporary instances,
422
    // such as "a + b + c", which is evaluated as "(a + b) + c", and the
423
    // temporary band/dataset corresponding to a + b will go out of scope
424
    // quickly.
425
    for (GDALRasterBand *&band : m_poBands)
1,861✔
426
    {
427
        auto poDS = band->GetDataset();
1,067✔
428
        if (auto poComputedDS = dynamic_cast<GDALComputedDataset *>(poDS))
1,067✔
429
        {
430
            auto poComputedDSNew =
431
                std::make_unique<GDALComputedDataset>(*poComputedDS);
483✔
432
            band = poComputedDSNew->GetRasterBand(1);
483✔
433
            m_bandDS.emplace_back(poComputedDSNew.release());
483✔
434
        }
435

436
        int bHasNoData = false;
1,067✔
437
        const double dfNoData = band->GetNoDataValue(&bHasNoData);
1,067✔
438
        if (bHasNoData)
1,067✔
439
        {
440
            poSourcedRasterBand->AddComplexSource(band, -1, -1, -1, -1, -1, -1,
9✔
441
                                                  -1, -1, 0, 1, dfNoData);
442
        }
443
        else
444
        {
445
            poSourcedRasterBand->AddSimpleSource(band);
1,058✔
446
        }
447
        poSourcedRasterBand->papoSources[poSourcedRasterBand->nSources - 1]
1,067✔
448
            ->SetName(CPLSPrintf("source%d", poSourcedRasterBand->nSources));
1,067✔
449
    }
450
    if (hasAtLeastOneNDV)
794✔
451
    {
452
        poBand->m_bHasNoData = true;
5✔
453
        if (bSameNDV)
5✔
454
        {
455
            poBand->m_dfNoDataValue = singleNDV;
2✔
456
        }
457
        else
458
        {
459
            poBand->m_dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
3✔
460
        }
461
        poSourcedRasterBand->SetNoDataValue(poBand->m_dfNoDataValue);
5✔
462
    }
463
}
794✔
464

465
/************************************************************************/
466
/*                       OperationToFunctionName()                      */
467
/************************************************************************/
468

469
/* static */ const char *GDALComputedDataset::OperationToFunctionName(
277✔
470
    GDALComputedRasterBand::Operation op)
471
{
472
    const char *ret = "";
277✔
473
    switch (op)
277✔
474
    {
475
        case GDALComputedRasterBand::Operation::OP_ADD:
47✔
476
            ret = "sum";
47✔
477
            break;
47✔
478
        case GDALComputedRasterBand::Operation::OP_SUBTRACT:
3✔
479
            ret = "diff";
3✔
480
            break;
3✔
481
        case GDALComputedRasterBand::Operation::OP_MULTIPLY:
41✔
482
            ret = "mul";
41✔
483
            break;
41✔
484
        case GDALComputedRasterBand::Operation::OP_DIVIDE:
×
485
            ret = "div";
×
486
            break;
×
487
        case GDALComputedRasterBand::Operation::OP_MIN:
9✔
488
            ret = "min";
9✔
489
            break;
9✔
490
        case GDALComputedRasterBand::Operation::OP_MAX:
9✔
491
            ret = "max";
9✔
492
            break;
9✔
493
        case GDALComputedRasterBand::Operation::OP_MEAN:
2✔
494
            ret = "mean";
2✔
495
            break;
2✔
496
        case GDALComputedRasterBand::Operation::OP_GT:
13✔
497
            ret = ">";
13✔
498
            break;
13✔
499
        case GDALComputedRasterBand::Operation::OP_GE:
16✔
500
            ret = ">=";
16✔
501
            break;
16✔
502
        case GDALComputedRasterBand::Operation::OP_LT:
13✔
503
            ret = "<";
13✔
504
            break;
13✔
505
        case GDALComputedRasterBand::Operation::OP_LE:
14✔
506
            ret = "<=";
14✔
507
            break;
14✔
508
        case GDALComputedRasterBand::Operation::OP_EQ:
18✔
509
            ret = "==";
18✔
510
            break;
18✔
511
        case GDALComputedRasterBand::Operation::OP_NE:
20✔
512
            ret = "!=";
20✔
513
            break;
20✔
514
        case GDALComputedRasterBand::Operation::OP_LOGICAL_AND:
18✔
515
            ret = "&&";
18✔
516
            break;
18✔
517
        case GDALComputedRasterBand::Operation::OP_LOGICAL_OR:
23✔
518
            ret = "||";
23✔
519
            break;
23✔
520
        case GDALComputedRasterBand::Operation::OP_CAST:
24✔
521
        case GDALComputedRasterBand::Operation::OP_TERNARY:
522
            break;
24✔
523
        case GDALComputedRasterBand::Operation::OP_ABS:
3✔
524
            ret = "mod";
3✔
525
            break;
3✔
526
        case GDALComputedRasterBand::Operation::OP_SQRT:
2✔
527
            ret = "sqrt";
2✔
528
            break;
2✔
NEW
529
        case GDALComputedRasterBand::Operation::OP_LOG:
×
NEW
530
            ret = "log";
×
NEW
531
            break;
×
532
        case GDALComputedRasterBand::Operation::OP_LOG10:
2✔
533
            ret = "log10";
2✔
534
            break;
2✔
NEW
535
        case GDALComputedRasterBand::Operation::OP_POW:
×
NEW
536
            ret = "pow";
×
NEW
537
            break;
×
538
    }
539
    return ret;
277✔
540
}
541

542
/************************************************************************/
543
/*                       GDALComputedRasterBand()                       */
544
/************************************************************************/
545

546
GDALComputedRasterBand::GDALComputedRasterBand(
483✔
547
    const GDALComputedRasterBand &other, bool)
483✔
548
    : GDALRasterBand()
483✔
549
{
550
    nRasterXSize = other.nRasterXSize;
483✔
551
    nRasterYSize = other.nRasterYSize;
483✔
552
    eDataType = other.eDataType;
483✔
553
    nBlockXSize = other.nBlockXSize;
483✔
554
    nBlockYSize = other.nBlockYSize;
483✔
555
}
483✔
556

557
//! @cond Doxygen_Suppress
558

559
/************************************************************************/
560
/*                       GDALComputedRasterBand()                       */
561
/************************************************************************/
562

563
GDALComputedRasterBand::GDALComputedRasterBand(
37✔
564
    Operation op, const std::vector<const GDALRasterBand *> &bands,
565
    double constant)
37✔
566
{
567
    CPLAssert(op == Operation::OP_ADD || op == Operation::OP_MIN ||
37✔
568
              op == Operation::OP_MAX || op == Operation::OP_MEAN ||
569
              op == Operation::OP_TERNARY);
570

571
    CPLAssert(!bands.empty());
37✔
572
    nRasterXSize = bands[0]->GetXSize();
37✔
573
    nRasterYSize = bands[0]->GetYSize();
37✔
574
    eDataType = bands[0]->GetRasterDataType();
37✔
575
    for (size_t i = 1; i < bands.size(); ++i)
95✔
576
    {
577
        eDataType = GDALDataTypeUnion(eDataType, bands[i]->GetRasterDataType());
58✔
578
    }
579

580
    bool hasAtLeastOneNDV = false;
37✔
581
    double singleNDV = 0;
37✔
582
    const bool bSameNDV =
583
        HaveAllBandsSameNoDataValue(const_cast<GDALRasterBand **>(bands.data()),
37✔
584
                                    bands.size(), hasAtLeastOneNDV, singleNDV);
585

586
    if (!bSameNDV)
37✔
587
    {
588
        eDataType = eDataType == GDT_Float64 ? GDT_Float64 : GDT_Float32;
×
589
    }
590
    else if (op == Operation::OP_TERNARY)
37✔
591
    {
592
        CPLAssert(bands.size() == 3);
18✔
593
        eDataType = GDALDataTypeUnion(bands[1]->GetRasterDataType(),
18✔
594
                                      bands[2]->GetRasterDataType());
18✔
595
    }
596
    else if (!std::isnan(constant) && eDataType != GDT_Float64)
19✔
597
    {
598
        if (op == Operation::OP_MIN || op == Operation::OP_MAX)
4✔
599
        {
600
            eDataType = GDALDataTypeUnionWithValue(eDataType, constant, false);
4✔
601
        }
602
        else
603
        {
604
            eDataType = (static_cast<float>(constant) == constant)
×
605
                            ? GDT_Float32
×
606
                            : GDT_Float64;
607
        }
608
    }
609
    bands[0]->GetBlockSize(&nBlockXSize, &nBlockYSize);
37✔
610
    auto l_poDS = std::make_unique<GDALComputedDataset>(
611
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
37✔
612
        op, bands, constant);
74✔
613
    m_poOwningDS.reset(l_poDS.release());
37✔
614
}
37✔
615

616
/************************************************************************/
617
/*                       GDALComputedRasterBand()                       */
618
/************************************************************************/
619

620
GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
78✔
621
                                               const GDALRasterBand &firstBand,
622
                                               const GDALRasterBand &secondBand)
78✔
623
{
624
    nRasterXSize = firstBand.GetXSize();
78✔
625
    nRasterYSize = firstBand.GetYSize();
78✔
626

627
    bool hasAtLeastOneNDV = false;
78✔
628
    double singleNDV = 0;
78✔
629
    GDALRasterBand *apoBands[] = {const_cast<GDALRasterBand *>(&firstBand),
630
                                  const_cast<GDALRasterBand *>(&secondBand)};
78✔
631
    const bool bSameNDV =
632
        HaveAllBandsSameNoDataValue(apoBands, 2, hasAtLeastOneNDV, singleNDV);
78✔
633

634
    const auto firstDT = firstBand.GetRasterDataType();
78✔
635
    const auto secondDT = secondBand.GetRasterDataType();
78✔
636
    if (!bSameNDV)
78✔
637
        eDataType = (firstDT == GDT_Float64 || secondDT == GDT_Float64)
6✔
638
                        ? GDT_Float64
6✔
639
                        : GDT_Float32;
640
    else if (IsComparisonOperator(op))
75✔
641
        eDataType = GDT_Byte;
43✔
642
    else if (op == Operation::OP_ADD && firstDT == GDT_Byte &&
32✔
643
             secondDT == GDT_Byte)
644
        eDataType = GDT_UInt16;
2✔
645
    else if (firstDT == GDT_Float32 && secondDT == GDT_Float32)
30✔
646
        eDataType = GDT_Float32;
1✔
647
    else if ((op == Operation::OP_MIN || op == Operation::OP_MAX) &&
29✔
648
             firstDT == secondDT)
649
        eDataType = firstDT;
1✔
650
    else
651
        eDataType = GDT_Float64;
28✔
652
    firstBand.GetBlockSize(&nBlockXSize, &nBlockYSize);
78✔
653
    auto l_poDS = std::make_unique<GDALComputedDataset>(
654
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
78✔
655
        op, &firstBand, nullptr, &secondBand, nullptr);
156✔
656
    m_poOwningDS.reset(l_poDS.release());
78✔
657
}
78✔
658

659
/************************************************************************/
660
/*                       GDALComputedRasterBand()                       */
661
/************************************************************************/
662

663
GDALComputedRasterBand::GDALComputedRasterBand(Operation op, double constant,
22✔
664
                                               const GDALRasterBand &band)
22✔
665
{
666
    CPLAssert(op == Operation::OP_DIVIDE || IsComparisonOperator(op) ||
22✔
667
              op == Operation::OP_POW);
668

669
    nRasterXSize = band.GetXSize();
22✔
670
    nRasterYSize = band.GetYSize();
22✔
671
    const auto firstDT = band.GetRasterDataType();
22✔
672
    if (IsComparisonOperator(op))
22✔
673
        eDataType = GDT_Byte;
18✔
674
    else if (firstDT == GDT_Float32 && static_cast<float>(constant) == constant)
4✔
675
        eDataType = GDT_Float32;
×
676
    else
677
        eDataType = GDT_Float64;
4✔
678
    band.GetBlockSize(&nBlockXSize, &nBlockYSize);
22✔
679
    auto l_poDS = std::make_unique<GDALComputedDataset>(
680
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
22✔
681
        op, nullptr, &constant, &band, nullptr);
44✔
682
    m_poOwningDS.reset(l_poDS.release());
22✔
683
}
22✔
684

685
/************************************************************************/
686
/*                       GDALComputedRasterBand()                       */
687
/************************************************************************/
688

689
GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
141✔
690
                                               const GDALRasterBand &band,
691
                                               double constant)
141✔
692
{
693
    nRasterXSize = band.GetXSize();
141✔
694
    nRasterYSize = band.GetYSize();
141✔
695
    const auto firstDT = band.GetRasterDataType();
141✔
696
    if (IsComparisonOperator(op))
141✔
697
        eDataType = GDT_Byte;
74✔
698
    else if (op == Operation::OP_ADD && firstDT == GDT_Byte &&
67✔
699
             constant >= -128 && constant <= 127 &&
10✔
700
             std::floor(constant) == constant)
10✔
701
        eDataType = GDT_Byte;
10✔
702
    else if (firstDT == GDT_Float32 && static_cast<float>(constant) == constant)
57✔
703
        eDataType = GDT_Float32;
8✔
704
    else
705
        eDataType = GDT_Float64;
49✔
706
    band.GetBlockSize(&nBlockXSize, &nBlockYSize);
141✔
707
    auto l_poDS = std::make_unique<GDALComputedDataset>(
708
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
141✔
709
        op, &band, nullptr, nullptr, &constant);
282✔
710
    m_poOwningDS.reset(l_poDS.release());
141✔
711
}
141✔
712

713
/************************************************************************/
714
/*                       GDALComputedRasterBand()                       */
715
/************************************************************************/
716

717
GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
9✔
718
                                               const GDALRasterBand &band)
9✔
719
{
720
    CPLAssert(op == Operation::OP_ABS || op == Operation::OP_SQRT ||
9✔
721
              op == Operation::OP_LOG || op == Operation::OP_LOG10);
722
    nRasterXSize = band.GetXSize();
9✔
723
    nRasterYSize = band.GetYSize();
9✔
724
    eDataType =
9✔
725
        band.GetRasterDataType() == GDT_Float32 ? GDT_Float32 : GDT_Float64;
9✔
726
    band.GetBlockSize(&nBlockXSize, &nBlockYSize);
9✔
727
    auto l_poDS = std::make_unique<GDALComputedDataset>(
728
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
9✔
729
        op, &band, nullptr, nullptr, nullptr);
18✔
730
    m_poOwningDS.reset(l_poDS.release());
9✔
731
}
9✔
732

733
/************************************************************************/
734
/*                       GDALComputedRasterBand()                       */
735
/************************************************************************/
736

737
GDALComputedRasterBand::GDALComputedRasterBand(Operation op,
24✔
738
                                               const GDALRasterBand &band,
739
                                               GDALDataType dt)
24✔
740
{
741
    CPLAssert(op == Operation::OP_CAST);
24✔
742
    nRasterXSize = band.GetXSize();
24✔
743
    nRasterYSize = band.GetYSize();
24✔
744
    eDataType = dt;
24✔
745
    band.GetBlockSize(&nBlockXSize, &nBlockYSize);
24✔
746
    auto l_poDS = std::make_unique<GDALComputedDataset>(
747
        this, nRasterXSize, nRasterYSize, eDataType, nBlockXSize, nBlockYSize,
24✔
748
        op, &band, nullptr, nullptr, nullptr);
48✔
749
    m_poOwningDS.reset(l_poDS.release());
24✔
750
}
24✔
751

752
//! @endcond
753

754
/************************************************************************/
755
/*                      ~GDALComputedRasterBand()                       */
756
/************************************************************************/
757

758
GDALComputedRasterBand::~GDALComputedRasterBand()
1,440✔
759
{
760
    if (m_poOwningDS)
794✔
761
        cpl::down_cast<GDALComputedDataset *>(m_poOwningDS.get())->nBands = 0;
311✔
762
    poDS = nullptr;
794✔
763
}
1,440✔
764

765
/************************************************************************/
766
/*                  GDALComputedRasterBand::GetNoDataValue()            */
767
/************************************************************************/
768

769
double GDALComputedRasterBand::GetNoDataValue(int *pbHasNoData)
1,377✔
770
{
771
    if (pbHasNoData)
1,377✔
772
        *pbHasNoData = m_bHasNoData;
1,377✔
773
    return m_dfNoDataValue;
1,377✔
774
}
775

776
/************************************************************************/
777
/*                    GDALComputedRasterBandRelease()                   */
778
/************************************************************************/
779

780
/** Release a GDALComputedRasterBandH
781
 *
782
 * @since 3.12
783
 */
784
void GDALComputedRasterBandRelease(GDALComputedRasterBandH hBand)
163✔
785
{
786
    delete GDALComputedRasterBand::FromHandle(hBand);
163✔
787
}
163✔
788

789
/************************************************************************/
790
/*                           IReadBlock()                               */
791
/************************************************************************/
792

793
CPLErr GDALComputedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
239✔
794
                                          void *pData)
795
{
796
    auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
239✔
797
    return l_poDS->m_oVRTDS.GetRasterBand(1)->ReadBlock(nBlockXOff, nBlockYOff,
239✔
798
                                                        pData);
239✔
799
}
800

801
/************************************************************************/
802
/*                           IRasterIO()                                */
803
/************************************************************************/
804

805
CPLErr GDALComputedRasterBand::IRasterIO(
208✔
806
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
807
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
808
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
809
{
810
    auto l_poDS = cpl::down_cast<GDALComputedDataset *>(poDS);
208✔
811
    return l_poDS->m_oVRTDS.GetRasterBand(1)->RasterIO(
208✔
812
        eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
813
        eBufType, nPixelSpace, nLineSpace, psExtraArg);
208✔
814
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc