Wildmeshing Toolkit
link_condition.cpp
Go to the documentation of this file.
1 #include "link_condition.hpp"
6 #include "link.hpp"
7 #include "link_iterable.hpp"
8 #include "open_star.hpp"
10 
11 namespace wmtk::simplex {
12 bool link_condition_closed_trimesh(const TriMesh& mesh, const Tuple& edge)
13 {
14  const Simplex v_a = Simplex::vertex(mesh, edge);
15  const Simplex v_b = Simplex::vertex(mesh, mesh.switch_tuple(edge, PrimitiveType::Vertex));
16  const Simplex e_ab = Simplex::edge(mesh, edge);
17 
18  IdSimplexCollection link_a(mesh);
19  link_a.reserve(24);
20  for (const IdSimplex& s : link_iterable(mesh, v_a)) {
21  link_a.add(s);
22  }
23  link_a.sort_and_clean();
24  IdSimplexCollection link_b(mesh);
25  link_b.reserve(24);
26  for (const IdSimplex& s : link_iterable(mesh, v_b)) {
27  link_b.add(s);
28  }
29  link_b.sort_and_clean();
30  IdSimplexCollection link_ab(mesh);
31  link_ab.reserve(2);
32  for (const IdSimplex& s : link_iterable(mesh, e_ab)) {
33  link_ab.add(s);
34  }
35  link_ab.sort_and_clean();
36 
37  const IdSimplexCollection link_a_link_b_intersection =
39 
40  return IdSimplexCollection::are_simplex_collections_equal(link_a_link_b_intersection, link_ab);
41 }
42 
43 bool link_condition(const EdgeMesh& mesh, const Tuple& edge)
44 {
45  const Tuple edge_switch_v = mesh.switch_tuple(edge, PrimitiveType::Vertex);
46  if (mesh.is_boundary_vertex(edge) && mesh.is_boundary_vertex(edge_switch_v)) {
47  return false;
48  }
50  mesh,
51  edge,
53  edge_switch_v,
55  return false;
56  }
57  return true;
58 }
59 
60 bool link_condition(const TriMesh& mesh, const Tuple& edge)
61 {
62  // step1 check link condition for closed case
63  if (!link_condition_closed_trimesh(mesh, edge)) {
64  return false;
65  }
66  // for the trimesh with boudanry cases, we add a dummy vertex w to the mesh, and connected it to
67  // all the boundary edges, then the mesh becomes a closed manifold mesh for all vertices but w.
68 
69  // check if dummy vertex w is included in the lhs
70  auto get_boundary_edges = [&mesh](const Tuple& _v) {
71  const Simplex input_v(mesh, PrimitiveType::Vertex, _v);
72  std::vector<Tuple> ret;
73  // get incident_edges from open_star
74  // incident_edges = cofaces_single_dimension_tuples(mesh, input_v,
75  // PrimitiveType::Edge);
76  auto incident_edges = cofaces_single_dimension_iterable(mesh, input_v, PrimitiveType::Edge);
77  for (const Tuple& _e : incident_edges) {
78  if (mesh.is_boundary(PrimitiveType::Edge, _e)) {
79  ret.push_back(mesh.switch_tuple(_e, PrimitiveType::Vertex));
80  }
81  }
82  return ret;
83  };
84 
85  // case 1: edge ab is a boundary edge, in this case dummy vertex w is in lnk(ab), need to check
86  // if there are any common edges connected with w in lnk_w^0(a)∩lnk_w^0(b)
87  const auto boundary_neighbors_a = get_boundary_edges(edge);
88  const auto boundary_neighbors_b =
89  get_boundary_edges(mesh.switch_tuple(edge, PrimitiveType::Vertex));
90  if (mesh.is_boundary_edge(edge)) {
91  assert(boundary_neighbors_a.size() == 2); // if guarantee 2-manifold
92  assert(boundary_neighbors_b.size() == 2); // if guarantee 2-manifold
93  for (auto e_a : boundary_neighbors_a) {
94  for (auto e_b : boundary_neighbors_b) {
96  mesh,
97  Simplex(mesh, PrimitiveType::Vertex, e_a),
98  Simplex(mesh, PrimitiveType::Vertex, e_b))) {
99  // find common edge, link condition fails
100  return false;
101  }
102  }
103  }
104  } else {
105  if (boundary_neighbors_a.size() == 0 || boundary_neighbors_b.size() == 0) {
106  // in this case, lnk_w^0(a) ∩ lnk_w^0(b) == lnk(a) ∩ lnk(b) == lnk(ab) == lnk_w^0(ab)
107  return true;
108  } else {
109  // in this case w \in lhs but not \in rhs
110  return false;
111  }
112  }
113 
114  return true;
115 }
116 
117 bool link_condition_closed_tetmesh(const TetMesh& mesh, const Tuple& edge)
118 {
119  // for closed mesh, if link(a) \intersect link(b) == link(ab)
120  const Simplex v_a = Simplex::vertex(mesh, edge);
121  const Simplex v_b = Simplex::vertex(mesh, mesh.switch_vertex(edge));
122  const Simplex e_ab = Simplex::edge(mesh, edge);
123 
124  IdSimplexCollection link_a(mesh);
125  link_a.reserve(128);
126  for (const IdSimplex& s : link_iterable(mesh, v_a)) {
127  link_a.add(s);
128  }
129  link_a.sort_and_clean();
130  IdSimplexCollection link_b(mesh);
131  link_b.reserve(128);
132  for (const IdSimplex& s : link_iterable(mesh, v_b)) {
133  link_b.add(s);
134  }
135  link_b.sort_and_clean();
136  IdSimplexCollection link_ab(mesh);
137  link_ab.reserve(32);
138  for (const IdSimplex& s : link_iterable(mesh, e_ab)) {
139  link_ab.add(s);
140  }
141  link_ab.sort_and_clean();
142 
143  const IdSimplexCollection link_a_link_b_intersection =
145 
146  return IdSimplexCollection::are_simplex_collections_equal(link_a_link_b_intersection, link_ab);
147 }
148 
149 bool link_condition(const TetMesh& mesh, const Tuple& edge)
150 {
151  // close mesh check
152  if (!link_condition_closed_tetmesh(mesh, edge)) {
153  return false;
154  }
155 
162  auto get_boundary_vertex_link = [&mesh](const Tuple& _v) {
163  const Simplex input_v(mesh, PrimitiveType::Vertex, _v);
164  // std::vector<Tuple> ret;
165  IdSimplexCollection ret(mesh);
166  // auto incident_faces =
167  // cofaces_single_dimension_tuples(mesh, input_v, PrimitiveType::Triangle);
168  auto incident_faces =
170  for (const Tuple& _f : incident_faces) {
171  if (mesh.is_boundary(PrimitiveType::Triangle, _f)) {
172  // assuming cofaces_single_dimension always return the tuple point to the input
173  // vertex
174  // ret.push_back(mesh.switch_tuples(_f, {PrimitiveType::Vertex,
175  // PrimitiveType::Edge})); ret.push_back(mesh.switch_edge(mesh.switch_vertex(_f)));
176  Tuple link_tuple =
178  ret.add(PrimitiveType::Edge, link_tuple);
179  ret.add(PrimitiveType::Vertex, link_tuple);
180  ret.add(
182  mesh.switch_tuple(link_tuple, PrimitiveType::Vertex));
183  }
184  }
185  return ret;
186  };
187 
188  auto get_boundary_edge_link = [&mesh](const Tuple& _v) {
189  const Simplex input_e(mesh, PrimitiveType::Edge, _v);
190  IdSimplexCollection ret(mesh);
191  auto incident_faces =
193  for (const Tuple& _f : incident_faces) {
194  if (mesh.is_boundary(PrimitiveType::Triangle, _f)) {
195  Tuple link_tuple =
197  ret.add(PrimitiveType::Vertex, link_tuple);
198  }
199  }
200  return ret;
201  };
202 
203  const Tuple& a_tuple = edge;
204  const Tuple b_tuple = mesh.switch_tuple(edge, PrimitiveType::Vertex);
205 
206  if (mesh.is_boundary_edge(edge)) {
207  IdSimplexCollection boundary_link_a = get_boundary_vertex_link(a_tuple);
208  boundary_link_a.sort_and_clean();
209  IdSimplexCollection boundary_link_b = get_boundary_vertex_link(b_tuple);
210  boundary_link_b.sort_and_clean();
211 
212  IdSimplexCollection boundary_link_ab = get_boundary_edge_link(edge);
213  boundary_link_ab.sort_and_clean();
214 
215  IdSimplexCollection boundary_link_a_link_b_intersection =
216  IdSimplexCollection::get_intersection(boundary_link_a, boundary_link_b);
217 
219  boundary_link_a_link_b_intersection,
220  boundary_link_ab);
221 
222  } else if (mesh.is_boundary_vertex(a_tuple) && mesh.is_boundary_vertex(b_tuple)) {
223  return false;
224  }
225 
226  return true;
227 }
228 
229 bool link_condition(const Mesh& mesh, const Tuple& edge)
230 {
231  return std::visit(
232  [&edge](auto&& m) noexcept {
233  using MType = std::decay_t<decltype(m.get())>;
234  if constexpr (std::is_same_v<MType, Mesh>) {
235  throw std::runtime_error("Link condition called on an unknown type of mesh - could "
236  "only cast it to Mesh");
237  } else if constexpr (std::is_same_v<MType, PointMesh>) {
238  return true;
239  } else {
240  return link_condition(m.get(), edge);
241  }
242  },
244 }
245 } // namespace wmtk::simplex
Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const override
switch the orientation of the Tuple of the given dimension
Definition: EdgeMesh.cpp:38
bool is_boundary_vertex(const Tuple &tuple) const
Definition: EdgeMesh.cpp:31
Tuple switch_tuples(const Tuple &tuple, const ContainerType &op_sequence) const
Performs a sequence of switch_tuple operations in the order specified in op_sequence.
Definition: MeshCRTP.hpp:135
bool is_boundary_vertex(const Tuple &tuple) const
Definition: TetMesh.cpp:400
Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const final override
switch the orientation of the Tuple of the given dimension
Definition: TetMesh.cpp:264
bool is_boundary_edge(const Tuple &tuple) const
Definition: TetMesh.cpp:388
Tuple switch_vertex(const Tuple &tuple) const
Definition: TetMesh.hpp:113
bool is_boundary(PrimitiveType pt, const Tuple &tuple) const final override
check if a simplex (encoded as a tuple/primitive pair) lies on a boundary or not
Definition: TetMesh.cpp:367
Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const final override
switch the orientation of the Tuple of the given dimension
Definition: TriMesh.cpp:98
bool is_boundary(PrimitiveType pt, const Tuple &tuple) const final override
check if a simplex (encoded as a tuple/primitive pair) lies on a boundary or not
Definition: TriMesh.cpp:57
bool is_boundary_edge(const Tuple &tuple) const
Definition: TriMesh.cpp:71
void sort_and_clean()
Sort simplex vector and remove duplicates.
static IdSimplexCollection get_intersection(const IdSimplexCollection &collection_a, const IdSimplexCollection &collection_b)
Get intersection of two simplex collections.
void add(const IdSimplex &simplex)
Add simplex to the collection.
static bool are_simplex_collections_equal(const IdSimplexCollection &collection_a, const IdSimplexCollection &collection_b)
Check if the two simplex collections are equal.
static Simplex edge(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:61
static Simplex vertex(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:56
static bool equal(const Mesh &m, const Simplex &s0, const Simplex &s1)
bool link_condition(const EdgeMesh &mesh, const Tuple &edge)
Check if the edge to collapse satisfying the link condition.
bool link_condition_closed_trimesh(const TriMesh &mesh, const Tuple &edge)
bool link_condition_closed_tetmesh(const TetMesh &mesh, const Tuple &edge)
LinkIterable link_iterable(const Mesh &mesh, const Simplex &simplex)
CofacesSingleDimensionIterable cofaces_single_dimension_iterable(const Mesh &mesh, const Simplex &simplex, const PrimitiveType cofaces_type)
ConstMeshVariantType as_const_mesh_variant(const Mesh &mesh)