OpenMesh: OpenMesh/Core/Mesh/SmartRange.hh Source File

| OpenMesh

SmartRange.hh
1 /* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2019, 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
52 namespace OpenMesh {
53
54 //== FORWARD DECLARATION ======================================================
55
56 //== CLASS DEFINITION =========================================================
57
58 namespace {
59
60 struct Identity
61 {
62 template <typename T>
63 T operator()(const T& _t) const { return _t; }
64 };
65
66 }
67
68 template <typename RangeT, typename HandleT, typename Functor>
69 struct FilteredSmartRangeT;
70
72 template <typename RangeT, typename HandleT>
73 struct SmartRangeT
74 {
75 using Handle = HandleT;
76 using SmartRange = SmartRangeT<RangeT, HandleT>;
77 using Range = RangeT;
78
79 // TODO: Someone with better c++ knowledge may improve the code below.
80
87 template <typename Functor>
88 auto sum(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
89 {
90 auto range = static_cast<const RangeT*>(this);
91 auto begin = range->begin();
92 auto end = range->end();
93 assert(begin != end);
94 typename std::decay<decltype (f(*begin))>::type result = f(*begin);
95 auto it = begin;
96 ++it;
97 for (; it != end; ++it)
98 result += f(*it);
99 return result;
100 }
101
108 template <typename Functor>
109 auto avg(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
110 {
111 auto range = static_cast<const RangeT*>(this);
112 auto begin = range->begin();
113 auto end = range->end();
114 assert(begin != end);
115 typename std::decay<decltype (f(*begin))>::type result = f(*begin);
116 auto it = begin;
117 ++it;
118 int n_elements = 1;
119 for (; it != end; ++it)
120 {
121 result += f(*it);
122 ++n_elements;
123 }
124 return (1.0 / n_elements) * result;
125 }
126
134 template <typename Functor, typename WeightFunctor>
135 auto avg(Functor&& f, WeightFunctor&& w) -> typename std::decay<decltype ((1.0/(w(std::declval<HandleT>())+w(std::declval<HandleT>())))*f(std::declval<HandleT>()))>::type
136 {
137 auto range = static_cast<const RangeT*>(this);
138 auto begin = range->begin();
139 auto end = range->end();
140 assert(begin != end);
141 typename std::decay<decltype (w(*begin))>::type weight = w(*begin);
142 typename std::decay<decltype (w(*begin)*f(*begin))>::type result = weight * f(*begin);
143 typename std::decay<decltype (w(*begin)+w(*begin))>::type weight_sum = weight;
144 auto it = begin;
145 ++it;
146 for (; it != end; ++it)
147 {
148 weight = w(*it);
149 result += weight*f(*it);
150 weight_sum += weight;
151 }
152 return (1.0 / weight_sum) * result;
153 }
154
162 template <typename Functor>
163 auto any_of(Functor&& f) -> bool
164 {
165 auto range = static_cast<const RangeT*>(this);
166 for (auto e : *range)
167 if (f(e))
168 return true;
169 return false;
170 }
171
179 template <typename Functor>
180 auto all_of(Functor&& f) -> bool
181 {
182 auto range = static_cast<const RangeT*>(this);
183 for (auto e : *range)
184 if (!f(e))
185 return false;
186 return true;
187 }
188
198 template <int n, typename Functor = Identity>
199 auto to_array(Functor&& f = {}) -> std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n>
200 {
201 auto range = static_cast<const RangeT*>(this);
202 std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n> res;
203 auto it = range->begin();
204 auto end = range->end();
205 int i = 0;
206 while (i < n && it != end)
207 res[i++] = f(*(it++));
208 return res;
209 }
210
218 template <typename Functor = Identity>
219 auto to_vector(Functor&& f = {}) -> std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
220 {
221 auto range = static_cast<const RangeT*>(this);
222 std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
223 for (const auto& e : *range)
224 res.push_back(f(e));
225 return res;
226 }
227
235 template <typename Functor = Identity>
236 auto to_set(Functor&& f = {}) -> std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
237 {
238 auto range = static_cast<const RangeT*>(this);
239 std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
240 for (const auto& e : *range)
241 res.insert(f(e));
242 return res;
243 }
244
253 template <typename Functor>
254 auto first(Functor&& f = {}) -> HandleT
255 {
256 auto range = static_cast<const RangeT*>(this);
257 for (const auto& e : *range)
258 if (f(e))
259 return e;
260 return HandleT();
261 }
262
269 template <typename Functor>
270 auto min(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
271 {
272 using std::min;
273
274 auto range = static_cast<const RangeT*>(this);
275 auto it = range->begin();
276 auto end = range->end();
277 assert(it != end);
278
279 typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
280 ++it;
281
282 for (; it != end; ++it)
283 res = min(res, f(*it));
284
285 return res;
286 }
287
294 template <typename Functor>
295 auto argmin(Functor&& f) -> HandleT
296 {
297 auto range = static_cast<const RangeT*>(this);
298 auto it = range->begin();
299 auto min_it = it;
300 auto end = range->end();
301 assert(it != end);
302
303 typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_min = f(*it);
304 ++it;
305
306 for (; it != end; ++it)
307 {
308 auto val = f(*it);
309 if (val < curr_min)
310 {
311 curr_min = val;
312 min_it = it;
313 }
314 }
315
316 return *min_it;
317 }
318
325 template <typename Functor>
326 auto max(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
327 {
328 using std::max;
329
330 auto range = static_cast<const RangeT*>(this);
331 auto it = range->begin();
332 auto end = range->end();
333 assert(it != end);
334
335 typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
336 ++it;
337
338 for (; it != end; ++it)
339 res = max(res, f(*it));
340
341 return res;
342 }
343
344
351 template <typename Functor>
352 auto argmax(Functor&& f) -> HandleT
353 {
354 auto range = static_cast<const RangeT*>(this);
355 auto it = range->begin();
356 auto max_it = it;
357 auto end = range->end();
358 assert(it != end);
359
360 typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_max = f(*it);
361 ++it;
362
363 for (; it != end; ++it)
364 {
365 auto val = f(*it);
366 if (val > curr_max)
367 {
368 curr_max = val;
369 max_it = it;
370 }
371 }
372
373 return *max_it;
374 }
375
383 template <typename Functor>
384 auto minmax(Functor&& f) -> std::pair<typename std::decay<decltype (f(std::declval<HandleT>()))>::type,
385 typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
386 {
387 return std::make_pair(this->min(f), this->max(f));
388 }
389
390
397 template <typename Functor>
398 auto count_if(Functor&& f) -> int
399 {
400 int count = 0;
401 auto range = static_cast<const RangeT*>(this);
402 for (const auto& e : *range)
403 if (f(e))
404 ++count;
405 return count;
406 }
407
408
415 template <typename Functor>
416 auto for_each(Functor&& f) -> void
417 {
418 auto range = static_cast<const RangeT*>(this);
419 for (const auto& e : *range)
420 f(e);
421 }
422
423
430 template <typename Functor>
431 auto filtered(Functor&& f) -> FilteredSmartRangeT<SmartRange, Handle, Functor>
432 {
433 auto range = static_cast<const RangeT*>(this);
434 return FilteredSmartRangeT<SmartRange, Handle, Functor>(std::forward<Functor>(f), (*range).begin(), (*range).end());
435 }
436 };
437
438
440 template <typename RangeT, typename HandleT, typename Functor>
441 struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, HandleT, Functor>, HandleT>
442 {
443 using BaseRange = SmartRangeT<FilteredSmartRangeT<RangeT, HandleT, Functor>, HandleT>;
444 using BaseIterator = decltype((std::declval<typename RangeT::Range>().begin()));
445
446 struct FilteredIterator : public BaseIterator
447 {
448
449 FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end)
450 {
451 if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one
452 operator++();
453 }
454
455 FilteredIterator(const FilteredIterator& other) = default;
456
457 FilteredIterator& operator=(const FilteredIterator& other)
458 {
459 BaseIterator::operator=(other);
460 end_ = other.end_;
461 return *this;
462 }
463
464 FilteredIterator& operator++()
465 {
466 if (BaseIterator::operator==(end_)) // don't go past end
467 return *this;
468
469 // go to next valid one
470 do
471 BaseIterator::operator++();
472 while (BaseIterator::operator!=(end_) && !f_(*(*this)));
473 return *this;
474 }
475
476 Functor f_; // Should iterators always get a reference to filter stored in range?
477 // Should iterators stay valid after range goes out of scope?
478 BaseIterator end_;
479 };
480
481 FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward<Functor>(f)), begin_(std::move(begin)), end_(std::move(end)){}
482 FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
483 FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }
484
485 Functor f_;
486 BaseIterator begin_;
487 BaseIterator end_;
488 };
489
490
491
492 //=============================================================================
493 } // namespace OpenMesh
494 //=============================================================================
495
496 //=============================================================================
OpenMesh
Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...
Definition: MeshItems.hh:59
OpenMesh::FilteredSmartRangeT
Class which applies a filter when iterating over elements.
Definition: SmartRange.hh:442
OpenMesh::SmartRangeT
Base class for all smart range types.
Definition: SmartRange.hh:74
OpenMesh::SmartRangeT::for_each
auto for_each(Functor &&f) -> void
Apply a functor to each element.
Definition: SmartRange.hh:416
OpenMesh::SmartRangeT::to_set
auto to_set(Functor &&f={}) -> std::set< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to set.
Definition: SmartRange.hh:236
OpenMesh::SmartRangeT::sum
auto sum(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the sum of elements.
Definition: SmartRange.hh:88
OpenMesh::SmartRangeT::to_array
auto to_array(Functor &&f={}) -> std::array< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, n >
Convert range to array.
Definition: SmartRange.hh:199
OpenMesh::SmartRangeT::argmax
auto argmax(Functor &&f) -> HandleT
Compute maximal element.
Definition: SmartRange.hh:352
OpenMesh::SmartRangeT::avg
auto avg(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the average of elements.
Definition: SmartRange.hh:109
OpenMesh::SmartRangeT::min
auto min(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute minimum.
Definition: SmartRange.hh:270
OpenMesh::SmartRangeT::minmax
auto minmax(Functor &&f) -> std::pair< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Computes minimum and maximum.
Definition: SmartRange.hh:384
OpenMesh::SmartRangeT::any_of
auto any_of(Functor &&f) -> bool
Check if any element fulfils condition.
Definition: SmartRange.hh:163
OpenMesh::SmartRangeT::first
auto first(Functor &&f={}) -> HandleT
Get the first element that fulfills a condition.
Definition: SmartRange.hh:254
OpenMesh::SmartRangeT::all_of
auto all_of(Functor &&f) -> bool
Check if all elements fulfil condition.
Definition: SmartRange.hh:180
OpenMesh::SmartRangeT::filtered
auto filtered(Functor &&f) -> FilteredSmartRangeT< SmartRange, Handle, Functor >
Only iterate over a subset of elements.
Definition: SmartRange.hh:431
OpenMesh::SmartRangeT::to_vector
auto to_vector(Functor &&f={}) -> std::vector< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to vector.
Definition: SmartRange.hh:219
OpenMesh::SmartRangeT::avg
auto avg(Functor &&f, WeightFunctor &&w) -> 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.
Definition: SmartRange.hh:135
OpenMesh::SmartRangeT::argmin
auto argmin(Functor &&f) -> HandleT
Compute minimal element.
Definition: SmartRange.hh:295
OpenMesh::SmartRangeT::max
auto max(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute maximum.
Definition: SmartRange.hh:326
OpenMesh::SmartRangeT::count_if
auto count_if(Functor &&f) -> int
Compute number of elements that satisfy a given predicate.
Definition: SmartRange.hh:398
OpenMesh::FilteredSmartRangeT::FilteredIterator
Definition: SmartRange.hh:447