MEPP2 Project
edge_selector.hpp
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.
11 #pragma once
12 
15 
17 
19 
20 #include <vector>
21 
22 namespace FEVV {
23 namespace Filters {
24 
64  template<typename FaceGraph,
65  typename GeometryTraits = FEVV::Geometry_traits< FaceGraph > >
66  std::vector<typename boost::graph_traits<FaceGraph>::edge_descriptor>
67  edge_selector_for_collapse(const FaceGraph& g,
68  bool is_g_2_manifold,
69  bool forbid_non_satisfying_link_condition,
70  bool forbid_non_manifold_edge,
71  bool forbid_edge_collapse_creating_non_manifold_split,
72  bool forbid_border_edge, // border edge processing is usually different from inner edges
73  bool forbid_inner_edge, // should be false, except when testing border edges
74  bool forbid_non_triangular_incident_face_to_edge, // most of algorithms can only handle edge collapses if all incident faces are triangular
75  bool forbid_edges_that_are_adjacent_to_collapsed_edges, // should be true most of the time, since local encoding will be tricky otherwise
76  bool forbid_edges_that_are_one_ring_edges_of_collapsed_edge_vertices, // must be true for full independent edge collapses; you should set the same value for next parameter
77  bool forbid_edges_that_are_incident_to_opposite_vertices_of_collapsed_edge_vertices, // must be true for full independent edge collapses
78  bool forbid_edges_that_are_incident_to_one_ring_of_collapsed_edge_vertices, // must be true to optimize the encoding of zeros in the vertex to split bit buffer
79  const std::set<typename boost::graph_traits<FaceGraph>::edge_descriptor>& external_forbidden_edges_to_collapse, // must be edges from g
80  const GeometryTraits &gt
81  )
82  {
84  std::vector<typename boost::graph_traits<FaceGraph>::edge_descriptor> batch_of_edges_to_collapse;
85  std::set<typename boost::graph_traits<FaceGraph>::edge_descriptor> forbidden_edges_to_collapse(external_forbidden_edges_to_collapse.begin(), external_forbidden_edges_to_collapse.end());
87  auto pm = get(boost::vertex_point, g);
88  auto edge_range_mesh = Helpers::edges(g);
89  for (auto edge_it = edge_range_mesh.begin(); edge_it != edge_range_mesh.end(); ++edge_it)
90  {
91  if (forbidden_edges_to_collapse.find(*edge_it) == forbidden_edges_to_collapse.end())
92  {
93  bool is_a_2_manifold_collapse = is_g_2_manifold ||
94  Helpers::is_2_manifold_edge(*edge_it);
95  bool edge_ok_for_collapse = is_g_2_manifold ||
96  !forbid_non_manifold_edge ||
97  ( is_a_2_manifold_collapse && // cannot encode neither cut vertices, nor complex edges with triplets (v,left, right)
98  Helpers::is_one_ring_2_manifold(source(*edge_it, g)) &&
99  Helpers::is_one_ring_2_manifold(target(*edge_it, g)));
100 
101  //if (forbid_non_satisfying_link_condition &&
102  // !CGAL::Euler::does_satisfy_link_condition(*edge_it, g) // not enough for non-manifold meshes and makes g non const
103  // )
104  //{
105  // forbidden_edges_to_collapse.insert(*edge_it);
106  // continue;
107  //}
108 
109  if (forbid_edge_collapse_creating_non_manifold_split && edge_ok_for_collapse)
110  {
111  // case where the merge of the 2 one-rings makes a cut vertex that cannot be processed by the 2-manifold vertex split
112  if (Helpers::is_surface_interior_edge(*edge_it) &&
113  Helpers::is_surface_border_vertex(source(*edge_it, g)) &&
114  Helpers::is_surface_border_vertex(target(*edge_it, g))
115  )
116  edge_ok_for_collapse = false;
117  }
118 
119  if (forbid_border_edge && edge_ok_for_collapse)
120  {
121  // forbid border edge collapse
122  if (Helpers::is_surface_border_edge(*edge_it))
123  edge_ok_for_collapse = false;
124  }
125  if (forbid_inner_edge && edge_ok_for_collapse)
126  {
127  // forbid inner edge collapse
128  if (Helpers::is_surface_interior_edge(*edge_it))
129  edge_ok_for_collapse = false;
130  }
131  bool is_a_triangular_collapse = true;
132 
133  if (forbid_non_triangular_incident_face_to_edge && edge_ok_for_collapse )
134  {
135  // forbid polygonal edge collapse
137  {
138  edge_ok_for_collapse = false;
139  is_a_triangular_collapse = false;
140  }
141  }
142 
143  if (forbid_non_triangular_incident_face_to_edge && is_a_2_manifold_collapse && is_a_triangular_collapse && edge_ok_for_collapse)
144  {
145  // local check to avoid face flipping
146  if (!FEVV::Operators::no_normal_flip_for_collapse(g, pm, *edge_it, source(*edge_it, g), get(pm, target(*edge_it, g)), gt) ||
147  !FEVV::Operators::no_normal_flip_for_collapse(g, pm, *edge_it, target(*edge_it, g), get(pm, source(*edge_it, g)), gt)
148  )
149  {
150  edge_ok_for_collapse = false;
151  }
152  }
153 
154  if (forbid_non_satisfying_link_condition && edge_ok_for_collapse)
155  {
156  auto incident_v1_range = Helpers::adjacent_vertices(source(*edge_it, g));
157  auto incident_v2_range = Helpers::adjacent_vertices(target(*edge_it, g));
158  auto iter_v1 = incident_v1_range.begin();
159  for (; (iter_v1 != incident_v1_range.end()) && edge_ok_for_collapse; ++iter_v1)
160  {
161  if (*iter_v1 == target(*edge_it, g))
162  continue;
163  auto iter_v2 = incident_v2_range.begin();
164  for (; iter_v2 != incident_v2_range.end(); ++iter_v2)
165  {
166  if (*iter_v2 == source(*edge_it, g))
167  continue;
168  if (*iter_v1 == *iter_v2)
169  {
170  typename boost::graph_traits<FaceGraph>::face_descriptor f = Helpers::common_face(Helpers::common_edge(source(*edge_it, g), *iter_v1),
171  Helpers::common_edge(target(*edge_it, g), *iter_v2)
172  );
173  // When there is a common neighbor, and if no face exist between these 3 vertices, we have two situations:
174  // 1) vertex in "the middle" of a triangle or 2) tunnel that can be sewn by the collapse
175  if (f == Helpers::null_face())
176  {
177  edge_ok_for_collapse = false;
178  break;
179  }
180  else if ((degree(Helpers::common_edge(source(*edge_it, g), *iter_v1), g) == 1) &&
181  (degree(Helpers::common_edge(target(*edge_it, g), *iter_v2), g) == 1)
182  )
183  { // case where you create a dangling edge [to avoid for the time being since most of mesh readers do not support it, except AIF native reader]
184  edge_ok_for_collapse = false;
185  break;
186  }
187  }
188  }
189  }
190  }
191  if (!edge_ok_for_collapse)
192  {
193  forbidden_edges_to_collapse.insert(*edge_it);
194  continue;
195  }
196 
197  batch_of_edges_to_collapse.push_back(*edge_it);
198  // remove incident edges from edges to collapse
199  auto v1_ad_container = Helpers::adjacent_vertices((*edge_it)->get_first_vertex());
200  auto v2_ad_container = Helpers::adjacent_vertices((*edge_it)->get_second_vertex());
201 
202  if (forbid_edges_that_are_adjacent_to_collapsed_edges)
203  {
204  for (auto it = v1_ad_container.begin(); it != v1_ad_container.end(); ++it)
205  {
206  if (*it == (*edge_it)->get_second_vertex())
207  continue;
208  forbidden_edges_to_collapse.insert(edge(*it, (*edge_it)->get_first_vertex(), g).first);
209  }
210 
211  for (auto it = v2_ad_container.begin(); it != v2_ad_container.end(); ++it)
212  {
213  if (*it == (*edge_it)->get_first_vertex())
214  continue;
215  forbidden_edges_to_collapse.insert(edge(*it, (*edge_it)->get_second_vertex(), g).first);
216  }
217  }
218 
219  if (forbid_edges_that_are_one_ring_edges_of_collapsed_edge_vertices)
220  {
221  // remove one-ring edges from edges to collapse
222  auto edge_set_v1 = Helpers::get_unordered_one_ring_edges((*edge_it)->get_first_vertex());
223  auto edge_set_v2 = Helpers::get_unordered_one_ring_edges((*edge_it)->get_second_vertex());
224 
225  for (auto it = edge_set_v1.begin(); it != edge_set_v1.end(); ++it)
226  {
227  forbidden_edges_to_collapse.insert(*it);
228  }
229 
230  for (auto it = edge_set_v2.begin(); it != edge_set_v2.end(); ++it)
231  {
232  forbidden_edges_to_collapse.insert(*it);
233  }
234  }
235 
236  if (forbid_edges_that_are_incident_to_opposite_vertices_of_collapsed_edge_vertices)
237  {
238  // remove incident edges to opposite vertices (e.g. incident edges to left and right vertices
239  // in a 2-manifold triangular case)
240 
241  // get incident vertices to faces that are incident to the edge *edge_it
242  auto f_range = Helpers::incident_faces(*edge_it);
243  auto iter_f = f_range.begin();
244  for (; iter_f != f_range.end(); ++iter_f)
245  {
246  auto v_range = Helpers::incident_vertices(*iter_f);
247  for (auto iter_v = v_range.begin(); iter_v != v_range.end(); ++iter_v)
248  {
249  if ((*iter_v != (*edge_it)->get_first_vertex()) && (*iter_v != (*edge_it)->get_second_vertex()))
250  {
251  auto e_range = Helpers::incident_edges(*iter_v);
252  forbidden_edges_to_collapse.insert(e_range.begin(), e_range.end());
253  }
254  }
255  }
256  }
257  if (forbid_edges_that_are_incident_to_one_ring_of_collapsed_edge_vertices)
258  {
259  // remove incident edges to one-ring vertices
260  for (auto it = v1_ad_container.begin(); it != v1_ad_container.end(); ++it)
261  {
262  auto edge_range = Helpers::incident_edges(*it);
263 
264  for (auto it2 = edge_range.begin(); it2 != edge_range.end(); ++it2)
265  {
266  forbidden_edges_to_collapse.insert(*it2);
267  }
268  }
269 
270  for (auto it = v2_ad_container.begin(); it != v2_ad_container.end(); ++it)
271  {
272  auto edge_range = Helpers::incident_edges(*it);
273 
274  for (auto it2 = edge_range.begin(); it2 != edge_range.end(); ++it2)
275  {
276  forbidden_edges_to_collapse.insert(*it2);
277  }
278  }
279  }
280  }
281  }
282  return batch_of_edges_to_collapse;
283  }
284 
319  template<typename FaceGraph,
320  typename GeometryTraits = FEVV::Geometry_traits< FaceGraph > >
321  std::vector<typename boost::graph_traits<FaceGraph>::edge_descriptor>
322  edge_selector_for_collapse( const FaceGraph& g,
323  bool is_g_2_manifold,
324  bool forbid_non_satisfying_link_condition,
325  bool forbid_non_manifold_edge,
326  bool forbid_edge_collapse_creating_non_manifold_split,
327  bool forbid_border_edge, // border edge processing is usually different from inner edges
328  bool forbid_inner_edge, // should be false, except when testing border edges
329  bool forbid_non_triangular_incident_face_to_edge, // most of algorithms can only handle edge collapses if all incident faces are triangular
330  bool forbid_edges_that_are_adjacent_to_collapsed_edges, // should be true most of the time, since local encoding will be tricky otherwise
331  bool forbid_edges_that_are_one_ring_edges_of_collapsed_edge_vertices, // must be true for full independent edge collapses; you should set the same value for next parameter
332  bool forbid_edges_that_are_incident_to_opposite_vertices_of_collapsed_edge_vertices, // must be true for full independent edge collapses
333  bool forbid_edges_that_are_incident_to_one_ring_of_collapsed_edge_vertices, // must be true for full independent edges collapses; you should set the same value for previous parameter
334  const GeometryTraits &gt
335  )
336  {
337  std::set<typename boost::graph_traits<FaceGraph>::edge_descriptor> empty_external_forbidden_edges_to_collapse;
338 
339  return edge_selector_for_collapse( g,
340  is_g_2_manifold,
341  forbid_non_satisfying_link_condition,
342  forbid_non_manifold_edge,
343  forbid_edge_collapse_creating_non_manifold_split,
344  forbid_border_edge,
345  forbid_inner_edge,
346  forbid_non_triangular_incident_face_to_edge,
347  forbid_edges_that_are_adjacent_to_collapsed_edges,
348  forbid_edges_that_are_one_ring_edges_of_collapsed_edge_vertices,
349  forbid_edges_that_are_incident_to_opposite_vertices_of_collapsed_edge_vertices,
350  forbid_edges_that_are_incident_to_one_ring_of_collapsed_edge_vertices,
351  empty_external_forbidden_edges_to_collapse,
352  gt);
353  }
354 } // namespace Filters
355 } // namespace FEVV
356 
Graph_traits_extension_aif.h
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::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::Geometry_traits
Refer to Geometry_traits_documentation_dummy for further documentation on provided types and algorith...
Definition: Geometry_traits.h:162
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
FEVV::DataStructures::AIF::edge
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_descriptor edge(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::halfedge_descriptor h, const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns the edge corresponding to h and opposite(h).
Definition: Graph_traits_aif.h:345
FEVV::get
FEVV::PCLPointCloudPointMap::value_type get(const FEVV::PCLPointCloudPointMap &pm, FEVV::PCLPointCloudPointMap::key_type key)
Specialization of get(point_map, key) for PCLPointCloud.
Definition: Graph_properties_pcl_point_cloud.h:117
topology_predicates.hpp
FEVV
Interfaces for plugins These interfaces will be used for different plugins.
Definition: Assert.h:16
no_normal_flip_for_collapse.hpp
FEVV::Operators::has_only_incident_triangular_faces
bool has_only_incident_triangular_faces(const typename boost::graph_traits< IncidentMutableFaceGraph >::edge_descriptor e, const IncidentMutableFaceGraph &g)
Function determining if the incident faces to e are all triangles.
Definition: topology_predicates.hpp:234
FEVV::Filters::edge_selector_for_collapse
std::vector< typename boost::graph_traits< FaceGraph >::edge_descriptor > edge_selector_for_collapse(const FaceGraph &g, bool is_g_2_manifold, bool forbid_non_satisfying_link_condition, bool forbid_non_manifold_edge, bool forbid_edge_collapse_creating_non_manifold_split, bool forbid_border_edge, bool forbid_inner_edge, bool forbid_non_triangular_incident_face_to_edge, bool forbid_edges_that_are_adjacent_to_collapsed_edges, bool forbid_edges_that_are_one_ring_edges_of_collapsed_edge_vertices, bool forbid_edges_that_are_incident_to_opposite_vertices_of_collapsed_edge_vertices, bool forbid_edges_that_are_incident_to_one_ring_of_collapsed_edge_vertices, const std::set< typename boost::graph_traits< FaceGraph >::edge_descriptor > &external_forbidden_edges_to_collapse, const GeometryTraits &gt)
Function used for cleaning the topology of mesh g. This can be seen as a preprocessing step for some ...
Definition: edge_selector.hpp:67
FEVV::Operators::no_normal_flip_for_collapse
bool no_normal_flip_for_collapse(const HalfedgeGraph &g, const PointMap &pm, typename boost::graph_traits< HalfedgeGraph >::edge_descriptor e, typename boost::graph_traits< HalfedgeGraph >::vertex_descriptor v, const typename GeometryTraits::Point &new_pos_v, const GeometryTraits &gt)
Function used to detected a local normal flip due to a vertex position change.
Definition: no_normal_flip_for_collapse.hpp:46
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
Geometry_traits.h
FEVV::DataStructures::AIF::adjacent_vertices
std::pair< typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::adjacency_iterator, typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::adjacency_iterator > adjacent_vertices(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::vertex_descriptor v, const FEVV::DataStructures::AIF::AIFMesh &)
Definition: Graph_traits_aif.h:217
FEVV::DataStructures::AIF::AIFTopologyHelpers
This class is an helper class associated to the AIFMesh structure. AIFTopologyHelpers implements all ...
Definition: AIFTopologyHelpers.h:57