Wildmeshing Toolkit
Loading...
Searching...
No Matches
axis_aligned_fusion.cpp
Go to the documentation of this file.
2
3#include <wmtk/Mesh.hpp>
4#include <wmtk/TetMesh.hpp>
5#include <wmtk/TriMesh.hpp>
6
7#include <wmtk/Types.hpp>
11
13
14
16
17std::shared_ptr<Mesh>
18axis_aligned_fusion(const Mesh& mesh, const std::vector<bool>& operating_axis, double eps)
19{
20 // get mesh dimension and checks
21 int64_t mesh_dim = mesh.top_cell_dimension();
22
23
24 std::map<std::string, std::vector<int64_t>> names;
25
26 // TODO: a lot of matrix copies to remove
27
28 switch (mesh_dim) {
29 case (2): {
30 if (operating_axis[2]) {
31 wmtk::logger().warn("Fusion on Z axis is not supported for 2D mesh.");
32 }
33
37 mesh.serialize(writer);
38
39 writer.get_position_matrix(V);
40 writer.get_FV_matrix(FV);
41
42 assert(V.rows() == mesh.get_all(PrimitiveType::Vertex).size());
43 assert(FV.rows() == mesh.get_all(PrimitiveType::Triangle).size());
44
45 // rescale to [0, 1]
46 Eigen::MatrixXd V_rescale(V.rows(), V.cols());
47
48 Eigen::VectorXd min_pos = V.colwise().minCoeff();
49
50 // if (abs(min_pos[2] - 0.0) > eps)
51 // throw std::runtime_error("has non-zero z coordinate on 2d mesh");
52
53 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
54 V_rescale.row(i) = V.row(i) - min_pos.transpose();
55 }
56
57 Eigen::VectorXd max_pos = V_rescale.colwise().maxCoeff();
58 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
59 V_rescale(i, 0) /= max_pos[0];
60 V_rescale(i, 1) /= max_pos[1];
61 }
62
63
64 // debug code
65 // std::cout << FV << std::endl;
66 // std::cout << V << std::endl;
67
68 std::map<int64_t, int64_t> vertex_map;
69
70 std::array<std::vector<std::pair<int64_t, Eigen::VectorXd>>, 2> vertices_on_zero;
71 std::array<std::vector<std::pair<int64_t, Eigen::VectorXd>>, 2> vertices_on_one;
72
73 int64_t v00 = -1;
74 int64_t v01 = -1;
75 int64_t v10 = -1;
76 int64_t v11 = -1;
77
78 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
79 const auto& pos = V_rescale.row(i);
80
81 if (abs(pos[0] - 0.0) < eps) {
82 vertices_on_zero[0].emplace_back(std::make_pair(i, pos));
83 }
84 if (abs(pos[1] - 0.0) < eps) {
85 vertices_on_zero[1].emplace_back(std::make_pair(i, pos));
86 }
87 if (abs(pos[0] - 1.0) < eps) {
88 vertices_on_one[0].emplace_back(std::make_pair(i, pos));
89 }
90 if (abs(pos[1] - 1.0) < eps) {
91 vertices_on_one[1].emplace_back(std::make_pair(i, pos));
92 }
93
94 // corners
95 if (abs(pos[0] - 0.0) < eps && abs(pos[1] - 0.0) < eps) {
96 if (v00 != -1) throw std::runtime_error("More than 1 vertices on corner 00.");
97 v00 = i;
98 }
99 if (abs(pos[0] - 0.0) < eps && abs(pos[1] - 1.0) < eps) {
100 if (v01 != -1) throw std::runtime_error("More than 1 vertices on corner 01.");
101 v01 = i;
102 }
103 if (abs(pos[0] - 1.0) < eps && abs(pos[1] - 0.0) < eps) {
104 if (v10 != -1) throw std::runtime_error("More than 1 vertices on corner 10.");
105 v10 = i;
106 }
107 if (abs(pos[0] - 1.0) < eps && abs(pos[1] - 1.0) < eps) {
108 if (v11 != -1) throw std::runtime_error("More than 1 vertices on corner 11.");
109 v11 = i;
110 }
111 }
112
113 // merge vertices
114 for (int axis = 0; axis < 2; ++axis) {
115 if (!operating_axis[axis]) continue;
116
117 if (vertices_on_zero[axis].size() != vertices_on_one[axis].size()) {
118 throw std::runtime_error("vertices size on the fusion axis does not match!");
119 }
120
121 auto cmp = [&](const std::pair<int64_t, Eigen::VectorXd>& a,
122 const std::pair<int64_t, Eigen::VectorXd>& b) {
123 return a.second[1 - axis] < b.second[1 - axis];
124 };
125
126 std::sort(vertices_on_zero[axis].begin(), vertices_on_zero[axis].end(), cmp);
127 std::sort(vertices_on_one[axis].begin(), vertices_on_one[axis].end(), cmp);
128
129 for (int64_t i = 0; i < vertices_on_zero[axis].size(); ++i) {
130 assert(
131 abs(vertices_on_zero[axis][i].second[1 - axis] -
132 vertices_on_one[axis][i].second[1 - axis]) < eps);
133
134 vertex_map[vertices_on_one[axis][i].first] = vertices_on_zero[axis][i].first;
135 }
136 }
137
138 // special case for fusion all axis
139 if (operating_axis[0] && operating_axis[1]) {
140 vertex_map[v00] = v00;
141 vertex_map[v01] = v00;
142 vertex_map[v10] = v00;
143 vertex_map[v11] = v00;
144 }
145
146 // create periodic mesh
147 RowVectors3l FV_new(FV.rows(), 3);
148
149 for (int64_t i = 0; i < FV.rows(); ++i) {
150 for (int64_t k = 0; k < 3; ++k) {
151 if (vertex_map.find(FV(i, k)) != vertex_map.end()) {
152 FV_new(i, k) = vertex_map[FV(i, k)];
153 } else {
154 FV_new(i, k) = FV(i, k);
155 }
156 }
157 }
158
159 Eigen::MatrixXd V_new_tmp(V.rows(), V.cols());
160
161 // remove unused vertices
162 std::map<int64_t, int64_t> v_consolidate_map;
163
164 int64_t v_valid_cnt = 0;
165 for (int64_t i = 0; i < V.rows(); ++i) {
166 if (vertex_map.find(i) == vertex_map.end() || vertex_map[i] == i) {
167 for (int k = 0; k < V_rescale.cols(); ++k) {
168 V_new_tmp(v_valid_cnt, k) = V(i, k);
169 }
170 v_consolidate_map[i] = v_valid_cnt++;
171
172 // std::cout << V_new_tmp << std::endl << std::endl;
173 }
174 }
175
176 Eigen::MatrixXd V_new(v_valid_cnt, V.cols());
177 V_new = V_new_tmp.block(0, 0, v_valid_cnt, V.cols());
178
179 // std::cout << V_new << std::endl << std::endl;
180
181
182 // update FV_new
183 for (int64_t i = 0; i < FV_new.rows(); ++i) {
184 for (int64_t k = 0; k < FV_new.cols(); ++k) {
185 FV_new(i, k) = v_consolidate_map[FV_new(i, k)];
186 }
187 }
188
189
190 TriMesh fusion_mesh;
191 fusion_mesh.initialize(FV_new);
192 // mesh_utils::set_matrix_attribute(V_new, "vertices", PrimitiveType::Vertex, fusion_mesh);
193
194 // TriMesh& m = dynamic_cast<TriMesh&>(*mesh);
195
196 // make a copy
197 // TriMesh child_mesh(std::move(m));
198 // std::shared_ptr<TriMesh> child_ptr = std::make_shared<TriMesh>(std::move(m));
199
200 TriMesh position_mesh;
201 position_mesh.initialize(FV);
203 V_rescale,
204 "vertices",
206 position_mesh);
207
208 // std::shared_ptr<TriMesh> child_ptr = std::make_shared<TriMesh>(std::move(position_mesh));
209
210 // auto child_map = multimesh::same_simplex_dimension_bijection(fusion_mesh, *child_ptr);
211
212
213 // fusion_mesh.register_child_mesh(child_ptr, child_map);
214
215 // names["periodic"] = fusion_mesh.absolute_multi_mesh_id();
216 // names["position"] = child_ptr->absolute_multi_mesh_id();
217
218 // cache.write_mesh(fusion_mesh, options.name, names);
219
220 // break;
221
222 std::shared_ptr<TriMesh> child_ptr = std::make_shared<TriMesh>(std::move(position_mesh));
223 std::shared_ptr<TriMesh> parent_ptr = std::make_shared<TriMesh>(std::move(fusion_mesh));
224
225 auto child_map = wmtk::multimesh::same_simplex_dimension_bijection(*parent_ptr, *child_ptr);
226 parent_ptr->register_child_mesh(child_ptr, child_map);
227
228 return parent_ptr;
229 }
230 case (3): {
233
235 mesh.serialize(writer);
236
237 writer.get_position_matrix(V);
238 writer.get_TV_matrix(TV);
239
240 assert(V.rows() == mesh.get_all(PrimitiveType::Vertex).size());
241 assert(TV.rows() == mesh.get_all(PrimitiveType::Tetrahedron).size());
242
243 // rescale to [0, 1]
244 RowVectors3d V_rescale(V.rows(), 3);
245
246 Vector3d min_pos = V.colwise().minCoeff();
247
248 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
249 V_rescale.row(i) = V.row(i) - min_pos.transpose();
250 }
251
252 Vector3d max_pos = V_rescale.colwise().maxCoeff();
253 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
254 V_rescale(i, 0) /= max_pos[0];
255 V_rescale(i, 1) /= max_pos[1];
256 V_rescale(i, 2) /= max_pos[2];
257 }
258
259 std::map<int64_t, int64_t> vertex_map;
260
261 std::array<std::vector<std::pair<int64_t, Eigen::VectorXd>>, 3> vertices_on_zero;
262 std::array<std::vector<std::pair<int64_t, Eigen::VectorXd>>, 3> vertices_on_one;
263
264 for (int64_t i = 0; i < V_rescale.rows(); ++i) {
265 const auto& pos = V_rescale.row(i);
266
267 for (int k = 0; k < 3; ++k) {
268 if (abs(pos[k] - 0.0) < eps) {
269 vertices_on_zero[k].push_back(std::make_pair(i, pos));
270 }
271 if (abs(pos[k] - 1.0) < eps) {
272 vertices_on_one[k].push_back(std::make_pair(i, pos));
273 }
274 }
275 }
276
277 // merge vertices
278 for (int axis = 0; axis < 3; ++axis) {
279 if (!operating_axis[axis]) continue;
280
281 if (vertices_on_zero[axis].size() != vertices_on_one[axis].size()) {
282 throw std::runtime_error("vertices size on the fusion axis does not match!");
283 }
284
285 auto cmp = [&](const std::pair<int64_t, Eigen::VectorXd>& a,
286 const std::pair<int64_t, Eigen::VectorXd>& b) {
287 if (abs(a.second[(axis + 2) % 3] - b.second[(axis + 2) % 3]) < eps) {
288 return a.second[(axis + 1) % 3] < b.second[(axis + 1) % 3];
289 } else {
290 return a.second[(axis + 2) % 3] < b.second[(axis + 2) % 3];
291 }
292 };
293
294 std::sort(vertices_on_zero[axis].begin(), vertices_on_zero[axis].end(), cmp);
295 std::sort(vertices_on_one[axis].begin(), vertices_on_one[axis].end(), cmp);
296
297 for (int64_t i = 0; i < vertices_on_zero[axis].size(); ++i) {
298 assert(
299 abs(vertices_on_zero[axis][i].second[(axis + 1) % 3] -
300 vertices_on_one[axis][i].second[(axis + 1) % 3]) < eps &&
301 abs(vertices_on_zero[axis][i].second[(axis + 2) % 3] -
302 vertices_on_one[axis][i].second[(axis + 2) % 3]) < eps);
303
304 vertex_map[vertices_on_one[axis][i].first] = vertices_on_zero[axis][i].first;
305 }
306 }
307
308 // // create periodic mesh
309 RowVectors4l TV_new(TV.rows(), 4);
310
311 for (int64_t i = 0; i < TV.rows(); ++i) {
312 for (int64_t k = 0; k < 4; ++k) {
313 if (vertex_map.find(TV(i, k)) != vertex_map.end()) {
314 int64_t v_root = vertex_map[TV(i, k)];
315 while (vertex_map.find(v_root) != vertex_map.end() &&
316 vertex_map[v_root] != v_root) {
317 v_root = vertex_map[v_root];
318 }
319 TV_new(i, k) = v_root;
320 } else {
321 TV_new(i, k) = TV(i, k);
322 }
323 }
324 }
325
326 // std::cout << TV_new << std::endl << std::endl;
327
328
329 RowVectors3d V_new_tmp(V.rows(), 3);
330
331 // remove unused vertices
332 std::map<int64_t, int64_t> v_consolidate_map;
333
334 int64_t v_valid_cnt = 0;
335 for (int64_t i = 0; i < V.rows(); ++i) {
336 if (vertex_map.find(i) == vertex_map.end() || vertex_map[i] == i) {
337 V_new_tmp(v_valid_cnt, 0) = V(i, 0);
338 V_new_tmp(v_valid_cnt, 1) = V(i, 1);
339 V_new_tmp(v_valid_cnt, 2) = V(i, 2);
340 v_consolidate_map[i] = v_valid_cnt++;
341
342 // std::cout << V_new_tmp << std::endl << std::endl;
343 }
344 }
345
346 RowVectors3d V_new(v_valid_cnt, 3);
347 V_new = V_new_tmp.block(0, 0, v_valid_cnt, 3);
348
349 // std::cout << V_new << std::endl << std::endl;
350
351
352 // update TV_new
353 for (int64_t i = 0; i < TV_new.rows(); ++i) {
354 for (int64_t k = 0; k < TV_new.cols(); ++k) {
355 TV_new(i, k) = v_consolidate_map[TV_new(i, k)];
356 }
357 }
358
359 // std::cout << TV_new << std::endl << std::endl;
360
361
362 TetMesh fusion_mesh;
363 fusion_mesh.initialize(TV_new);
364 // mesh_utils::set_matrix_attribute(V_new, "vertices", PrimitiveType::Vertex, fusion_mesh);
365
366 TetMesh position_mesh;
367 position_mesh.initialize(TV);
369 V_rescale,
370 "vertices",
372 position_mesh);
373
374 std::shared_ptr<TetMesh> child_ptr = std::make_shared<TetMesh>(std::move(position_mesh));
375 std::shared_ptr<TetMesh> parent_ptr = std::make_shared<TetMesh>(std::move(fusion_mesh));
376
377 auto child_map = wmtk::multimesh::same_simplex_dimension_bijection(*parent_ptr, *child_ptr);
378 parent_ptr->register_child_mesh(child_ptr, child_map);
379
380 return parent_ptr;
381 }
382 default: {
383 throw std::runtime_error("mesh dimension not supported");
384 }
385 }
386 return {};
387}
388} // namespace wmtk::components::multimesh
void serialize(MeshWriter &writer, const Mesh *local_root=nullptr) const
Definition Mesh.cpp:93
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition Mesh.cpp:18
int64_t top_cell_dimension() const
Definition Mesh.hpp:978
void initialize(Eigen::Ref< const RowVectors4l > TV, Eigen::Ref< const RowVectors6l > TE, Eigen::Ref< const RowVectors4l > TF, Eigen::Ref< const RowVectors4l > TT, Eigen::Ref< const VectorXl > VT, Eigen::Ref< const VectorXl > ET, Eigen::Ref< const VectorXl > FT)
Definition TetMesh.cpp:79
void initialize(Eigen::Ref< const RowVectors3l > FV, Eigen::Ref< const RowVectors3l > FE, Eigen::Ref< const RowVectors3l > FF, Eigen::Ref< const VectorXl > VF, Eigen::Ref< const VectorXl > EF)
Definition TriMesh.cpp:176
void get_position_matrix(MatrixX< double > &matrix)
void get_TV_matrix(MatrixX< int64_t > &matrix)
void get_FV_matrix(MatrixX< int64_t > &matrix)
std::shared_ptr< Mesh > axis_aligned_fusion(const Mesh &mesh, const std::vector< bool > &operating_axis, double eps)
attribute::MeshAttributeHandle set_matrix_attribute(const Mat &data, const std::string &name, const PrimitiveType &type, Mesh &mesh)
Definition mesh_utils.hpp:9
std::vector< std::array< Tuple, 2 > > same_simplex_dimension_bijection(const Mesh &parent, const Mesh &child)
int cmp(const Rational &r, const Rational &r1)
Definition Rational.cpp:259
RowVectors< int64_t, 3 > RowVectors3l
Definition Types.hpp:47
Rational abs(const Rational &r0)
Definition Rational.cpp:328
RowVectors< int64_t, 4 > RowVectors4l
Definition Types.hpp:48
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
Vector< double, 3 > Vector3d
Definition Types.hpp:39
RowVectors< double, 3 > RowVectors3d
Definition Types.hpp:51
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Definition Types.hpp:14