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

Generated by: LCOV version 1.14