ranges.hh 19.8 KB
Newer Older
1
2
3
#pragma once

#include <cstddef>
4
5
#include <map>
#include <set>
6
7
8
9
10
11
#include <vector>

#include "iterators.hh"

namespace polymesh
{
Philip Trettner's avatar
Philip Trettner committed
12
13
14
15
16
17
template <class T>
struct aabb
{
    T min;
    T max;
};
Philip Trettner's avatar
Philip Trettner committed
18

19
20
21
22
23
24
25
template <class V, class W>
struct weighted_sample
{
    V value;
    W weight;
};

Philip Trettner's avatar
Philip Trettner committed
26
template <class this_t, class ElementT>
Philip Trettner's avatar
Philip Trettner committed
27
28
29
struct smart_range
{
    /// returns the first element in this range
Philip Trettner's avatar
Philip Trettner committed
30
31
32
33
    /// returns invalid on empty ranges (or default ctor'd one)
    ElementT first() const;
    /// returns the last element in this range
    /// returns invalid on empty ranges (or default ctor'd one)
Philip Trettner's avatar
Philip Trettner committed
34
    /// TODO: how to make this O(1)
Philip Trettner's avatar
Philip Trettner committed
35
    ElementT last() const;
Philip Trettner's avatar
Philip Trettner committed
36

37
38
    /// returns true if the range is empty
    bool empty() const;
Philip Trettner's avatar
Philip Trettner committed
39
40
    /// returns true if the range is non-empty
    bool any() const;
41
    /// returns true if any value fulfils p(v)
Philip Trettner's avatar
Philip Trettner committed
42
43
    /// also works for boolean attributes
    template <class PredT>
Philip Trettner's avatar
Philip Trettner committed
44
    bool any(PredT&& p) const;
45
    /// returns true if all values fulfil p(v)
Philip Trettner's avatar
Philip Trettner committed
46
47
    /// also works for boolean attributes
    template <class PredT>
Philip Trettner's avatar
Philip Trettner committed
48
49
50
51
52
53
    bool all(PredT&& p) const;

    /// returns the number of elements in this range
    /// NOTE: this is an O(n) operation, prefer size() if available
    /// TODO: maybe SFINAE to implement this via size() if available?
    int count() const;
54
55
56
    /// returns the number of elements fulfilling p(v) in this range
    template <class PredT>
    int count(PredT&& p) const;
Philip Trettner's avatar
Philip Trettner committed
57

58
59
60
61
62
    /// calculates min(f(e)) over all elements
    /// undefined behavior if range is empty
    /// works for std::min and everything reachable by ADL (calls min(_, _))
    template <class FuncT>
    auto min(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
Philip Trettner's avatar
Philip Trettner committed
63
64
65
66
67
    /// returns e that minimizes f(e)
    /// undefined behavior if range is empty
    /// requires working comparison operators for the result
    template <class FuncT>
    ElementT min_by(FuncT&& f) const;
68
69
70
71
72
    /// calculates max(f(e)) over all elements
    /// undefined behavior if range is empty
    /// works for std::max and everything reachable by ADL (calls max(_, _))
    template <class FuncT>
    auto max(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
Philip Trettner's avatar
Philip Trettner committed
73
74
75
76
77
    /// returns e that maximizes f(e)
    /// undefined behavior if range is empty
    /// requires working comparison operators for the result
    template <class FuncT>
    ElementT max_by(FuncT&& f) const;
78
79
80
81
82
83
84
85
86
87
    /// calculates the sum of f(e) over all elements
    /// undefined behavior if range is empty
    /// requires operator+ for the elements
    template <class FuncT>
    auto sum(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
    /// calculates the avg of f(e) over all elements
    /// undefined behavior if range is empty
    /// requires operator+ for the elements as well as operator/(ElementT, int)
    template <class FuncT>
    auto avg(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
Philip Trettner's avatar
Philip Trettner committed
88

89
90
91
92
93
94
    /// calculates the weighted avg of f(e) with weight w(e) over all elements
    /// undefined behavior if range is empty
    /// requires operator+ for the elements and weights as well as operator/(ElementT, WeightT)
    template <class FuncT, class WeightT>
    auto weighted_avg(FuncT&& f, WeightT&& w) const -> tmp::decayed_result_type_of<FuncT, ElementT>;

Philip Trettner's avatar
Philip Trettner committed
95
96
97
98
99
100
101
102
103
104
105
    /// calculates the f-mean of this range
    /// the f-mean is f_inv(avg(f))
    template <class FuncT, class FuncInvT>
    auto f_mean(FuncT&& f, FuncInvT&& f_inv) const -> tmp::decayed_result_type_of<FuncInvT, tmp::decayed_result_type_of<FuncT, ElementT>>;
    /// calculates the arithmetic mean of f(e) for this range (same as avg)
    template <class FuncT>
    auto arithmetic_mean(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;
    /// calculates the geometric mean of f(e) for this range (also known as log-average)
    template <class FuncT>
    auto geometric_mean(FuncT&& f) const -> tmp::decayed_result_type_of<FuncT, ElementT>;

106
107
108
109
110
111
112
113
    /// calculates the aabb (min and max) of f(e) over all elements
    /// undefined behavior if range is empty
    /// works for std::min/max and everything reachable by ADL (calls min/max(_, _))
    template <class FuncT>
    auto aabb(FuncT&& f) const -> polymesh::aabb<tmp::decayed_result_type_of<FuncT, ElementT>>;
    /// same as aabb(...)
    template <class FuncT>
    auto minmax(FuncT&& f) const -> polymesh::aabb<tmp::decayed_result_type_of<FuncT, ElementT>>;
Philip Trettner's avatar
Philip Trettner committed
114
115
116
117
118
    /// returns {e_min, e_max} that minimizes/maximizes f(e)
    /// undefined behavior if range is empty
    /// requires working comparison operators for the result
    template <class FuncT>
    polymesh::aabb<ElementT> minmax_by(FuncT&& f) const;
119

120
121
122
123
124
125
126
127
128
129
130
131
132
    /// converts this range to a vector
    std::vector<ElementT> to_vector() const;
    /// converts this range to a set
    std::set<ElementT> to_set() const;
    /// converts this range to a vector containing f(v) entries
    template <class FuncT>
    auto to_vector(FuncT&& f) const -> std::vector<tmp::decayed_result_type_of<FuncT, ElementT>>;
    /// converts this range to a set containing f(v) entries
    template <class FuncT>
    auto to_set(FuncT&& f) const -> std::set<tmp::decayed_result_type_of<FuncT, ElementT>>;
    /// converts this range to a map containing {v, f(v)} entries
    template <class FuncT>
    auto to_map(FuncT&& f) const -> std::map<ElementT, tmp::decayed_result_type_of<FuncT, ElementT>>;
Philip Trettner's avatar
Philip Trettner committed
133

134
    // TODO: (requires new ranges)
Philip Trettner's avatar
Philip Trettner committed
135
136
137
138
    // - filter (or where?)
    // - map
    // - skip
    // - only_valid
139
    // - conversions from vector/set/map
Philip Trettner's avatar
Philip Trettner committed
140
141
};

142
143
// ================= COLLECTION =================

Philip Trettner's avatar
Philip Trettner committed
144
template <class mesh_ptr, class tag, class iterator>
Philip Trettner's avatar
Philip Trettner committed
145
struct smart_collection : smart_range<smart_collection<mesh_ptr, tag, iterator>, typename primitive<tag>::handle>
146
{
Philip Trettner's avatar
Philip Trettner committed
147
    template <class AttrT>
Philip Trettner's avatar
Philip Trettner committed
148
    using attribute = typename primitive<tag>::template attribute<AttrT>;
Philip Trettner's avatar
Philip Trettner committed
149
    using handle = typename primitive<tag>::handle;
150

Philip Trettner's avatar
Philip Trettner committed
151
    /// Number of primitives, INCLUDING those marked for deletion
152
    /// O(1) computation
Philip Trettner's avatar
Philip Trettner committed
153
    int size() const;
Philip Trettner's avatar
Philip Trettner committed
154
155

    /// Ensures that a given number of primitives can be stored without reallocation
Philip Trettner's avatar
Philip Trettner committed
156
    void reserve(int capacity) const;
157

Philip Trettner's avatar
Philip Trettner committed
158
    /// Creates a new primitive attribute
159
160
    template <class AttrT>
    attribute<AttrT> make_attribute() const;
Philip Trettner's avatar
Philip Trettner committed
161
    /// Creates a new primitive attribute with a given default value
162
163
164
165
166
167
168
169
    template <class AttrT>
    attribute<AttrT> make_attribute_with_default(AttrT const& def_value) const;
    /// Creates a new primitive attribute and copies the given data
    template <class AttrT>
    attribute<AttrT> make_attribute_from_data(std::vector<AttrT> const& data) const;
    /// Creates a new primitive attribute and copies the given data
    template <class AttrT>
    attribute<AttrT> make_attribute_from_data(AttrT const* data, int cnt) const;
Philip Trettner's avatar
Philip Trettner committed
170
    /// Creates a new primitive attribute and initializes it with f(h) for each handle h
171
172
    template <class FuncT, class AttrT = tmp::decayed_result_type_of<FuncT, handle>>
    attribute<AttrT> make_attribute(FuncT&& f, AttrT const& def_value = AttrT()) const;
Philip Trettner's avatar
Philip Trettner committed
173
174
175
176
177

    // Iteration:
    iterator begin() const;
    iterator end() const;

Philip Trettner's avatar
Philip Trettner committed
178
179
180
181
182
183
    /// returns a handle chosen uniformly at random
    /// NOTE: when only valid handles are allowed, this will use rejection sampling
    ///       and thus get very slow if a lot of data is invalid
    template <class Generator>
    handle random(Generator& g) const;

Philip Trettner's avatar
Philip Trettner committed
184
protected:
Philip Trettner's avatar
Philip Trettner committed
185
    /// Backreference to mesh
Philip Trettner's avatar
Philip Trettner committed
186
    mesh_ptr mesh;
Philip Trettner's avatar
Philip Trettner committed
187
188
189
190

    friend class Mesh;
};

Philip Trettner's avatar
Philip Trettner committed
191
/// Collection of all vertices of a mesh
Philip Trettner's avatar
Philip Trettner committed
192
/// Basically a smart std::vector
Philip Trettner's avatar
Philip Trettner committed
193
194
template <class iterator>
struct vertex_collection : smart_collection<Mesh*, vertex_tag, iterator>
Philip Trettner's avatar
Philip Trettner committed
195
{
196
197
198
199
    /// Adds a new vertex and returns its handle
    /// Does NOT invalidate any iterator!
    vertex_handle add() const;

Philip Trettner's avatar
Philip Trettner committed
200
201
202
203
    /// Collapsed the given vertex by removing it and merging the adjacent faces
    /// Preserves half-edge properties but not face ones
    void collapse(vertex_handle v) const;

204
205
206
    /// Removes a vertex (and all adjacent faces and edges)
    /// (marks them as removed, compactify mesh to actually remove them)
    void remove(vertex_handle v) const;
207
208
209
210
211

    /// applies an index remapping to all vertex indices
    /// p[curr_idx] = new_idx
    /// NOTE: invalidates all affected handles/iterators
    void permute(std::vector<int> const& p) const;
212
213
};

Philip Trettner's avatar
Philip Trettner committed
214
/// Collection of all faces of a mesh
215
/// Basically a smart std::vector
Philip Trettner's avatar
Philip Trettner committed
216
217
template <class iterator>
struct face_collection : smart_collection<Mesh*, face_tag, iterator>
218
219
220
221
222
{
    /// Adds a face consisting of N vertices
    /// The vertices must already be sorted in CCW order
    /// (note: trying to add already existing halfedges triggers assertions)
    template <size_t N>
Philip Trettner's avatar
Philip Trettner committed
223
    face_handle add(const vertex_handle (&v_handles)[N]) const;
Philip Trettner's avatar
Philip Trettner committed
224
225
226
    face_handle add(vertex_handle v0, vertex_handle v1, vertex_handle v2) const;
    face_handle add(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const;
    face_handle add(std::vector<vertex_handle> const& v_handles) const;
227
    face_handle add(vertex_handle const* v_handles, int vcnt) const;
Philip Trettner's avatar
Philip Trettner committed
228
    template <size_t N>
Philip Trettner's avatar
Philip Trettner committed
229
    face_handle add(const halfedge_handle (&half_loop)[N]) const;
Philip Trettner's avatar
Philip Trettner committed
230
231
232
    face_handle add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2) const;
    face_handle add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2, halfedge_handle h3) const;
    face_handle add(std::vector<halfedge_handle> const& half_loop) const;
233
    face_handle add(halfedge_handle const* half_loop, int vcnt) const;
234

Philip Trettner's avatar
Philip Trettner committed
235
236
237
238
    /// Splits a face by inserting a vertex (which is returned) and creating triangles towards it
    /// Preserves half-edge attributes
    /// The face itself is deleted and multiple new ones are created
    vertex_handle split(face_handle f) const;
Philip Trettner's avatar
Philip Trettner committed
239
240
    /// same as before but splits at a given ISOLATED vertex
    void split(face_handle f, vertex_handle v) const;
Philip Trettner's avatar
Philip Trettner committed
241

242
243
244
245
    /// Fills the half-edge ring of a given boundary half-edge
    /// Returns the new face
    face_handle fill(halfedge_handle h) const;

246
247
248
    /// Removes a face (adjacent edges and vertices are NOT removed)
    /// (marks it as removed, compactify mesh to actually remove it)
    void remove(face_handle f) const;
249
250
251
252
253

    /// applies an index remapping to all face indices
    /// p[curr_idx] = new_idx
    /// NOTE: invalidates all affected handles/iterators
    void permute(std::vector<int> const& p) const;
254
255
};

Philip Trettner's avatar
Philip Trettner committed
256
/// Collection of all edges of a mesh
257
/// Basically a smart std::vector
Philip Trettner's avatar
Philip Trettner committed
258
259
template <class iterator>
struct edge_collection : smart_collection<Mesh*, edge_tag, iterator>
260
{
Philip Trettner's avatar
Philip Trettner committed
261
262
    /// Adds an edge between two existing, distinct vertices
    /// if edge already exists, returns it
Philip Trettner's avatar
Philip Trettner committed
263
    edge_handle add_or_get(vertex_handle v_from, vertex_handle v_to) const;
Philip Trettner's avatar
Philip Trettner committed
264
265
266
    /// Adds an edge between two existing, distict halfedges
    /// if edge already exists, returns it
    edge_handle add_or_get(halfedge_handle h_from, halfedge_handle h_to) const;
Philip Trettner's avatar
Philip Trettner committed
267
268
269
270
271
272
273
274
275

    /// Returns the edge handle between two vertices (invalid if not found)
    /// O(valence) computation
    edge_handle find(vertex_handle v_from, vertex_handle v_to) const;

    /// Splits this edge in half by inserting a vertex (which is returned)
    /// Preserves face attributes
    /// The edge itself is deleted and two new ones are created
    vertex_handle split(edge_handle e) const;
Philip Trettner's avatar
Philip Trettner committed
276
277
    /// same as before but splits at a given ISOLATED vertex
    void split(edge_handle e, vertex_handle v) const;
Philip Trettner's avatar
Philip Trettner committed
278
279
280
281
282
283
284
285
286

    /// Moves both half-edges vertices to their next half-edge vertex
    /// Equivalent to an edge flip if both faces are triangular
    /// Preserves all attributes
    /// NOTE: does not work on boundaries!
    /// TODO: image
    void rotate_next(edge_handle e) const;
    /// Same as rotate_next but with the previous half-edge
    void rotate_prev(edge_handle e) const;
Philip Trettner's avatar
Philip Trettner committed
287

288
289
290
    /// Removes an edge (and both adjacent faces, vertices are NOT removed)
    /// (marks them as removed, compactify mesh to actually remove them)
    void remove(edge_handle e) const;
291
292
293
294
295

    /// applies an index remapping to all edge indices
    /// p[curr_idx] = new_idx
    /// NOTE: invalidates all affected handles/iterators
    void permute(std::vector<int> const& p) const;
Philip Trettner's avatar
Philip Trettner committed
296
};
Philip Trettner's avatar
Philip Trettner committed
297

Philip Trettner's avatar
Philip Trettner committed
298
299
/// Collection of all half-edges of a mesh
/// Basically a smart std::vector
Philip Trettner's avatar
Philip Trettner committed
300
301
template <class iterator>
struct halfedge_collection : smart_collection<Mesh*, halfedge_tag, iterator>
Philip Trettner's avatar
Philip Trettner committed
302
303
304
305
{
    /// Adds an half-edge between two existing, distinct vertices
    /// if half-edge already exists, returns it
    /// (always adds opposite half-edge as well)
Philip Trettner's avatar
Philip Trettner committed
306
    halfedge_handle add_or_get(vertex_handle v_from, vertex_handle v_to) const;
Philip Trettner's avatar
Philip Trettner committed
307
308
309
310
    /// Adds an half-edge between two existing, distinct hafledges
    /// if half-edge already exists, returns it
    /// (always adds opposite half-edge as well)
    halfedge_handle add_or_get(halfedge_handle h_from, halfedge_handle h_to) const;
Philip Trettner's avatar
Philip Trettner committed
311
312
313
314
315

    /// Returns the half-edge handle between two vertices (invalid if not found)
    /// O(valence) computation
    halfedge_handle find(vertex_handle v_from, vertex_handle v_to) const;

Philip Trettner's avatar
Philip Trettner committed
316
317
318
319
320
    /// Collapsed the given half-edge by removing it, keeping the to_vertex, and creating new triangles
    /// Preserves half-edge properties but not face or vertex ones
    /// Similar to a vertex collapse of the `from` vertex with triangulation towards `to`
    void collapse(halfedge_handle h) const;

Philip Trettner's avatar
Philip Trettner committed
321
322
    /// Splits this half-edge in half by inserting a vertex (which is returned)
    /// Preserves face attributes
Philip Trettner's avatar
Philip Trettner committed
323
    /// Contrary to edges().split, the edge is preserved and a single new one is inserted AFTER h
Philip Trettner's avatar
Philip Trettner committed
324
325
    /// (thus h->next() is the newly inserted edge and h->vertex_to() is the returned vertex)
    vertex_handle split(halfedge_handle h) const;
Philip Trettner's avatar
Philip Trettner committed
326
327
    /// same as before but splits at a given ISOLATED vertex
    void split(halfedge_handle h, vertex_handle v) const;
Philip Trettner's avatar
Philip Trettner committed
328

329
330
331
    /// Given an isolated vertex v, inserts a self-adjacent edge at the to-vertex to v
    void attach(halfedge_handle h, vertex_handle v) const;

Philip Trettner's avatar
Philip Trettner committed
332
333
334
335
336
337
338
339
    /// Moves the to-vertex of this half-edge to the same as the next half-edge
    /// Preserves all attributes
    /// NOTE: does not work on boundaries!
    /// NOTE: does not work on triangles!
    /// TODO: image
    void rotate_next(halfedge_handle h) const;
    /// Same as rotate_next but with the previous half-edge
    void rotate_prev(halfedge_handle h) const;
Philip Trettner's avatar
Philip Trettner committed
340
341
342
343

    /// Removes the edge and both half-edges belonging to it (and both adjacent faces, vertices are NOT removed)
    /// (marks them as removed, compactify mesh to actually remove them)
    void remove_edge(halfedge_handle h) const;
344
345
};

Philip Trettner's avatar
Philip Trettner committed
346
// vertices
347

Philip Trettner's avatar
Philip Trettner committed
348
349
350
struct all_vertex_collection : vertex_collection<primitive<vertex_tag>::all_iterator>
{
};
351

Philip Trettner's avatar
Philip Trettner committed
352
353
354
struct all_vertex_const_collection : smart_collection<Mesh const*, vertex_tag, primitive<vertex_tag>::all_iterator>
{
};
355

Philip Trettner's avatar
Philip Trettner committed
356
357
struct valid_vertex_collection : vertex_collection<primitive<vertex_tag>::valid_iterator>
{
358
359
};

Philip Trettner's avatar
Philip Trettner committed
360
struct valid_vertex_const_collection : smart_collection<Mesh const*, vertex_tag, primitive<vertex_tag>::valid_iterator>
361
{
Philip Trettner's avatar
Philip Trettner committed
362
};
363

Philip Trettner's avatar
Philip Trettner committed
364
// faces
365

Philip Trettner's avatar
Philip Trettner committed
366
367
struct all_face_collection : face_collection<primitive<face_tag>::all_iterator>
{
368
369
};

Philip Trettner's avatar
Philip Trettner committed
370
struct all_face_const_collection : smart_collection<Mesh const*, face_tag, primitive<face_tag>::all_iterator>
371
{
Philip Trettner's avatar
Philip Trettner committed
372
};
373

Philip Trettner's avatar
Philip Trettner committed
374
375
376
struct valid_face_collection : face_collection<primitive<face_tag>::valid_iterator>
{
};
377

Philip Trettner's avatar
Philip Trettner committed
378
379
380
struct valid_face_const_collection : smart_collection<Mesh const*, face_tag, primitive<face_tag>::valid_iterator>
{
};
Philip Trettner's avatar
Philip Trettner committed
381

Philip Trettner's avatar
Philip Trettner committed
382
// edges
383

Philip Trettner's avatar
Philip Trettner committed
384
385
386
struct all_edge_collection : edge_collection<primitive<edge_tag>::all_iterator>
{
};
Philip Trettner's avatar
Philip Trettner committed
387

Philip Trettner's avatar
Philip Trettner committed
388
389
struct all_edge_const_collection : smart_collection<Mesh const*, edge_tag, primitive<edge_tag>::all_iterator>
{
390
391
};

Philip Trettner's avatar
Philip Trettner committed
392
struct valid_edge_collection : edge_collection<primitive<edge_tag>::valid_iterator>
393
{
Philip Trettner's avatar
Philip Trettner committed
394
};
395

Philip Trettner's avatar
Philip Trettner committed
396
397
398
struct valid_edge_const_collection : smart_collection<Mesh const*, edge_tag, primitive<edge_tag>::valid_iterator>
{
};
399

Philip Trettner's avatar
Philip Trettner committed
400
// half-edges
401

Philip Trettner's avatar
Philip Trettner committed
402
403
struct all_halfedge_collection : halfedge_collection<primitive<halfedge_tag>::all_iterator>
{
404
405
};

Philip Trettner's avatar
Philip Trettner committed
406
struct all_halfedge_const_collection : smart_collection<Mesh const*, halfedge_tag, primitive<halfedge_tag>::all_iterator>
407
{
Philip Trettner's avatar
Philip Trettner committed
408
};
409

Philip Trettner's avatar
Philip Trettner committed
410
411
412
struct valid_halfedge_collection : halfedge_collection<primitive<halfedge_tag>::valid_iterator>
{
};
413

Philip Trettner's avatar
Philip Trettner committed
414
415
struct valid_halfedge_const_collection : smart_collection<Mesh const*, halfedge_tag, primitive<halfedge_tag>::valid_iterator>
{
416
};
Philip Trettner's avatar
Philip Trettner committed
417

418
419
// ================= RINGS =================

Philip Trettner's avatar
Philip Trettner committed
420
template <class this_t, class tag>
Philip Trettner's avatar
Philip Trettner committed
421
struct primitive_ring : smart_range<this_t, typename primitive<tag>::handle>
Philip Trettner's avatar
Philip Trettner committed
422
{
Philip Trettner's avatar
Philip Trettner committed
423
424
    using handle = typename primitive<tag>::handle;

Philip Trettner's avatar
Philip Trettner committed
425
426
    face_handle face;

Philip Trettner's avatar
Philip Trettner committed
427
    /// Number of elements
Philip Trettner's avatar
Philip Trettner committed
428
429
    /// O(result) computation
    int size() const;
430
    /// Returns true if handle is contained in this ring
Philip Trettner's avatar
Philip Trettner committed
431
    bool contains(handle v) const;
Philip Trettner's avatar
Philip Trettner committed
432
433
};

Philip Trettner's avatar
Philip Trettner committed
434
435
template <class tag, class circulator>
struct face_primitive_ring : primitive_ring<face_primitive_ring<tag, circulator>, tag>
436
437
{
    face_handle face;
Philip Trettner's avatar
Philip Trettner committed
438
    face_primitive_ring(face_handle f) { face = f; }
439
440

    // Iteration:
Philip Trettner's avatar
Philip Trettner committed
441
442
    circulator begin() const { return {face.any_halfedge(), false}; }
    circulator end() const { return {face.any_halfedge(), true}; }
443
444
};

Philip Trettner's avatar
Philip Trettner committed
445
446
template <class tag, class circulator>
struct vertex_primitive_ring : primitive_ring<vertex_primitive_ring<tag, circulator>, tag>
447
{
Philip Trettner's avatar
Philip Trettner committed
448
449
    vertex_handle vertex;
    vertex_primitive_ring(vertex_handle v) { vertex = v; }
450
451

    // Iteration:
Philip Trettner's avatar
Philip Trettner committed
452
453
    circulator begin() const { return {vertex.any_outgoing_halfedge(), vertex.is_isolated()}; }
    circulator end() const { return {vertex.any_outgoing_halfedge(), true}; }
454
455
};

Philip Trettner's avatar
Philip Trettner committed
456
457
458
459
460
461
462
463
464
465
466
template <class tag, class circulator>
struct halfedge_primitive_ring : primitive_ring<halfedge_primitive_ring<tag, circulator>, tag>
{
    halfedge_handle halfedge;
    halfedge_primitive_ring(halfedge_handle h) { halfedge = h; }

    // Iteration:
    circulator begin() const { return {halfedge, false}; }
    circulator end() const { return {halfedge, true}; }
};

Philip Trettner's avatar
Philip Trettner committed
467
/// all vertices belonging to a face
Philip Trettner's avatar
Philip Trettner committed
468
struct face_vertex_ring : face_primitive_ring<vertex_tag, face_vertex_circulator>
469
{
Philip Trettner's avatar
Philip Trettner committed
470
    using face_primitive_ring<vertex_tag, face_vertex_circulator>::face_primitive_ring;
Philip Trettner's avatar
Philip Trettner committed
471
};
472

Philip Trettner's avatar
Philip Trettner committed
473
/// all halfedges belonging to a face
Philip Trettner's avatar
Philip Trettner committed
474
struct face_halfedge_ring : face_primitive_ring<halfedge_tag, face_halfedge_circulator>
Philip Trettner's avatar
Philip Trettner committed
475
{
Philip Trettner's avatar
Philip Trettner committed
476
    using face_primitive_ring<halfedge_tag, face_halfedge_circulator>::face_primitive_ring;
477
478
};

Philip Trettner's avatar
Philip Trettner committed
479
/// all edges belonging to a face
Philip Trettner's avatar
Philip Trettner committed
480
struct face_edge_ring : face_primitive_ring<edge_tag, face_edge_circulator>
481
{
Philip Trettner's avatar
Philip Trettner committed
482
    using face_primitive_ring<edge_tag, face_edge_circulator>::face_primitive_ring;
Philip Trettner's avatar
Philip Trettner committed
483
};
484

Philip Trettner's avatar
Philip Trettner committed
485
/// all adjacent faces belonging to a face
Philip Trettner's avatar
Philip Trettner committed
486
struct face_face_ring : face_primitive_ring<face_tag, face_face_circulator>
Philip Trettner's avatar
Philip Trettner committed
487
{
Philip Trettner's avatar
Philip Trettner committed
488
    using face_primitive_ring<face_tag, face_face_circulator>::face_primitive_ring;
Philip Trettner's avatar
Philip Trettner committed
489
};
490

Philip Trettner's avatar
Philip Trettner committed
491
/// all outgoing half-edges from a vertex
Philip Trettner's avatar
Philip Trettner committed
492
struct vertex_halfedge_out_ring : vertex_primitive_ring<halfedge_tag, vertex_halfedge_out_circulator>
Philip Trettner's avatar
Philip Trettner committed
493
{
Philip Trettner's avatar
Philip Trettner committed
494
    using vertex_primitive_ring<halfedge_tag, vertex_halfedge_out_circulator>::vertex_primitive_ring;
495
496
497
};

/// all incoming half-edges from a vertex
Philip Trettner's avatar
Philip Trettner committed
498
struct vertex_halfedge_in_ring : vertex_primitive_ring<halfedge_tag, vertex_halfedge_in_circulator>
499
{
Philip Trettner's avatar
Philip Trettner committed
500
    using vertex_primitive_ring<halfedge_tag, vertex_halfedge_in_circulator>::vertex_primitive_ring;
501
502
503
};

/// all adjacent vertices of a vertex
Philip Trettner's avatar
Philip Trettner committed
504
struct vertex_vertex_ring : vertex_primitive_ring<vertex_tag, vertex_vertex_circulator>
505
{
Philip Trettner's avatar
Philip Trettner committed
506
    using vertex_primitive_ring<vertex_tag, vertex_vertex_circulator>::vertex_primitive_ring;
507
508
509
};

/// all adjacent edges of a vertex
Philip Trettner's avatar
Philip Trettner committed
510
struct vertex_edge_ring : vertex_primitive_ring<edge_tag, vertex_edge_circulator>
511
{
Philip Trettner's avatar
Philip Trettner committed
512
    using vertex_primitive_ring<edge_tag, vertex_edge_circulator>::vertex_primitive_ring;
513
514
515
};

/// all adjacent faces of a vertex (INCLUDES invalid ones for boundaries)
Philip Trettner's avatar
Philip Trettner committed
516
struct vertex_face_ring : vertex_primitive_ring<face_tag, vertex_face_circulator>
517
{
Philip Trettner's avatar
Philip Trettner committed
518
    using vertex_primitive_ring<face_tag, vertex_face_circulator>::vertex_primitive_ring;
519
520
};

Philip Trettner's avatar
Philip Trettner committed
521
522
523
524
525
/// all half-edges along a ring (next -> next -> ...)
struct halfedge_ring : halfedge_primitive_ring<halfedge_tag, halfedge_ring_circulator>
{
    using halfedge_primitive_ring<halfedge_tag, halfedge_ring_circulator>::halfedge_primitive_ring;
};
526
}