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