Scroom  0.14
linearsegment.hh
Go to the documentation of this file.
1 /*
2  * Scroom - Generic viewer for 2D data
3  * Copyright (C) 2009-2022 Kees-Jan Dijkzeul
4  *
5  * SPDX-License-Identifier: LGPL-2.1
6  */
7 
8 #pragma once
9 
10 #include <cmath>
11 #include <ostream>
12 #include <type_traits>
13 
14 #include <boost/operators.hpp>
15 
16 #include <scroom/rounding.hh>
17 
18 namespace Scroom::Utils
19 {
20  constexpr double epsilon = 1e-6;
21 
22  template <typename T>
23  bool isZero(T v);
24 
25  template <>
26  inline bool isZero<int>(int v)
27  {
28  return v == 0;
29  }
30 
31  template <>
32  inline bool isZero<double>(double v)
33  {
34  return std::abs(v) < epsilon;
35  }
36 
37  template <typename T>
38  bool areEqual(T a, T b)
39  {
40  return isZero(a - b);
41  }
42 
43  template <typename T>
44  class Segment
45  : public boost::addable2<Segment<T>, T>
46  , public boost::subtractable2<Segment<T>, T>
47  , public boost::multipliable2<Segment<T>, T>
48  , public boost::dividable2<Segment<T>, T>
49  , public boost::andable<Segment<T>>
50  {
51  public:
52  using value_type = T;
53 
55  : start(0)
56  , size(0)
57  {
58  }
59 
60  Segment(value_type start_, value_type size_)
61  : start(start_)
62  , size(size_)
63  {
64  normalize();
65  }
66 
68  template <bool T_is_int = std::is_same<int, typename std::remove_cv<T>::type>::value>
69  explicit Segment(typename std::enable_if<!T_is_int, Segment<int> const&>::type other)
70  : start(other.getStart())
71  , size(other.getSize())
72  {
73  }
74 
75  [[nodiscard]] Segment moveTo(value_type p) const { return Segment(p, size); }
76 
77  [[nodiscard]] bool contains(value_type p) const { return start <= p && p < (start + size); }
78 
79  [[nodiscard]] bool contains(const Segment<value_type>& other) const
80  {
81  return getStart() <= other.getStart() && other.getEnd() <= getEnd();
82  }
83 
84  [[nodiscard]] bool intersects(const Segment<value_type>& other) const
85  {
86  return getStart() < other.getEnd() && other.getStart() < getEnd() && !isEmpty() && !other.isEmpty();
87  }
88 
90 
91  [[nodiscard]] Segment<value_type> intersection(const Segment<value_type>& other) const
92  {
93  const value_type newStart = std::max(getStart(), other.getStart());
94  const value_type newEnd = std::min(getEnd(), other.getEnd());
95  const value_type newSize = newEnd - newStart;
96 
97  if(newSize >= 0)
98  {
99  return Segment<value_type>(newStart, newSize);
100  }
101 
102  return Segment<value_type>(); // empty segment
103  }
104 
105  void intersect(const Segment<value_type>& other) { *this = intersection(other); }
106 
107  [[nodiscard]] Segment<value_type> before(value_type v) const
108  {
109  if(v < start)
110  {
111  return Segment<value_type>();
112  }
113  if(v < start + size)
114  {
115  return Segment<value_type>(start, v - start);
116  }
117  return *this;
118  }
119 
120  [[nodiscard]] Segment<value_type> after(value_type v) const
121  {
122  if(v > start + size)
123  {
124  return Segment<value_type>();
125  }
126  if(v > start)
127  {
128  return Segment<value_type>(v, start + size - v);
129  }
130  return *this;
131  }
132 
133  [[nodiscard]] value_type getStart() const { return start; }
134 
135  [[nodiscard]] value_type getEnd() const { return start + size; }
136 
137  [[nodiscard]] value_type getSize() const { return size; }
138 
139  [[nodiscard]] bool isEmpty() const { return isZero(getSize()); }
140 
141  bool operator==(const Segment<value_type>& other) const
142  {
143  if(isEmpty() != other.isEmpty())
144  {
145  return false;
146  }
147 
148  if(isEmpty())
149  {
150  return true;
151  }
152 
153  return areEqual(start, other.start) && areEqual(size, other.size);
154  }
155 
156  bool operator!=(const Segment<value_type>& other) const { return !(*this == other); }
157 
159  {
160  start += n;
161  return *this;
162  }
164  {
165  start -= n;
166  return *this;
167  }
169  {
170  start *= n;
171  size *= n;
172  return *this;
173  }
175  {
176  start /= n;
177  size /= n;
178  return *this;
179  }
181  {
182  intersect(other);
183  return *this;
184  }
186  {
187  const auto end = getEnd();
188  start = n;
189  setEnd(end);
190  }
191  void setSize(value_type n) { size = n; }
193  {
194  size = n - start;
195  normalize();
196  }
197 
198  template <typename U>
199  [[nodiscard]] Segment<U> to() const
200  {
201  return {
202  static_cast<U>(start),
203  static_cast<U>(size),
204  };
205  }
206 
207  private:
208  void normalize()
209  {
210  if(size < 0)
211  {
212  start += size;
213  size = -size;
214  }
215  }
216 
217 
220  };
221 
222  template <typename T>
223  Segment<T> make_segment(T start, T size)
224  {
225  return Segment<T>(start, size);
226  }
227 
228  template <typename T>
230  {
231  return Segment<T>(start, end - start);
232  }
233 
234  template <typename T>
235  std::ostream& operator<<(std::ostream& os, const Segment<T>& s)
236  {
237  return os << '(' << s.getStart() << ',' << s.getSize() << ')';
238  }
239 
241  {
243  }
244 
245  template <typename T>
247  {
248  return s.getStart() + s.getSize() / 2;
249  }
250 
251 } // namespace Scroom::Utils
Scroom::Utils::isZero
bool isZero(T v)
round_up_to_multiple_of
T round_up_to_multiple_of(T value, T factor)
Definition: rounding.hh:38
Scroom::Utils::isZero< double >
bool isZero< double >(double v)
Definition: linearsegment.hh:32
Scroom::Utils
Definition: assertions.hh:14
round_down_to_multiple_of
T round_down_to_multiple_of(T value, T factor)
Definition: rounding.hh:44
Scroom::Utils::Segment::operator+=
Segment< value_type > & operator+=(value_type n)
Definition: linearsegment.hh:158
Scroom::Utils::Segment::contains
bool contains(value_type p) const
Definition: linearsegment.hh:77
Scroom::Utils::Segment::operator&=
Segment< value_type > & operator&=(const Segment< value_type > &other)
Definition: linearsegment.hh:180
Scroom::Utils::epsilon
constexpr double epsilon
Definition: linearsegment.hh:20
Scroom::Utils::Segment::getEnd
value_type getEnd() const
Definition: linearsegment.hh:135
Scroom::Utils::Segment::normalize
void normalize()
Definition: linearsegment.hh:208
Scroom::Utils::make_segment_from_start_end
Segment< T > make_segment_from_start_end(T start, T end)
Definition: linearsegment.hh:229
Scroom::Utils::Segment::value_type
T value_type
Definition: linearsegment.hh:52
Scroom::Utils::Segment::Segment
Segment()
Definition: linearsegment.hh:54
Scroom::Utils::Segment::operator==
bool operator==(const Segment< value_type > &other) const
Definition: linearsegment.hh:141
Scroom::Utils::Segment::operator-=
Segment< value_type > & operator-=(value_type n)
Definition: linearsegment.hh:163
Scroom::Utils::Segment::setSize
void setSize(value_type n)
Definition: linearsegment.hh:191
Scroom::Utils::Segment::operator/=
Segment< value_type > & operator/=(value_type n)
Definition: linearsegment.hh:174
Scroom::Utils::Segment::contains
bool contains(const Segment< value_type > &other) const
Definition: linearsegment.hh:79
Scroom::Utils::Segment::intersects
bool intersects(const Segment< value_type > &other) const
Definition: linearsegment.hh:84
Scroom::Utils::areEqual
bool areEqual(T a, T b)
Definition: linearsegment.hh:38
Scroom::Utils::isZero< int >
bool isZero< int >(int v)
Definition: linearsegment.hh:26
Scroom::Utils::Segment
Definition: linearsegment.hh:44
Scroom::Utils::Segment::reduceSizeToMultipleOf
void reduceSizeToMultipleOf(value_type m)
Definition: linearsegment.hh:89
Scroom::Utils::Segment::size
value_type size
Definition: linearsegment.hh:219
Scroom::Utils::Segment::start
value_type start
Definition: linearsegment.hh:218
Scroom::Utils::Segment::intersect
void intersect(const Segment< value_type > &other)
Definition: linearsegment.hh:105
b
static void b(const B::Ptr &)
Definition: gtkhelper-tests.cc:32
Scroom::Utils::Segment::to
Segment< U > to() const
Definition: linearsegment.hh:199
Scroom::Utils::Segment::Segment
Segment(value_type start_, value_type size_)
Definition: linearsegment.hh:60
Scroom::Utils::Segment::moveTo
Segment moveTo(value_type p) const
Definition: linearsegment.hh:75
Scroom::Utils::Segment::operator!=
bool operator!=(const Segment< value_type > &other) const
Definition: linearsegment.hh:156
Scroom::Utils::Segment::intersection
Segment< value_type > intersection(const Segment< value_type > &other) const
Definition: linearsegment.hh:91
Scroom::Utils::Segment::setEnd
void setEnd(value_type n)
Definition: linearsegment.hh:192
Scroom::Utils::make_segment
Segment< T > make_segment(T start, T size)
Definition: linearsegment.hh:223
Scroom::Utils::center
T center(Segment< T > s)
Definition: linearsegment.hh:246
Scroom::Utils::Segment::getStart
value_type getStart() const
Definition: linearsegment.hh:133
Scroom::Utils::operator<<
std::ostream & operator<<(std::ostream &os, const Segment< T > &s)
Definition: linearsegment.hh:235
Scroom::Utils::roundOutward
Segment< double > roundOutward(Segment< double > s)
Definition: linearsegment.hh:240
Scroom::Utils::Segment::isEmpty
bool isEmpty() const
Definition: linearsegment.hh:139
Scroom::Utils::Segment::getSize
value_type getSize() const
Definition: linearsegment.hh:137
Scroom::Utils::Segment::Segment
Segment(typename std::enable_if<!T_is_int, Segment< int > const & >::type other)
Definition: linearsegment.hh:69
Scroom::Utils::Segment::operator*=
Segment< value_type > & operator*=(value_type n)
Definition: linearsegment.hh:168
rounding.hh
Scroom::Utils::Segment::before
Segment< value_type > before(value_type v) const
Definition: linearsegment.hh:107
Scroom::Utils::Segment::after
Segment< value_type > after(value_type v) const
Definition: linearsegment.hh:120
Scroom::Utils::Segment::setStart
void setStart(value_type n)
Definition: linearsegment.hh:185