LCOV - code coverage report
Current view: top level - alg/marching_squares - level_generator.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 102 116 87.9 %
Date: 2025-01-18 12:42:00 Functions: 36 36 100.0 %

          Line data    Source code
       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      829288 :     Range(Iterator b, Iterator e) : begin_(b), end_(e)
      29             :     {
      30      829288 :     }
      31             : 
      32     1632637 :     Iterator begin() const
      33             :     {
      34     1632637 :         return begin_;
      35             :     }
      36             : 
      37      830047 :     Iterator end() const
      38             :     {
      39      830047 :         return end_;
      40             :     }
      41             : 
      42             :   private:
      43             :     Iterator begin_;
      44             :     Iterator end_;
      45             : };
      46             : 
      47             : template <typename LevelIterator> class RangeIterator
      48             : {
      49             :   public:
      50     1658363 :     RangeIterator(const LevelIterator &parent, int idx)
      51     1658363 :         : parent_(parent), idx_(idx)
      52             :     {
      53     1658363 :     }
      54             : 
      55             :     // Warning: this is a "pseudo" iterator, since operator* returns a value,
      56             :     // not a reference. This means we cannot have operator->
      57      217521 :     std::pair<int, double> operator*() const
      58             :     {
      59      217521 :         return std::make_pair(idx_, parent_.level(idx_));
      60             :     }
      61             : 
      62      917356 :     bool operator!=(const RangeIterator &other) const
      63             :     {
      64      917356 :         return idx_ != other.idx_;
      65             :     }
      66             : 
      67      978732 :     const RangeIterator &operator++()
      68             :     {
      69      978732 :         idx_++;
      70      978732 :         return *this;
      71             :     }
      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          49 :     FixedLevelRangeIterator(const double *levels, size_t count, double minLevel,
      84             :                             double maxLevel)
      85          49 :         : levels_(levels), count_(count), minLevel_(minLevel),
      86          49 :           maxLevel_(maxLevel)
      87             :     {
      88          49 :     }
      89             : 
      90      828901 :     Range<Iterator> range(double min, double max) const
      91             :     {
      92      828901 :         if (min > max)
      93        1573 :             std::swap(min, max);
      94      828901 :         size_t b = 0;
      95     2199784 :         for (; b != count_ && levels_[b] < fudge(min, minLevel_, levels_[b]);
      96             :              b++)
      97             :             ;
      98      828901 :         if (min == max)
      99             :             return Range<Iterator>(Iterator(*this, int(b)),
     100      714535 :                                    Iterator(*this, int(b)));
     101      114366 :         size_t e = b;
     102      201731 :         for (; e != count_ && levels_[e] <= fudge(max, minLevel_, levels_[e]);
     103             :              e++)
     104             :             ;
     105             :         return Range<Iterator>(Iterator(*this, int(b)),
     106      114366 :                                Iterator(*this, int(e)));
     107             :     }
     108             : 
     109      221345 :     double level(int idx) const
     110             :     {
     111      221345 :         if (idx >= int(count_))
     112        1399 :             return maxLevel_;
     113      219946 :         return levels_[size_t(idx)];
     114             :     }
     115             : 
     116       87364 :     double minLevel() const
     117             :     {
     118       87364 :         return minLevel_;
     119             :     }
     120             : 
     121          23 :     size_t levelsCount() const
     122             :     {
     123          23 :         return count_;
     124             :     }
     125             : 
     126             :   private:
     127             :     const double *levels_;
     128             :     size_t count_;
     129             :     const double minLevel_;
     130             :     const double maxLevel_;
     131             : };
     132             : 
     133             : struct TooManyLevelsException : public std::exception
     134             : {
     135           4 :     const char *what() const throw() override
     136             :     {
     137             :         return "Input values and/or interval settings would lead to too many "
     138           4 :                "levels";
     139             :     }
     140             : };
     141             : 
     142             : // Arbitrary threshold to avoid too much computation time and memory
     143             : // consumption
     144             : constexpr int knMAX_NUMBER_LEVELS = 100 * 1000;
     145             : 
     146             : struct IntervalLevelRangeIterator
     147             : {
     148             :     typedef RangeIterator<IntervalLevelRangeIterator> Iterator;
     149             : 
     150             :     // Construction by a offset and an interval
     151          42 :     IntervalLevelRangeIterator(double offset, double interval, double minLevel)
     152          42 :         : offset_(offset), interval_(interval), minLevel_(minLevel)
     153             :     {
     154          42 :     }
     155             : 
     156         383 :     Range<Iterator> range(double min, double max) const
     157             :     {
     158         383 :         if (min > max)
     159          25 :             std::swap(min, max);
     160             : 
     161             :         // compute the min index, adjusted to the fudged value if needed
     162         383 :         double df_i1 = ceil((min - offset_) / interval_);
     163         383 :         if (!(df_i1 >= INT_MIN && df_i1 < INT_MAX))
     164           0 :             throw TooManyLevelsException();
     165         383 :         int i1 = static_cast<int>(df_i1);
     166         383 :         double l1 = fudge(min, minLevel_, level(i1));
     167         383 :         if (l1 > min)
     168             :         {
     169          28 :             df_i1 = ceil((l1 - offset_) / interval_);
     170          28 :             if (!(df_i1 >= INT_MIN && df_i1 < INT_MAX))
     171           0 :                 throw TooManyLevelsException();
     172          28 :             i1 = static_cast<int>(df_i1);
     173             :         }
     174         383 :         Iterator b(*this, i1);
     175             : 
     176         383 :         if (min == max)
     177         220 :             return Range<Iterator>(b, b);
     178             : 
     179             :         // compute the max index, adjusted to the fudged value if needed
     180         163 :         double df_i2 = floor((max - offset_) / interval_) + 1;
     181         163 :         if (!(df_i2 >= INT_MIN && df_i2 < INT_MAX))
     182           1 :             throw TooManyLevelsException();
     183         162 :         int i2 = static_cast<int>(df_i2);
     184         162 :         double l2 = fudge(max, minLevel_, level(i2));
     185         162 :         if (l2 > max)
     186             :         {
     187           0 :             df_i2 = floor((l2 - offset_) / interval_) + 1;
     188           0 :             if (!(df_i2 >= INT_MIN && df_i2 < INT_MAX))
     189           0 :                 throw TooManyLevelsException();
     190           0 :             i2 = static_cast<int>(df_i2);
     191             :         }
     192         162 :         Iterator e(*this, i2);
     193             : 
     194             :         // Arbitrary threshold to avoid too much computation time and memory
     195             :         // consumption
     196         162 :         if (i2 > i1 + static_cast<double>(knMAX_NUMBER_LEVELS))
     197           1 :             throw TooManyLevelsException();
     198             : 
     199         161 :         return Range<Iterator>(b, e);
     200             :     }
     201             : 
     202        1600 :     double level(int idx) const
     203             :     {
     204        1600 :         return idx * interval_ + offset_;
     205             :     }
     206             : 
     207          79 :     double minLevel() const
     208             :     {
     209          79 :         return minLevel_;
     210             :     }
     211             : 
     212             :   private:
     213             :     const double offset_;
     214             :     const double interval_;
     215             :     const double minLevel_;
     216             : };
     217             : 
     218             : class ExponentialLevelRangeIterator
     219             : {
     220             :   public:
     221             :     typedef RangeIterator<ExponentialLevelRangeIterator> Iterator;
     222             : 
     223           8 :     ExponentialLevelRangeIterator(double base, double minLevel)
     224           8 :         : base_(base), base_ln_(std::log(base_)), minLevel_(minLevel)
     225             :     {
     226           8 :     }
     227             : 
     228          34 :     double level(int idx) const
     229             :     {
     230          34 :         if (idx <= 0)
     231           0 :             return 0.0;
     232          34 :         return std::pow(base_, idx - 1);
     233             :     }
     234             : 
     235           8 :     Range<Iterator> range(double min, double max) const
     236             :     {
     237           8 :         if (min > max)
     238           0 :             std::swap(min, max);
     239             : 
     240           8 :         int i1 = index1(min);
     241           8 :         double l1 = fudge(min, minLevel_, level(i1));
     242           8 :         if (l1 > min)
     243           0 :             i1 = index1(l1);
     244           8 :         Iterator b(*this, i1);
     245             : 
     246           8 :         if (min == max)
     247           0 :             return Range<Iterator>(b, b);
     248             : 
     249           8 :         int i2 = index2(max);
     250           8 :         double l2 = fudge(max, minLevel_, level(i2));
     251           8 :         if (l2 > max)
     252           0 :             i2 = index2(l2);
     253           8 :         Iterator e(*this, i2);
     254             : 
     255             :         // Arbitrary threshold to avoid too much computation time and memory
     256             :         // consumption
     257           8 :         if (i2 > i1 + static_cast<double>(knMAX_NUMBER_LEVELS))
     258           2 :             throw TooManyLevelsException();
     259             : 
     260           6 :         return Range<Iterator>(b, e);
     261             :     }
     262             : 
     263             :     double minLevel() const
     264             :     {
     265             :         return minLevel_;
     266             :     }
     267             : 
     268             :   private:
     269           8 :     int index1(double plevel) const
     270             :     {
     271           8 :         if (plevel < 1.0)
     272           3 :             return 1;
     273           5 :         const double dfVal = ceil(std::log(plevel) / base_ln_) + 1;
     274           5 :         if (!(dfVal >= INT_MIN && dfVal < INT_MAX))
     275           0 :             throw TooManyLevelsException();
     276           5 :         return static_cast<int>(dfVal);
     277             :     }
     278             : 
     279           8 :     int index2(double plevel) const
     280             :     {
     281           8 :         if (plevel < 1.0)
     282           0 :             return 0;
     283           8 :         const double dfVal = floor(std::log(plevel) / base_ln_) + 1 + 1;
     284           8 :         if (!(dfVal >= INT_MIN && dfVal < INT_MAX))
     285           0 :             throw TooManyLevelsException();
     286           8 :         return static_cast<int>(dfVal);
     287             :     }
     288             : 
     289             :     // exponentiation base
     290             :     const double base_;
     291             :     const double base_ln_;
     292             :     const double minLevel_;
     293             : };
     294             : 
     295             : }  // namespace marching_squares
     296             : #endif

Generated by: LCOV version 1.14