1 // This is brl/bbas/bmsh3d/bmsh3d_mesh.cxx
2 #include <list>
3 #include <set>
4 #include <map>
5 #include <queue>
6 #include <iostream>
7 #include "bmsh3d_mesh.h"
8 //:
9 // \file
10 // \brief Mesh
11 //
12 // \author
13 // MingChing Chang April 22, 2005
14 //
15 // \verbatim
16 // Modifications
17 // <none>
18 // \endverbatim
19 //
20 //-------------------------------------------------------------------------
21
22 #include <cassert>
23 #ifdef _MSC_VER
24 # include "vcl_msvc_warnings.h"
25 #endif
26 #include "vgl/vgl_point_3d.h"
27 #include "vgl/vgl_distance.h"
28 #include "vul/vul_printf.h"
29
30 #include "bmsh3d_he_mesh.h"
31
move_faces_to_set(std::vector<std::vector<int>> & from_faces,std::vector<std::vector<int>> & to_faces)32 void move_faces_to_set (std::vector<std::vector<int> >& from_faces,
33 std::vector<std::vector<int> >& to_faces)
34 {
35 to_faces.insert (to_faces.end(), from_faces.begin(), from_faces.end());
36 }
37
38
get_avg_edge_len_from_F()39 double bmsh3d_ifs_mesh::get_avg_edge_len_from_F ()
40 {
41 double d, avg_len = 0;
42 unsigned int count = 0;
43 vgl_point_3d<double> P0, P1;
44 assert (facemap_.size() != 0);
45
46 //Loop through each mesh face and count bnd edge len.
47 auto it = facemap_.begin();
48 for (; it != facemap_.end(); it++) {
49 bmsh3d_face* F = (*it).second;
50 int sz = F->vertices().size();
51 assert (sz > 1);
52 for (int i=0; i<sz-1; i++) {
53 P0 = F->vertices(i)->pt();
54 P1 = F->vertices(i+1)->pt();
55 d = vgl_distance (P0, P1);
56 avg_len += d;
57 }
58 P0 = F->vertices(0)->pt();
59 P1 = F->vertices(sz-1)->pt();
60 d = vgl_distance (P0, P1);
61 avg_len += d;
62 count += sz;
63 }
64
65 assert (count != 0);
66 return avg_len / count;
67 }
68
69 //############################################################################
70
bmsh3d_mesh(const bmsh3d_mesh & mesh)71 bmsh3d_mesh::bmsh3d_mesh(const bmsh3d_mesh& mesh)
72 : bmsh3d_ifs_mesh(mesh), edge_id_counter_(mesh.edge_id_counter_), i_traverse_flag_(mesh.i_traverse_flag_),
73 b_watertight_(mesh.b_watertight_)
74 {
75 #if 0 // commented out
76 // deep copy the edgemap
77 std::map<int, bmsh3d_edge* > edgemap = mesh.edgemap_;
78 std::map<int, bmsh3d_edge* >::iterator edge_it = edgemap.begin();
79 while (edge_it != edgemap.end()) {
80 // create new edges
81 bmsh3d_edge* edge = edge_it->second;
82 bmsh3d_vertex* s_vertex = edge->sV();
83 bmsh3d_vertex* eV = edge->eV();
84
85
86 bmsh3d_vertex* s = this->_new_vertex();
87 bmsh3d_vertex* e = this->_new_vertex();
88 s->get_pt().set(s_vertex->get_pt());
89 this->add_new_edge(s, e);
90 edge_it++;
91 }
92
93 // deep copy the faces
94 std::map<int, bmsh3d_face* > facemap = mesh.facemap();
95 std::map<int, bmsh3d_edge* >::iterator face_it = facemap.begin();
96 while (face_it != facemap.end()) {
97 bmsh3d_face* f = new bmsh3d_face(face_it->second);
98 this->_add_face(f);
99 face_it++;
100 }
101 #else // 0
102 assert(!"NYI");
103 #endif // 0
104 }
105
_connect_F_E_end(bmsh3d_face * F,bmsh3d_edge * E)106 bmsh3d_halfedge* _connect_F_E_end (bmsh3d_face* F, bmsh3d_edge* E)
107 {
108 //The halfedge will be deleted when the face disconnect from the F.
109 auto* halfedge = new bmsh3d_halfedge (E, F);
110 //Handle the both-way connectivity of halfedge-face.
111 F->_connect_HE_to_end (halfedge);
112 //Handle the both-way connectivity of halfedge-edge.
113 E->_connect_HE_to_end (halfedge);
114 return halfedge;
115 }
116
117 // ----------------------------------------------------------------------------
118
119
120 //: Count the size of mesh faces indices for visualization using SoIndexedFaceSet
_count_faces_indices_ifs()121 unsigned int bmsh3d_ifs_mesh::_count_faces_indices_ifs()
122 {
123 unsigned int totalVertices = 0;
124 auto it = facemap_.begin();
125 for (; it != facemap_.end(); it++) {
126 bmsh3d_face* F = (*it).second;
127 assert (F->vertices().size() != 0);
128 unsigned int nVer = F->vertices().size();
129 nVer = nVer + 1; //the '-1' field
130 totalVertices += nVer;
131 }
132 return totalVertices;
133 }
134
135 //: Count the size of mesh faces indices for visualization using SoIndexedFaceSet
136 // Skip the unmarked face with false i_visited_
_count_visited_faces_indices_ifs()137 unsigned int bmsh3d_ifs_mesh::_count_visited_faces_indices_ifs()
138 {
139 unsigned int totalVertices = 0;
140 auto it = facemap_.begin();
141 for (; it != facemap_.end(); it++) {
142 bmsh3d_face* F = (*it).second;
143 if (! F->b_visited())
144 continue; //skip the unmarked F.
145
146 unsigned int nVer = F->vertices().size();
147 nVer = nVer + 1; //the '-1' field
148 totalVertices += nVer;
149 }
150 return totalVertices;
151 }
152
153 //: Assign IFS_vidx using the vertex ids
154 // For instance, used in the surface mesh reconstruction,
155 // where the indices of the vertices is known.
ifs_assign_Vs_vid_by_id()156 void bmsh3d_ifs_mesh::ifs_assign_Vs_vid_by_id ()
157 {
158 auto it = facemap_.begin();
159 for (; it != facemap_.end(); it++) {
160 bmsh3d_face* F = (*it).second;
161 F->_ifs_assign_Vs_vid_by_id ();
162 }
163 }
164
165 //: Assign IFS_vid using the order of the vertex in the map
166 // The first vertex will have vid_ = 0 and the last in the map
167 // will have vid_ = (num_vertices - 1);
assign_IFS_vertex_vid_by_vertex_order()168 void bmsh3d_ifs_mesh::assign_IFS_vertex_vid_by_vertex_order()
169 {
170 this->reset_vertex_traversal();
171 int vid_count = 0;
172 for (bmsh3d_vertex* vb = nullptr; this->next_vertex(vb); vid_count ++) {
173 bmsh3d_vertex* vertex = (vb);
174 vertex->set_vid(vid_count);
175 }
176
177 return;
178 }
179
mark_unmeshed_pts()180 void bmsh3d_ifs_mesh::mark_unmeshed_pts ()
181 {
182 //Reset the unmeshed flag of each point.
183 auto vit = vertexmap_.begin();
184 for (; vit != vertexmap_.end(); vit++) {
185 bmsh3d_vertex* V = (*vit).second;
186 V->set_meshed (false);
187 }
188
189 //Go through all mesh faces and mark incident points.
190 auto fit = facemap_.begin();
191 for (; fit != facemap_.end(); fit++) {
192 bmsh3d_face* F = (*fit).second;
193
194 for (unsigned int i=0; i<F->vertices().size(); i++) {
195 bmsh3d_vertex* V = F->vertices(i);
196 V->set_meshed (true);
197 }
198 }
199 }
200
delete_unmeshed_pts()201 void bmsh3d_ifs_mesh::delete_unmeshed_pts ()
202 {
203 mark_unmeshed_pts ();
204
205 //Go through each point and delete unmeshed ones.
206 auto vit = vertexmap_.begin();
207 while (vit != vertexmap_.end()) {
208 bmsh3d_vertex* V = (*vit).second;
209 if (! V->b_meshed()) {
210 vit++;
211 remove_vertex (V);
212 }
213 else
214 vit++;
215 }
216 }
217
218 // ###################################################################
219
get_avg_edge_len_from_F()220 double bmsh3d_mesh::get_avg_edge_len_from_F ()
221 {
222 if (! is_MHE())
223 return bmsh3d_ifs_mesh::get_avg_edge_len_from_F ();
224
225 double avg_len = 0;
226 unsigned int count = 0;
227 assert (facemap_.size() != 0);
228
229 //Loop through each mesh face and count bnd edge len.
230 auto it = facemap_.begin();
231 for (; it != facemap_.end(); it++) {
232 bmsh3d_face* F = (*it).second;
233 assert (F->halfedge());
234 assert (F->halfedge()->next());
235
236 bmsh3d_halfedge* HE = F->halfedge();
237 do {
238 avg_len += HE->edge()->length();
239 count++;
240 HE = HE->next();
241 }
242 while (HE != F->halfedge());
243 }
244
245 assert (count != 0);
246 return avg_len / count;
247 }
248
249 //: Count the size of mesh faces indices for visualization using SoIndexedFaceSet
count_faces_indices()250 unsigned int bmsh3d_mesh::count_faces_indices()
251 {
252 if (is_MHE())
253 return _count_faces_indices_mhe ();
254 else
255 return _count_faces_indices_ifs ();
256 }
257
258 //: Count the size of mesh faces indices for visualization using SoIndexedFaceSet
_count_faces_indices_mhe()259 unsigned int bmsh3d_mesh::_count_faces_indices_mhe()
260 {
261 unsigned int totalVertices = 0;
262 auto it = facemap_.begin();
263 for (; it != facemap_.end(); it++) {
264 bmsh3d_face* F = (*it).second;
265 std::vector<bmsh3d_vertex*> vertices;
266 F->get_ordered_Vs (vertices);
267 unsigned int nVer = vertices.size();
268 nVer = nVer + 1; //the '-1' field
269 totalVertices += nVer;
270 }
271 return totalVertices;
272 }
273
274 //: Add all faces' incident edges and vertices into the map.
_update_incident_Es_Vs()275 void bmsh3d_mesh::_update_incident_Es_Vs ()
276 {
277 auto it = facemap_.begin();
278 for (; it != facemap_.end(); it++) {
279 bmsh3d_face* F = (*it).second;
280
281 bmsh3d_halfedge* HE = F->halfedge();
282 do {
283 bmsh3d_edge* E = HE->edge();
284 _add_edge (E);
285 _add_vertex (E->vertices(0));
286 _add_vertex (E->vertices(1));
287 HE = HE->next();
288 }
289 while (HE != F->halfedge());
290 }
291 }
292
remove_F_del_isolated_Es(bmsh3d_face * F)293 void bmsh3d_mesh::remove_F_del_isolated_Es (bmsh3d_face* F)
294 {
295 //The list of edges to delete.
296 std::vector<bmsh3d_edge*> edges_to_del;
297 bmsh3d_halfedge* HE = F->halfedge();
298 do {
299 bmsh3d_edge* E = HE->edge();
300 if (E->halfedge()->pair() == nullptr)
301 edges_to_del.push_back (E);
302 HE = HE->next();
303 }
304 while (HE != F->halfedge());
305
306 remove_face (F);
307
308 for (auto & i : edges_to_del) {
309 remove_edge (i);
310 }
311 }
312
313 //: Create and add a mesh face from a given set of ordered edges.
add_new_face(const std::vector<bmsh3d_edge * > & ordered_edges)314 bmsh3d_face* bmsh3d_mesh::add_new_face (const std::vector<bmsh3d_edge*>& ordered_edges)
315 {
316 //Create and add the new face to the structure.
317 bmsh3d_face* F = _new_face();
318 _add_face (F);
319
320 //Create the first halfedge of incidence relationship
321 assert (ordered_edges.size() > 2);
322 auto* HE = new bmsh3d_halfedge (ordered_edges[0], F);
323 F->set_halfedge (HE);
324 ordered_edges[0]->_connect_HE_to_end (HE); //add the HE to the edge's pair_ structure.
325
326 //for each next_edge, create a halfedge and add the incidence connectivity.
327 for (unsigned int i=1; i<ordered_edges.size(); i++) {
328 bmsh3d_edge* e = ordered_edges[i];
329 auto* nextHE = new bmsh3d_halfedge (e, F);
330
331 //add the nextHE to the edge's pair_ structure.
332 e->_connect_HE_to_end (nextHE);
333
334 //add to the circular list of halfedges.
335 HE->set_next (nextHE);
336 HE = nextHE;
337 }
338
339 //finish the circular list of halfedges.
340 HE->set_next (F->halfedge());
341
342 return F;
343 }
344
345 // ----------------------------------------------------------------------------
346 // Print a summary of mesh properties
print_summary(std::ostream & str)347 void bmsh3d_mesh::print_summary(std::ostream& str)
348 {
349 str << "\n-------------------------------------------------\n"
350 << "Mesh info\n"
351 << "Number of vertices = " << this->vertexmap().size() << '\n'
352 << "Number of faces = " << this->facemap().size() << '\n'
353 << "Number of edges = " << this->edgemap().size() << '\n';
354 }
355
print_topo_summary(void)356 void bmsh3d_mesh::print_topo_summary (void)
357 {
358 vul_printf (std::cerr, "\nThe reconstructed surface mesh is:\n");
359
360 bool b_2_manifold;
361 unsigned int n_bnd_edges = count_bnd_edges (b_2_manifold);
362
363 if (b_2_manifold)
364 vul_printf (std::cerr, "\t- 2-manifold\n");
365 else
366 vul_printf (std::cerr, "\t- non-2-manifold\n");
367
368 int max_sides = count_max_polygon_sides ();
369
370 if (max_sides == 3)
371 vul_printf (std::cerr, "\t- triangular\n");
372 else
373 vul_printf (std::cerr, "\t- non-triangular, max %u polygon sides.\n", max_sides);
374
375
376 if (n_bnd_edges == 0)
377 vul_printf (std::cerr, "\t- closed watertight surface.\n\n");
378 else
379 vul_printf (std::cerr, "\t- non-watertight, %u boundary edges.\n\n", n_bnd_edges);
380 }
381
clone_mesh_ifs_3d(bmsh3d_mesh * M)382 bmsh3d_mesh* clone_mesh_ifs_3d (bmsh3d_mesh* M)
383 {
384 //Assume M is in data structure mode of IFS, no isolated edge.
385 auto* newM = new bmsh3d_mesh ();
386
387 //Clone all vertices of M.
388 //Note: use _new_vertex() to create a new vertex.
389 auto vit = M->vertexmap().begin();
390 for (; vit != M->vertexmap().end(); vit++) {
391 bmsh3d_vertex* V = (*vit).second;
392 bmsh3d_vertex* newV = newM->_new_vertex (V->id());
393 newV->set_pt (V->pt());
394 newM->_add_vertex (newV);
395 }
396 newM->set_vertex_id_counter (M->vertex_id_counter());
397 newM->set_free_objects_in_destructor (M->b_free_objects_in_destructor());
398
399 //Clone all faces of M.
400 auto fit = M->facemap().begin();
401 for (; fit != M->facemap().end(); fit++) {
402 bmsh3d_face* F = (*fit).second;
403 bmsh3d_face* newF = newM->_new_face (F->id());
404 for (unsigned int i=0; i<F->vertices().size(); i++) {
405 int vid = F->vertices(i)->id();
406 bmsh3d_vertex* newV = newM->vertexmap (vid);
407 newF->_ifs_add_vertex (newV);
408 }
409 newM->_add_face (newF);
410 }
411 newM->set_face_id_counter (M->face_id_counter());
412
413 return newM;
414 }
415
add_F_to_M(std::vector<int> & vids,bmsh3d_mesh * M)416 bmsh3d_face* add_F_to_M (std::vector<int>& vids, bmsh3d_mesh* M)
417 {
418 //First find or create the set of order edges of this face.
419 //assumption: vids is ordered a circular way.
420 std::vector<bmsh3d_edge*> ordered_edges;
421
422 //Add one more vertex to the end for circulation.
423 vids.push_back (vids[0]);
424 for (unsigned int i=0; i<vids.size()-1; i++) {
425 bmsh3d_vertex* V0 = M->vertexmap (vids[i]);
426 if (V0 == nullptr) { //if vertex not found, create a new vertex.
427 V0 = M->_new_vertex (vids[i]);
428 M->_add_vertex (V0);
429 }
430 bmsh3d_vertex* V1 = M->vertexmap (vids[i+1]);
431 if (V1 == nullptr) { //if vertex not found, create a new vertex.
432 V1 = M->_new_vertex (vids[i+1]);
433 M->_add_vertex (V1);
434 }
435
436 bmsh3d_edge* E = E_sharing_2V (V0, V1);
437 if (E == nullptr) //if edge not found, create a new edge.
438 E = M->add_new_edge (V0, V1);
439
440 ordered_edges.push_back (E);
441 }
442
443 //Create the face from the set of ordered edges.
444 bmsh3d_face* newF = M->add_new_face (ordered_edges);
445 return newF;
446 }
447
add_F_to_M_check_topo(std::vector<int> & vids,bmsh3d_mesh * M)448 bmsh3d_face* add_F_to_M_check_topo (std::vector<int>& vids, bmsh3d_mesh* M)
449 {
450 //First find or create the set of order edges of this face.
451 //assumption: vids is ordered a circular way.
452 std::vector<bmsh3d_edge*> ordered_edges;
453
454 //Add one more vertex to the end for circulation.
455 vids.push_back (vids[0]);
456
457 //The topo. error only occur for existing edges or vertices.
458 VTOPO_TYPE vt;
459
460 for (unsigned int i=0; i<vids.size()-1; i++) {
461 bmsh3d_vertex* V0 = M->vertexmap (vids[i]);
462 if (V0 == nullptr) { //if vertex not found, create a new vertex.
463 V0 = M->_new_vertex (vids[i]);
464 M->_add_vertex (V0);
465 }
466 else { //Check V0 for non-2-manifold 1-ring
467 vt = V0->detect_vtopo_type();
468 if (vt==VTOPO_2_MANIFOLD_1RING || vt==VTOPO_NON_MANIFOLD_1RING)
469 return nullptr;
470 }
471
472 bmsh3d_vertex* V1 = M->vertexmap (vids[i+1]);
473 if (V1 == nullptr) { //if vertex not found, create a new vertex.
474 V1 = M->_new_vertex (vids[i+1]);
475 M->_add_vertex (V1);
476 }
477 else { //Check V1 for non-2-manifold 1-ring
478 vt = V1->detect_vtopo_type();
479 if (vt==VTOPO_2_MANIFOLD_1RING || vt==VTOPO_NON_MANIFOLD_1RING)
480 return nullptr;
481 }
482
483 bmsh3d_edge* E = E_sharing_2V (V0, V1);
484 if (E == nullptr) { //if edge not found, create a new edge.
485 E = M->add_new_edge (V0, V1);
486 }
487 else { //Check E for non-2-manifold topology.
488 if (E->n_incident_Fs() > 1)
489 return nullptr;
490 }
491
492 ordered_edges.push_back (E);
493 }
494
495 //Create the face from the set of ordered edges.
496 bmsh3d_face* newF = M->add_new_face (ordered_edges);
497 return newF;
498 }
499
add_M_faces_to_IFSset(bmsh3d_mesh * M,std::vector<std::vector<int>> & faces)500 void add_M_faces_to_IFSset (bmsh3d_mesh* M, std::vector<std::vector<int> >& faces)
501 {
502 auto fit = M->facemap().begin();
503 for (; fit != M->facemap().end(); fit++) {
504 bmsh3d_face* F = (*fit).second;
505 std::vector<int> vids;
506 F->get_ordered_V_ids (vids);
507 faces.push_back (vids);
508 }
509 }
510
511 // ----------------------------------------------------------------------------
bmsh3d_mesh_print_object_size()512 void bmsh3d_mesh_print_object_size ()
513 {
514 vul_printf (std::cerr, "\n\n");
515 std::vector<bmsh3d_edge*> tmp_vector;
516 std::cout << "size of std::vector: "<< sizeof(tmp_vector) << std::endl;
517 std::list<bmsh3d_edge*> tmp_list;
518 std::cout << "size of std::list: "<< sizeof(tmp_list) << std::endl;
519 std::set<bmsh3d_edge*> tmp_set;
520 std::cout << "size of std::set: "<< sizeof(tmp_set) << std::endl;
521 std::set<bmsh3d_edge*> tmp_map;
522 std::cout << "size of std::map: "<< sizeof(tmp_map) << std::endl;
523 vul_printf (std::cerr, "\n");
524
525 vul_printf (std::cerr, " Object Size (bytes)\n");
526 vul_printf (std::cerr, "------------------------------------\n");
527 vul_printf (std::cerr, "vispt_elm %3d\n", sizeof (vispt_elm));
528 vul_printf (std::cerr, "bmsh3d_vertex -- %3d\n", sizeof (bmsh3d_vertex));
529 vul_printf (std::cerr, "\n");
530 vul_printf (std::cerr, "bmsh3d_halfedge -- %3d\n", sizeof (bmsh3d_halfedge));
531 vul_printf (std::cerr, "bmsh3d_edge -- %3d\n", sizeof (bmsh3d_edge));
532 vul_printf (std::cerr, "\n");
533 vul_printf (std::cerr, "bmsh3d_face -- %3d\n", sizeof (bmsh3d_face));
534 vul_printf (std::cerr, "\n");
535
536 vul_printf (std::cerr, "bmsh3d_pt_set %3d\n", sizeof (bmsh3d_pt_set));
537 vul_printf (std::cerr, "bmsh3d_ifs_mesh %3d\n", sizeof (bmsh3d_ifs_mesh));
538 vul_printf (std::cerr, "bmsh3d_mesh %3d\n", sizeof (bmsh3d_mesh));
539 }
540
is_2_manifold()541 bool bmsh3d_mesh::is_2_manifold ()
542 {
543 auto it = edgemap_.begin();
544 for (; it != edgemap_.end(); it++) {
545 bmsh3d_edge* edge = (*it).second;
546 if (edge->n_incident_Fs() > 2)
547 return false;
548 }
549 return true;
550 }
551
count_max_polygon_sides()552 unsigned int bmsh3d_mesh::count_max_polygon_sides ()
553 {
554 unsigned int max_sides = 0;
555 auto it = facemap_.begin();
556 for (; it != facemap_.end(); it++) {
557 bmsh3d_face* F = (*it).second;
558
559 unsigned int sides = F->n_incident_Es();
560 if (sides > max_sides)
561 max_sides = sides;
562 }
563
564 return max_sides;
565 }
566
567 //: Return number of edges in traversing the IFS data structure.
568 // Note that an internal edge can be used twice.
count_ifs_dup_edges()569 unsigned int bmsh3d_mesh::count_ifs_dup_edges ()
570 {
571 unsigned int count = 0;
572 auto it = facemap_.begin();
573 for (; it != facemap_.end(); it++) {
574 bmsh3d_face* F = (*it).second;
575 count += F->vertices().size();
576 }
577 return count;
578 }
579
580 //: Return total boundary edges
581 // Also determine if this mesh is watertight or not.
count_bnd_edges(bool & b_2_manifold)582 unsigned int bmsh3d_mesh::count_bnd_edges (bool& b_2_manifold)
583 {
584 b_2_manifold = true;
585 unsigned int bnd_edges = 0;
586
587 auto it = edgemap_.begin();
588 for (; it != edgemap_.end(); it++) {
589 bmsh3d_edge* edge = (*it).second;
590
591 unsigned int count = edge->n_incident_Fs();
592 if (count > 2)
593 b_2_manifold = false;
594 if (count < 2)
595 bnd_edges++;
596 }
597 b_watertight_ = (bnd_edges == 0);
598 return bnd_edges;
599 }
600
get_avg_edge_len()601 double bmsh3d_mesh::get_avg_edge_len ()
602 {
603 unsigned int count_edge = 0;
604 double sum_length = 0;
605
606 assert (edgemap_.size() != 0);
607 auto it = edgemap_.begin();
608 for (; it != edgemap_.end(); it++) {
609 bmsh3d_edge* edge = (*it).second;
610
611 double len = edge->length();
612 count_edge++;
613 sum_length += len;
614 }
615
616 double avg_len = sum_length / count_edge;
617 return avg_len;
618 }
619
620 //: Merge two faces who sharing an edge together.
621 // Only valid if E is a 2-manifold edge.
622 // Delete edge E and add all remaining halfedges of F2 to F1, and then delete E and F2.
623 // Result of merged face is in F1.
624 //
m2_mesh_merge_face(bmsh3d_face * F1,bmsh3d_face * F2,bmsh3d_edge * E)625 void bmsh3d_mesh::m2_mesh_merge_face (bmsh3d_face* F1, bmsh3d_face* F2 ,bmsh3d_edge* E)
626 {
627 assert (F1 != F2);
628 std::cout << "mesh_merge_faces " << F1->id() << " with " << F2->id() << std::endl;
629
630 bmsh3d_vertex* Vs = E->sV();
631 bmsh3d_vertex* Ve = E->eV();
632 bmsh3d_halfedge* HE1 = E->get_HE_of_F (F1);
633 bmsh3d_halfedge* HE2 = E->get_HE_of_F (F2);
634
635 bmsh3d_halfedge* F1_HE_head = F1->find_other_HE (Vs, HE1);
636 bmsh3d_halfedge* F1_HE_tail = F1->find_other_HE (Ve, HE1);
637 //Swap the head & tail if necessary
638 if (F1_HE_head->next() != HE1) {
639 assert (F1_HE_tail->next() == HE1);
640 bmsh3d_halfedge* temp = F1_HE_tail;
641 F1_HE_tail = F1_HE_head;
642 F1_HE_head = temp;
643 }
644
645 //Traverse all halfedges of F2 and add to F1 in order.
646 bmsh3d_halfedge* HE = HE2->next();
647 while (HE != HE2) {
648 F1_HE_head->set_next (HE);
649 HE->set_face (F1);
650 F1_HE_head = HE;
651 HE = HE->next();
652 }
653 F1_HE_head->set_next (F1_HE_tail);
654
655 //Delete F2. Note that most of F2's halfedges now belongs to F1.
656 F2->set_halfedge (HE2);
657 HE2->set_next (nullptr);
658 remove_face (F2);
659
660 //Remove HE1: the other incidence of edge E.
661 E->_disconnect_HE (HE1);
662 delete HE1;
663 assert (E->halfedge() == nullptr);
664 remove_edge (E);
665
666 //Sort F1's HE list.
667 F1->set_halfedge (F1_HE_tail);
668 F1->_sort_HEs_circular ();
669 F1->_ifs_clear_vertices ();
670 }
671
672 //########################################################################
673
674 //: For 2-manifold mesh only.
675 // This function fix each face's halfedges in a consistent order.
676 // Pick one face and fix the orientation of its halfedges using right hand rule on it.
677 // propagation the orientation to all adjacent faces
678 // result: for a 2-manifold mesh, all edges in general has two incident faces
679 // (otherwise this edge is on the boundary of the mesh)
680 // after this orientation fix, for all edges, the 2 sides (halfedges) of it
681 // on both adjacent faces has different direction.
682 // Parameter:
683 // mesh: the mesh under work
684 // sfaceid: the id of the starting face
685 // b_flip_sface: flip the orientation of the starting face or not.
manifold_fix_faces_orientation(bmsh3d_mesh * mesh,int sfaceid,bool b_use_e_vertex_as_next)686 void manifold_fix_faces_orientation (bmsh3d_mesh* mesh, int sfaceid, bool b_use_e_vertex_as_next)
687 {
688 mesh->reset_traverse ();
689
690 // Fix the starting_face
691 bmsh3d_face* starting_face = mesh->facemap (sfaceid);
692 bmsh3d_halfedge* startHE = starting_face->halfedge();
693 if (b_use_e_vertex_as_next)
694 starting_face->set_orientation (startHE, startHE->edge()->eV());
695 else
696 starting_face->set_orientation (startHE, startHE->edge()->sV());
697
698 starting_face->set_i_visited (mesh->i_traverse_flag());
699
700 // Propagation of the orientation to all other faces
701 // The front here is the halfedge with associated faces to propagate.
702 std::queue<bmsh3d_halfedge*> he_queue;
703
704 // Put all adjacent faces into the queue
705 bmsh3d_halfedge* HE = startHE;
706 do {
707 bmsh3d_edge* edge = HE->edge();
708 // assume 2-manifold mesh
709 if (edge->halfedge()->face() != starting_face)
710 he_queue.push (edge->halfedge());
711 else if (edge->halfedge()->pair())
712 he_queue.push (edge->halfedge()->pair());
713
714 HE = HE->next();
715 }
716 while (HE != startHE);
717
718 // the main while loop.
719 while (!he_queue.empty()) {
720 // pop one
721 bmsh3d_halfedge* front_he = he_queue.front();
722 he_queue.pop();
723
724 // find the already oriented next_v on the other side
725 bmsh3d_halfedge* sorted_he = front_he->pair();
726 bmsh3d_halfedge* sorted_he_next = sorted_he->next();
727
728 bmsh3d_vertex* next_v = incident_V_of_Es (sorted_he->edge(), sorted_he_next->edge());
729 next_v = front_he->edge()->other_V (next_v);
730
731 bmsh3d_face* front_face = front_he->face();
732 // this check is necessary. note that a face can be traversed more than once.
733 if (front_face->is_visited (mesh->i_traverse_flag()))
734 continue;
735
736 // fix orientation of it
737 front_face->set_orientation (front_he, next_v);
738
739 front_face->set_i_visited (mesh->i_traverse_flag());
740
741 // put all non-visited face in the queue
742 bmsh3d_halfedge* HE = front_face->halfedge();
743 do {
744 bmsh3d_edge* edge = HE->edge();
745 // assume 2-manifold mesh
746 if (edge->halfedge()->face() != front_face) {
747 if (! edge->halfedge()->face()->is_visited(mesh->i_traverse_flag()))
748 he_queue.push (edge->halfedge());
749 }
750 else if (edge->halfedge()->pair()) {
751 bmsh3d_face* F = edge->halfedge()->pair()->face();
752 assert (F != front_face);
753 if (!F->is_visited (mesh->i_traverse_flag()))
754 he_queue.push (edge->halfedge()->pair());
755 }
756
757 HE = HE->next();
758 }
759 while (HE != front_face->halfedge());
760 }
761 }
762