Coverage Report

Created: 2025-06-13 06:29

/src/gdal/frmts/vrt/vrtreclassifier.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
*
3
 * Project:  Virtual GDAL Datasets
4
 * Purpose:  Implementation of Reclassifier
5
 * Author:   Daniel Baston
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2025, ISciences LLC
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#pragma once
14
15
#include "gdal.h"
16
#include "cpl_error.h"
17
18
#include <map>
19
#include <optional>
20
#include <utility>
21
#include <vector>
22
23
namespace gdal
24
{
25
26
/**
27
 * Class to manage reclassification of pixel values
28
 */
29
class Reclassifier
30
{
31
  public:
32
    /// Character separating elements in a list of mapping
33
    static constexpr char MAPPING_INTERVAL_SEP_CHAR = ';';
34
35
    /// Character separating source interval from target value
36
    static constexpr char MAPPING_FROMTO_SEP_CHAR = '=';
37
38
    /**
39
     * Internal struct to hold an interval of values to be reclassified
40
     */
41
    struct Interval
42
    {
43
        /// minimum value of range
44
        double dfMin;
45
46
        /// maximum value of range
47
        double dfMax;
48
49
        /// Set the interval to represent a single value [x,x]
50
        void SetToConstant(double dfVal);
51
52
        /** Parse an interval. The interval may be either a single constant value,
53
         *  or two comma-separated values enclosed by parentheses/brackets to
54
         *  represent open/closed intervals.
55
         *
56
         * @param pszText string from which to parse an interval
57
         * @param end pointer to first non-consumed character
58
         * @return CE_None on success, CE_Failure otherwise
59
         */
60
        CPLErr Parse(const char *pszText, char **end);
61
62
        /// Returns true of the interval represents a single value [x,x]
63
        bool IsConstant() const
64
0
        {
65
0
            return dfMin == dfMax;
66
0
        }
67
68
        /// Returns true if the interval contains a value
69
        bool Contains(double x) const
70
0
        {
71
0
            return x >= dfMin && x <= dfMax;
72
0
        }
73
74
        /// Returns true if the intervals overlap
75
        bool Overlaps(const Interval &other) const;
76
    };
77
78
    /** Initialize a Reclassifier from text. The text consists of a series of
79
     *  SOURCE=DEST mappings, separated by a semicolon.
80
     *
81
     *  Each SOURCE element much be one of:
82
     *  - a constant value
83
     *  - a range of values, such as (3, 4] or [7, inf]
84
     *  - the value NO_DATA, for which the provided NoData value will be
85
     *    substituted
86
     *  - the value DEFAULT, to define a DEST for any value that does not
87
     *    match another SOURCE mapping
88
     *
89
     *  Each DEST element must be one of:
90
     *  - a constant value
91
     *  - the value NO_DATA, for which the provided NoData value will be
92
     *    substituted
93
     *
94
     *  An error will be returned if:
95
     *  - NO_DATA is used by a NoData value is not defined.
96
     *  - a DEST value does not fit into the destination data type
97
     *
98
     * @param pszText text to parse
99
     * @param noDataValue NoData value
100
     * @param eBufType Destination data type
101
     * @return CE_None if no errors occurred, CE_Failure otherwise
102
     */
103
    CPLErr Init(const char *pszText, std::optional<double> noDataValue,
104
                GDALDataType eBufType);
105
106
    /** Set a mapping between an interval and (optionally) a destination value.
107
     *  If no destination value is provided, values matching the interval
108
     *  will be passed through unmodified. It will not be verified that these values
109
     *  fit within the destination data type.
110
     */
111
    void AddMapping(const Interval &interval, std::optional<double> dfDstVal);
112
113
    /** Reclassify a value
114
     *
115
     * @param srcVal the value to reclassify
116
     * @param bFoundInterval set to True if the value could be reclassified
117
     * @return the reclassified value
118
     */
119
    double Reclassify(double srcVal, bool &bFoundInterval) const;
120
121
    /** If true, values not matched by any interval will be
122
     *  returned unmodified. It will not be verified that these values
123
     *  fit within the destination data type.
124
     */
125
    void SetDefaultPassThrough(bool value)
126
0
    {
127
0
        m_defaultPassThrough = value;
128
0
    }
129
130
    /** Sets a default value for any value not matched by any interval.
131
     */
132
    void SetDefaultValue(double value)
133
0
    {
134
0
        m_defaultValue = value;
135
0
    }
136
137
    /** Sets a value for an input NaN value
138
     */
139
    void SetNaNValue(double value)
140
0
    {
141
0
        m_NaNValue = value;
142
0
    }
143
144
    /** Prepare reclassifier for use. No more mappings may be added.
145
     */
146
    CPLErr Finalize();
147
148
  private:
149
    /// mapping of ranges to outputs
150
    std::vector<std::pair<Interval, std::optional<double>>>
151
        m_aoIntervalMappings{};
152
153
    /// output value for NaN inputs
154
    std::optional<double> m_NaNValue{};
155
156
    /// output value for inputs not matching any Interval
157
    std::optional<double> m_defaultValue{};
158
159
    /// whether to pass unmatched inputs through unmodified
160
    bool m_defaultPassThrough{false};
161
};
162
163
}  // namespace gdal