MEPP2 Project
test_mesh_defects_aif.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 
19 
23 
25 
27 
28 #include <vector>
29 #include <set>
30 #include <map>
31 
32 #include <algorithm>
33 #include <cstdlib> // EXIT_SUCCESS and EXIT_FAILURE symbols
34 
35 using namespace FEVV::DataStructures::AIF;
36 template< typename IterFaceType, typename PointMap >
37 AIFMeshT extract_vertex_local_neighborhood(IterFaceType begin, IterFaceType end, PointMap pm)
38 {
40  AIFMeshT res;
41  auto pm_new = get(boost::vertex_point, res);
42  std::map<vertex_descriptor, vertex_descriptor> from_current_to_new;
43  auto iter_f = begin;
44  for (; iter_f != end; ++iter_f)
45  {
46  std::vector<vertex_descriptor> face_vertices; // for current new face to add
47  auto vertex_range = AIFHelpers::incident_vertices(*iter_f);
48  auto iter_v = vertex_range.begin();
49  for (; iter_v != vertex_range.end(); ++iter_v)
50  {
51  if (from_current_to_new.find(*iter_v) == from_current_to_new.end())
52  {
54  from_current_to_new[*iter_v] = v_n;
55  auto p = get(pm, *iter_v); // to avoid some writing bugs
56  put(pm_new, v_n, p);
57  }
58  face_vertices.push_back(from_current_to_new[*iter_v]);
59  }
60 
61  CGAL::Euler::add_face(face_vertices, res);
62  }
63  return res;
64 }
65 template<typename PointMap>
68  const AIFMeshT& /*g*/,
69  PointMap pm)
70 {
71  auto face_range = AIFHelpers::incident_faces(v);
72 
73  return extract_vertex_local_neighborhood(face_range.begin(), face_range.end(), pm);
74 }
75 template<typename PointMap>
77  typename boost::graph_traits< AIFMeshT >::edge_descriptor e,
78  const AIFMeshT& g,
79  PointMap pm)
80 {
81  typedef typename boost::graph_traits< AIFMeshT >::face_descriptor face_descriptor;
82 
83  auto face_range_s = AIFHelpers::incident_faces(source(e,g));
84  auto face_range_t = AIFHelpers::incident_faces(target(e, g));
85 
86  std::set<face_descriptor> faces(face_range_s.begin(), face_range_s.end());
87  faces.insert(face_range_t.begin(), face_range_t.end());
88 
89  return extract_vertex_local_neighborhood(faces.begin(), faces.end(), pm);
90 }
91 
92 static bool argument_analysis(std::string& arg, const std::string& arg_name, bool update_arg_tolower_case = true)
93 {
94  if (arg != "y" && arg != "n" &&
95  arg != "Y" && arg != "N")
96  {
97  std::cerr << "Cannot understand input for " + arg_name + ". "
98  "Please use either \"y\" or \"n\" "
99  << std::endl;
100  return false;
101  }
102  else if (update_arg_tolower_case)
103  {
104  if (arg == "Y")
105  arg = "y";
106  else if (arg == "N")
107  arg = "n";
108  }
109  return true;
110 }
111 
112 #if 0 // unused
113 static void replace(std::string& to_modify, const std::string& substring_to_search, const std::string& substring_to_use)
114 {
115  size_t pos = to_modify.find(substring_to_search);
116  while (pos != std::string::npos)
117  {
118  to_modify.replace(pos, substring_to_search.size(), substring_to_use);
119  pos = to_modify.find(substring_to_search, pos + substring_to_use.size());
120  }
121 }
122 #endif
123 
124 template< typename MutableFaceIncidentGraph >
125 typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor
127 {
128  typedef boost::graph_traits< MutableFaceIncidentGraph > GraphTraits;
129 
131  typedef typename GraphTraits::edge_descriptor edge_descriptor;
132 
135  AIFHelpers::link_vertex_and_edge(s_tmp, e_tmp, AIFHelpers::vertex_pos::FIRST);
136  AIFHelpers::link_vertex_and_edge(t_tmp, e_tmp, AIFHelpers::vertex_pos::SECOND);
137 
138  return e_tmp;
139 }
140 
141 template< typename MutableFaceIncidentGraph >
142 static void remove_adjacent_edges(MutableFaceIncidentGraph &g,
143  std::vector< typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor >& selected_edges_to_make_independent,
144  std::vector< typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor>& removed_edges)
145 {
146  typedef boost::graph_traits< MutableFaceIncidentGraph > GraphTraits;
147 
149  typedef typename GraphTraits::edge_descriptor edge_descriptor;
150  //typedef typename GraphTraits::face_descriptor face_descriptor;
151 
152  removed_edges.clear();
153  std::set< edge_descriptor > set_removed_edges;
154  auto iter_e = selected_edges_to_make_independent.begin(), iter_e_e = selected_edges_to_make_independent.end();
155  while (iter_e != iter_e_e)
156  {
157  if (set_removed_edges.find(*iter_e) != set_removed_edges.end())
158  {
159  ++iter_e;
160  continue;
161  }
162  vertex_descriptor s = source(*iter_e, g);
163  vertex_descriptor t = target(*iter_e, g);
164 
165  auto edges_pair = in_edges(s, g);
166  auto iter_e2 = edges_pair.first;
167  for (; iter_e2 != edges_pair.second; ++iter_e2)
168  {
169  if (*iter_e2 == *iter_e)
170  continue;
171 
172  //auto iter_res = std::find(selected_edges_to_make_independent.begin(), selected_edges_to_make_independent.end(), *iter_e2);
173  //if (iter_res != selected_edges_to_make_independent.end())
174  //{
175  // removed_edges.push_back(*iter_res);
176  // selected_edges_to_make_independent.erase(iter_res);
177  //}
178 
179  set_removed_edges.insert(*iter_e2);
180  }
181  auto res_edges = AIFHelpers::get_unordered_one_ring_edges(s); // to ensure no 2 edges of the same polygonal face are selected
182  set_removed_edges.insert(res_edges.begin(), res_edges.end());
183 
184  edges_pair = in_edges(t, g);
185  iter_e2 = edges_pair.first;
186  for (; iter_e2 != edges_pair.second; ++iter_e2)
187  {
188  if (*iter_e2 == *iter_e)
189  continue;
190 
191  //auto iter_res = std::find(selected_edges_to_make_independent.begin(), selected_edges_to_make_independent.end(), *iter_e2);
192  //if (iter_res != selected_edges_to_make_independent.end())
193  //{
194  // removed_edges.push_back(*iter_res);
195  // selected_edges_to_make_independent.erase(iter_res);
196  //}
197 
198  set_removed_edges.insert(*iter_e2);
199  }
200  res_edges = AIFHelpers::get_unordered_one_ring_edges(t); // to ensure no 2 edges of the same polygonal face are selected
201  set_removed_edges.insert(res_edges.begin(), res_edges.end());
202 
203  ++iter_e;
204  }
205  auto iter_e_s = set_removed_edges.begin();
206  auto iter_e_s_e = set_removed_edges.end();
207  for (; iter_e_s != iter_e_s_e; ++iter_e_s)
208  {
209  auto iter_res = std::find(selected_edges_to_make_independent.begin(), selected_edges_to_make_independent.end(), *iter_e_s);
210  if (iter_res != selected_edges_to_make_independent.end())
211  {
212  removed_edges.push_back(*iter_res);
213  selected_edges_to_make_independent.erase(iter_res);
214  }
215  }
216 }
217 
218 template< typename MutableFaceIncidentGraph >
219 static size_t nb_different_incident_face_segment_indices(const MutableFaceIncidentGraph &g,
220  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor e
221 )
222 {
223  std::set<int> segment_indices;
224  auto src_incident_faces_pair = in_edges(e, g);
225  auto iter_f = src_incident_faces_pair.first;
226  for (; iter_f != src_incident_faces_pair.second; ++iter_f)
227  {
228  int current_face_id = g.template GetProperty< AIFMeshT::face_type::ptr, int >(
229  "f:2_manifold_component_seg", (*iter_f)->GetIndex());
230 
231  segment_indices.insert(current_face_id);
232  }
233  return segment_indices.size();
234 }
235 template< typename MutableFaceIncidentGraph >
236 static bool has_that_incident_face_segment_index(const MutableFaceIncidentGraph &g,
237  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor e,
238  int index
239 )
240 {
241  auto src_incident_faces_pair = in_edges(e, g);
242  auto iter_f = src_incident_faces_pair.first;
243  for (; iter_f != src_incident_faces_pair.second; ++iter_f)
244  {
245  int current_face_id = g.template GetProperty< AIFMeshT::face_type::ptr, int >(
246  "f:2_manifold_component_seg", (*iter_f)->GetIndex());
247 
248  if (current_face_id == index)
249  return true;
250  }
251  return false;
252 }
253 template< typename MutableFaceIncidentGraph >
254 static bool has_only_that_incident_face_segment_index(const MutableFaceIncidentGraph &g,
255  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor e,
256  int index
257 )
258 {
259  auto src_incident_faces_pair = in_edges(e, g);
260  auto iter_f = src_incident_faces_pair.first;
261  for (; iter_f != src_incident_faces_pair.second; ++iter_f)
262  {
263  int current_face_id = g.template GetProperty< AIFMeshT::face_type::ptr, int >(
264  "f:2_manifold_component_seg", (*iter_f)->GetIndex());
265 
266  if (current_face_id != index)
267  return false;
268  }
269  return true;
270 }
271 template< typename MutableFaceIncidentGraph >
272 static void replace_vertex_in_incident_edges(MutableFaceIncidentGraph &g,
273  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor v, // current vertex to replace
274  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor replace, // vertex used for the replace
275  typename boost::graph_traits<MutableFaceIncidentGraph >::face_descriptor current_f,
276  const std::vector< typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor >&
277  complex_edges // to forbid the update of edges that are incident to faces than are incident to complex edges (including current complex edge)
278  )
279 {
280  typedef boost::graph_traits< MutableFaceIncidentGraph > GraphTraits;
281 
283  typedef typename GraphTraits::edge_descriptor edge_descriptor;
284  typedef typename GraphTraits::face_descriptor face_descriptor;
285 
286  assert(v!= AIFHelpers::null_vertex());
287  assert(replace != AIFHelpers::null_vertex());
288  assert(current_f != AIFHelpers::null_face());
289 
290  int current_face_id = g.template GetProperty< AIFMeshT::face_type::ptr, int >(
291  "f:2_manifold_component_seg", current_f->GetIndex());
292 
293  std::set<vertex_descriptor> forbidden_vertices;
294  std::set<edge_descriptor> forbidden_edges;
295  auto iter_ec = complex_edges.begin(), iter_ec_e = complex_edges.end();
296  forbidden_edges.insert(iter_ec, iter_ec_e);
297 
298  // some incident edges of v vertex are put onto replace vertex
299  auto src_incident_edges_range = AIFHelpers::incident_edges(v);
300  std::set<edge_descriptor> copy_incident_edges_for_removal(src_incident_edges_range.begin(), src_incident_edges_range.end());
301  auto iter_e = copy_incident_edges_for_removal.begin();
302  auto iter_e_e = copy_incident_edges_for_removal.end();
303  for (; iter_e != iter_e_e; ++iter_e)
304  {
305  if (forbidden_edges.find(*iter_e)!= forbidden_edges.end())
306  continue;
307  // here we know that *iter_e is not a complexe edge
308  // we thus update only edges that have one or two incident faces
309  // with segment id = current_face_id
310  if (has_only_that_incident_face_segment_index(g, *iter_e, current_face_id))
311  {
312  if (AIFHelpers::are_incident(v, *iter_e))
313  {
314  AIFHelpers::remove_edge(v, *iter_e);
315  if(AIFHelpers::are_incident(*iter_e, v))
316  AIFHelpers::add_vertex(*iter_e, replace, AIFHelpers::vertex_position(*iter_e, v));
317  if (!AIFHelpers::are_incident(replace, *iter_e))
318  AIFHelpers::add_edge(replace, *iter_e);
319  }
320  }
321  else if (has_that_incident_face_segment_index(g, *iter_e, current_face_id))
322  {
323  if (!AIFHelpers::are_incident(v, *iter_e))
324  continue;
325 
326  auto res_pair = AIFHelpers::add_edge( AIFHelpers::opposite_vertex(*iter_e, v),
327  replace, // the new edge will be added in its incident edges
328  g);
329  assert(res_pair.second); // the edge has been created (false when the edge was existing)
330  edge_descriptor new_e = res_pair.first;
331 
332  auto face_range_pair = in_edges(*iter_e, g);
333  std::set<face_descriptor> copy_incident_faces_for_removal(face_range_pair.first, face_range_pair.second);
334  auto iter_f = copy_incident_faces_for_removal.begin(), iter_f_e = copy_incident_faces_for_removal.end();
335  for (; iter_f != iter_f_e; ++iter_f)
336  {
337  if (g.template GetProperty< AIFMeshT::face_type::ptr, int >(
338  "f:2_manifold_component_seg", (*iter_f)->GetIndex()) == current_face_id)
339  {
340  assert(AIFHelpers::are_incident(*iter_f, *iter_e));
342  AIFHelpers::remove_edge(*iter_f, *iter_e);
343  AIFHelpers::remove_face(*iter_e, *iter_f);
344  AIFHelpers::add_edge_to_face_after_edge(*iter_f, pe, new_e);
345  AIFHelpers::add_face(new_e, *iter_f);
346  }
347  }
348  }
349  }
350 }
351 template< typename MutableFaceIncidentGraph >
353  MutableFaceIncidentGraph &/*g*/,
354  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor e,
355  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor pe,
356  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor ae,
360  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor>& v_old_to_v_new, // mapping v_old->v_new
362  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor>& v_new_to_old // mapping v_new->v_old
363 )
364 {
365  v_pe_old = AIFHelpers::common_vertex(pe, e);
366  if (v_pe_old == AIFHelpers::null_vertex())
367  {
368  if (v_new_to_old.find(pe->get_first_vertex()) != v_new_to_old.end())
369  v_pe_old = v_new_to_old[pe->get_first_vertex()];
370  else if (v_new_to_old.find(pe->get_second_vertex()) != v_new_to_old.end())
371  v_pe_old = v_new_to_old[pe->get_second_vertex()];
372  }
373  else if (v_old_to_v_new.find(v_pe_old) == v_old_to_v_new.end())
374  {
375  if (v_new_to_old.find(v_pe_old) != v_new_to_old.end())
376  v_pe_old = v_new_to_old[v_pe_old];
377  }
378  if (v_pe_old == AIFHelpers::null_vertex())
379  {
380  std::cerr << "you may have a similar face with different face id" << std::endl;
381  }
382  v_ae_old = AIFHelpers::common_vertex(ae, e);
383  if (v_ae_old == AIFHelpers::null_vertex())
384  {
385  if (v_new_to_old.find(ae->get_first_vertex()) != v_new_to_old.end())
386  v_ae_old = v_new_to_old[ae->get_first_vertex()];
387  else if (v_new_to_old.find(ae->get_second_vertex()) != v_new_to_old.end())
388  v_ae_old = v_new_to_old[ae->get_second_vertex()];
389  }
390  else if (v_old_to_v_new.find(v_ae_old) == v_old_to_v_new.end())
391  {
392  if (v_new_to_old.find(v_ae_old) != v_new_to_old.end())
393  v_ae_old = v_new_to_old[v_ae_old];
394  }
395  if (v_ae_old == AIFHelpers::null_vertex())
396  {
397  std::cerr << "you may have a similar face with different face id" << std::endl;
398  }
399 }
400 template< typename MutableFaceIncidentGraph, typename PointMap >
402  MutableFaceIncidentGraph &g,
403  PointMap& pm,
404  typename boost::graph_traits<MutableFaceIncidentGraph >::face_descriptor f, // current face in which e is replaced
405  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor e, // current edge to replace
406  typename boost::graph_traits<MutableFaceIncidentGraph >::edge_descriptor replace, // edge used to replace e
408  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor>& v_old_to_v_new, // mapping v_old->v_new
410  typename boost::graph_traits<MutableFaceIncidentGraph >::vertex_descriptor>& v_new_to_old // mapping v_new->v_old
411  )
412 {
413  typedef boost::graph_traits< MutableFaceIncidentGraph > GraphTraits;
414 
416  typedef typename GraphTraits::edge_descriptor edge_descriptor;
417  //typedef typename GraphTraits::face_descriptor face_descriptor;
419  if (!AIFHelpers::are_incident(f, e))
420  return;
421 
422  assert(!AIFHelpers::are_incident(f, replace));
424  int current_face_id = g.template GetProperty< AIFMeshT::face_type::ptr, int >(
425  "f:2_manifold_component_seg", f->GetIndex());
427  // for other components: update incidence relationships
430 
431  vertex_descriptor v_pe_old, v_ae_old;
432  calculate_previous_and_after_vertices(g, e, pe, ae, v_pe_old, v_ae_old, v_old_to_v_new, v_new_to_old);
436  AIFHelpers::add_face(replace, f);
437 
438  AIFHelpers::remove_edge(v_pe_old, e);
439  AIFHelpers::remove_edge(v_ae_old, e);
440  AIFHelpers::add_edge(v_pe_old, replace);
441  AIFHelpers::add_edge(v_ae_old, replace);
442 
443  if (degree(replace, g) == 1)
444  { // first time replace is added to a face
445  auto p = get(pm, v_pe_old); // to avoid some writing bugs
446  put(pm, source(replace, g), p);
447  p = get(pm, v_ae_old);
448  put(pm, target(replace, g), p);
449 
450  AIFHelpers::add_edge(source(replace, g), pe);
451  if (has_only_that_incident_face_segment_index(g, pe, current_face_id))
452  {
453  AIFHelpers::add_vertex(pe, source(replace, g), AIFHelpers::vertex_position(pe, v_pe_old));
454  }
455  // else the update will be done in replace_vertex_in_incident_edges
456  AIFHelpers::add_edge(target(replace, g), ae);
457  if (has_only_that_incident_face_segment_index(g, ae, current_face_id))
458  {
459  AIFHelpers::add_vertex(ae, target(replace, g), AIFHelpers::vertex_position(ae, v_ae_old));
460  }
461  // else the update will be done in replace_vertex_in_incident_edges
462  v_old_to_v_new[v_pe_old] = source(replace, g);
463  v_old_to_v_new[v_ae_old] = target(replace, g);
464  v_new_to_old[source(replace, g)] = v_pe_old;
465  v_new_to_old[target(replace, g)] = v_ae_old;
466  }
467  //else
468  //{
469  // AIFHelpers::add_edge(v_old_to_v_new[v_pe_old], pe);
470  // if (has_only_that_incident_face_segment_index(g, pe, current_face_id))
471  // {
472  // if((v_old_to_v_new.find(v_pe_old) != v_old_to_v_new.end()) && !AIFHelpers::are_incident(pe, v_old_to_v_new[v_pe_old]))
473  // AIFHelpers::add_vertex(pe, v_old_to_v_new[v_pe_old], AIFHelpers::vertex_position(pe, v_pe_old));
474  // }
475  // // else the update will be done in replace_vertex_in_incident_edges
476  // AIFHelpers::add_edge(v_old_to_v_new[v_ae_old], ae);
477  // if (has_only_that_incident_face_segment_index(g, ae, current_face_id))
478  // {
479  // if ((v_old_to_v_new.find(v_ae_old) != v_old_to_v_new.end()) && !AIFHelpers::are_incident(ae, v_old_to_v_new[v_ae_old]))
480  // AIFHelpers::add_vertex(ae, v_old_to_v_new[v_ae_old], AIFHelpers::vertex_position(ae, v_ae_old));
481  // }
482  // // else the update will be done in replace_vertex_in_incident_edges
483  //}
484 }
485 
486 template< typename MutableFaceIncidentGraph, typename PointIndexMap >
487 static bool has_different_vertex_indices(MutableFaceIncidentGraph &g, const PointIndexMap& idm,
488  typename boost::graph_traits<MutableFaceIncidentGraph >::face_descriptor f)
489 {
491  auto vertex_range = AIFHelpers::incident_vertices(f);
492  auto iter_v = vertex_range.begin();
493  std::map<vertex_descriptor, int> v_to_index;
494  for (; iter_v != vertex_range.end(); ++iter_v)
495  {
496  v_to_index[*iter_v] = get(idm, *iter_v);
497  }
498 
499  return (degree(f, g) == v_to_index.size()) ;
500 }
501 
502 static int process_one_mesh_file( const std::string& input_file_path,
503  const std::string& colorize_mesh,
504  const std::string& remove_isolated_elements, // except isolated faces for the time being
505  const std::string& resolve_vertices_with_similar_incident_edges,
506  const std::string& make_2_mani_not_2_mani)
507 {
508  typedef AIFMeshReader reader_type;
509  typedef AIFMeshWriter writer_type;
510  typedef boost::graph_traits< reader_type::output_type > GraphTraits;
511  typedef FEVV::Geometry_traits<AIFMeshT> GeometryTraits;
512 
513  typedef typename GraphTraits::vertex_iterator vertex_iterator;
515  typedef typename GraphTraits::edge_iterator edge_iterator;
516  typedef typename GraphTraits::edge_descriptor edge_descriptor;
517  typedef typename GraphTraits::face_iterator face_iterator;
518  typedef typename GraphTraits::face_descriptor face_descriptor;
520  reader_type my_reader;
521  reader_type::ptr_output ptr_mesh;
522  try
523  {
524  ptr_mesh = my_reader.read(input_file_path);
525  }
526  catch (const std::invalid_argument &e)
527  {
528  std::cerr << "Invalid Argument Exception catch while reading "
529  << input_file_path << " :" << std::endl
530  << e.what() << std::endl;
531  exit(EXIT_FAILURE);
532  }
533  catch (const std::ios_base::failure &e)
534  {
535  std::cerr << "IOS Failure Exception catch while reading " << input_file_path
536  << " :" << std::endl
537  << e.what() << std::endl;
538  exit(EXIT_FAILURE);
539  }
540  catch (const std::length_error &le)
541  {
542  std::cerr << "[AIF] Exception caught while reading input file "
543  << input_file_path << ": " << le.what() << std::endl;
544  BOOST_ASSERT_MSG(false, "[AIF] Exception caught while reading input file.");
545  }
547  GeometryTraits gt(*ptr_mesh);
548  auto pos_pm = get(boost::vertex_point, *ptr_mesh);
549  auto vertex_idm = get(boost::vertex_index, *ptr_mesh);
550  auto edge_idm = get(boost::edge_index, *ptr_mesh);
552  const AIFMeshT::Vector red(255, 0, 0);
553  const AIFMeshT::Vector green(0, 255, 0);
554  const AIFMeshT::Vector blue(0, 0, 255);
555  const AIFMeshT::Vector white(255, 255, 255);
556  if (colorize_mesh == "y")
557  {
558  if (!ptr_mesh->isPropertyMap< AIFMeshT::vertex_type::ptr >("v:color"))
559  { // create a property map to store vertex colors if not already created
560  ptr_mesh->AddPropertyMap< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >("v:color");
561  if (!ptr_mesh->isPropertyMap< AIFMeshT::vertex_type::ptr >("v:color"))
562  throw std::runtime_error("Failed to create vertex-color property map.");
563  }
564  if (!ptr_mesh->isPropertyMap< AIFMeshT::edge_type::ptr >("e:color"))
565  { // create a property map to store edge colors if not already created
566  ptr_mesh->AddPropertyMap< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >("e:color");
567  if (!ptr_mesh->isPropertyMap< AIFMeshT::edge_type::ptr >("e:color"))
568  throw std::runtime_error("Failed to create edge-color property map.");
569  }
570  if (!ptr_mesh->isPropertyMap< AIFMeshT::face_type::ptr >("f:color"))
571  { // create a property map to store face colors if not already created
572  ptr_mesh->AddPropertyMap< AIFMeshT::face_type::ptr, AIFMeshT::Vector >("f:color");
573  if (!ptr_mesh->isPropertyMap< AIFMeshT::face_type::ptr >("f:color"))
574  throw std::runtime_error("Failed to create face-color property map.");
575  }
576  }
577  if (make_2_mani_not_2_mani == "y")
578  {
579  if (!ptr_mesh->isPropertyMap< AIFMeshT::face_type::ptr >("f:2_manifold_component_seg"))
580  { // create a property map to store face segment indices if not already created
581  ptr_mesh->AddPropertyMap< AIFMeshT::face_type::ptr, int >("f:2_manifold_component_seg");
582  if (!ptr_mesh->isPropertyMap< AIFMeshT::face_type::ptr >("f:2_manifold_component_seg"))
583  throw std::runtime_error("Failed to create face 2-manifold components property map.");
584  }
585  // compute the face segmentation
586  std::set<face_descriptor> to_process,
587  all_faces(faces(*ptr_mesh).first, faces(*ptr_mesh).second); // not yet processed
588  bool first_phase = true // true when it still remains at least one face with no incident complex edge
589  , second_phase_first_subphase=true;
590  int current_id = 0, nb_used_id = 0;
591  auto iter_f_first = std::find_if(all_faces.begin(), all_faces.end(), AIFHelpers::is_not_incident_to_complex_edge);
592  if (iter_f_first == all_faces.end())
593  {
594  first_phase = false;
595  iter_f_first = all_faces.begin();
596  }
597  to_process.insert(*iter_f_first);
598  all_faces.erase(iter_f_first);
599 
600  while (!to_process.empty())
601  {
602  face_descriptor current_f = *to_process.begin();
603  ptr_mesh->SetProperty< AIFMeshT::face_type::ptr, int >(
604  "f:2_manifold_component_seg", current_f->GetIndex(), current_id);
605 
606  to_process.erase(to_process.begin());
607 
608  auto vector_faces = AIFHelpers::adjacent_faces(current_f, true);
609  auto iter_f = vector_faces.begin(), iter_f_end = vector_faces.end();
610  for (; iter_f != iter_f_end; ++iter_f)
611  {
612  assert(*iter_f != current_f);
613  if ((all_faces.find(*iter_f) != all_faces.end()) // not already processed
614  &&
615  (!first_phase ||
617  *iter_f))
618  && AIFHelpers::have_consistent_orientation(current_f, *iter_f)
619  )
620  {
621  edge_descriptor e_tmp = AIFHelpers::common_edge(current_f, *iter_f);
622  if ((!first_phase || AIFHelpers::is_surface_regular_edge(e_tmp))
623  //&& (AIFHelpers::is_regular_vertex(source(e_tmp, *ptr_mesh))
624  //&& AIFHelpers::is_regular_vertex(target(e_tmp, *ptr_mesh)))
625  )
626  {
627  to_process.insert(*iter_f);
628  all_faces.erase(*iter_f);
629  }
630  }
631  }
632  if (!first_phase)
633  {
634  if (second_phase_first_subphase)
635  {
636  if ((to_process.size() > 1))
637  { // second phase (segmentation of faces incident to at least one complex edge)
638  std::set<face_descriptor> new_face_set;
639  // only keep the face with closest normal to current_f (except current_f itself)
640  auto iter_f = to_process.begin(), iter_f_end = to_process.end(); // be careful: faces in to_process
641  // are not necessarily adjacent
642  auto current_n = FEVV::Operators::calculate_face_normal(current_f, *ptr_mesh, pos_pm, gt);
643  bool first = true;
644  double best_val = -1.1, val_f1 = -1.1, val_f2 = -1.1;
645  face_descriptor best_f = AIFHelpers::null_face(),
646  other_f1 = AIFHelpers::null_face(),
647  other_f2 = AIFHelpers::null_face();
648  size_t cpt_neigh = 0;
649  for (; iter_f != iter_f_end; ++iter_f)
650  {
651  if (*iter_f == current_f)
652  continue;
653  if (!AIFHelpers::are_adjacent(current_f, *iter_f))
654  continue; // if the two faces do not share an edge continue
655  auto neighbor_n = FEVV::Operators::calculate_face_normal(*iter_f, *ptr_mesh, pos_pm, gt);
656  double tmp = gt.dot_product(current_n, neighbor_n);
657  if (first)
658  {
659  best_val = val_f1 = tmp;
660  best_f = *iter_f;
661  first = false;
662  other_f1 = *iter_f;
663  ++cpt_neigh;
664  }
665  else
666  {
667  ++cpt_neigh;
668  other_f2 = *iter_f;
669  val_f2 = tmp;
670  if (tmp > best_val)
671  {
672  best_val = tmp;
673  best_f = *iter_f;
674  }
675  }
676  }
677  if (best_f != AIFHelpers::null_face())
678  {
679  if (cpt_neigh == 2)
680  {
681  current_n = FEVV::Operators::calculate_face_normal(other_f1, *ptr_mesh, pos_pm, gt);
682  auto neighbor_n = FEVV::Operators::calculate_face_normal(other_f2, *ptr_mesh, pos_pm, gt);
683  double tmp = gt.dot_product(current_n, neighbor_n);
684  if (tmp > best_val) // if the 2 neighboring faces better match together then take one of the two
685  new_face_set.insert(best_f);
686  else if(val_f1 > val_f2)
687  new_face_set.insert(other_f2);
688  else
689  new_face_set.insert(other_f1);
690  }
691  else
692  new_face_set.insert(best_f);
693  }
694  to_process.swap(new_face_set);
695  }
697  second_phase_first_subphase = false;
698  if (to_process.size() > 0)
699  {
700  ++nb_used_id;
701  current_id = nb_used_id;
702  }
703  }
704  else
705  {
706  std::set<face_descriptor> new_face_set;
707  to_process.swap(new_face_set);
708  }
709  }
710  if (to_process.empty() && !all_faces.empty())
711  {
712  iter_f_first = std::find_if(
713  all_faces.begin(),
714  all_faces.end(),
716  if (iter_f_first == all_faces.end())
717  { // we estimate the correct next face id by looking at its already processed neighbors
718  first_phase = false;
719  iter_f_first = all_faces.begin();
720  auto vector_faces = AIFHelpers::adjacent_faces(*iter_f_first, true);
721  auto iter_f = vector_faces.begin(), iter_f_end = vector_faces.end();
722  auto current_n = FEVV::Operators::calculate_face_normal(*iter_f_first, *ptr_mesh, pos_pm, gt);
723  int id_best_match = -1; // look for the face with a consistent orientation
724  // that has the closest normal correspondence
725  double best_val = -1.1;
726  for (; iter_f != iter_f_end; ++iter_f)
727  {
728  if ((all_faces.find(*iter_f) == all_faces.end()) // already processed
729  //&& AIFHelpers::is_not_incident_to_complex_edge(*iter_f)
730  && AIFHelpers::have_consistent_orientation(*iter_f_first, *iter_f)
731  )
732  {
733  int current_f_id = ptr_mesh->template GetProperty< AIFMeshT::face_type::ptr, int >(
734  "f:2_manifold_component_seg", (*iter_f)->GetIndex());
735 
736  auto neighbor_n = FEVV::Operators::calculate_face_normal(*iter_f, *ptr_mesh, pos_pm, gt);
737  double tmp = gt.dot_product(current_n, neighbor_n);
738  if (id_best_match == -1)
739  {
740  id_best_match = current_f_id;
741  best_val = tmp;
742  }
743  else if (FEVV::Operators::are_similar_faces(*iter_f_first, *iter_f, *ptr_mesh) // similar in topology
744  || (std::abs(tmp+1.)<1e-5) // similar in spirit, not in topology
745  )
746  { // they must be matched together
747  id_best_match = current_f_id;
748  best_val = tmp;
749  break;
750  }
751  else
752  {
753  if (tmp > best_val)
754  {
755  best_val = tmp;
756  id_best_match = current_f_id;
757  }
758  }
759  }
760  }
761  if (id_best_match == -1)
762  { // no valid neighbord found => current_id must take the next available integer value
763  ++nb_used_id;
764  current_id = nb_used_id ;
765  }
766  else
767  { // at least one valid neighbor => take the same id
768  current_id = id_best_match;
769  }
770 
771  second_phase_first_subphase = true;
772  }
773  else
774  { // a new connected component with at least one face without complex incident edges
775  ++current_id;
776  ++nb_used_id;
777  }
778  to_process.insert(*iter_f_first);
779  all_faces.erase(iter_f_first);
780 
781  }
782  }
783  std::cout << "segmented into " << (nb_used_id + 1) << " 2-manifold components." << std::endl;
784  }
786  // 1 - Count number of isolated/complex/normal elements
787 
788  // VERTICES
789  auto iterator_pair_v = vertices(*ptr_mesh);
790  vertex_iterator vi = iterator_pair_v.first;
791  vertex_iterator vi_end = iterator_pair_v.second;
792  int nb_isolated_vertices = 0, nb_cut_vertices = 0, nb_t_junction_vertices = 0,
793  nb_vertices_with_similar_incident_edges = 0;
794  std::vector< vertex_descriptor > v_to_remeove;
795  std::vector< vertex_descriptor > cut_vertices;
796  std::vector< vertex_descriptor > t_junction_vertices;
797  for (; vi != vi_end; ++vi)
798  {
800  {
801  ++nb_isolated_vertices;
802 
803  if (remove_isolated_elements == "y")
804  v_to_remeove.push_back(*vi);
805  else
806  {
807  if (colorize_mesh == "y")
808  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
809  "v:color", (*vi)->GetIndex(), red);
810  }
811  }
813  {
814  ++nb_t_junction_vertices;
815  //std::cout << "T-junction detected!" << std::endl;
816  if (make_2_mani_not_2_mani == "y")
817  t_junction_vertices.push_back(*vi);
818  else
819  if (colorize_mesh == "y")
820  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
821  "v:color", (*vi)->GetIndex(), blue);
822  }
823  else if (AIFHelpers::is_cut_vertex(*vi) &&
824  !FEVV::DataStructures::AIF::AIFMeshHelpers::has_adjacent_T_junction_vertex(*vi, *ptr_mesh, gt) && // we must process T-junction vectices first
825  !AIFHelpers::is_incident_to_dangling_or_complex_edge(*vi) // we must process dangling and complex edges first
826  ) // and we can even either create new cut vertices
827  { // during the complex edge processing or resolve a cut
828  ++nb_cut_vertices; // vertex...
829  if (make_2_mani_not_2_mani == "y")
830  cut_vertices.push_back(*vi);
831  else
832  if (colorize_mesh == "y")
833  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
834  "v:color", (*vi)->GetIndex(), blue);
835  }
837  *vi, *ptr_mesh))
838  {
839  ++nb_vertices_with_similar_incident_edges;
840 
841  if (resolve_vertices_with_similar_incident_edges == "y")
843  else
844  if (colorize_mesh == "y")
845  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
846  "v:color", (*vi)->GetIndex(), blue);
847  }
848  else
849  {
850  if (colorize_mesh == "y")
851  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
852  "v:color", (*vi)->GetIndex(), green);
853  }
854  }
855 
856  // EDGES
857  auto iterator_pair_e = edges(*ptr_mesh);
858  edge_iterator ei = iterator_pair_e.first;
859  edge_iterator ei_end = iterator_pair_e.second;
860  int nb_isolated_edges = 0,
861  nb_dangling_edges = 0,
862  nb_complex_edges = 0,
863  nb_non_consitently_oriented_incident_face_edges = 0,
864  nb_border_edges = 0;
865  std::vector< edge_descriptor > e_to_remeove;
866  std::vector< edge_descriptor > dangling_edges,
867  complex_edges,
868  non_consitently_oriented_incident_face_edges;
869  for (; ei != ei_end; ++ei)
870  {
872  {
873  ++nb_isolated_edges;
874  if (remove_isolated_elements == "y")
875  e_to_remeove.push_back(*ei);
876  else
877  {
878  if (colorize_mesh == "y")
879  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
880  "e:color", (*ei)->GetIndex(), red);
881  }
882  }
883  else if (AIFHelpers::is_dangling_edge(*ei))
884  {
885  ++nb_dangling_edges;
886  if (make_2_mani_not_2_mani == "y")
887  dangling_edges.push_back(*ei);
888  else
889  {
890  if (colorize_mesh == "y")
891  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
892  "e:color", (*ei)->GetIndex(), red);
893  }
894  }
895  else if (AIFHelpers::is_complex_edge(*ei))
896  {
897  ++nb_complex_edges;
898  if (make_2_mani_not_2_mani == "y")
899  complex_edges.push_back(*ei);
900  else
901  {
902  if (colorize_mesh == "y")
903  {
904  /* ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
905  "v:color", (*ei)->get_first_vertex()->GetIndex(), blue);
906  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
907  "v:color", (*ei)->get_second_vertex()->GetIndex(), blue);*/
908 
909  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
910  "e:color", (*ei)->GetIndex(), blue);
911  }
912  }
913  }
915  {
916  // should be treated by duplicating edges when a 2-manifold mesh is
917  // expected as output (to extract after complex edges, since a complex
918  // edge has also non consistently oriented incident faces)
919  ++nb_non_consitently_oriented_incident_face_edges;
920  if (make_2_mani_not_2_mani == "y")
921  non_consitently_oriented_incident_face_edges.push_back(*ei);
922  else
923  {
924  if (colorize_mesh == "y")
925  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
926  "e:color", (*ei)->GetIndex(), red);
927  }
928  }
930  {
931  ++nb_border_edges;
932  if (colorize_mesh == "y")
933  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
934  "e:color", (*ei)->GetIndex(), white);
935  }
936  else
937  {
938  if (colorize_mesh == "y")
939  ptr_mesh->SetProperty< AIFMeshT::edge_type::ptr, AIFMeshT::Vector >(
940  "e:color", (*ei)->GetIndex(), green);
941  }
942  }
943 
944  // FACES
945  auto iterator_pair_f = faces(*ptr_mesh);
946  face_iterator fi = iterator_pair_f.first;
947  face_iterator fi_end = iterator_pair_f.second;
948  int nb_isolated_faces = 0, nb_degenerated_faces = 0;
949  std::vector< face_descriptor > f_to_remeove;
950  for (; fi != fi_end; ++fi)
951  {
953  { // note that removing isolated faces may create hole in the surface!
954  // especially after processing cut vertices.
955  // Therefore, it is rather advised to preserved them, and use
956  // a higher level algorithm to keep or remove them.
957  ++nb_isolated_faces;
958  //if (remove_isolated_elements == "y")
959  // f_to_remeove.push_back(*fi);
960  //else
961  {
962  if (colorize_mesh == "y")
963  ptr_mesh->SetProperty< AIFMeshT::face_type::ptr, AIFMeshT::Vector >(
964  "f:color", (*fi)->GetIndex(), red);
965  }
966  }
967  else
968  {
969  if (colorize_mesh == "y")
970  ptr_mesh->SetProperty< AIFMeshT::face_type::ptr, AIFMeshT::Vector >(
971  "f:color", (*fi)->GetIndex(), green);
972  }
973 
975  ++nb_degenerated_faces;
976  }
978  // 2 - Remove isolated elements + output filename generation
979  std::string suffix = "";
980  if (remove_isolated_elements == "y")
981  {
982  if (nb_isolated_vertices != 0
983  || nb_isolated_edges != 0
984  //|| nb_isolated_faces != 0
985  )
986  {
988  f_to_remeove.begin(), f_to_remeove.end(), ptr_mesh);
990  e_to_remeove.begin(), e_to_remeove.end(), ptr_mesh);
992  v_to_remeove.begin(), v_to_remeove.end(), ptr_mesh);
993  suffix = "_without_isolated_elmt";
994  if (resolve_vertices_with_similar_incident_edges == "y")
995  suffix += "_and_similar_incident_edges";
996  }
997  else if (resolve_vertices_with_similar_incident_edges == "y")
998  suffix = "_without_similar_incident_edges";
999 
1000  if (make_2_mani_not_2_mani == "y")
1001  suffix += "_without_non_manifold_elm";
1002  }
1003  else if (resolve_vertices_with_similar_incident_edges == "y")
1004  {
1005  suffix = "_without_similar_incident_edges";
1006  if (make_2_mani_not_2_mani == "y")
1007  suffix += "_without_non_manifold_elm";
1008  }
1009  else if (make_2_mani_not_2_mani == "y")
1010  suffix = "_without_non_manifold_elm";
1012  // 3 - Process non-2-manifold elements
1013 
1014  // remove dangling edges (+ update list of cut vertices)
1015  auto iter_e = dangling_edges.begin(), iter_e_end = dangling_edges.end();
1016  while (iter_e != iter_e_end)
1017  {
1018  if (degree(source(*iter_e, *ptr_mesh), *ptr_mesh) == 1)
1019  {
1020  auto v_tmp = target(*iter_e, *ptr_mesh);
1021  FEVV::Operators::collapse_edge_keep_target(*ptr_mesh, *iter_e);
1022  if (AIFHelpers::is_cut_vertex(v_tmp))
1023  {
1024  ++nb_cut_vertices; // vertex...
1025  if (make_2_mani_not_2_mani == "y")
1026  cut_vertices.push_back(v_tmp);
1027  else
1028  if (colorize_mesh == "y")
1029  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
1030  "v:color", v_tmp->GetIndex(), blue);
1031  }
1032  }
1033  else
1034  {
1035  auto v_tmp = source(*iter_e, *ptr_mesh);
1036  FEVV::Operators::collapse_edge_keep_source(*ptr_mesh, *iter_e);
1037  if (AIFHelpers::is_cut_vertex(v_tmp))
1038  {
1039  ++nb_cut_vertices; // vertex...
1040  if (make_2_mani_not_2_mani == "y")
1041  cut_vertices.push_back(v_tmp);
1042  else
1043  if (colorize_mesh == "y")
1044  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
1045  "v:color", v_tmp->GetIndex(), blue);
1046  }
1047  }
1048  ++iter_e;
1049  }
1050 
1051  // decomplexify complex edges (+ update list of cut vertices)
1052  std::vector< edge_descriptor > selected_complex_edges(complex_edges.begin(), complex_edges.end()),
1053  remaining_complex_edges;
1054 decomplexification:
1055  remove_adjacent_edges(*ptr_mesh, selected_complex_edges, remaining_complex_edges);
1056  while (!selected_complex_edges.empty())
1057  {
1058  std::cout << "New decomplexification step for an independent set of complex edges" << std::endl;
1059  iter_e = selected_complex_edges.begin(), iter_e_end = selected_complex_edges.end();
1060  int i = 0;
1061  while (iter_e != iter_e_end)
1062  {
1063  //{ // mesh file writing debug
1064  // auto res_mesh =
1065  // extract_edge_local_neighborhood(*iter_e, *ptr_mesh, pos_pm);
1066  // writer_type my_writer;
1067  // try
1068  // {
1069  // my_writer.write(res_mesh,
1070  // FEVV::FileUtils::get_file_name(input_file_path) + "_edge_" + FEVV::StrUtils::convert((*iter_e)->GetIndex()) + ".off");
1071  // }
1072  // catch (...)
1073  // {
1074  // std::cout << "writing failed";
1075  // exit(EXIT_FAILURE);
1076  // }
1077  //}
1078  // complex edges
1079  std::cout << "Information of current complex edge (" << i << "/" << selected_complex_edges.size() << "): " << std::endl; // debug
1080  std::cout << "\tedge id: " << get(edge_idm, *iter_e) << std::endl; // debug
1081  std::cout << "\tsource vertex: " << get(vertex_idm, source(*iter_e, *ptr_mesh)) << std::endl; // debug
1082  std::cout << "\ttarget vertex: " << get(vertex_idm, target(*iter_e, *ptr_mesh)) << std::endl; // debug
1083  std::cout << "\tdegree: " << degree(*iter_e, *ptr_mesh) << std::endl; // debug
1084  std::cout << "\tnb incident different segment: " << nb_different_incident_face_segment_indices(*ptr_mesh, *iter_e) << std::endl; // debug
1087  auto faces_range_pair = in_edges(*iter_e, *ptr_mesh); // get incident faces
1088  std::set<face_descriptor> current_faces(faces_range_pair.first, faces_range_pair.second),
1089  next_faces;
1090  std::map<int, edge_descriptor> face_id_to_edge;
1091  std::map<vertex_descriptor, vertex_descriptor> v_old_to_v_new, v_new_to_old;
1092  bool first = true;
1093  while (!current_faces.empty())
1094  {
1095  face_descriptor current_f = *current_faces.begin();
1096  int current_id = ptr_mesh->template GetProperty< AIFMeshT::face_type::ptr, int >(
1097  "f:2_manifold_component_seg", current_f->GetIndex());
1098  if (first)
1099  { // the first component keep the initial complex edge
1100  face_id_to_edge.insert(std::make_pair(current_id, *iter_e));
1101  }
1102  else if (face_id_to_edge.find(current_id) == face_id_to_edge.end())
1103  { // other components use a duplicate
1104  std::cout << "create a new edge" << std::endl; // debug
1106  face_id_to_edge.insert(std::make_pair(current_id, e_tmp));
1107  }
1108 
1109  auto iter_f = current_faces.begin(), iter_f_end = current_faces.end();
1110  for (; iter_f != iter_f_end; ++iter_f)
1111  {
1112  if (ptr_mesh->template GetProperty< AIFMeshT::face_type::ptr, int >(
1113  "f:2_manifold_component_seg", (*iter_f)->GetIndex()) != current_id)
1114  next_faces.insert(*iter_f);
1115  else
1116  { // during the current step we process all faces with the same current_id
1117  if (first)
1118  continue;
1119 
1120  // for other components: update incidence relationships
1123  calculate_previous_and_after_vertices(*ptr_mesh, *iter_e, pe, ae, v_pe_old, v_ae_old, v_old_to_v_new, v_new_to_old);
1124 
1126  *ptr_mesh,
1127  pos_pm,
1128  *iter_f,
1129  *iter_e,
1130  face_id_to_edge[current_id], // edge used to replace e
1131  v_old_to_v_new,
1132  v_new_to_old);
1133 
1134  std::cout << "\torientation: " << get(vertex_idm, v_pe_old) << " -> " << get(vertex_idm, v_ae_old); // debug
1135  std::cout << "\treplaced by: " << get(vertex_idm, v_old_to_v_new[v_pe_old]) << " -> " << get(vertex_idm, v_old_to_v_new[v_ae_old]) << " with edge id: " << get(edge_idm, face_id_to_edge[current_id]); // debug
1136  std::cout << std::endl; // debug
1137 
1138  assert(!AIFHelpers::is_degenerated_face(*iter_f));
1139 
1140  bool is_the_last = true;
1141  auto iter_f2 = iter_f;
1142  ++iter_f2;
1143  for (; iter_f2 != iter_f_end; ++iter_f2)
1144  if (ptr_mesh->template GetProperty< AIFMeshT::face_type::ptr, int >(
1145  "f:2_manifold_component_seg", (*iter_f2)->GetIndex()) == current_id)
1146  {
1147  is_the_last = false;
1148  break;
1149  }
1150  if (is_the_last)
1151  {
1152  // do this replacement for the last current face with the same id
1153  replace_vertex_in_incident_edges(*ptr_mesh, v_pe_old, v_old_to_v_new[v_pe_old], *iter_f, complex_edges);
1154  replace_vertex_in_incident_edges(*ptr_mesh, v_ae_old, v_old_to_v_new[v_ae_old], *iter_f, complex_edges);
1155 
1156  assert(!AIFHelpers::are_incident(v_pe_old, face_id_to_edge[current_id]));
1157  assert(!AIFHelpers::are_incident(v_ae_old, face_id_to_edge[current_id]));
1158  assert(has_different_vertex_indices(*ptr_mesh, vertex_idm, *iter_f));
1159  }
1160  }
1161  }
1162  first = false;
1163  current_faces.swap(next_faces);
1164  next_faces.clear();
1165  }
1166 
1167  // update cut vertices
1168  auto iter_map = face_id_to_edge.begin(), iter_map_e = face_id_to_edge.end();
1169  for (; iter_map != iter_map_e; ++iter_map)
1170  {
1171  auto v_tmp = source(iter_map->second, *ptr_mesh);
1172  if (AIFHelpers::is_cut_vertex(v_tmp))
1173  {
1174  ++nb_cut_vertices; // vertex...
1175  if (make_2_mani_not_2_mani == "y")
1176  cut_vertices.push_back(v_tmp);
1177  else
1178  if (colorize_mesh == "y")
1179  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
1180  "v:color", v_tmp->GetIndex(), blue);
1181  }
1182  v_tmp = target(iter_map->second, *ptr_mesh);
1183  if (AIFHelpers::is_cut_vertex(v_tmp))
1184  {
1185  ++nb_cut_vertices; // vertex...
1186  if (make_2_mani_not_2_mani == "y")
1187  cut_vertices.push_back(v_tmp);
1188  else
1189  if (colorize_mesh == "y")
1190  ptr_mesh->SetProperty< AIFMeshT::vertex_type::ptr, AIFMeshT::Vector >(
1191  "v:color", v_tmp->GetIndex(), blue);
1192  }
1193  }
1194 
1195  ++iter_e;
1196  ++i;
1197  }
1198  selected_complex_edges = remaining_complex_edges;
1199  remove_adjacent_edges(*ptr_mesh, selected_complex_edges, remaining_complex_edges);
1200  }
1201  if (!non_consitently_oriented_incident_face_edges.empty())
1202  {
1203  std::cout << "New decomplexification step for an independent set of edges incident to 2 non-consitently oriented faces" << std::endl;
1204  selected_complex_edges = non_consitently_oriented_incident_face_edges;
1205  non_consitently_oriented_incident_face_edges.clear();
1206  goto decomplexification;
1207  }
1208  // duplicate cut vertices [local partition and cutting]
1209  auto iter_v = cut_vertices.begin(), iter_v_end = cut_vertices.end();
1210  while (iter_v != iter_v_end)
1211  {
1212  //{ // mesh file writing debug
1213  // auto res_mesh =
1214  // extract_vertex_local_neighborhood(*iter_v, *ptr_mesh, pos_pm);
1215  // writer_type my_writer;
1216  // try
1217  // {
1218  // my_writer.write(res_mesh,
1219  // FEVV::FileUtils::get_file_name(input_file_path) + "_vertex_" + FEVV::StrUtils::convert((*iter_v)->GetIndex()) + ".off");
1220  // }
1221  // catch (...)
1222  // {
1223  // std::cout << "writing failed";
1224  // exit(EXIT_FAILURE);
1225  // }
1226  //}
1227  // cut vertices
1228  if (AIFHelpers::is_cut_vertex(*iter_v))
1229  std::cout << "degree of current cut vertex: " << degree(*iter_v, *ptr_mesh) << std::endl; // debug
1230  else
1231  {
1232  std::cout << "current vertex is not more a cut vertex!" << std::endl;
1233  ++iter_v;
1234  continue;
1235  }
1236  // pieces of surface need to replace *iter_v by a new vertex
1237  // except for the first piece of surface which keeps *iter_v
1238  auto face_range = AIFHelpers::incident_faces(*iter_v);
1239 
1240  std::set<face_descriptor> current_faces(face_range.begin(), face_range.end()),
1241  next_faces;
1242  std::map<int, vertex_descriptor> face_id_to_vertex;
1243  bool first = true;
1244  while (!current_faces.empty())
1245  {
1246  face_descriptor current_f = *current_faces.begin();
1247  int current_id = ptr_mesh->template GetProperty< AIFMeshT::face_type::ptr, int >(
1248  "f:2_manifold_component_seg", current_f->GetIndex());
1249 
1250  if (first)
1251  { // the first component keep the initial cut vertex
1252  face_id_to_vertex.insert(std::make_pair(current_id, *iter_v));
1253 
1254  // also continue for the same piece of surface else add to next_faces
1255  // remove edge-adjacent face around *iter_v
1256  edge_descriptor e1 = AIFHelpers::common_edge(*iter_v, current_f);
1257  edge_descriptor e2 = AIFHelpers::common_edge(*iter_v, current_f, e1);
1258  face_descriptor current_f_tmp = current_f;
1259  while ((degree(e1, *ptr_mesh) == 2) &&
1260  (current_faces.find(current_f_tmp) != current_faces.end()))
1261  {
1262  auto face_range2 = AIFHelpers::incident_faces(e1);
1263  auto it_f2 = face_range2.begin();
1264  for (; it_f2 != face_range2.end(); ++it_f2)
1265  {
1266  if (*it_f2 != current_f_tmp)
1267  {
1268  current_faces.erase(current_f_tmp);
1269  current_f_tmp = *it_f2;
1270  e1 = AIFHelpers::common_edge(*iter_v, current_f_tmp, e1);
1271  break;
1272  }
1273  }
1274  }
1275  if (current_f_tmp != current_f)
1276  current_faces.erase(current_f_tmp);
1277  if (degree(e2, *ptr_mesh) == 2)
1278  current_faces.insert(current_f);
1279  while ((degree(e2, *ptr_mesh) == 2) &&
1280  (current_faces.find(current_f) != current_faces.end()))
1281  {
1282  auto face_range2 = AIFHelpers::incident_faces(e2);
1283  auto it_f2 = face_range2.begin();
1284  for (; it_f2 != face_range2.end(); ++it_f2)
1285  {
1286  if (*it_f2 != current_f)
1287  {
1288  current_faces.erase(current_f);
1289  current_f = *it_f2;
1290  e2 = AIFHelpers::common_edge(*iter_v, current_f, e2);
1291  break;
1292  }
1293  }
1294  }
1295 
1296  }
1297  else
1298  {
1299  std::cout << "create a new vertex" << std::endl; // debug
1300  vertex_descriptor v_tmp = AIFHelpers::add_vertex(*ptr_mesh);
1301  auto p = get(pos_pm, *iter_v); // to avoid some writing bugs
1302  put(pos_pm, v_tmp, p);
1303 
1304  face_id_to_vertex.insert(std::make_pair(current_id, v_tmp));
1305  }
1306 
1307  auto iter_f = current_faces.begin(), iter_f_end = current_faces.end();
1308  std::map<face_descriptor, bool> face_to_next;
1309  for (; iter_f != iter_f_end; ++iter_f)
1310  if (current_f == *iter_f)
1311  face_to_next[*iter_f] = false;
1312  else if (AIFHelpers::are_incident_to_vertex_and_edge_connected(*iter_v, current_f, *iter_f))
1313  face_to_next[*iter_f] = false;
1314  else
1315  face_to_next[*iter_f] = true;
1316  iter_f = current_faces.begin();
1317  for (; iter_f != iter_f_end; ++iter_f)
1318  {
1319  if (face_to_next[*iter_f])
1320  next_faces.insert(*iter_f);
1321  else
1322  {
1323  if (first)
1324  {
1325  continue;
1326  }
1327 
1328  auto edge_range = AIFHelpers::incident_edges(*iter_f);
1329  auto it_e = edge_range.begin();
1330  for (; it_e != edge_range.end(); ++it_e)
1331  {
1332  if (AIFHelpers::are_incident(*it_e, *iter_v))
1333  {
1334  AIFHelpers::remove_edge(*iter_v, *it_e);
1335  AIFHelpers::add_edge(face_id_to_vertex[current_id], *it_e);
1336  AIFHelpers::add_vertex(*it_e, face_id_to_vertex[current_id], AIFHelpers::vertex_position(*it_e, *iter_v));
1337  }
1338  }
1339  }
1340  }
1341 
1342  first = false;
1343  current_faces.swap(next_faces);
1344  next_faces.clear();
1345  }
1346 
1347  if (AIFHelpers::is_cut_vertex(*iter_v))
1348  {
1349  std::cout << "failed to correct current vertex!" << std::endl; // debug
1350  { // mesh file writing debug
1351  auto res_mesh =
1352  extract_vertex_local_neighborhood(*iter_v, *ptr_mesh, pos_pm);
1353  writer_type my_writer;
1354  try
1355  {
1356  my_writer.write(res_mesh,
1357  FEVV::FileUtils::get_file_name(input_file_path) + "_vertex_after_" + FEVV::StrUtils::convert((*iter_v)->GetIndex()) + ".off");
1358  }
1359  catch (...)
1360  {
1361  std::cout << "writing failed";
1362  exit(EXIT_FAILURE);
1363  }
1364  }
1365  }
1366  ++iter_v;
1367  }
1369  assert(AIFHelpers::check_mesh_validity(ptr_mesh));
1371  // 4 - Save corrected mesh
1372  writer_type my_writer;
1373  try
1374  {
1375  if (FEVV::FileUtils::get_file_extension(input_file_path) == ".ply")
1376  my_writer.write(ptr_mesh,
1377  FEVV::FileUtils::get_file_name(input_file_path) + suffix +
1378  ".off");
1379  else
1380  my_writer.write(ptr_mesh,
1381  FEVV::FileUtils::get_file_name(input_file_path) + suffix +
1382  FEVV::FileUtils::get_file_extension(input_file_path));
1383  }
1384  catch (...)
1385  {
1386  std::cout << "writing failed";
1387  exit(EXIT_FAILURE);
1388  }
1390  std::cout << "The mesh file named "
1391  << FEVV::FileUtils::get_file_name(input_file_path) +
1392  FEVV::FileUtils::get_file_extension(input_file_path);
1393  if (nb_isolated_vertices > 0 || nb_t_junction_vertices > 0 || nb_cut_vertices > 0 || nb_isolated_edges > 0 ||
1394  nb_dangling_edges > 0 || nb_complex_edges > 0 || nb_non_consitently_oriented_incident_face_edges > 0 )
1395  std::cout << " is not 2-manifold " << std::endl;
1396  else
1397  std::cout << " is 2-manifold" << std::endl;
1398 
1399  std::string prefix =
1400  (remove_isolated_elements == "y")
1401  ? "Number of removed isolated"
1402  : "Number of isolated";
1403  std::cout << prefix << " vertices: " << nb_isolated_vertices << std::endl;
1404  std::cout << prefix << " edges: " << nb_isolated_edges << std::endl;
1405  std::cout << prefix << " faces (not removed yet): " << nb_isolated_faces << std::endl;
1407  prefix = (resolve_vertices_with_similar_incident_edges == "y")
1408  ? "Number of resolved vertices with similar incident edges: "
1409  : "Number of vertices with similar incident edges: ";
1410  std::cout << prefix << nb_vertices_with_similar_incident_edges << std::endl;
1412  std::cout << "Number of T-junction vertices: " << nb_t_junction_vertices << std::endl;
1413  std::cout << "Number of cut vertices: " << nb_cut_vertices << std::endl;
1414  std::cout << "Number of dangling edges: " << nb_dangling_edges << std::endl;
1415  std::cout << "Number of complex edges: " << nb_complex_edges;
1416  if(remaining_complex_edges.empty())
1417  std::cout << std::endl;
1418  else
1419  std::cout << " (" << remaining_complex_edges.size() << " not resolved due to local dependency). " << std::endl;
1420  std::cout << "Number of edges incident to 2 faces with inconsistent orientation: " << nb_non_consitently_oriented_incident_face_edges << std::endl;
1421  std::cout << "Number of surface border edges: " << nb_border_edges << std::endl;
1422  std::cout << "Number of degenerated faces: " << nb_degenerated_faces << std::endl;
1424  return EXIT_SUCCESS;
1425 }
1426 
1427 int
1428 main(int narg, char **argv)
1429 {
1430  if(narg < 3 || narg > 6)
1431  {
1432  std::cerr << "Cannot proceed arguments. Please use " << argv[0]
1433  << " meshfilename_or_meshfolder colorize_mesh [remove_isolated_elements "
1434  "[resolve_vertices_with_similar_incident_edges [make_2_mani_not_2_mani]]]"
1435  << std::endl;
1436  return EXIT_FAILURE;
1437  }
1438  std::string input_path(argv[1]);
1439  if (!boost::filesystem::exists(input_path) && !boost::filesystem::is_directory(input_path))
1440  {
1441  std::cerr << input_path << " does not exist. Exit. " << std::endl;
1442  return EXIT_FAILURE;
1443  }
1444  std::string colorize_mesh = (argv[2]);
1445  if(!argument_analysis(colorize_mesh, "colorizing output mesh", true))
1446  return EXIT_FAILURE;
1447  std::string remove_isolated_elements(((narg > 3) ? argv[3] : "n"));
1448  if (!argument_analysis(remove_isolated_elements, "removing of isolated elements", true))
1449  return EXIT_FAILURE;
1450  std::string resolve_vertices_with_similar_incident_edges(
1451  ((narg > 4) ? argv[4] : "n"));
1452  if (!argument_analysis(resolve_vertices_with_similar_incident_edges, "resolving similar/duplicate incident edges", true))
1453  return EXIT_FAILURE;
1454  std::string make_2_mani_not_2_mani(((narg > 5) ? argv[5] : "n"));
1455  if (!argument_analysis(make_2_mani_not_2_mani, "resolving not 2-manifold elements", true))
1456  return EXIT_FAILURE;
1458  if(!boost::filesystem::is_directory(input_path))
1459  process_one_mesh_file(input_path,
1460  colorize_mesh,
1461  remove_isolated_elements,
1462  resolve_vertices_with_similar_incident_edges,
1463  make_2_mani_not_2_mani);
1464  else
1465  {
1467  boost::filesystem::directory_iterator end_iter;
1468  for (boost::filesystem::directory_iterator dir_itr(input_path);
1469  dir_itr != end_iter;
1470  ++dir_itr)
1471  {
1472  try
1473  {
1474  if (boost::filesystem::is_directory(dir_itr->status()))
1475  {
1476  std::string dir_name_without_base = dir_itr->path().string();
1477 
1478  std::string command = "\"";
1479  for (int i = 0; i < narg; ++i)
1480  {
1481  switch (i)
1482  {
1483  case 0:
1484  {
1485  std::string cmd_tmp = argv[i];
1486  //replace(cmd_tmp, " ", "\\ ");
1487  command += "\"" + cmd_tmp + "\"";
1488  }
1489  break;
1490  case 1:
1491  //replace(dir_name_without_base, " ", "\\ ");
1492  command += "\"" + dir_name_without_base + "\"";
1493  break;
1494  default:
1495  command += std::string(argv[i]);
1496  }
1497 
1498  if (i < narg - 1)
1499  command += std::string(" ");
1500  }
1501  command += "\"";
1502  int r = system(command.c_str());
1503  if (r == -1)
1504  {
1505  std::cerr << " the following command is run: " << command << " failed (child process generation issue)." << std::endl;
1506  }
1507 
1508  continue; // ignore it for the current process
1509  }
1510  else if (!boost::filesystem::is_regular_file(dir_itr->status()))
1511  {
1512  continue; // ignore it
1513  }
1514 
1515  }
1516  catch (const std::exception & ex)
1517  {
1518  std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl;
1519  }
1520 
1521  if (dir_itr->path().extension().string() == ".msh" || dir_itr->path().extension().string() == ".off" || dir_itr->path().extension().string() == ".obj"
1522 #ifdef FEVV_USE_VTK
1523  || dir_itr->path().extension().string() == ".vtk" || dir_itr->path().extension().string() == ".vtp" || dir_itr->path().extension().string() == ".vtu"
1524 #endif
1525  )
1526  {
1527  process_one_mesh_file(dir_itr->path().string(),
1528  colorize_mesh,
1529  remove_isolated_elements,
1530  resolve_vertices_with_similar_incident_edges,
1531  make_2_mani_not_2_mani);
1532  }
1533  }
1534  }
1536  //system("pause");
1537  return EXIT_SUCCESS;
1538 }
extract_vertex_local_neighborhood
AIFMeshT extract_vertex_local_neighborhood(IterFaceType begin, IterFaceType end, PointMap pm)
Definition: test_mesh_defects_aif.cpp:37
CGAL::Euler::add_face
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::face_descriptor add_face(const VertexRange &vr, FEVV::DataStructures::AIF::AIFMesh &g)
Definition: Graph_traits_aif.h:1104
FEVV::DataStructures::AIF::vertices
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_iterator > vertices(const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns the iterator range of the vertices of the mesh.
Definition: Graph_traits_aif.h:172
collapse_edge.hpp
FEVV::DataStructures::AIF::AIFMeshWriter
This class represents an AIFMesh object writer. An AIFMeshWriter writes a mesh file (....
Definition: AIFMeshWriter.hpp:37
FEVV::DataStructures::AIF::AIFTopologyHelpers::common_edge
static edge_descriptor common_edge(vertex_descriptor vertex1, vertex_descriptor vertex2)
Definition: AIFTopologyHelpers.h:458
FEVV::StrUtils::convert
void convert(const std::string &str, ConvertType &elem)
Definition: StringUtilities.hpp:81
has_that_incident_face_segment_index
static bool has_that_incident_face_segment_index(const MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor e, int index)
Definition: test_mesh_defects_aif.cpp:236
FEVV::DataStructures::AIF::AIFVertex::ptr
boost::shared_ptr< self > ptr
Definition: AIFVertex.hpp:47
FEVV::DataStructures::AIF::AIFTopologyHelpers::incident_vertices
static boost::iterator_range< vertex_container_in_edge::const_iterator > incident_vertices(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:1189
FEVV::DataStructures::AIF::AIFTopologyHelpers::remove_faces
static void remove_faces(InputIt first, InputIt last, MeshType &mesh)
Definition: AIFTopologyHelpers.h:3193
has_only_that_incident_face_segment_index
static bool has_only_that_incident_face_segment_index(const MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor e, int index)
Definition: test_mesh_defects_aif.cpp:254
FEVV::Operators::collapse_edge_keep_source
void collapse_edge_keep_source(MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor &e)
Collapse an edge of the graph. The edge to collapse is given as a non-oriented edge....
Definition: collapse_edge.hpp:45
FEVV::DataStructures::AIF::degree
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::degree_size_type degree(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_descriptor u, const FEVV::DataStructures::AIF::AIFMesh &)
Definition: Graph_traits_aif.h:548
FEVV::DataStructures::AIF::AIFTopologyHelpers::add_face
static face_descriptor add_face(ptr_mesh mesh)
Definition: AIFTopologyHelpers.h:2887
FEVV::DataStructures::AIF::AIFTopologyHelpers::opposite_vertex
static vertex_descriptor opposite_vertex(edge_descriptor edge, vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:1270
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_isolated_edge
static bool is_isolated_edge(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:995
FEVV::DataStructures::AIF::AIFMeshReader::ptr_output
superclass::ptr_output ptr_output
Definition: AIFMeshReader.hpp:43
FEVV::DataStructures::AIF
Definition: AIFCellContainer.h:15
FEVV::Operators::are_similar_faces
static bool are_similar_faces(const typename boost::graph_traits< FaceIncidentGraph >::face_descriptor f1, const typename boost::graph_traits< FaceIncidentGraph >::face_descriptor f2, const FaceIncidentGraph &g, bool take_into_account_face_rientation=false)
Function determining if the arguments are similar faces (parallel faces).
Definition: topology_predicates.hpp:99
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_isolated_face
static bool is_isolated_face(face_descriptor face)
Definition: AIFTopologyHelpers.h:1511
FEVV::DataStructures::AIF::AIFTopologyHelpers::are_incident_to_vertex_and_edge_connected
static bool are_incident_to_vertex_and_edge_connected(vertex_descriptor vertex, face_descriptor face1, face_descriptor face2)
Definition: AIFTopologyHelpers.h:875
process_one_mesh_file
static int process_one_mesh_file(const std::string &input_file_path, const std::string &colorize_mesh, const std::string &remove_isolated_elements, const std::string &resolve_vertices_with_similar_incident_edges, const std::string &make_2_mani_not_2_mani)
Definition: test_mesh_defects_aif.cpp:502
FEVV::DataStructures::AIF::AIFMesh::ptr
boost::shared_ptr< Self > ptr
Definition: AIFMesh.hpp:50
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_degenerated_face
static bool is_degenerated_face(face_descriptor face)
Definition: AIFTopologyHelpers.h:1530
FEVV::DataStructures::AIF::edges
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_iterator > edges(const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns the iterator range of the edges of the mesh.
Definition: Graph_traits_aif.h:238
FEVV::DataStructures::AIF::AIFTopologyHelpers::remove_edges
static void remove_edges(InputIt first, InputIt last, MeshType &mesh)
Definition: AIFTopologyHelpers.h:3067
replace_edge_by_new_one_and_update_incidency
static void replace_edge_by_new_one_and_update_incidency(MutableFaceIncidentGraph &g, PointMap &pm, typename boost::graph_traits< MutableFaceIncidentGraph >::face_descriptor f, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor e, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor replace, std::map< typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor > &v_old_to_v_new, std::map< typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor > &v_new_to_old)
Definition: test_mesh_defects_aif.cpp:401
argument_analysis
static bool argument_analysis(std::string &arg, const std::string &arg_name, bool update_arg_tolower_case=true)
Definition: test_mesh_defects_aif.cpp:92
FEVV::DataStructures::AIF::AIFMeshHelpers::is_a_T_junction_vertex
static bool is_a_T_junction_vertex(vertex_descriptor v, ref_mesh mesh, const GeometryTraits &gt)
Definition: AIFMeshHelpers.h:62
FEVV::DataStructures::AIF::AIFMeshReader::read
ptr_output read(const std::string &filePath)
Definition: AIFMeshReader.inl:50
GraphConcept::edge_descriptor
boost::graph_traits< G >::edge_descriptor edge_descriptor
Definition: test_boost_graph_concept_aif.cpp:23
FEVV::DataStructures::AIF::AIFMeshHelpers::has_adjacent_T_junction_vertex
static bool has_adjacent_T_junction_vertex(vertex_descriptor v, ref_mesh mesh, const GeometryTraits &gt)
Definition: AIFMeshHelpers.h:161
FEVV::DataStructures::AIF::AIFTopologyHelpers::remove_face
static void remove_face(face_descriptor face, ptr_mesh mesh)
Definition: AIFTopologyHelpers.h:3120
FEVV::DataStructures::AIF::AIFFace::ptr
boost::shared_ptr< self > ptr
Definition: AIFFace.hpp:52
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_not_incident_to_complex_edge
static bool is_not_incident_to_complex_edge(face_descriptor face)
Definition: AIFTopologyHelpers.h:2057
FEVV::DataStructures::AIF::AIFTopologyHelpers::are_adjacent
static bool are_adjacent(vertex_descriptor vertex1, vertex_descriptor vertex2)
Definition: AIFTopologyHelpers.h:358
FEVV::Geometry_traits
Refer to Geometry_traits_documentation_dummy for further documentation on provided types and algorith...
Definition: Geometry_traits.h:162
FEVV::DataStructures::AIF::AIFTopologyHelpers::vertex_position
static vertex_pos vertex_position(edge_descriptor edge, vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:1252
calculate_previous_and_after_vertices
static void calculate_previous_and_after_vertices(MutableFaceIncidentGraph &, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor e, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor pe, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor ae, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor &v_pe_old, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor &v_ae_old, std::map< typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor > &v_old_to_v_new, std::map< typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor > &v_new_to_old)
Definition: test_mesh_defects_aif.cpp:352
FEVV::DataStructures::AIF::AIFTopologyHelpers::add_edge
static edge_descriptor add_edge(ptr_mesh mesh)
Definition: AIFTopologyHelpers.h:2772
FEVV::DataStructures::AIF::AIFTopologyHelpers::incident_faces
static boost::iterator_range< face_container_in_vertex::const_iterator > incident_faces(vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:415
FEVV::DataStructures::AIF::get
ValueT & get(const typename FEVV::DataStructures::AIF::PropertyMap< ValueT > &pm, KeyT k)
Specialization of get(pmap, key) for AIF.
Definition: Graph_properties_aif.h:175
FEVV::DataStructures::AIF::AIFTopologyHelpers::null_face
static face_descriptor null_face()
Definition: AIFTopologyHelpers.h:114
FEVV::DataStructures::AIF::source
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_descriptor source(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_descriptor e, const FEVV::DataStructures::AIF::AIFMesh &)
Returns the source vertex of e.
Definition: Graph_traits_aif.h:387
properties_aif.h
FEVV::DataStructures::AIF::AIFTopologyHelpers::get_edge_of_face_before_edge
static edge_descriptor get_edge_of_face_before_edge(face_descriptor face, edge_descriptor next_edge)
Definition: AIFTopologyHelpers.h:4399
FEVV::Operators::calculate_face_normal
GeometryTraits::Vector calculate_face_normal(typename boost::graph_traits< HalfedgeGraph >::face_descriptor f, const HalfedgeGraph &g, const PointMap &pm, const GeometryTraits &gt)
Calculate "some" normal to the considered face.
Definition: calculate_face_normal.hpp:33
FEVV::FileUtils::get_file_name
std::string get_file_name(const std::string &file_name)
Definition: FileUtilities.hpp:128
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_dangling_edge
static bool is_dangling_edge(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:1009
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_cut_vertex
static bool is_cut_vertex(vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:173
FEVV::DataStructures::AIF::AIFTopologyHelpers::link_vertex_and_edge
static void link_vertex_and_edge(vertex_descriptor vertex, edge_descriptor edge, vertex_pos position)
Definition: AIFTopologyHelpers.h:515
FEVV::Operators::collapse_edge_keep_target
void collapse_edge_keep_target(MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor &e)
Collapse an edge of the graph. The edge to collapse is given as a non-oriented edge....
Definition: collapse_edge.hpp:180
Graph_properties_aif.h
FEVV::DataStructures::AIF::AIFMeshWriter::write
void write(const ptr_input inputMesh, const std::string &filePath)
Definition: AIFMeshWriter.inl:28
FEVV::DataStructures::AIF::AIFTopologyHelpers::remove_edge
static void remove_edge(edge_descriptor edge, ptr_mesh mesh)
Definition: AIFTopologyHelpers.h:3012
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_surface_border_edge
static bool is_surface_border_edge(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:949
AIFMesh.hpp
FEVV::DataStructures::AIF::faces
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::face_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::face_iterator > faces(const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns an iterator range over all faces of the mesh.
Definition: Graph_traits_aif.h:679
main
int main(int narg, char **argv)
Definition: test_mesh_defects_aif.cpp:1428
writer_type
AIFMeshWriter writer_type
Definition: test_reader_writer_aif.cpp:23
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_isolated_vertex
static bool is_isolated_vertex(vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:159
has_different_vertex_indices
static bool has_different_vertex_indices(MutableFaceIncidentGraph &g, const PointIndexMap &idm, typename boost::graph_traits< MutableFaceIncidentGraph >::face_descriptor f)
Definition: test_mesh_defects_aif.cpp:487
FEVV::DataStructures::AIF::target
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_descriptor target(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_descriptor e, const FEVV::DataStructures::AIF::AIFMesh &)
Returns the target vertex of e.
Definition: Graph_traits_aif.h:400
FEVV::Operators::contains_similar_incident_edges
static bool contains_similar_incident_edges(const typename boost::graph_traits< FaceIncidentGraph >::vertex_descriptor v_to_keep, const FaceIncidentGraph &g)
Function determining if a pair of similar/parallel edges exists among the incident edges of vertex v_...
Definition: topology_predicates.hpp:62
remove_adjacent_edges
static void remove_adjacent_edges(MutableFaceIncidentGraph &g, std::vector< typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor > &selected_edges_to_make_independent, std::vector< typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor > &removed_edges)
Definition: test_mesh_defects_aif.cpp:142
Graph_traits_aif.h
FEVV::DataStructures::AIF::AIFTopologyHelpers::add_edge_to_face_after_edge
static void add_edge_to_face_after_edge(face_descriptor face, edge_descriptor prev_edge, edge_descriptor edge)
Definition: AIFTopologyHelpers.h:4438
FEVV::DataStructures::AIF::AIFTopologyHelpers::get_edge_of_face_after_edge
static edge_descriptor get_edge_of_face_after_edge(face_descriptor face, edge_descriptor prev_edge)
Definition: AIFTopologyHelpers.h:4366
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_complex_edge
static bool is_complex_edge(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:1022
FEVV::DataStructures::AIF::AIFTopologyHelpers::get_unordered_one_ring_edges
static std::set< edge_descriptor > get_unordered_one_ring_edges(vertex_descriptor v)
Definition: AIFTopologyHelpers.h:3481
FEVV::DataStructures::AIF::AIFEdge::ptr
boost::shared_ptr< self > ptr
Definition: AIFEdge.hpp:56
FEVV::DataStructures::AIF::AIFTopologyHelpers::common_vertex
static vertex_descriptor common_vertex(edge_descriptor edge1, edge_descriptor edge2)
Definition: AIFTopologyHelpers.h:1055
GraphConcept::g
G g
Definition: test_boost_graph_concept_aif.cpp:43
FEVV::DataStructures::AIF::AIFVector
Definition: AIFProperties.h:173
FEVV::DataStructures::AIF::AIFTopologyHelpers::check_mesh_validity
static bool check_mesh_validity(ptr_cmesh mesh)
Definition: AIFTopologyHelpers.h:2641
FEVV::FileUtils::get_file_extension
std::string get_file_extension(const std::string &file_name)
Definition: FileUtilities.hpp:36
reader_type
AIFMeshReader reader_type
Definition: test_reader_writer_aif.cpp:22
replace_vertex_in_incident_edges
static void replace_vertex_in_incident_edges(MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor v, typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor replace, typename boost::graph_traits< MutableFaceIncidentGraph >::face_descriptor current_f, const std::vector< typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor > &complex_edges)
Definition: test_mesh_defects_aif.cpp:272
FEVV::DataStructures::AIF::in_edges
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::in_edge_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::in_edge_iterator > in_edges(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_descriptor u, const FEVV::DataStructures::AIF::AIFMesh &)
Definition: Graph_traits_aif.h:451
FEVV::Operators::resolve_similar_incident_edges
static void resolve_similar_incident_edges(typename boost::graph_traits< MutableFaceIncidentGraph >::vertex_descriptor v_to_keep, MutableFaceIncidentGraph &g)
Remove/resolve similar/parallel edges for all incident edges of v_to_keep vertex.
Definition: similarity.hpp:102
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_surface_regular_edge
static bool is_surface_regular_edge(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:960
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_incident_to_consistently_oriented_faces
static bool is_incident_to_consistently_oriented_faces(edge_descriptor edge)
Definition: AIFTopologyHelpers.h:2025
calculate_face_normal.hpp
create_new_edge_with_its_incident_vertices
boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor create_new_edge_with_its_incident_vertices(MutableFaceIncidentGraph &g)
Definition: test_mesh_defects_aif.cpp:126
FEVV::DataStructures::AIF::AIFTopologyHelpers::is_incident_to_dangling_or_complex_edge
static bool is_incident_to_dangling_or_complex_edge(vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:199
AIFMeshHelpers.h
Geometry_traits_aif.h
FEVV::DataStructures::AIF::AIFTopologyHelpers::incident_edges
static boost::iterator_range< edge_container_in_vertex::const_iterator > incident_edges(vertex_descriptor vertex)
Definition: AIFTopologyHelpers.h:399
msdm2::vertex_descriptor
boost::graph_traits< MeshT >::vertex_descriptor vertex_descriptor
Definition: msdm2_surfacemesh.h:33
extract_edge_local_neighborhood
AIFMeshT extract_edge_local_neighborhood(typename boost::graph_traits< AIFMeshT >::edge_descriptor e, const AIFMeshT &g, PointMap pm)
Definition: test_mesh_defects_aif.cpp:76
FEVV::DataStructures::AIF::AIFMesh
This class represents an AIF structure. AIF structure can deal with both manifold and non-manifold su...
Definition: AIFMesh.hpp:47
similarity.hpp
FEVV::DataStructures::AIF::AIFTopologyHelpers::add_vertex
static vertex_descriptor add_vertex(ptr_mesh mesh)
Definition: AIFTopologyHelpers.h:2709
FEVV::DataStructures::AIF::AIFTopologyHelpers::null_vertex
static vertex_descriptor null_vertex()
Definition: AIFTopologyHelpers.h:112
FEVV::DataStructures::AIF::AIFMeshReader
This class represents an AIFMesh object reader. An AIFMeshReader reads a mesh file (....
Definition: AIFMeshReader.hpp:37
AIFMeshReader.hpp
FEVV::DataStructures::AIF::AIFTopologyHelpers::are_incident
static bool are_incident(vertex_descriptor vertex, edge_descriptor edge)
Function determining if the arguments share an incidence relation.
Definition: AIFTopologyHelpers.h:303
FileUtilities.hpp
FEVV::DataStructures::AIF::AIFTopologyHelpers::adjacent_faces
static std::vector< face_descriptor > adjacent_faces(face_descriptor face, bool one_neighborhood_sharing_edge=true)
Definition: AIFTopologyHelpers.h:1871
FEVV::DataStructures::AIF::AIFTopologyHelpers::have_consistent_orientation
static bool have_consistent_orientation(face_descriptor face1, face_descriptor face2)
Definition: AIFTopologyHelpers.h:1972
FEVV::DataStructures::AIF::AIFTopologyHelpers::remove_vertices
static void remove_vertices(InputIt first, InputIt last, MeshType &mesh)
Definition: AIFTopologyHelpers.h:3000
FEVV::DataStructures::AIF::put
void put(const typename FEVV::DataStructures::AIF::PropertyMap< ValueT > &pm, KeyT k, const ValueT &v)
Specialization of put(pmap, key, value) for AIF.
Definition: Graph_properties_aif.h:214
nb_different_incident_face_segment_indices
static size_t nb_different_incident_face_segment_indices(const MutableFaceIncidentGraph &g, typename boost::graph_traits< MutableFaceIncidentGraph >::edge_descriptor e)
Definition: test_mesh_defects_aif.cpp:219
AIFMeshWriter.hpp