Developer Documentation
Loading...
Searching...
No Matches
SmartRange.hh
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openmesh.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenMesh. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 * ========================================================================= */
41
42
43#pragma once
44
45#include <utility>
46#include <array>
47#include <vector>
48#include <set>
49
50//== NAMESPACES ===============================================================
51
52namespace OpenMesh {
53
54//== FORWARD DECLARATION ======================================================
55
56//== CLASS DEFINITION =========================================================
57
58namespace {
59
60struct Identity
61{
62 template <typename T>
63 T operator()(const T& _t) const { return _t; }
64};
65
66}
67
68template <typename RangeT, typename HandleT, typename Functor>
69struct FilteredSmartRangeT;
70
72template <typename RangeT, typename HandleT>
74{
75 using Handle = HandleT;
77 using Range = RangeT;
78
79 // TODO: Someone with better c++ knowledge may improve the code below.
80
83 auto size() const -> size_t
84 {
85 auto range = static_cast<const RangeT*>(this);
86 return std::distance(range->begin(), range->end());
87 }
88
95 template <typename Functor>
96 auto sum(Functor&& f) const -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
97 {
98 auto range = static_cast<const RangeT*>(this);
99 auto begin = range->begin();
100 auto end = range->end();
101 assert(begin != end);
102 typename std::decay<decltype (f(*begin))>::type result = f(*begin);
103 auto it = begin;
104 ++it;
105 for (; it != end; ++it)
106 result += f(*it);
107 return result;
108 }
109
116 template <typename Functor>
117 auto avg(Functor&& f) const -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
118 {
119 auto range = static_cast<const RangeT*>(this);
120 auto begin = range->begin();
121 auto end = range->end();
122 assert(begin != end);
123 typename std::decay<decltype (f(*begin))>::type result = f(*begin);
124 auto it = begin;
125 ++it;
126 int n_elements = 1;
127 for (; it != end; ++it)
128 {
129 result += f(*it);
130 ++n_elements;
131 }
132 return (1.0 / n_elements) * result;
133 }
134
142 template <typename Functor, typename WeightFunctor>
143 auto avg(Functor&& f, WeightFunctor&& w) const -> typename std::decay<decltype ((1.0/(w(std::declval<HandleT>())+w(std::declval<HandleT>())))*f(std::declval<HandleT>()))>::type
144 {
145 auto range = static_cast<const RangeT*>(this);
146 auto begin = range->begin();
147 auto end = range->end();
148 assert(begin != end);
149 typename std::decay<decltype (w(*begin))>::type weight = w(*begin);
150 typename std::decay<decltype (w(*begin)*f(*begin))>::type result = weight * f(*begin);
151 typename std::decay<decltype (w(*begin)+w(*begin))>::type weight_sum = weight;
152 auto it = begin;
153 ++it;
154 for (; it != end; ++it)
155 {
156 weight = w(*it);
157 result += weight*f(*it);
158 weight_sum += weight;
159 }
160 return (1.0 / weight_sum) * result;
161 }
162
170 template <typename Functor>
171 auto any_of(Functor&& f) const -> bool
172 {
173 auto range = static_cast<const RangeT*>(this);
174 for (auto e : *range)
175 if (f(e))
176 return true;
177 return false;
178 }
179
187 template <typename Functor>
188 auto all_of(Functor&& f) const -> bool
189 {
190 auto range = static_cast<const RangeT*>(this);
191 for (auto e : *range)
192 if (!f(e))
193 return false;
194 return true;
195 }
196
206 template <int n, typename Functor = Identity>
207 auto to_array(Functor&& f = {}) const -> std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n>
208 {
209 auto range = static_cast<const RangeT*>(this);
210 std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n> res;
211 auto it = range->begin();
212 auto end = range->end();
213 int i = 0;
214 while (i < n && it != end)
215 res[i++] = f(*(it++));
216 return res;
217 }
218
226 template <typename Functor = Identity>
227 auto to_vector(Functor&& f = {}) const -> std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
228 {
229 auto range = static_cast<const RangeT*>(this);
230 std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
231 for (const auto& e : *range)
232 res.push_back(f(e));
233 return res;
234 }
235
243 template <typename Functor = Identity>
244 auto to_set(Functor&& f = {}) const -> std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
245 {
246 auto range = static_cast<const RangeT*>(this);
247 std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
248 for (const auto& e : *range)
249 res.insert(f(e));
250 return res;
251 }
252
261 template <typename Functor>
262 auto first(Functor&& f = {}) const -> HandleT
263 {
264 auto range = static_cast<const RangeT*>(this);
265 for (const auto& e : *range)
266 if (f(e))
267 return e;
268 return HandleT();
269 }
270
277 template <typename Functor>
278 auto min(Functor&& f) const -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
279 {
280 using std::min;
281
282 auto range = static_cast<const RangeT*>(this);
283 auto it = range->begin();
284 auto end = range->end();
285 assert(it != end);
286
287 typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
288 ++it;
289
290 for (; it != end; ++it)
291 res = min(res, f(*it));
292
293 return res;
294 }
295
302 template <typename Functor>
303 auto argmin(Functor&& f) const -> HandleT
304 {
305 auto range = static_cast<const RangeT*>(this);
306 auto it = range->begin();
307 auto min_it = it;
308 auto end = range->end();
309 assert(it != end);
310
311 typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_min = f(*it);
312 ++it;
313
314 for (; it != end; ++it)
315 {
316 auto val = f(*it);
317 if (val < curr_min)
318 {
319 curr_min = val;
320 min_it = it;
321 }
322 }
323
324 return *min_it;
325 }
326
333 template <typename Functor>
334 auto max(Functor&& f) const -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
335 {
336 using std::max;
337
338 auto range = static_cast<const RangeT*>(this);
339 auto it = range->begin();
340 auto end = range->end();
341 assert(it != end);
342
343 typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
344 ++it;
345
346 for (; it != end; ++it)
347 res = max(res, f(*it));
348
349 return res;
350 }
351
352
359 template <typename Functor>
360 auto argmax(Functor&& f) const -> HandleT
361 {
362 auto range = static_cast<const RangeT*>(this);
363 auto it = range->begin();
364 auto max_it = it;
365 auto end = range->end();
366 assert(it != end);
367
368 typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_max = f(*it);
369 ++it;
370
371 for (; it != end; ++it)
372 {
373 auto val = f(*it);
374 if (val > curr_max)
375 {
376 curr_max = val;
377 max_it = it;
378 }
379 }
380
381 return *max_it;
382 }
383
391 template <typename Functor>
392 auto minmax(Functor&& f) const -> std::pair<typename std::decay<decltype (f(std::declval<HandleT>()))>::type,
393 typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
394 {
395 return std::make_pair(this->min(f), this->max(f));
396 }
397
398
405 template <typename Functor>
406 auto count_if(Functor&& f) const -> int
407 {
408 int count = 0;
409 auto range = static_cast<const RangeT*>(this);
410 for (const auto& e : *range)
411 if (f(e))
412 ++count;
413 return count;
414 }
415
416
423 template <typename Functor>
424 auto for_each(Functor&& f) const -> void
425 {
426 auto range = static_cast<const RangeT*>(this);
427 for (const auto& e : *range)
428 f(e);
429 }
430
431
438 template <typename Functor>
440 {
441 auto range = static_cast<const RangeT*>(this);
442 return FilteredSmartRangeT<SmartRange, Handle, Functor>(std::forward<Functor>(f), (*range).begin(), (*range).end());
443 }
444};
445
446
448template <typename RangeT, typename HandleT, typename Functor>
449struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, HandleT, Functor>, HandleT>
450{
452 using BaseIterator = decltype((std::declval<typename RangeT::Range>().begin()));
453
454 struct FilteredIterator : public BaseIterator
455 {
456
457 FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end)
458 {
459 if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one
460 operator++();
461 }
462
463 FilteredIterator(const FilteredIterator& other) = default;
464
465 FilteredIterator& operator=(const FilteredIterator& other)
466 {
467 BaseIterator::operator=(other);
468 end_ = other.end_;
469 return *this;
470 }
471
472 FilteredIterator& operator++()
473 {
474 if (BaseIterator::operator==(end_)) // don't go past end
475 return *this;
476
477 // go to next valid one
478 do
479 BaseIterator::operator++();
480 while (BaseIterator::operator!=(end_) && !f_(*(*this)));
481 return *this;
482 }
483
484 Functor f_; // Should iterators always get a reference to filter stored in range?
485 // Should iterators stay valid after range goes out of scope?
486 BaseIterator end_;
487 };
488
489 FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward<Functor>(f)), begin_(std::move(begin)), end_(std::move(end)){}
490 FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
491 FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }
492
493 Functor f_;
494 BaseIterator begin_;
495 BaseIterator end_;
496};
497
498
499
500//=============================================================================
501} // namespace OpenMesh
502//=============================================================================
503
504//=============================================================================
Class which applies a filter when iterating over elements.
Base class for all smart range types.
Definition SmartRange.hh:74
auto to_set(Functor &&f={}) const -> std::set< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to set.
auto sum(Functor &&f) const -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the sum of elements.
Definition SmartRange.hh:96
auto argmin(Functor &&f) const -> HandleT
Compute minimal element.
auto count_if(Functor &&f) const -> int
Compute number of elements that satisfy a given predicate.
auto to_vector(Functor &&f={}) const -> std::vector< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to vector.
auto argmax(Functor &&f) const -> HandleT
Compute maximal element.
auto filtered(Functor &&f) const -> FilteredSmartRangeT< SmartRange, Handle, Functor >
Only iterate over a subset of elements.
auto minmax(Functor &&f) const -> std::pair< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Computes minimum and maximum.
auto all_of(Functor &&f) const -> bool
Check if all elements fulfil condition.
auto first(Functor &&f={}) const -> HandleT
Get the first element that fulfills a condition.
auto min(Functor &&f) const -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute minimum.
auto avg(Functor &&f, WeightFunctor &&w) const -> typename std::decay< decltype((1.0/(w(std::declval< HandleT >())+w(std::declval< HandleT >()))) *f(std::declval< HandleT >()))>::type
Computes the weighted average of elements.
auto to_array(Functor &&f={}) const -> std::array< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, n >
Convert range to array.
auto avg(Functor &&f) const -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the average of elements.
auto for_each(Functor &&f) const -> void
Apply a functor to each element.
auto size() const -> size_t
Computes number of elements.
Definition SmartRange.hh:83
auto any_of(Functor &&f) const -> bool
Check if any element fulfils condition.
auto max(Functor &&f) const -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute maximum.