33 "shortest edge collapse works only for edge, triangle, or tet meshes: {}",
42 std::vector<attribute::MeshAttributeHandle> other_position_handles =
47 std::vector<attribute::MeshAttributeHandle> inversion_position_handles;
50 logger().info(
"Adding inversion check on collapsing mesh.");
51 inversion_position_handles.emplace_back(position_handle);
53 for (
auto& h : other_position_handles) {
54 if (h.mesh().top_cell_dimension() == h.dimension()) {
55 logger().info(
"Adding inversion check on other mesh.");
56 inversion_position_handles.emplace_back(h);
60 if (inversion_position_handles.empty()) {
61 logger().warn(
"Shortest-edge collapse should check for inversions but there was no "
62 "position handle that is valid for inversion checks.");
66 std::vector<attribute::MeshAttributeHandle> pass_through_attributes =
69 for (
auto& h : other_position_handles) {
70 pass_through_attributes.emplace_back(h);
75 auto visited_edge_flag =
78 auto update_flag_func = [](Eigen::Ref<const Eigen::MatrixXd> P) -> Eigen::VectorX<char> {
79 assert(P.cols() == 2);
80 assert(P.rows() == 2 || P.rows() == 3);
81 return Eigen::VectorX<char>::Constant(1,
char(1));
84 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<char, double>>(
91 auto edge_length_attribute =
93 auto edge_length_accessor = mesh.
create_accessor(edge_length_attribute.as<
double>());
95 auto compute_edge_length = [](Eigen::Ref<const Eigen::MatrixXd> P) -> Eigen::VectorXd {
96 assert(P.cols() == 2);
97 assert(P.rows() == 2 || P.rows() == 3);
98 return Eigen::VectorXd::Constant(1, (P.col(0) - P.col(1)).norm());
100 auto edge_length_update =
101 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
102 edge_length_attribute,
104 compute_edge_length);
105 edge_length_update->run_on_all();
109 Eigen::VectorXd bmin(position_handle.
dimension());
110 bmin.setConstant(std::numeric_limits<double>::max());
111 Eigen::VectorXd bmax(position_handle.
dimension());
112 bmax.setConstant(std::numeric_limits<double>::lowest());
118 const auto p = pt_accessor.vector_attribute(v);
119 for (int64_t d = 0; d < bmax.size(); ++d) {
120 bmin[d] = std::min(bmin[d], p[d]);
121 bmax[d] = std::max(bmax[d], p[d]);
125 const double bbdiag = (bmax - bmin).norm();
127 const double length_abs = bbdiag * options.
length_rel;
130 "bbox max {}, bbox min {}, diag {}, target edge length {}",
138 return edge_length_accessor.const_scalar_attribute(s.tuple());
140 pass_through_attributes.push_back(edge_length_attribute);
141 auto todo = std::make_shared<TodoSmallerInvariant>(
143 edge_length_attribute.as<
double>(),
144 4. / 5. * length_abs);
148 auto invariant_link_condition = std::make_shared<MultiMeshLinkConditionInvariant>(mesh);
150 auto invariant_interior_edge = std::make_shared<invariants::InvariantCollection>(mesh);
151 auto invariant_interior_vertex = std::make_shared<invariants::InvariantCollection>(mesh);
153 auto set_all_invariants = [&](
auto&& m) {
154 invariant_interior_edge->add(
156 invariant_interior_vertex->add(
162 auto invariant_mm_map = std::make_shared<MultiMeshMapValidInvariant>(mesh);
165 std::vector<attribute::MeshAttributeHandle> position_handles;
166 position_handles.emplace_back(position_handle);
170 auto collapse = std::make_shared<wmtk::operations::EdgeCollapse>(mesh);
171 collapse->add_invariant(todo);
172 collapse->add_invariant(invariant_link_condition);
173 collapse->add_invariant(invariant_mm_map);
177 const double env_size = bbdiag * options.
envelope_size.value();
178 bool envelope_added =
false;
181 logger().info(
"Adding envelope check on collapsing mesh.");
182 collapse->add_invariant(std::make_shared<wmtk::invariants::EnvelopeInvariant>(
186 envelope_added =
true;
189 for (
auto& h : other_position_handles) {
190 if (h.mesh().top_cell_dimension() < h.dimension()) {
191 logger().info(
"Adding envelope check on other mesh.");
192 collapse->add_invariant(
193 std::make_shared<wmtk::invariants::EnvelopeInvariant>(h, env_size, h));
194 envelope_added =
true;
198 if (!envelope_added) {
199 logger().warn(
"Shortest-edge collapse should check for inversion but there was no "
200 "position handle that is valid for inversion checks.");
204 for (
auto& h : inversion_position_handles) {
205 collapse->add_invariant(
209 collapse->set_new_attribute_strategy(
212 collapse->add_transfer_strategy(tag_update);
214 collapse->set_priority(short_edges_first_priority);
215 collapse->add_transfer_strategy(edge_length_update);
219 collapse->add_invariant(invariant_interior_edge);
222 for (
const auto& pos_handle : position_handles) {
223 auto pos_collapse_strategy =
224 std::make_shared<wmtk::operations::CollapseNewAttributeStrategy<double>>(
227 pos_collapse_strategy->set_simplex_predicate(
229 collapse->set_new_attribute_strategy(pos_handle, pos_collapse_strategy);
232 for (
const auto& pos_handle : position_handles) {
233 collapse->set_new_attribute_strategy(
240 for (
const auto& attr : pass_through_attributes) {
241 collapse->set_new_attribute_strategy(attr);
244 auto propagate_position = [](
const Eigen::MatrixXd& P) -> Eigen::VectorXd {
return P; };
245 for (
auto& h : other_position_handles) {
246 auto transfer_position =
247 std::make_shared<operations::SingleAttributeTransferStrategy<double, double>>(
251 collapse->add_transfer_strategy(transfer_position);
271 "Executed {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, executing: {}",