Wildmeshing Toolkit
Loading...
Searching...
No Matches
test_component_wildmeshing.cpp
Go to the documentation of this file.
1#include <catch2/catch_test_macros.hpp>
2#include <nlohmann/json.hpp>
3#include <wmtk/TetMesh.hpp>
4#include <wmtk/Types.hpp>
6#include <wmtk/components/utils/Paths.hpp>
8#include <wmtk/io/Cache.hpp>
11#include <wmtk/utils/orient.hpp>
12
15#include <wmtk/utils/Logger.hpp>
16
17
18#include <wmtk/Scheduler.hpp>
21
34
35
40
59
60#include <fstream>
61
62using namespace wmtk::components::utils;
63using namespace wmtk;
64using namespace simplex;
65using namespace operations;
66using namespace operations::tri_mesh;
67using namespace operations::tet_mesh;
68using namespace operations::composite;
69using namespace wmtk::attribute;
70using namespace function;
71using namespace invariants;
72
73using json = nlohmann::json;
74
75const std::filesystem::path data_dir = WMTK_DATA_DIR;
76
77TEST_CASE("wildmeshing", "[components][wildmeshing][.]")
78{
79 wmtk::io::Cache cache("wmtk_cache", ".");
80
81 json input_component_json = {
82 {"name", "mesh"},
83 {"file", data_dir / "adaptive_tessellation_test" / "after_smooth_uv.msh"},
84 // {"file", data_dir / "2d" / "rect1.msh"},
85 {"ignore_z", true}};
86 wmtk::components::input(Paths(), input_component_json, cache);
87
88
89 json input =
90 R"({
91 "passes": 10,
92 "input": "mesh",
93 "target_edge_length": 0.01,
94 "intermediate_output": true,
95 "attributes": {"position": "vertices"},
96 "pass_through": [],
97 "output": "test"
98 })"_json;
99
100 CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
101}
102
103
104TEST_CASE("wildmeshing_3d", "[components][wildmeshing][.]")
105{
106 wmtk::io::Cache cache("wmtk_cache", ".");
107
108 json input_component_json = {
109 {"name", "mesh"},
110 // {"input", data_dir / "sphere_coarse_.msh"},
111 // {"input", data_dir / "tet.msh"},
112 // {"file", data_dir / "sphere_coarse_005_.msh"},
113 {"file", data_dir / "cube_2.msh"},
114 {"ignore_z", false}};
115 wmtk::components::input(Paths(), input_component_json, cache);
116
117 json attributes = {{"position", "vertices"}};
118
119 json input = {
120 {"passes", 10},
121 {"input", "mesh"},
122 {"target_edge_length", 0.05},
123 {"intermediate_output", false},
124 {"output", "test_mm"},
125 {"pass_through", std::vector<int64_t>()},
126 {"attributes", attributes}};
127
128
129 CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
130}
131
132TEST_CASE("wildmeshing_3d_multimesh", "[components][wildmeshing][.]")
133{
134 wmtk::io::Cache cache("wmtk_cache", ".");
135
136 json input_component_json = {
137 {"name", "mesh"},
138 // {"input", data_dir / "sphere_coarse_.msh"},
139 // {"input", data_dir / "tet.msh"},
140 {"file", data_dir / "sphere_coarse_005_.msh"},
141 {"ignore_z", false}};
142 wmtk::components::input(Paths(), input_component_json, cache);
143
144 json attributes = {{"position", "vertices"}};
145
146 json input = {
147 {"passes", 10},
148 {"input", "mesh"},
149 {"target_edge_length", 0.1},
150 {"intermediate_output", true},
151 {"output", "test_multimesh"},
152 {"pass_through", std::vector<int64_t>()},
153 {"attributes", attributes}};
154
155
156 CHECK_NOTHROW(wmtk::components::wildmeshing(Paths(), input, cache));
157}
158
160 const std::string& path,
161 const std::string& name,
162 std::function<std::shared_ptr<Operation>(
163 Mesh&,
164 std::shared_ptr<Rounding>&,
167 std::vector<attribute::MeshAttributeHandle>&,
171 create_op)
172{
173 // const double target_edge_length = 1.21271;
174 const double target_max_amips = 10;
175 const double min_edge_length = 0.001;
176 const double target_edge_length = 1.04; // for collapse
177 // const double target_edge_length = 0.59019; // for split and swap
178
179 std::ifstream file(data_dir / path);
180 std::vector<Vector3r> vertices;
181 std::vector<Vector4l> tets;
182 std::string x, y, z, token;
183
184 while (file.good()) {
185 std::string line;
186 std::getline(file, line);
187 std::istringstream iss(line);
188 iss >> token;
189 if (line[0] == 'v') {
190 int sx = line.find(' ', 2);
191 x = line.substr(2, sx - 2);
192
193 int sy = line.find(' ', sx + 1);
194 y = line.substr(sx + 1, sy - (sx + 1));
195
196 int sz = line.find(' ', sy + 1);
197 z = line.substr(sy + 1, sz - (sy + 1));
198
199 vertices.emplace_back(x, y, z);
200 } else if (line[0] == 't') {
201 Vector4l f;
202 iss >> f[0] >> f[1] >> f[3] >> f[2];
203 tets.push_back(f);
204 }
205 }
206
207 RowVectors3r v(vertices.size(), 3);
208 for (int64_t i = 0; i < vertices.size(); ++i) {
209 v.row(i) = vertices[i];
210 }
211
212 RowVectors4l t(tets.size(), 4);
213 for (int64_t i = 0; i < tets.size(); ++i) {
214 t.row(i) = tets[i];
215 const auto ori = wmtk::utils::wmtk_orient3d(
216 v.row(t(i, 0)),
217 v.row(t(i, 1)),
218 v.row(t(i, 2)),
219 v.row(t(i, 3)));
220 CHECK(ori > 0);
221 }
222
223 const Vector3d bbox_max(
224 v.col(0).cast<double>().maxCoeff(),
225 v.col(1).cast<double>().maxCoeff(),
226 v.col(2).cast<double>().maxCoeff());
227 const Vector3d bbox_min(
228 v.col(0).cast<double>().minCoeff(),
229 v.col(1).cast<double>().minCoeff(),
230 v.col(2).cast<double>().minCoeff());
231
232 // std::cout << bbox_max << std::endl;
233 // std::cout << bbox_min << std::endl;
234
235 double diag = (bbox_max - bbox_min).norm();
236 std::cout << diag << std::endl;
237 std::cout << 0.05 * diag << std::endl;
238
239
240 auto mesh = std::make_shared<TetMesh>();
241 mesh->initialize(t);
242 mesh_utils::set_matrix_attribute(v, "vertices", PrimitiveType::Vertex, *mesh);
243 logger().info("Mesh has {} vertices {} tests", vertices.size(), tets.size());
244
245
247 auto pt_attribute = mesh->get_attribute_handle<Rational>("vertices", PrimitiveType::Vertex);
248 auto pt_accessor = mesh->create_accessor(pt_attribute.as<Rational>());
249
250 auto amips_attribute =
251 mesh->register_attribute<double>("wildmeshing_amips", mesh->top_simplex_type(), 1);
252 auto amips_accessor = mesh->create_accessor(amips_attribute.as<double>());
253 // amips update
254 auto compute_amips = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorXd {
255 assert(P.rows() == 2 || P.rows() == 3); // rows --> attribute dimension
256 assert(P.cols() == P.rows() + 1);
257 if (P.cols() == 3) {
258 // triangle
259 assert(P.rows() == 2);
260 std::array<double, 6> pts;
261 for (size_t i = 0; i < 3; ++i) {
262 for (size_t j = 0; j < 2; ++j) {
263 pts[2 * i + j] = P(j, i).to_double();
264 }
265 }
266 const double a = Tri_AMIPS_energy(pts);
267 return Eigen::VectorXd::Constant(1, a);
268 } else {
269 // tet
270 assert(P.rows() == 3);
271 std::array<double, 12> pts;
272 for (size_t i = 0; i < 4; ++i) {
273 for (size_t j = 0; j < 3; ++j) {
274 pts[3 * i + j] = P(j, i).to_double();
275 }
276 }
277 const double a = Tet_AMIPS_energy(pts);
278 return Eigen::VectorXd::Constant(1, a);
279 }
280 };
281 auto amips_update =
282 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, Rational>>(
283 amips_attribute,
284 pt_attribute,
285 compute_amips);
286 amips_update->run_on_all();
287
289 // Storing edge lengths
290 auto edge_length_attribute =
291 mesh->register_attribute<double>("edge_length", PrimitiveType::Edge, 1);
292 auto edge_length_accessor = mesh->create_accessor(edge_length_attribute.as<double>());
293 // Edge length update
294 auto compute_edge_length = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorXd {
295 assert(P.cols() == 2);
296 assert(P.rows() == 2 || P.rows() == 3);
297 return Eigen::VectorXd::Constant(1, sqrt((P.col(0) - P.col(1)).squaredNorm().to_double()));
298 };
299 auto edge_length_update =
300 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, Rational>>(
301 edge_length_attribute,
302 pt_attribute,
303 compute_edge_length);
304 edge_length_update->run_on_all();
305
306 auto visited_edge_flag =
307 mesh->register_attribute<char>("visited_edge", PrimitiveType::Edge, 1, false, char(1));
308
309 // auto target_edge_length_attribute = mesh->register_attribute<double>(
310 // "wildmeshing_target_edge_length",
311 // PrimitiveType::Edge,
312 // 1,
313 // false,
314 // target_edge_length); // defaults to target edge length
315
316
317 // auto compute_target_edge_length =
318 // [target_edge_length,
319 // target_max_amips,
320 // min_edge_length,
321 // target_edge_length_attribute,
322 // &mesh](const Eigen::MatrixXd& P, const std::vector<Tuple>& neighs) -> Eigen::VectorXd {
323 // auto target_edge_length_accessor =
324 // mesh->create_accessor(target_edge_length_attribute.as<double>());
325
326 // assert(P.rows() == 1); // rows --> attribute dimension
327 // assert(!neighs.empty());
328 // assert(P.cols() == neighs.size());
329 // const double current_target_edge_length =
330 // target_edge_length_accessor.const_scalar_attribute(neighs[0]);
331 // const double max_amips = P.maxCoeff();
332
333 // double new_target_edge_length = current_target_edge_length;
334 // if (max_amips > target_max_amips) {
335 // new_target_edge_length *= 0.5;
336 // } else {
337 // new_target_edge_length *= 1.5;
338 // }
339 // new_target_edge_length =
340 // std::min(new_target_edge_length, target_edge_length); // upper bound
341 // new_target_edge_length = std::max(new_target_edge_length, min_edge_length); // lower bound
342
343 // return Eigen::VectorXd::Constant(1, new_target_edge_length);
344 // };
345 // auto target_edge_length_update =
346 // std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
347 // target_edge_length_attribute,
348 // amips_attribute,
349 // compute_target_edge_length);
350 auto update_flag_func = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorX<char> {
351 assert(P.cols() == 2);
352 assert(P.rows() == 2 || P.rows() == 3);
353 return Eigen::VectorX<char>::Constant(1, char(1));
354 };
355 auto flag_update =
356 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, Rational>>(
357 visited_edge_flag,
358 pt_attribute,
359 update_flag_func);
360
361
362 std::vector<attribute::MeshAttributeHandle> pass_through_attributes;
363 pass_through_attributes.push_back(edge_length_attribute);
364 pass_through_attributes.push_back(amips_attribute);
365 // pass_through_attributes.push_back(target_edge_length_attribute);
366
367 // ////////////////////////////////////////////////////
368
369 auto inversion_invariant =
370 std::make_shared<SimplexInversionInvariant<Rational>>(*mesh, pt_attribute.as<Rational>());
371
373
374 auto rounding_pt_attribute =
375 mesh->get_attribute_handle_typed<Rational>("vertices", PrimitiveType::Vertex);
376 auto rounding = std::make_shared<Rounding>(*mesh, rounding_pt_attribute);
377 rounding->add_invariant(
378 std::make_shared<RoundedInvariant>(*mesh, pt_attribute.as<Rational>(), true));
379 rounding->add_invariant(inversion_invariant);
381
382
383 Scheduler scheduler;
384 int success = 10;
385 while (success > 0) {
386 auto stats = scheduler.run_operation_on_all(*rounding);
387 logger().info(
388 "Rounding, {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, "
389 "executing: {}. Total {}",
390 stats.number_of_performed_operations(),
391 stats.number_of_successful_operations(),
392 stats.number_of_failed_operations(),
393 stats.collecting_time,
394 stats.sorting_time,
395 stats.executing_time,
396 stats.total_time());
397
398 success = stats.number_of_successful_operations();
399
400 int64_t unrounded = 0;
401 for (const auto& v : mesh->get_all(PrimitiveType::Vertex)) {
402 const auto p = pt_accessor.vector_attribute(v);
403 for (int64_t d = 0; d < 3; ++d) {
404 if (!p[d].is_rounded()) {
405 ++unrounded;
406 break;
407 }
408 }
409 }
410
411 logger().info("Mesh has {} unrounded vertices", unrounded);
412 }
413
414 auto op = create_op(
415 *mesh,
416 rounding,
417 pt_attribute,
418 visited_edge_flag,
419 pass_through_attributes,
420 amips_update,
421 edge_length_update,
422 flag_update);
423
424 auto stats = scheduler.run_operation_on_all(*op, visited_edge_flag.as<char>());
425 logger().info(
426 "{}, {} ops (S/F) {}/{}. Passes: {}. Time collecting: {}, sorting: {}, "
427 "executing: {}; total {}. Passes (avg) collecting: {}, sorting: {}, executing: {}",
428 name,
429 stats.number_of_performed_operations(),
430 stats.number_of_successful_operations(),
431 stats.number_of_failed_operations(),
432 stats.sub_stats.size(),
433 stats.collecting_time,
434 stats.sorting_time,
435 stats.executing_time,
436 stats.total_time(),
437 stats.avg_sub_collecting_time(),
438 stats.avg_sub_sorting_time(),
439 stats.avg_sub_executing_time());
440
441 int64_t unrounded = 0;
442 for (const auto& v : mesh->get_all(PrimitiveType::Vertex)) {
443 const auto p = pt_accessor.vector_attribute(v);
444 for (int64_t d = 0; d < 3; ++d) {
445 if (!p[d].is_rounded()) {
446 ++unrounded;
447 break;
448 }
449 }
450 }
451
452 logger().info("Mesh has {} unrounded vertices", unrounded);
453
454 double max_energy = std::numeric_limits<double>::lowest();
455 double min_energy = std::numeric_limits<double>::max();
456 for (const auto& t : mesh->get_all(mesh->top_simplex_type())) {
457 // double e = amips->get_value(simplex::Simplex(mesh->top_simplex_type(), t));
458 double e = amips_accessor.scalar_attribute(t);
459 max_energy = std::max(max_energy, e);
460 min_energy = std::min(min_energy, e);
461 }
462
463 logger().info("Max AMIPS Energy: {}, Min AMIPS Energy: {}", max_energy, min_energy);
464 logger().info(
465 "{} vertices, {} edges, {} tets",
466 mesh->get_all(PrimitiveType::Vertex).size(),
467 mesh->get_all(PrimitiveType::Edge).size(),
468 mesh->get_all(PrimitiveType::Tetrahedron).size());
469
470 logger().info(
471 "Reference performance of original TetWild: split: 0.08s, collapse: 1.81525s, swap: 0.24s");
472}
473
474
475TEST_CASE("tetwild-split", "[components][wildmeshing][.]")
476{
477 logger().set_level(spdlog::level::debug);
478
480 "split_initial_state_test.obj",
481 "Split",
482 [](Mesh& mesh,
483 std::shared_ptr<Rounding>& rounding,
484 MeshAttributeHandle& pt_attribute,
485 MeshAttributeHandle& visited_edge_flag,
486 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
488 amips_update,
490 edge_length_update,
492 tag_update) {
493 const double target_edge_length = 0.59019;
494 const double target_max_amips = 10;
495 const double min_edge_length = 0.001;
496
497 auto target_edge_length_attribute = mesh.register_attribute<double>(
498 "wildmeshing_target_edge_length",
499 PrimitiveType::Edge,
500 1,
501 false,
502 target_edge_length); // defaults to target edge length
503
504
505 auto compute_target_edge_length =
506 [target_edge_length,
507 target_max_amips,
508 min_edge_length,
509 target_edge_length_attribute,
510 &mesh](
511 const Eigen::MatrixXd& P,
512 const std::vector<Tuple>& neighs) -> Eigen::VectorXd {
513 auto target_edge_length_accessor =
514 mesh.create_accessor(target_edge_length_attribute.as<double>());
515
516 assert(P.rows() == 1); // rows --> attribute dimension
517 assert(!neighs.empty());
518 assert(P.cols() == neighs.size());
519 const double current_target_edge_length =
520 target_edge_length_accessor.const_scalar_attribute(neighs[0]);
521 const double max_amips = P.maxCoeff();
522
523 double new_target_edge_length = current_target_edge_length;
524 if (max_amips > target_max_amips) {
525 new_target_edge_length *= 0.5;
526 } else {
527 new_target_edge_length *= 1.5;
528 }
529 new_target_edge_length =
530 std::min(new_target_edge_length, target_edge_length); // upper bound
531 new_target_edge_length =
532 std::max(new_target_edge_length, min_edge_length); // lower bound
533
534 return Eigen::VectorXd::Constant(1, new_target_edge_length);
535 };
536
537 pass_through_attributes.push_back(target_edge_length_attribute);
538
539 auto update_flag_func = [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorX<char> {
540 assert(P.cols() == 2);
541 assert(P.rows() == 2 || P.rows() == 3);
542 return Eigen::VectorX<char>::Constant(1, char(1));
543 };
544
545 auto edge_length_attribute =
546 mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
547
548 auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
549
550 auto long_edges_first = [&](const simplex::Simplex& s) {
551 assert(s.primitive_type() == PrimitiveType::Edge);
552 return -edge_length_accessor.scalar_attribute(s);
553 };
554
555 auto todo_larger = std::make_shared<TodoLargerInvariant>(
556 mesh,
557 edge_length_attribute.as<double>(),
558 target_edge_length_attribute.as<double>(),
559 4.0 / 3.0);
560
561 auto split = std::make_shared<EdgeSplit>(mesh);
562 split->set_priority(long_edges_first);
563
564 split->add_invariant(todo_larger);
565
566 split->set_new_attribute_strategy(pt_attribute);
567 split->set_new_attribute_strategy(
568 visited_edge_flag,
571 for (const auto& attr : pass_through_attributes) {
572 split->set_new_attribute_strategy(attr);
573 }
574
575 split->add_transfer_strategy(amips_update);
576 split->add_transfer_strategy(edge_length_update);
577 split->add_transfer_strategy(tag_update);
578
579 auto split_then_round = std::make_shared<AndOperationSequence>(mesh);
580 split_then_round->add_operation(split);
581 split_then_round->add_operation(rounding);
582
583 return split_then_round;
584 });
585}
586
587TEST_CASE("tetwild-collapse", "[components][wildmeshing][.]")
588{
589 // logger().set_level(spdlog::level::trace);
591 "collapse_initial_state_104985.obj",
592 "Collapse",
593 [](Mesh& mesh,
594 std::shared_ptr<Rounding>& rounding,
595 MeshAttributeHandle& pt_attribute,
596 MeshAttributeHandle& visited_edge_flag,
597 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
599 amips_update,
601 edge_length_update,
603 tag_update) {
604 const double target_edge_length = 1.04;
605 const double target_max_amips = 10;
606 const double min_edge_length = 0.001;
607
608 auto target_edge_length_attribute = mesh.register_attribute<double>(
609 "wildmeshing_target_edge_length",
610 PrimitiveType::Edge,
611 1,
612 false,
613 target_edge_length); // defaults to target edge length
614
615 pass_through_attributes.push_back(target_edge_length_attribute);
616
617 auto edge_length_attribute =
618 mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
619
620 auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
621
622
623 auto clps_strat =
624 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
625 clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
626 // clps_strat->set_strategy(CollapseBasicStrategy::Default);
627 clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
628
629
630 auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
631 mesh,
632 pt_attribute.as<Rational>());
633 auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
634 auto invariant_separate_substructures =
635 std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
636
637 auto short_edges_first = [&](const simplex::Simplex& s) {
638 assert(s.primitive_type() == PrimitiveType::Edge);
639 return edge_length_accessor.scalar_attribute(s);
640 };
641
642 auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
643 mesh,
644 edge_length_attribute.as<double>(),
645 target_edge_length_attribute.as<double>(),
646 4.0 / 5.0);
647
648 std::shared_ptr<function::PerSimplexFunction> amips =
649 std::make_shared<AMIPS>(mesh, pt_attribute);
650
651 auto function_invariant = std::make_shared<MaxFunctionInvariant>(
652 mesh.top_simplex_type(),
653 amips,
654 pt_attribute.as<Rational>());
655
657 // 2) EdgeCollapse
659 auto collapse = std::make_shared<EdgeCollapse>(mesh);
660 // THis triggers a segfault in release
661 // collapse->set_priority(short_edges_first);
662
663 collapse->add_invariant(todo_smaller);
664 collapse->add_invariant(invariant_separate_substructures);
665 collapse->add_invariant(link_condition);
666 collapse->add_invariant(inversion_invariant);
667 collapse->add_invariant(function_invariant);
668 // collapse->add_invariant(envelope_invariant);
669
670 collapse->set_new_attribute_strategy(pt_attribute, clps_strat);
671 collapse->add_transfer_strategy(tag_update);
672 collapse->set_new_attribute_strategy(
673 visited_edge_flag,
675 for (const auto& attr : pass_through_attributes) {
676 collapse->set_new_attribute_strategy(attr);
677 }
678
679 collapse->add_transfer_strategy(amips_update);
680 collapse->add_transfer_strategy(edge_length_update);
681 // proj_collapse->add_transfer_strategy(target_edge_length_update);
682
683 auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
684 collapse_then_round->add_operation(collapse);
685 collapse_then_round->add_operation(rounding);
686
687 return collapse_then_round;
688 });
689}
690
691TEST_CASE("tetwild-collapse-twoway", "[components][wildmeshing][.]")
692{
693 logger().set_level(spdlog::level::debug);
695 "collapse_initial_state_104985.obj",
696 "Collapse-Two",
697 [](Mesh& mesh,
698 std::shared_ptr<Rounding>& rounding,
699 MeshAttributeHandle& pt_attribute,
700 MeshAttributeHandle& visited_edge_flag,
701 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
703 amips_update,
705 edge_length_update,
707 tag_update) {
708 const double target_edge_length = 1.04;
709 const double target_max_amips = 10;
710 const double min_edge_length = 0.001;
711
712 auto target_edge_length_attribute = mesh.register_attribute<double>(
713 "wildmeshing_target_edge_length",
714 PrimitiveType::Edge,
715 1,
716 false,
717 target_edge_length); // defaults to target edge length
718
719 pass_through_attributes.push_back(target_edge_length_attribute);
720
721 auto edge_length_attribute =
722 mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
723
724 auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
725
726
727 auto clps_strat =
728 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
729 clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
730 // clps_strat->set_strategy(CollapseBasicStrategy::Default);
731 clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
732
733
734 auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
735 mesh,
736 pt_attribute.as<Rational>());
737 auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
738 auto invariant_separate_substructures =
739 std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
740
741 auto short_edges_first = [&](const simplex::Simplex& s) {
742 assert(s.primitive_type() == PrimitiveType::Edge);
743 return edge_length_accessor.scalar_attribute(s);
744 };
745
746 auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
747 mesh,
748 edge_length_attribute.as<double>(),
749 target_edge_length_attribute.as<double>(),
750 4.0 / 5.0);
751
752 std::shared_ptr<function::PerSimplexFunction> amips =
753 std::make_shared<AMIPS>(mesh, pt_attribute);
754
755 auto function_invariant = std::make_shared<MaxFunctionInvariant>(
756 mesh.top_simplex_type(),
757 amips,
758 pt_attribute.as<Rational>());
759
761 // 2) EdgeCollapse
763 auto clps_strat1 =
764 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
765 clps_strat1->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
766 // clps_strat1->set_strategy(CollapseBasicStrategy::Default);
767 clps_strat1->set_strategy(CollapseBasicStrategy::CopyOther);
768
769 auto clps_strat2 =
770 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
771 clps_strat2->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
772 // clps_strat2->set_strategy(CollapseBasicStrategy::Default);
773 clps_strat2->set_strategy(CollapseBasicStrategy::CopyTuple);
774
775 auto setup_collapse = [&](std::shared_ptr<EdgeCollapse>& collapse) {
776 collapse->add_invariant(invariant_separate_substructures);
777 collapse->add_invariant(link_condition);
778 collapse->add_invariant(inversion_invariant);
779 collapse->add_invariant(function_invariant);
780
781
782 collapse->set_new_attribute_strategy(
783 visited_edge_flag,
785
786 collapse->add_transfer_strategy(tag_update);
787 for (const auto& attr : pass_through_attributes) {
788 collapse->set_new_attribute_strategy(attr);
789 }
790 // THis triggers a segfault in release
791 collapse->set_priority(short_edges_first);
792
793 // collapse->add_invariant(envelope_invariant);
794
795 collapse->add_transfer_strategy(amips_update);
796 collapse->add_transfer_strategy(edge_length_update);
797 // proj_collapse->add_transfer_strategy(target_edge_length_update);
798 };
799
800 auto collapse1 = std::make_shared<EdgeCollapse>(mesh);
801 collapse1->set_new_attribute_strategy(pt_attribute, clps_strat1);
802 setup_collapse(collapse1);
803
804 auto collapse2 = std::make_shared<EdgeCollapse>(mesh);
805 collapse2->set_new_attribute_strategy(pt_attribute, clps_strat2);
806 setup_collapse(collapse2);
807
808 auto collapse = std::make_shared<OrOperationSequence>(mesh);
809 collapse->add_operation(collapse1);
810 collapse->add_operation(collapse2);
811 collapse->add_invariant(todo_smaller);
812
813 auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
814 collapse_then_round->add_operation(collapse);
815 collapse_then_round->add_operation(rounding);
816
817 return collapse_then_round;
818 });
819}
820
821TEST_CASE("tetwild-collapse-simulated", "[components][wildmeshing][.]")
822{
823 logger().set_level(spdlog::level::debug);
825 "collapse_initial_state_104985.obj",
826 "Collapse-Two",
827 [](Mesh& mesh,
828 std::shared_ptr<Rounding>& rounding,
829 MeshAttributeHandle& pt_attribute,
830 MeshAttributeHandle& visited_edge_flag,
831 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
833 amips_update,
835 edge_length_update,
837 tag_update) {
838 const double target_edge_length = 1.04;
839 const double target_max_amips = 10;
840 const double min_edge_length = 0.001;
841
842 auto target_edge_length_attribute = mesh.register_attribute<double>(
843 "wildmeshing_target_edge_length",
844 PrimitiveType::Edge,
845 1,
846 false,
847 target_edge_length); // defaults to target edge length
848
849 pass_through_attributes.push_back(target_edge_length_attribute);
850
851 auto edge_length_attribute =
852 mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
853
854 auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
855
856
857 auto clps_strat =
858 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
859 clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
860 // clps_strat->set_strategy(CollapseBasicStrategy::Default);
861 clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
862
863 auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
864 mesh,
865 pt_attribute.as<Rational>());
866 auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
867 auto invariant_separate_substructures =
868 std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
869
870 auto short_edges_first = [&](const simplex::Simplex& s) {
871 assert(s.primitive_type() == PrimitiveType::Edge);
872 return edge_length_accessor.scalar_attribute(s);
873 };
874
875 auto todo_smaller = std::make_shared<TodoSmallerInvariant>(
876 mesh,
877 edge_length_attribute.as<double>(),
878 target_edge_length_attribute.as<double>(),
879 4.0 / 5.0);
880
881 std::shared_ptr<function::PerSimplexFunction> amips =
882 std::make_shared<AMIPS>(mesh, pt_attribute);
883
884 auto function_invariant = std::make_shared<MaxFunctionInvariant>(
885 mesh.top_simplex_type(),
886 amips,
887 pt_attribute.as<Rational>());
888
890 // 2) EdgeCollapse
892 auto clps_strat1 =
893 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
894 clps_strat1->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
895 // clps_strat1->set_strategy(CollapseBasicStrategy::Default);
896 clps_strat1->set_strategy(CollapseBasicStrategy::CopyOther);
897
898 auto clps_strat2 =
899 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
900 clps_strat2->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
901 // clps_strat2->set_strategy(CollapseBasicStrategy::Default);
902 clps_strat2->set_strategy(CollapseBasicStrategy::CopyTuple);
903
904 auto setup_collapse = [&](std::shared_ptr<EdgeCollapse>& collapse) {
905 collapse->add_invariant(invariant_separate_substructures);
906 collapse->add_invariant(link_condition);
907 collapse->add_invariant(inversion_invariant);
908 // collapse->add_invariant(function_invariant);
909
910
911 collapse->set_new_attribute_strategy(
912 visited_edge_flag,
914
915 collapse->add_transfer_strategy(tag_update);
916 for (const auto& attr : pass_through_attributes) {
917 collapse->set_new_attribute_strategy(attr);
918 }
919 // THis triggers a segfault in release
920 collapse->set_priority(short_edges_first);
921
922 // collapse->add_invariant(envelope_invariant);
923
924 collapse->add_transfer_strategy(amips_update);
925 collapse->add_transfer_strategy(edge_length_update);
926 // proj_collapse->add_transfer_strategy(target_edge_length_update);
927 };
928
929 auto amips_attribute =
930 mesh.get_attribute_handle<double>("wildmeshing_amips", PrimitiveType::Tetrahedron);
931
932 auto collapse1 = std::make_shared<EdgeCollapse>(mesh);
933 collapse1->add_invariant(std::make_shared<CollapseEnergyBeforeInvariant>(
934 mesh,
935 pt_attribute.as<Rational>(),
936 amips_attribute.as<double>(),
937 1));
938 collapse1->set_new_attribute_strategy(pt_attribute, clps_strat1);
939 setup_collapse(collapse1);
940
941 auto collapse2 = std::make_shared<EdgeCollapse>(mesh);
942 collapse2->add_invariant(std::make_shared<CollapseEnergyBeforeInvariant>(
943 mesh,
944 pt_attribute.as<Rational>(),
945 amips_attribute.as<double>(),
946 0));
947 collapse2->set_new_attribute_strategy(pt_attribute, clps_strat2);
948 setup_collapse(collapse2);
949
950 auto collapse = std::make_shared<OrOperationSequence>(mesh);
951 collapse->add_operation(collapse1);
952 collapse->add_operation(collapse2);
953 collapse->add_invariant(todo_smaller);
954
955 auto collapse_then_round = std::make_shared<AndOperationSequence>(mesh);
956 collapse_then_round->add_operation(collapse);
957 collapse_then_round->add_operation(rounding);
958
959 return collapse_then_round;
960 });
961}
962
963
964TEST_CASE("tetwild-swap", "[components][wildmeshing][.]")
965{
966 logger().set_level(spdlog::level::debug);
968 "swap_initial_state.obj",
969 "Swap",
970 [](Mesh& mesh,
971 std::shared_ptr<Rounding>& rounding,
972 MeshAttributeHandle& pt_attribute,
973 MeshAttributeHandle& visited_edge_flag,
974 std::vector<attribute::MeshAttributeHandle>& pass_through_attributes,
976 amips_update,
978 edge_length_update,
980 tag_update) {
981 const double target_edge_length = 0.59019;
982 const double target_max_amips = 10;
983 const double min_edge_length = 0.001;
984
985 auto target_edge_length_attribute = mesh.register_attribute<double>(
986 "wildmeshing_target_edge_length",
987 PrimitiveType::Edge,
988 1,
989 false,
990 target_edge_length); // defaults to target edge length
991
992 pass_through_attributes.push_back(target_edge_length_attribute);
993
994 auto edge_length_attribute =
995 mesh.get_attribute_handle<double>("edge_length", PrimitiveType::Edge);
996
997 auto edge_length_accessor = mesh.create_accessor(edge_length_attribute.as<double>());
998
999
1000 auto clps_strat =
1001 std::make_shared<CollapseNewAttributeStrategy<Rational>>(pt_attribute);
1002 clps_strat->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
1003 // clps_strat->set_strategy(CollapseBasicStrategy::Default);
1004 clps_strat->set_strategy(CollapseBasicStrategy::CopyOther);
1005
1006
1007 auto inversion_invariant = std::make_shared<SimplexInversionInvariant<Rational>>(
1008 mesh,
1009 pt_attribute.as<Rational>());
1010 auto link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
1011 auto invariant_separate_substructures =
1012 std::make_shared<invariants::SeparateSubstructuresInvariant>(mesh);
1013
1014 auto long_edges_first = [&](const simplex::Simplex& s) {
1015 assert(s.primitive_type() == PrimitiveType::Edge);
1016 return -edge_length_accessor.scalar_attribute(s);
1017 };
1018
1019 std::shared_ptr<function::PerSimplexFunction> amips =
1020 std::make_shared<AMIPS>(mesh, pt_attribute);
1021
1023 // 3) Swap
1025
1026 // swap56
1027
1028 auto swap56 = std::make_shared<MinOperationSequence>(mesh);
1029 for (int i = 0; i < 5; ++i) {
1030 auto swap = std::make_shared<TetEdgeSwap>(mesh, i);
1031 swap->collapse().add_invariant(invariant_separate_substructures);
1032 swap->collapse().add_invariant(link_condition);
1033 swap->collapse().set_new_attribute_strategy(
1034 pt_attribute,
1035 CollapseBasicStrategy::CopyOther);
1036 swap->split().set_new_attribute_strategy(pt_attribute);
1037 swap->split().set_new_attribute_strategy(
1038 visited_edge_flag,
1041 swap->collapse().set_new_attribute_strategy(
1042 visited_edge_flag,
1044
1045 swap->add_invariant(std::make_shared<Swap56EnergyBeforeInvariant>(
1046 mesh,
1047 pt_attribute.as<Rational>(),
1048 i));
1049
1050 for (const auto& attr : pass_through_attributes) {
1051 swap->split().set_new_attribute_strategy(attr);
1052 swap->collapse().set_new_attribute_strategy(attr);
1053 }
1054
1055 swap56->add_operation(swap);
1056 }
1057
1058 auto swap56_energy_check = [&](int64_t idx, const simplex::Simplex& t) -> double {
1059 constexpr static PrimitiveType PV = PrimitiveType::Vertex;
1060 constexpr static PrimitiveType PE = PrimitiveType::Edge;
1061 constexpr static PrimitiveType PF = PrimitiveType::Triangle;
1062 constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron;
1063
1064 auto accessor = mesh.create_const_accessor(pt_attribute.as<Rational>());
1065
1066 const Tuple e0 = t.tuple();
1067 const Tuple e1 = mesh.switch_tuple(e0, PV);
1068
1069 std::array<Tuple, 5> v;
1070 auto iter_tuple = e0;
1071 for (int64_t i = 0; i < 5; ++i) {
1072 v[i] = mesh.switch_tuples(iter_tuple, {PE, PV});
1073 iter_tuple = mesh.switch_tuples(iter_tuple, {PF, PT});
1074 }
1075 if (iter_tuple != e0) return 0;
1076 assert(iter_tuple == e0);
1077
1078 // five iterable vertices remap to 0-4 by m_collapse_index, 0: m_collapse_index, 5:
1079 // e0, 6: e1
1080 std::array<Eigen::Vector3<Rational>, 7> positions = {
1081 {accessor.const_vector_attribute(v[(idx + 0) % 5]),
1082 accessor.const_vector_attribute(v[(idx + 1) % 5]),
1083 accessor.const_vector_attribute(v[(idx + 2) % 5]),
1084 accessor.const_vector_attribute(v[(idx + 3) % 5]),
1085 accessor.const_vector_attribute(v[(idx + 4) % 5]),
1086 accessor.const_vector_attribute(e0),
1087 accessor.const_vector_attribute(e1)}};
1088
1089 std::array<Eigen::Vector3d, 7> positions_double = {
1090 {positions[0].cast<double>(),
1091 positions[1].cast<double>(),
1092 positions[2].cast<double>(),
1093 positions[3].cast<double>(),
1094 positions[4].cast<double>(),
1095 positions[5].cast<double>(),
1096 positions[6].cast<double>()}};
1097
1098 std::array<std::array<int, 4>, 6> new_tets = {
1099 {{{0, 1, 2, 5}},
1100 {{0, 2, 3, 5}},
1101 {{0, 3, 4, 5}},
1102 {{0, 1, 2, 6}},
1103 {{0, 2, 3, 6}},
1104 {{0, 3, 4, 6}}}};
1105
1106 double new_energy_max = std::numeric_limits<double>::lowest();
1107
1108 for (int i = 0; i < 6; ++i) {
1110 positions[new_tets[i][0]],
1111 positions[new_tets[i][1]],
1112 positions[new_tets[i][2]],
1113 positions[new_tets[i][3]]) > 0) {
1115 positions_double[new_tets[i][0]][0],
1116 positions_double[new_tets[i][0]][1],
1117 positions_double[new_tets[i][0]][2],
1118 positions_double[new_tets[i][1]][0],
1119 positions_double[new_tets[i][1]][1],
1120 positions_double[new_tets[i][1]][2],
1121 positions_double[new_tets[i][2]][0],
1122 positions_double[new_tets[i][2]][1],
1123 positions_double[new_tets[i][2]][2],
1124 positions_double[new_tets[i][3]][0],
1125 positions_double[new_tets[i][3]][1],
1126 positions_double[new_tets[i][3]][2],
1127 }});
1128
1129
1130 if (energy > new_energy_max) new_energy_max = energy;
1131 } else {
1133 positions_double[new_tets[i][1]][0],
1134 positions_double[new_tets[i][1]][1],
1135 positions_double[new_tets[i][1]][2],
1136 positions_double[new_tets[i][0]][0],
1137 positions_double[new_tets[i][0]][1],
1138 positions_double[new_tets[i][0]][2],
1139 positions_double[new_tets[i][2]][0],
1140 positions_double[new_tets[i][2]][1],
1141 positions_double[new_tets[i][2]][2],
1142 positions_double[new_tets[i][3]][0],
1143 positions_double[new_tets[i][3]][1],
1144 positions_double[new_tets[i][3]][2],
1145 }});
1146
1147
1148 if (energy > new_energy_max) new_energy_max = energy;
1149 }
1150 }
1151
1152 return new_energy_max;
1153 };
1154
1155 swap56->set_value_function(swap56_energy_check);
1156 swap56->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 5));
1157
1158 // swap44
1159
1160 auto swap44 = std::make_shared<MinOperationSequence>(mesh);
1161 for (int i = 0; i < 2; ++i) {
1162 auto swap = std::make_shared<TetEdgeSwap>(mesh, i);
1163 swap->collapse().add_invariant(invariant_separate_substructures);
1164 swap->collapse().add_invariant(link_condition);
1165 swap->collapse().set_new_attribute_strategy(
1166 pt_attribute,
1167 CollapseBasicStrategy::CopyOther);
1168 swap->split().set_new_attribute_strategy(pt_attribute);
1169 swap->split().set_new_attribute_strategy(
1170 visited_edge_flag,
1173 swap->collapse().set_new_attribute_strategy(
1174 visited_edge_flag,
1176
1177 swap->add_invariant(std::make_shared<Swap44EnergyBeforeInvariant>(
1178 mesh,
1179 pt_attribute.as<Rational>(),
1180 i));
1181
1182 for (const auto& attr : pass_through_attributes) {
1183 swap->split().set_new_attribute_strategy(attr);
1184 swap->collapse().set_new_attribute_strategy(attr);
1185 }
1186
1187 swap44->add_operation(swap);
1188 }
1189
1190 auto swap44_energy_check = [&](int64_t idx, const simplex::Simplex& t) -> double {
1191 constexpr static PrimitiveType PV = PrimitiveType::Vertex;
1192 constexpr static PrimitiveType PE = PrimitiveType::Edge;
1193 constexpr static PrimitiveType PF = PrimitiveType::Triangle;
1194 constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron;
1195
1196 auto accessor = mesh.create_const_accessor(pt_attribute.as<Rational>());
1197
1198 // get the coords of the vertices
1199 // input edge end points
1200 const Tuple e0 = t.tuple();
1201 const Tuple e1 = mesh.switch_tuple(e0, PV);
1202 // other four vertices
1203 std::array<Tuple, 4> v;
1204 auto iter_tuple = e0;
1205 for (int64_t i = 0; i < 4; ++i) {
1206 v[i] = mesh.switch_tuples(iter_tuple, {PE, PV});
1207 iter_tuple = mesh.switch_tuples(iter_tuple, {PF, PT});
1208 }
1209
1210 if (iter_tuple != e0) return 0;
1211 assert(iter_tuple == e0);
1212
1213 std::array<Eigen::Vector3<Rational>, 6> positions = {
1214 {accessor.const_vector_attribute(v[(idx + 0) % 4]),
1215 accessor.const_vector_attribute(v[(idx + 1) % 4]),
1216 accessor.const_vector_attribute(v[(idx + 2) % 4]),
1217 accessor.const_vector_attribute(v[(idx + 3) % 4]),
1218 accessor.const_vector_attribute(e0),
1219 accessor.const_vector_attribute(e1)}};
1220 std::array<Eigen::Vector3d, 6> positions_double = {
1221 {positions[0].cast<double>(),
1222 positions[1].cast<double>(),
1223 positions[2].cast<double>(),
1224 positions[3].cast<double>(),
1225 positions[4].cast<double>(),
1226 positions[5].cast<double>()}};
1227
1228 std::array<std::array<int, 4>, 4> new_tets = {
1229 {{{0, 1, 2, 4}}, {{0, 2, 3, 4}}, {{0, 1, 2, 5}}, {{0, 2, 3, 5}}}};
1230
1231 double new_energy_max = std::numeric_limits<double>::lowest();
1232
1233 for (int i = 0; i < 4; ++i) {
1235 positions[new_tets[i][0]],
1236 positions[new_tets[i][1]],
1237 positions[new_tets[i][2]],
1238 positions[new_tets[i][3]]) > 0) {
1240 positions_double[new_tets[i][0]][0],
1241 positions_double[new_tets[i][0]][1],
1242 positions_double[new_tets[i][0]][2],
1243 positions_double[new_tets[i][1]][0],
1244 positions_double[new_tets[i][1]][1],
1245 positions_double[new_tets[i][1]][2],
1246 positions_double[new_tets[i][2]][0],
1247 positions_double[new_tets[i][2]][1],
1248 positions_double[new_tets[i][2]][2],
1249 positions_double[new_tets[i][3]][0],
1250 positions_double[new_tets[i][3]][1],
1251 positions_double[new_tets[i][3]][2],
1252 }});
1253
1254 if (energy > new_energy_max) new_energy_max = energy;
1255 } else {
1257 positions_double[new_tets[i][1]][0],
1258 positions_double[new_tets[i][1]][1],
1259 positions_double[new_tets[i][1]][2],
1260 positions_double[new_tets[i][0]][0],
1261 positions_double[new_tets[i][0]][1],
1262 positions_double[new_tets[i][0]][2],
1263 positions_double[new_tets[i][2]][0],
1264 positions_double[new_tets[i][2]][1],
1265 positions_double[new_tets[i][2]][2],
1266 positions_double[new_tets[i][3]][0],
1267 positions_double[new_tets[i][3]][1],
1268 positions_double[new_tets[i][3]][2],
1269 }});
1270
1271 if (energy > new_energy_max) new_energy_max = energy;
1272 }
1273 }
1274
1275 return new_energy_max;
1276 };
1277
1278 swap44->set_value_function(swap44_energy_check);
1279 swap44->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 4));
1280
1281 // swap 32
1282 auto swap32 = std::make_shared<TetEdgeSwap>(mesh, 0);
1283 swap32->add_invariant(std::make_shared<EdgeValenceInvariant>(mesh, 3));
1284 swap32->add_invariant(
1285 std::make_shared<Swap32EnergyBeforeInvariant>(mesh, pt_attribute.as<Rational>()));
1286
1287 swap32->collapse().add_invariant(invariant_separate_substructures);
1288 swap32->collapse().add_invariant(link_condition);
1289 swap32->collapse().set_new_attribute_strategy(
1290 pt_attribute,
1291 CollapseBasicStrategy::CopyOther);
1292 swap32->split().set_new_attribute_strategy(pt_attribute);
1293 swap32->split().set_new_attribute_strategy(
1294 visited_edge_flag,
1297 swap32->collapse().set_new_attribute_strategy(
1298 visited_edge_flag,
1300
1301 for (const auto& attr : pass_through_attributes) {
1302 swap32->split().set_new_attribute_strategy(attr);
1303 swap32->collapse().set_new_attribute_strategy(attr);
1304 }
1305
1306 // all swaps
1307
1308 auto swap_all = std::make_shared<OrOperationSequence>(mesh);
1309 // swap_all->add_invariant(std::make_shared<InteriorEdgeInvariant>(mesh));
1310 swap_all->add_operation(swap32);
1311 swap_all->add_operation(swap44);
1312 swap_all->add_operation(swap56);
1313 swap_all->add_transfer_strategy(tag_update);
1314
1315 auto swap_then_round = std::make_shared<AndOperationSequence>(mesh);
1316 swap_then_round->add_operation(swap_all);
1317 // swap_then_round->add_operation(swap44);
1318 swap_then_round->add_invariant(std::make_shared<InteriorEdgeInvariant>(mesh));
1319 swap_then_round->add_operation(rounding);
1320
1321
1322 return swap_then_round;
1323 });
1324}
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
attribute::MeshAttributeHandle get_attribute_handle(const std::string &name, const PrimitiveType ptype) const
Definition Mesh.hpp:903
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
PrimitiveType top_simplex_type() const
Definition Mesh.hpp:982
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition Scheduler.cpp:33
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
Definition Scheduler.hpp:16
The Tuple is the basic navigation tool in our mesh data structure.
Definition Tuple.hpp:19
auto as() const -> const held_handle_type< held_type_from_primitive< T >()> &
constexpr wmtk::PrimitiveType PT
constexpr wmtk::PrimitiveType PF
std::shared_ptr< Mesh > input(const std::filesystem::path &file, const bool ignore_z_if_zero, const std::vector< std::string > &tetrahedron_attributes)
Definition input.cpp:12
std::vector< std::pair< std::shared_ptr< Mesh >, std::string > > wildmeshing(const WildMeshingOptions &option)
auto amips(const Eigen::MatrixBase< Derived > &B)
Definition amips.hpp:20
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
Definition amips.cpp:380
double Tet_AMIPS_energy(const std::array< double, 12 > &T)
Definition AMIPS.cpp:375
double Tri_AMIPS_energy(const std::array< double, 6 > &T)
Definition AMIPS.cpp:473
attribute::MeshAttributeHandle set_matrix_attribute(const Mat &data, const std::string &name, const PrimitiveType &type, Mesh &mesh)
Definition mesh_utils.hpp:9
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
bool link_condition(const EdgeMesh &mesh, const Tuple &edge)
Check if the edge to collapse satisfying the link condition.
int wmtk_orient3d(const Eigen::Ref< const Eigen::Vector3< Rational > > &p0, const Eigen::Ref< const Eigen::Vector3< Rational > > &p1, const Eigen::Ref< const Eigen::Vector3< Rational > > &p2, const Eigen::Ref< const Eigen::Vector3< Rational > > &p3)
Definition orient.cpp:75
constexpr PrimitiveType PE
RowVectors< int64_t, 4 > RowVectors4l
Definition Types.hpp:48
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
Vector< int64_t, 4 > Vector4l
Definition Types.hpp:36
Vector< double, 3 > Vector3d
Definition Types.hpp:39
RowVectors< Rational, 3 > RowVectors3r
Definition Types.hpp:53
constexpr PrimitiveType PV
const std::filesystem::path data_dir
TEST_CASE("wildmeshing", "[components][wildmeshing][.]")
void run_tetwild_test(const std::string &path, const std::string &name, std::function< std::shared_ptr< Operation >(Mesh &, std::shared_ptr< Rounding > &, MeshAttributeHandle &, MeshAttributeHandle &, std::vector< attribute::MeshAttributeHandle > &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< double, Rational > > &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< double, Rational > > &, std::shared_ptr< wmtk::operations::SingleAttributeTransferStrategy< char, Rational > > &)> create_op)
nlohmann::json json
Definition input.cpp:9