Coverage Report

Created: 2025-06-13 06:29

/src/gdal/alg/marching_squares/level_generator.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  Marching square algorithm
4
 * Purpose:  Core algorithm implementation for contour line generation.
5
 * Author:   Oslandia <infos at oslandia dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2018, Oslandia <infos at oslandia dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
#ifndef MARCHING_SQUARE_LEVEL_GENERATOR_H
13
#define MARCHING_SQUARE_LEVEL_GENERATOR_H
14
15
#include <climits>
16
#include <vector>
17
#include <limits>
18
#include <cmath>
19
#include <cstdlib>
20
#include "utility.h"
21
22
namespace marching_squares
23
{
24
25
template <class Iterator> class Range
26
{
27
  public:
28
0
    Range(Iterator b, Iterator e) : begin_(b), end_(e)
29
0
    {
30
0
    }
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator> >::Range(marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>, marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>)
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator> >::Range(marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>, marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>)
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator> >::Range(marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>, marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>)
31
32
    Iterator begin() const
33
0
    {
34
0
        return begin_;
35
0
    }
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator> >::begin() const
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator> >::begin() const
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator> >::begin() const
36
37
    Iterator end() const
38
0
    {
39
0
        return end_;
40
0
    }
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator> >::end() const
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator> >::end() const
Unexecuted instantiation: marching_squares::Range<marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator> >::end() const
41
42
  private:
43
    Iterator begin_;
44
    Iterator end_;
45
};
46
47
template <typename LevelIterator> class RangeIterator
48
{
49
  public:
50
    RangeIterator(const LevelIterator &parent, int idx)
51
0
        : parent_(parent), idx_(idx)
52
0
    {
53
0
    }
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>::RangeIterator(marching_squares::ExponentialLevelRangeIterator const&, int)
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>::RangeIterator(marching_squares::IntervalLevelRangeIterator const&, int)
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>::RangeIterator(marching_squares::FixedLevelRangeIterator const&, int)
54
55
    // Warning: this is a "pseudo" iterator, since operator* returns a value,
56
    // not a reference. This means we cannot have operator->
57
    std::pair<int, double> operator*() const
58
0
    {
59
0
        return std::make_pair(idx_, parent_.level(idx_));
60
0
    }
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>::operator*() const
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>::operator*() const
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>::operator*() const
61
62
    bool operator!=(const RangeIterator &other) const
63
0
    {
64
0
        return idx_ != other.idx_;
65
0
    }
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>::operator!=(marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator> const&) const
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>::operator!=(marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator> const&) const
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>::operator!=(marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator> const&) const
66
67
    const RangeIterator &operator++()
68
0
    {
69
0
        idx_++;
70
0
        return *this;
71
0
    }
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::ExponentialLevelRangeIterator>::operator++()
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::IntervalLevelRangeIterator>::operator++()
Unexecuted instantiation: marching_squares::RangeIterator<marching_squares::FixedLevelRangeIterator>::operator++()
72
73
  private:
74
    const LevelIterator &parent_;
75
    int idx_;
76
};
77
78
class FixedLevelRangeIterator
79
{
80
  public:
81
    typedef RangeIterator<FixedLevelRangeIterator> Iterator;
82
83
    FixedLevelRangeIterator(const double *levels, size_t count, double minLevel,
84
                            double maxLevel)
85
0
        : levels_(levels), count_(count), minLevel_(minLevel),
86
0
          maxLevel_(maxLevel)
87
0
    {
88
0
    }
89
90
    Range<Iterator> range(double min, double max) const
91
0
    {
92
0
        if (min > max)
93
0
            std::swap(min, max);
94
0
        size_t b = 0;
95
0
        for (; b != count_ && levels_[b] < fudge(min, minLevel_, levels_[b]);
96
0
             b++)
97
0
            ;
98
0
        if (min == max)
99
0
            return Range<Iterator>(Iterator(*this, int(b)),
100
0
                                   Iterator(*this, int(b)));
101
0
        size_t e = b;
102
0
        for (; e != count_ && levels_[e] <= fudge(max, minLevel_, levels_[e]);
103
0
             e++)
104
0
            ;
105
0
        return Range<Iterator>(Iterator(*this, int(b)),
106
0
                               Iterator(*this, int(e)));
107
0
    }
108
109
    double level(int idx) const
110
0
    {
111
0
        if (idx >= int(count_))
112
0
            return maxLevel_;
113
0
        return levels_[size_t(idx)];
114
0
    }
115
116
    double minLevel() const
117
0
    {
118
0
        return minLevel_;
119
0
    }
120
121
    size_t levelsCount() const
122
0
    {
123
0
        return count_;
124
0
    }
125
126
  private:
127
    const double *levels_;
128
    size_t count_;
129
    const double minLevel_;
130
    const double maxLevel_;
131
};
132
133
#if defined(__clang__)
134
#pragma clang diagnostic push
135
#pragma clang diagnostic ignored "-Wweak-vtables"
136
#endif
137
138
struct TooManyLevelsException : public std::exception
139
{
140
    const char *what() const throw() override
141
0
    {
142
0
        return "Input values and/or interval settings would lead to too many "
143
0
               "levels";
144
0
    }
145
};
146
147
#if defined(__clang__)
148
#pragma clang diagnostic pop
149
#endif
150
151
// Arbitrary threshold to avoid too much computation time and memory
152
// consumption
153
constexpr int knMAX_NUMBER_LEVELS = 100 * 1000;
154
155
struct IntervalLevelRangeIterator
156
{
157
    typedef RangeIterator<IntervalLevelRangeIterator> Iterator;
158
159
    // Construction by a offset and an interval
160
    IntervalLevelRangeIterator(double offset, double interval, double minLevel)
161
0
        : offset_(offset), interval_(interval), minLevel_(minLevel)
162
0
    {
163
0
    }
164
165
    Range<Iterator> range(double min, double max) const
166
0
    {
167
0
        if (min > max)
168
0
            std::swap(min, max);
169
170
        // compute the min index, adjusted to the fudged value if needed
171
0
        double df_i1 = ceil((min - offset_) / interval_);
172
0
        if (!(df_i1 >= INT_MIN && df_i1 < INT_MAX))
173
0
            throw TooManyLevelsException();
174
0
        int i1 = static_cast<int>(df_i1);
175
0
        double l1 = fudge(min, minLevel_, level(i1));
176
0
        if (l1 > min)
177
0
        {
178
0
            df_i1 = ceil((l1 - offset_) / interval_);
179
0
            if (!(df_i1 >= INT_MIN && df_i1 < INT_MAX))
180
0
                throw TooManyLevelsException();
181
0
            i1 = static_cast<int>(df_i1);
182
0
        }
183
0
        Iterator b(*this, i1);
184
185
0
        if (min == max)
186
0
            return Range<Iterator>(b, b);
187
188
        // compute the max index, adjusted to the fudged value if needed
189
0
        double df_i2 = floor((max - offset_) / interval_) + 1;
190
0
        if (!(df_i2 >= INT_MIN && df_i2 < INT_MAX))
191
0
            throw TooManyLevelsException();
192
0
        int i2 = static_cast<int>(df_i2);
193
0
        double l2 = fudge(max, minLevel_, level(i2));
194
0
        if (l2 > max)
195
0
        {
196
0
            df_i2 = floor((l2 - offset_) / interval_) + 1;
197
0
            if (!(df_i2 >= INT_MIN && df_i2 < INT_MAX))
198
0
                throw TooManyLevelsException();
199
0
            i2 = static_cast<int>(df_i2);
200
0
        }
201
0
        Iterator e(*this, i2);
202
203
        // Arbitrary threshold to avoid too much computation time and memory
204
        // consumption
205
0
        if (i2 > i1 + static_cast<double>(knMAX_NUMBER_LEVELS))
206
0
            throw TooManyLevelsException();
207
208
0
        return Range<Iterator>(b, e);
209
0
    }
210
211
    double level(int idx) const
212
0
    {
213
0
        return idx * interval_ + offset_;
214
0
    }
215
216
    double minLevel() const
217
0
    {
218
0
        return minLevel_;
219
0
    }
220
221
  private:
222
    const double offset_;
223
    const double interval_;
224
    const double minLevel_;
225
};
226
227
class ExponentialLevelRangeIterator
228
{
229
  public:
230
    typedef RangeIterator<ExponentialLevelRangeIterator> Iterator;
231
232
    ExponentialLevelRangeIterator(double base, double minLevel)
233
0
        : base_(base), base_ln_(std::log(base_)), minLevel_(minLevel)
234
0
    {
235
0
    }
236
237
    double level(int idx) const
238
0
    {
239
0
        if (idx <= 0)
240
0
            return 0.0;
241
0
        return std::pow(base_, idx - 1);
242
0
    }
243
244
    Range<Iterator> range(double min, double max) const
245
0
    {
246
0
        if (min > max)
247
0
            std::swap(min, max);
248
249
0
        int i1 = index1(min);
250
0
        double l1 = fudge(min, minLevel_, level(i1));
251
0
        if (l1 > min)
252
0
            i1 = index1(l1);
253
0
        Iterator b(*this, i1);
254
255
0
        if (min == max)
256
0
            return Range<Iterator>(b, b);
257
258
0
        int i2 = index2(max);
259
0
        double l2 = fudge(max, minLevel_, level(i2));
260
0
        if (l2 > max)
261
0
            i2 = index2(l2);
262
0
        Iterator e(*this, i2);
263
264
        // Arbitrary threshold to avoid too much computation time and memory
265
        // consumption
266
0
        if (i2 > i1 + static_cast<double>(knMAX_NUMBER_LEVELS))
267
0
            throw TooManyLevelsException();
268
269
0
        return Range<Iterator>(b, e);
270
0
    }
271
272
    double minLevel() const
273
0
    {
274
0
        return minLevel_;
275
0
    }
276
277
  private:
278
    int index1(double plevel) const
279
0
    {
280
0
        if (plevel < 1.0)
281
0
            return 1;
282
0
        const double dfVal = ceil(std::log(plevel) / base_ln_) + 1;
283
0
        if (!(dfVal >= INT_MIN && dfVal < INT_MAX))
284
0
            throw TooManyLevelsException();
285
0
        return static_cast<int>(dfVal);
286
0
    }
287
288
    int index2(double plevel) const
289
0
    {
290
0
        if (plevel < 1.0)
291
0
            return 0;
292
0
        const double dfVal = floor(std::log(plevel) / base_ln_) + 1 + 1;
293
0
        if (!(dfVal >= INT_MIN && dfVal < INT_MAX))
294
0
            throw TooManyLevelsException();
295
0
        return static_cast<int>(dfVal);
296
0
    }
297
298
    // exponentiation base
299
    const double base_;
300
    const double base_ln_;
301
    const double minLevel_;
302
};
303
304
}  // namespace marching_squares
305
#endif