-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFilteredTriMesh.hh
419 lines (364 loc) · 14.3 KB
/
FilteredTriMesh.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
#ifndef TRIMESH_FILTER_HH
#define TRIMESH_FILTER_HH
#include "common.hh"
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
/*
* This is a simplified representation of patch. It only contains necessary information whether a seam is boundary/merged or not
*/
class Patch_boundary {
public:
bool developable = true;
double seam_score = 0;
size_t n_merged_seams = 0;
boost::dynamic_bitset<> boundary_seam_idx;
boost::dynamic_bitset<> merged_seam_idx;
boost::dynamic_bitset<> merged_subMesh_idx;
Patch_boundary() {}
Patch_boundary(size_t n_seam_segments, size_t n_subMeshes) :
boundary_seam_idx(n_seam_segments),
merged_seam_idx(n_seam_segments),
merged_subMesh_idx(n_subMeshes) {}
Patch_boundary(boost::archive::text_iarchive &ia)
{
ia >> *this;
}
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & developable;
ar & seam_score;
ar & n_merged_seams;
ar & boundary_seam_idx;
ar & merged_seam_idx;
ar & merged_subMesh_idx;
}
};
// True means it's contained in this sub-mesh
struct Predicate {
boost::dynamic_bitset<> m_vertex_filter;
boost::dynamic_bitset<> m_edge_filter;
boost::dynamic_bitset<> m_halfedge_filter;
boost::dynamic_bitset<> m_face_filter;
bool operator()(VertexHandle vh) const {
return m_vertex_filter[vh.idx()];
}
bool operator()(EdgeHandle eh) const {
return m_edge_filter[eh.idx()];
}
bool operator()(HalfedgeHandle heh) const {
return m_halfedge_filter[heh.idx()];
}
bool operator()(FaceHandle fh) const {
return m_face_filter[fh.idx()];
}
};
struct Boundary_predicate {
boost::dynamic_bitset<> m_boundary_vertex_filter;
boost::dynamic_bitset<> m_boundary_edge_filter;
bool operator()(VertexHandle vh) const {
return m_boundary_vertex_filter[vh.idx()];
}
bool operator()(EdgeHandle eh) const {
return m_boundary_edge_filter[eh.idx()];
}
};
template <class Iter>
struct Range {
Iter m_begin;
Iter m_end;
Range(Iter begin, Iter end) : m_begin(begin), m_end(end) {}
Iter begin() {
return m_begin;
}
Iter end() {
return m_end;
}
};
class FilteredVertexIter;
class FilteredEdgeIter;
class FilteredHalfedgeIter;
class FilteredFaceIter;
/**
* @brief This class stores essential information of a submesh of trimesh.
*/
class FilteredTriMesh
{
private:
TriMesh *m_mesh;
Predicate predicate;
Boundary_predicate boundary_predicate;
/* @brief Given a halfedge handle, return the flattened position of "from" vertex of this halfedge.
* We use halfedge handle to store the flattened position of boundary vertex because a boundary vertex in the original mesh
* may map to two vertices after split. In such case, vertex-to-vertex mapping is not one-to-one.
* We use halfedge-to-vertex mapping which is one-to-one.
*/
std::map<HalfedgeHandle, int> boundary_vertex_mapping;
std::map<VertexHandle, int> non_boundary_vertex_mapping;
/// Stores the flattened position with the indices of mapping above
std::vector<TriMesh::Point> flattened_position;
HalfedgeHandle get_nearby_boundary_halfedge(HalfedgeHandle heh);
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & predicate.m_vertex_filter;
ar & predicate.m_edge_filter;
ar & predicate.m_halfedge_filter;
ar & predicate.m_face_filter;
ar & boundary_predicate.m_boundary_vertex_filter;
ar & boundary_predicate.m_boundary_edge_filter;
ar & merged_subMesh_idx;
ar & merged_seam_idx;
ar & merged_edge_idx;
ar & boundary_vertex_mapping;
ar & non_boundary_vertex_mapping;
ar & flattened_position;
ar & max_distortion;
ar & seam_score;
ar & n_merged_seams;
}
public:
/* Use this to record which sub-meshes do this patch have merged
* A patch with bits [1,0,0,0,0,....] mean it contains #1 sub-mesh
* A patch with bits [0,1,1,0,0,....] mean it merged #2 and #3 sub-meshes
*/
typedef boost::dynamic_bitset<> Patch_idx;
/* Use this to record which seam segment do this patch have merged
* A patch with bits [1,0,0,0,0,....] mean it merged #1 seam
* A patch with bits [0,1,1,0,0,....] mean it merged #2 and #3 seams
*/
typedef boost::dynamic_bitset<> Seam_idx;
Patch_idx merged_subMesh_idx;
Seam_idx merged_seam_idx;
/* Use this to record which edge handle do this patch have merged
* A merged edge should not be added to boundary anymore
* A patch with bits [1,0,0,0,0,....] mean it merged #1 edge
* A patch with bits [0,1,1,0,0,....] mean it merged #2 and #3 edges
*/
boost::dynamic_bitset<> merged_edge_idx;
// The face area difference between original sub-mesh & flattened sub-mesh
double max_distortion = -1;
// The seam score by evaluating weightFunction (lower is better)
double seam_score = -1;
int n_merged_seams = 0;
// A flag used for determine whether it's developable
bool developable = true;
/// You shouldn't use this constructor unless you just need to allocate a variable and assigned it later.
FilteredTriMesh() {}
FilteredTriMesh(TriMesh *mesh,
boost::archive::text_iarchive &ia);
FilteredTriMesh(TriMesh *mesh,
std::set<FaceHandle> &faces,
std::set<EdgeHandle> &boundary_edges);
/// Copy constructor (backward compatible with old boost code)
FilteredTriMesh(const FilteredTriMesh& other);
FilteredTriMesh& operator=(const FilteredTriMesh& other);
/// Move constructor
FilteredTriMesh(FilteredTriMesh&& other) noexcept;
FilteredTriMesh& operator=(FilteredTriMesh&& other) noexcept;
bool is_valid(VertexHandle vh) const;
bool is_valid(EdgeHandle eh) const;
bool is_valid(HalfedgeHandle heh) const;
bool is_valid(FaceHandle fh) const;
bool is_boundary(VertexHandle vh) const;
bool is_boundary(EdgeHandle eh) const;
bool is_boundary(HalfedgeHandle heh) const;
/* For the T-shape boundary like darts, we called the extrusion part dual boundary.
* Each of them will be split into two edges after flattening.
* However, the original mesh contains only one edge. So we need to take care of such edges
*/
///@{
bool is_dual_boundary(EdgeHandle eh) const;
bool is_dual_boundary(HalfedgeHandle eh) const;
///@}
/// The filtered iterators of original operations
///@{
unsigned long n_vertices() const;
Range<FilteredVertexIter> vertices() const;
Range<FilteredEdgeIter> edges() const;
Range<FilteredHalfedgeIter> halfedges() const;
Range<FilteredFaceIter> faces() const;
/// There seems to be some problem about filter_iterator with circulator
/// You should use *(iter.base()) instead of *iter
///@{
// FilteredRange<TriMesh::ConstFaceVertexIter, Predicate> fv_range(FaceHandle fh) const;
// FilteredRange<TriMesh::ConstFaceHalfedgeIter, Predicate> fh_range(FaceHandle fh) const;
// boost::filter_iterator<Predicate, TriMesh::ConstFaceVertexIter> cfv_begin(FaceHandle fh) const;
// boost::filter_iterator<Predicate, TriMesh::ConstFaceVertexIter> cfv_end(FaceHandle fh) const;
/// For face-halfedge circulator, if a face is valid, then its all related halfedges are valid
/// Thus we don't need to filter them
Range<TriMesh::ConstFaceHalfedgeIter> fh_range(FaceHandle fh) const;
///@}
Range<FilteredVertexIter> boundary_vertices() const;
Range<FilteredEdgeIter> boundary_edges() const;
///@}
/// Filtered functions
///@{
VertexHandle vertex_handle(int idx);
EdgeHandle edge_handle(HalfedgeHandle heh) const;
HalfedgeHandle halfedge_handle(EdgeHandle eh, int idx) const;
HalfedgeHandle halfedge_handle(FaceHandle fh) const;
HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle heh) const;
HalfedgeHandle next_halfedge_handle(HalfedgeHandle heh) const;
HalfedgeHandle next_boundary_halfedge_handle(HalfedgeHandle heh) const;
HalfedgeHandle prev_halfedge_handle(HalfedgeHandle heh) const;
HalfedgeHandle prev_boundary_halfedge_handle(HalfedgeHandle heh) const;
VertexHandle from_vertex_handle(HalfedgeHandle heh) const;
VertexHandle to_vertex_handle(HalfedgeHandle heh) const;
size_t valence(VertexHandle vh) const;
TriMesh::Point& point(VertexHandle vh);
const TriMesh::Color& color(FaceHandle fh) const;
double calc_edge_length(EdgeHandle eh) const;
double calc_edge_length(HalfedgeHandle heh) const;
double calc_sector_angle(HalfedgeHandle heh) const;
double calc_sector_area(HalfedgeHandle heh) const;
///@}
/// Additional operations
///@{
int n_duplicated_vertices();
TriMesh::Point& flattened_non_boundary_point(VertexHandle vh);
TriMesh::Point& flattened_boundary_point(HalfedgeHandle heh);
double getSumInnerAngle(HalfedgeHandle from, HalfedgeHandle to);
int get_non_boundary_vertex_idx(VertexHandle vh);
int get_boundary_vertex_idx(HalfedgeHandle heh);
///@}
/// Use this if you want to use operations for original unfiltered mesh
TriMesh *mesh() const;
};
template <class HandleType, class Derived>
class FilteredIterator :
public boost::iterator_facade< FilteredIterator<HandleType, Derived>,
HandleType,
boost::forward_traversal_tag,
HandleType>
{
public:
FilteredIterator(const FilteredTriMesh &mesh,
const boost::dynamic_bitset<> &filter,
size_t pos = 0) :
m_mesh(mesh), m_filter(filter), m_pos(pos) {
}
protected:
friend class boost::iterator_core_access;
void increment() {
m_pos = m_filter.find_next(m_pos);
}
bool equal(FilteredIterator<HandleType, Derived> const& other) const {
auto handle1 = this->dereference();
auto handle2 = *other;
return handle1 == handle2;
}
HandleType dereference() const {
auto handle = static_cast<const Derived*>(this)->dereference_impl();
return handle;
}
const FilteredTriMesh &m_mesh;
const boost::dynamic_bitset<> &m_filter;
size_t m_pos;
};
class FilteredVertexIter : public FilteredIterator<VertexHandle, FilteredVertexIter> {
public:
FilteredVertexIter(const FilteredTriMesh &mesh,
const boost::dynamic_bitset<> &filter,
size_t pos) :
FilteredIterator(mesh, filter, pos) {
}
VertexHandle dereference_impl() const {
return m_mesh.mesh()->vertex_handle(m_pos);
}
};
class FilteredEdgeIter : public FilteredIterator<EdgeHandle, FilteredEdgeIter> {
public:
FilteredEdgeIter(const FilteredTriMesh &mesh,
const boost::dynamic_bitset<> &filter,
size_t pos) :
FilteredIterator(mesh, filter, pos) {
}
EdgeHandle dereference_impl() const {
return m_mesh.mesh()->edge_handle(m_pos);
}
};
class FilteredHalfedgeIter : public FilteredIterator<HalfedgeHandle, FilteredHalfedgeIter> {
public:
FilteredHalfedgeIter(const FilteredTriMesh &mesh,
const boost::dynamic_bitset<> &filter,
size_t pos) :
FilteredIterator(mesh, filter, pos) {
}
HalfedgeHandle dereference_impl() const {
return m_mesh.mesh()->halfedge_handle(m_pos);
}
};
class FilteredFaceIter : public FilteredIterator<FaceHandle, FilteredFaceIter> {
public:
FilteredFaceIter(const FilteredTriMesh &mesh,
const boost::dynamic_bitset<> &filter,
size_t pos) :
FilteredIterator(mesh, filter, pos) {
}
FaceHandle dereference_impl() const {
return m_mesh.mesh()->face_handle(m_pos);
}
};
namespace boost {
namespace serialization {
template <typename Ar, typename Block, typename Alloc>
void save(Ar& ar, dynamic_bitset<Block, Alloc> const& bs, unsigned) {
size_t num_bits = bs.size();
std::vector<Block> blocks(bs.num_blocks());
to_block_range(bs, blocks.begin());
ar & num_bits & blocks;
}
template <typename Ar, typename Block, typename Alloc>
void load(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned) {
size_t num_bits;
std::vector<Block> blocks;
ar & num_bits & blocks;
bs.resize(num_bits);
from_block_range(blocks.begin(), blocks.end(), bs);
bs.resize(num_bits);
}
template <typename Ar, typename Block, typename Alloc>
void serialize(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned version) {
split_free(ar, bs, version);
}
template <typename Ar>
void serialize(Ar& ar, VertexHandle& handle, unsigned version) {
int idx = handle.idx();
ar & idx;
handle = VertexHandle(idx);
}
template <typename Ar>
void serialize(Ar& ar, EdgeHandle& handle, unsigned version) {
int idx = handle.idx();
ar & idx;
handle = EdgeHandle(idx);
}
template <typename Ar>
void serialize(Ar& ar, HalfedgeHandle& handle, unsigned version) {
int idx = handle.idx();
ar & idx;
handle = HalfedgeHandle(idx);
}
template <typename Ar>
void serialize(Ar& ar, FaceHandle& handle, unsigned version) {
int idx = handle.idx();
ar & idx;
handle = FaceHandle(idx);
}
template <typename Ar>
void serialize(Ar& ar, OpenMesh::Vec3d& vec, unsigned version) {
ar & vec[0];
ar & vec[1];
ar & vec[2];
}
}
}
#endif //TRIMESH_FILTER_HH