farm-ng-core
region.h
Go to the documentation of this file.
1 
2 // Copyright (c) 2011, Hauke Strasdat
3 // Copyright (c) 2012, Steven Lovegrove
4 // Copyright (c) 2021, farm-ng, inc.
5 //
6 // Use of this source code is governed by an MIT-style
7 // license that can be found in the LICENSE file or at
8 // https://opensource.org/licenses/MIT.
9 
10 #pragma once
11 
12 #include "sophus/common/common.h"
15 
16 namespace sophus {
17 
18 template <concepts::PointType TPoint>
19 class Region;
20 
24 
25 template <concepts::ScalarType TScalar>
30 
31 template <concepts::ScalarType TScalar>
36 
37 template <concepts::ScalarType TScalar>
42 
43 /// A region is a closed interval [a, b] with a being the lower bound (=min) and
44 /// b being the upper bound (=max).
45 ///
46 /// Here, the bounds a, b sre either both scalars (e.g. floats, doubles)
47 /// or fixed length vectors/arrays (such as Eigen::Vector3f or Eigen::Array2d).
48 ///
49 /// Special case for integer numbers:
50 ///
51 /// An integer number X is considered being equivalent to a real region
52 /// [X-0.5, X+0.5].
53 template <concepts::PointType TPoint>
54 class Region {
55  public:
57  using Point = TPoint;
59 
60  static int constexpr kRows = PointTraits<TPoint>::kRows;
61  static int constexpr kCols = PointTraits<TPoint>::kCols;
62  static_assert(kRows >= 1);
63  static_assert(kCols >= 1);
64  static int constexpr kDim = kRows * kCols;
65 
66  /// Creates an uninitialized region.
67  static auto uninitialized() noexcept -> Region<TPoint> {
68  return Region(UninitTag{});
69  }
70 
71  /// Creates and empty region.
72  static auto empty() noexcept -> Region<TPoint> {
74  region.min_max_ = {
76  return region;
77  }
78 
79  /// Creates unbounded region.
80  ///
81  /// If TPoint is floating point, the region is [-inf, +inf].
82  static auto unbounded() noexcept -> Region<TPoint> {
84  region.min_max_ = {
86  return region;
87  }
88 
89  /// Creates a region from a given point.
90  ///
91  /// If TPoint is a floating point then the region is considered degenerated.
92  static auto from(TPoint const& p) noexcept -> Region<TPoint> {
94  SOPHUS_ASSERT(!isNan(p));
95  region.min_max_[0] = p;
96  region.min_max_[1] = p;
97  return region;
98  }
99 
100  /// Creates Region from two points, min and max.
101  ///
102  /// The points min, max need not to be ordered. After construction it will be
103  /// true that this->min() <= this->max().
104  static auto fromMinMax(TPoint const& min, TPoint const& max) noexcept
105  -> Region<TPoint> {
106  auto region = Region<TPoint>::empty();
109  region.extend(min);
110  region.extend(max);
111  return region;
112  }
113 
114  /// Convenient constructor to create a Segment from two points p1 and p2.
115  ///
116  /// The points need not to be ordered. After construction it will be true
117  /// that this->min() <= this->max().
118  ///
119  /// Note: This constructor is only available for scalar regions. For
120  /// multi-dim regions, use the fromMinMax() factory instead.,
121  template <class TScalar>
122  requires std::is_same_v<TPoint, TScalar> Region(
123  TScalar const& p1, TScalar const& p2)
124  noexcept : min_max_{p1, p1} {
125  SOPHUS_ASSERT(!isNan(p1));
126  SOPHUS_ASSERT(!isNan(p2));
127  this->extend(p2);
128  }
129 
130  template <class TScalar>
131  requires(kDim == 2) static auto createPerAxis(
132  Region<TScalar> const& segment_x,
133  Region<TScalar> const& segment_y) noexcept -> Region2<TScalar> {
135  region.setElem(segment_x, 0);
136  region.setElem(segment_y, 1);
137  return region;
138  }
139 
140  template <class TScalar>
141  requires(kDim == 3) static auto createPerAxis(
142  Region<TScalar> const& segment_x,
143  Region<TScalar> const& segment_y,
144  Region<TScalar> const& segment_z) noexcept -> Region2<TScalar> {
146  region.setElem(segment_x, 0);
147  region.setElem(segment_y, 1);
148  region.setElem(segment_z, 2);
149  return region;
150  }
151 
152  template <class TScalar>
153  requires(kDim == 4) static auto createPerAxis(
154  Region<TScalar> const& segment_x,
155  Region<TScalar> const& segment_y,
156  Region<TScalar> const& segment_z,
157  Region<TScalar> const& segment_w) noexcept -> Region2<TScalar> {
159  region.setElem(segment_x, 0);
160  region.setElem(segment_y, 1);
161  region.setElem(segment_z, 2);
162  region.setElem(segment_w, 3);
163  return region;
164  }
165 
166  /// Precondition: !this->isEmptpy()
167  [[nodiscard]] auto getElem(size_t row) const -> Region<Scalar> const& {
168  return {
169  SOPHUS_UNWRAP(tryGetElem(min(), row)),
170  SOPHUS_UNWRAP(tryGetElem(max(), row))};
171  }
172 
173  /// Precondition: !this->isEmptpy()
174  void setElem(size_t row, Region<Scalar> const& s) {
175  SOPHUS_UNWRAP(trySetElem(min(), s, row));
176  SOPHUS_UNWRAP(trySetElem(max(), s, row));
177  }
178 
179  /// Returns the lower bound of the region.
180  ///
181  /// Precondition: !this->isEmptpy()
182  [[nodiscard]] auto min() const noexcept -> TPoint const& {
183  SOPHUS_ASSERT(!this->isEmpty());
184  return min_max_[0];
185  }
186 
187  /// Returns the upper bound of the region.
188  ///
189  /// Precondition: !this->isEmptpy()
190  [[nodiscard]] auto max() const noexcept -> TPoint const& {
191  SOPHUS_ASSERT(!this->isEmpty());
192  return min_max_[1];
193  }
194 
195  /// Returns the lower bound of the region if it exit and nullopt otherwise.
196  [[nodiscard]] auto tryMin() const noexcept -> std::optional<TPoint> {
197  if (isEmpty()) {
198  return std::nullopt;
199  }
200  return min_max_[0];
201  }
202 
203  /// Returns the lower bound of the region if it exists and nullopt otherwise.
204  [[nodiscard]] auto tryMax() const noexcept -> std::optional<TPoint> {
205  if (isEmpty()) {
206  return std::nullopt;
207  }
208  return min_max_[1];
209  }
210 
211  /// Returns the clamped version of the given point.
212  ///
213  /// Precondition: !this->isEmptpy()
214  [[nodiscard]] auto clamp(TPoint const& point) const noexcept -> TPoint {
215  return sophus::clamp(point, min(), max());
216  }
217 
218  /// Returns true if the region contains the given point.
219  [[nodiscard]] auto contains(TPoint const& point) const noexcept -> bool {
220  if (isEmpty()) {
221  return false;
222  }
223  return isLessEqual(min(), point) && isLessEqual(point, max());
224  }
225 
226  /// Returns the range of the region.
227  ///
228  /// It is zero if the region is not proper.
229  [[nodiscard]] auto range() const noexcept -> TPoint {
230  if (isEmpty()) {
231  return zero<TPoint>();
232  }
233  if constexpr (kIsInteger) {
234  // For integers, we consider e.g. {2} == [1.5, 2.5] hence range of
235  // Region(2, 3) == [1.5, 3.5] is 2.
236  return plus(eval(max() - min()), 1);
237  }
238  return eval(max() - min());
239  }
240 
241  /// Returns the mid point.
242  ///
243  /// Note: If TPoint is an integer point then the result will be rounded to
244  /// the closed integer.
245  ///
246  /// Precondition: !this->isEmptpy()
247  [[nodiscard]] auto mid() const noexcept -> TPoint {
248  return eval(min() + range() / 2);
249  }
250 
251  /// Extends this by other region.
252  auto extend(Region const& other) noexcept -> Region<TPoint>& {
253  if (other.isEmpty()) {
254  return *this;
255  }
256  if (this->isEmpty()) {
257  *this = other;
258  return *this;
259  }
260  min_max_[0] = sophus::min(min(), other.min());
261  min_max_[1] = sophus::max(max(), other.max());
262  return *this;
263  }
264 
265  /// Extends this by given point.
266  auto extend(TPoint const& point) noexcept -> Region<TPoint>& {
267  if (this->isEmpty()) {
268  *this = from(point);
269  } else {
270  min_max_[0] = sophus::min(min(), point);
271  min_max_[1] = sophus::max(max(), point);
272  }
273  return *this;
274  }
275 
276  /// Returns translated region.
277  [[nodiscard]] auto translated(TPoint const& p) const noexcept
278  -> Region<TPoint> {
279  return Region<TPoint>::fromMinMax(min_max_[0] + p, min_max_[1] + p);
280  }
281 
282  template <class TOtherPoint>
283  auto cast() const noexcept -> Region<TOtherPoint> {
284  if (isEmpty()) {
286  }
287  if constexpr (kIsInteger == Region<TOtherPoint>::kIsInteger) {
288  // case 1: floating => floating and integer => integer is trivial
289  return Region<TOtherPoint>(
290  sophus::cast<TOtherPoint>(min()), sophus::cast<TOtherPoint>(max()));
291  }
292  if constexpr (kIsInteger && !Region<TOtherPoint>::kIsInteger) {
293  // case 2: integer to floating.
294  //
295  // example: [2, 5] -> [1.5, 5.5]
296  return Region<TOtherPoint>(
297  plus(sophus::cast<TOtherPoint>(min()), -0.5),
298  plus(sophus::cast<TOtherPoint>(max()), 0.5));
299  }
300  // case 3: floating to integer.
301  static_assert(
303  "For floating to integer: call encloseCast() or roundCast() "
304  "instead.");
305  }
306 
307  /// Returns the smallest integer region which contains this.
308  ///
309  /// example: [1.2, 1.3] -> [1, 2]
310  template <class TOtherPoint>
311  auto encloseCast() const noexcept -> Region<TOtherPoint> {
312  static_assert(!kIsInteger && Region<TOtherPoint>::kIsInteger);
313  if (isEmpty()) {
315  }
316  return Region<TOtherPoint>(
317  sophus::cast<TOtherPoint>(sophus::floor(min())),
318  sophus::cast<TOtherPoint>(sophus::ceil(max())));
319  }
320 
321  /// Rounds given region bounds and returns resulting integer region.
322  ///
323  /// example: [1.2, 2.3] -> [1, 2]
324  /// example: [1.1, 2.7] -> [1, 3]
325  template <class TOtherPoint>
326  auto roundCast() const noexcept -> Region<TOtherPoint> {
327  if (isEmpty()) {
329  }
330  static_assert(!kIsInteger && Region<TOtherPoint>::kIsInteger);
331  return Region<TOtherPoint>(
332  sophus::cast<TOtherPoint>(sophus::round(min())),
333  sophus::cast<TOtherPoint>(sophus::round(max())));
334  }
335 
336  /// Returns true if region is empty.
337  [[nodiscard]] auto isEmpty() const noexcept -> bool {
338  return allTrue(min_max_[0] == PointTraits<TPoint>::max()) &&
339  allTrue(min_max_[1] == PointTraits<TPoint>::lowest());
340  }
341 
342  /// Returns true if region contains a single floating point number.
343  [[nodiscard]] auto isDegenerated() const noexcept -> bool {
344  return !kIsInteger && allTrue(min_max_[0] == min_max_[1]);
345  }
346 
347  /// Returns true if region is neither empty nor degenerated.
348  /// Hence it contains a range of values.
349  [[nodiscard]] auto isProper() const noexcept -> bool {
350  return !this->isEmpty() && !this->isDegenerated();
351  }
352 
353  /// Returns true if region has no bounds.
354  [[nodiscard]] auto isUnbounded() const noexcept -> bool {
355  return allTrue(min_max_[0] == PointTraits<TPoint>::lowest()) &&
356  allTrue(min_max_[1] == PointTraits<TPoint>::max());
357  }
358 
359  private:
360  explicit Region(UninitTag /*unused*/) {}
361 
362  // invariant: this->isEmpty() or min_max[0] <= min_max[1]
363  std::array<TPoint, 2> min_max_;
364 };
365 
366 template <class TT>
367 auto operator==(Region<TT> const& lhs, Region<TT> const& rhs) -> bool {
368  return lhs.min() == rhs.min() && lhs.max() == rhs.max();
369 }
370 
371 } // namespace sophus
sophus::round
auto round(TPoint s)
Definition: vector_space.h:157
sophus::Region::min
auto min() const noexcept -> TPoint const &
Returns the lower bound of the region.
Definition: region.h:182
sophus::Region::requires
requires(kDim==2) static auto createPerAxis(Region< TScalar > const &segment_x
SOPHUS_ASSERT
#define SOPHUS_ASSERT(...)
Definition: common.h:40
sophus::Region::extend
auto extend(Region const &other) noexcept -> Region< TPoint > &
Extends this by other region.
Definition: region.h:252
sophus::clamp
auto clamp(TPoint const &val, TPoint const &lo, TPoint const &hi) -> TPoint
Definition: vector_space.h:124
sophus::Region::unbounded
static auto unbounded() noexcept -> Region< TPoint >
Creates unbounded region.
Definition: region.h:82
SOPHUS_UNWRAP
#define SOPHUS_UNWRAP(...)
Definition: common.h:52
sophus
Image MutImage, owning images types.
Definition: num_diff.h:20
sophus::min
auto min(TPoint const &a, TPoint const &b) -> TPoint
Definition: vector_space.h:104
sophus::allTrue
auto allTrue(TPoint const &p) -> bool
Definition: vector_space.h:54
sophus::Region::tryMin
auto tryMin() const noexcept -> std::optional< TPoint >
Returns the lower bound of the region if it exit and nullopt otherwise.
Definition: region.h:196
sophus::Region::roundCast
auto roundCast() const noexcept -> Region< TOtherPoint >
Rounds given region bounds and returns resulting integer region.
Definition: region.h:326
sophus::Region::translated
auto translated(TPoint const &p) const noexcept -> Region< TPoint >
Returns translated region.
Definition: region.h:277
sophus::isNan
auto isNan(TPoint const &p) -> bool
Definition: vector_space.h:84
sophus::Region::fromMinMax
static auto fromMinMax(TPoint const &min, TPoint const &max) noexcept -> Region< TPoint >
Creates Region from two points, min and max.
Definition: region.h:104
sophus::Region::empty
static auto empty() noexcept -> Region< TPoint >
Creates and empty region.
Definition: region.h:72
sophus::Region::isUnbounded
auto isUnbounded() const noexcept -> bool
Returns true if region has no bounds.
Definition: region.h:354
sophus::Region::region
return region
Definition: region.h:137
sophus::Region::max
auto max() const noexcept -> TPoint const &
Returns the upper bound of the region.
Definition: region.h:190
sophus::Region::extend
auto extend(TPoint const &point) noexcept -> Region< TPoint > &
Extends this by given point.
Definition: region.h:266
sophus::isLessEqual
auto isLessEqual(TPoint const &lhs, TPoint const &rhs) -> bool
Definition: vector_space.h:183
sophus::ceil
auto ceil(TPoint s)
Definition: vector_space.h:143
sophus::Region::Region
requires std::is_same_v< TPoint, TScalar > Region(TScalar const &p1, TScalar const &p2) noexcept
Convenient constructor to create a Segment from two points p1 and p2.
Definition: region.h:122
sophus::Region::kRows
static constexpr int kRows
Definition: region.h:60
sophus::Region::kIsInteger
static constexpr bool kIsInteger
Definition: region.h:56
sophus::Region::from
static auto from(TPoint const &p) noexcept -> Region< TPoint >
Creates a region from a given point.
Definition: region.h:92
sophus::Region::tryMax
auto tryMax() const noexcept -> std::optional< TPoint >
Returns the lower bound of the region if it exists and nullopt otherwise.
Definition: region.h:204
sophus::plus
auto plus(TPoint p, TPoint s)
Definition: vector_space.h:171
sophus::Region::Point
TPoint Point
Definition: region.h:57
sophus::Region::kDim
static constexpr int kDim
Definition: region.h:64
sophus::Region::segment_z
Region< TScalar > const Region< TScalar > const & segment_z
Definition: region.h:156
sophus::Region::contains
auto contains(TPoint const &point) const noexcept -> bool
Returns true if the region contains the given point.
Definition: region.h:219
sophus::Region::isProper
auto isProper() const noexcept -> bool
Returns true if region is neither empty nor degenerated. Hence it contains a range of values.
Definition: region.h:349
sophus::trySetElem
auto trySetElem(TPoint &p, TPoint s, size_t row, size_t col=0) -> Expected< Success >
Definition: vector_space.h:212
sophus::Region::cast
auto cast() const noexcept -> Region< TOtherPoint >
Definition: region.h:283
sophus::operator==
auto operator==(Region< TT > const &lhs, Region< TT > const &rhs) -> bool
Definition: region.h:367
common.h
sophus::Region::kCols
static constexpr int kCols
Definition: region.h:61
sophus::Region::range
auto range() const noexcept -> TPoint
Returns the range of the region.
Definition: region.h:229
sophus::Region::Scalar
typename PointTraits< TPoint >::Scalar Scalar
Definition: region.h:58
sophus::Region::encloseCast
auto encloseCast() const noexcept -> Region< TOtherPoint >
Returns the smallest integer region which contains this.
Definition: region.h:311
sophus::floor
auto floor(TPoint s)
Definition: vector_space.h:129
sophus::Region::uninitialized
static auto uninitialized() noexcept -> Region< TPoint >
Creates an uninitialized region.
Definition: region.h:67
vector_space_traits.h
sophus::tryGetElem
auto tryGetElem(TPoint const &p, size_t row, size_t col=0) -> Expected< TPoint >
Definition: vector_space.h:193
sophus::PointTraits
Definition: point_traits.h:20
sophus::Region::clamp
auto clamp(TPoint const &point) const noexcept -> TPoint
Returns the clamped version of the given point.
Definition: region.h:214
sophus::max
auto max(TPoint const &a, TPoint const &b) -> TPoint
Definition: vector_space.h:114
sophus::Region::setElem
void setElem(size_t row, Region< Scalar > const &s)
Precondition: !this->isEmptpy()
Definition: region.h:174
sophus::eval
auto eval(TPoint const &p)
Definition: vector_space.h:44
sophus::Region::isEmpty
auto isEmpty() const noexcept -> bool
Returns true if region is empty.
Definition: region.h:337
sophus::Region::mid
auto mid() const noexcept -> TPoint
Returns the mid point.
Definition: region.h:247
sophus::Region::segment_y
Region< TScalar > const & segment_y
Definition: region.h:143
sophus::Region
A region is a closed interval [a, b] with a being the lower bound (=min) and b being the upper bound ...
Definition: region.h:19
vector_space.h
sophus::Region::isDegenerated
auto isDegenerated() const noexcept -> bool
Returns true if region contains a single floating point number.
Definition: region.h:343
sophus::UninitTag
Definition: common.h:70
sophus::Region::getElem
auto getElem(size_t row) const -> Region< Scalar > const &
Precondition: !this->isEmptpy()
Definition: region.h:167