62 "isotropic remeshing works only for triangle meshes: {}",
72 throw std::runtime_error(
"Either absolute or relative length must be set!");
78 std::vector<attribute::MeshAttributeHandle> keeps = pass_through_attributes;
79 keeps.emplace_back(position);
80 keeps.insert(keeps.end(), other_positions.begin(), other_positions.end());
91 std::optional<attribute::MeshAttributeHandle> position_for_inversion =
95 assert(
dynamic_cast<TriMesh*
>(&position.mesh()) !=
nullptr);
99 const double length_min = (4. / 5.) * length;
100 const double length_max = (4. / 3.) * length;
102 std::vector<attribute::MeshAttributeHandle> positions = other_positions;
103 positions.push_back(position);
105 auto invariant_link_condition =
106 std::make_shared<wmtk::invariants::MultiMeshLinkConditionInvariant>(mesh);
108 auto invariant_min_edge_length = std::make_shared<MinEdgeLengthInvariant>(
110 position.as<
double>(),
111 length_max * length_max);
113 auto invariant_max_edge_length = std::make_shared<MaxEdgeLengthInvariant>(
115 position.as<
double>(),
116 length_min * length_min);
118 auto invariant_interior_edge = std::make_shared<invariants::InvariantCollection>(mesh);
119 auto invariant_interior_vertex = std::make_shared<invariants::InvariantCollection>(mesh);
121 auto set_all_invariants = [&](
auto&& m) {
122 invariant_interior_edge->add(
124 invariant_interior_vertex->add(
130 auto invariant_valence_improve =
131 std::make_shared<invariants::ValenceImprovementInvariant>(mesh);
133 auto invariant_mm_map = std::make_shared<MultiMeshMapValidInvariant>(mesh);
135 auto update_position_func = [](
const Eigen::MatrixXd& P) -> Eigen::VectorXd {
138 std::shared_ptr<wmtk::operations::SingleAttributeTransferStrategy<double, double>>
143 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
144 other_positions.front(),
146 update_position_func);
149 using namespace operations;
153 std::vector<std::shared_ptr<Operation>> ops;
156 wmtk::logger().debug(
"Configure isotropic remeshing split");
157 auto op_split = std::make_shared<EdgeSplit>(mesh);
158 op_split->add_invariant(invariant_min_edge_length);
160 op_split->add_invariant(invariant_interior_edge);
162 for (
auto& p : positions) {
163 op_split->set_new_attribute_strategy(
165 SplitBasicStrategy::None,
166 SplitRibBasicStrategy::Mean);
168 for (
const auto& attr : pass_through_attributes) {
169 op_split->set_new_attribute_strategy(attr);
171 assert(op_split->attribute_new_all_configured());
172 ops.push_back(op_split);
177 wmtk::logger().debug(
"Configure isotropic remeshing collapse");
178 auto op_collapse = std::make_shared<EdgeCollapse>(mesh);
179 op_collapse->add_invariant(invariant_link_condition);
180 if (position_for_inversion) {
182 position_for_inversion.value().mesh(),
183 position_for_inversion.value().as<
double>()));
186 op_collapse->add_invariant(invariant_max_edge_length);
187 op_collapse->add_invariant(invariant_mm_map);
191 op_collapse->add_invariant(
192 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
196 op_collapse->add_invariant(invariant_interior_edge);
198 for (
auto& p : positions) {
199 auto tmp = std::make_shared<CollapseNewAttributeStrategy<double>>(p);
200 tmp->set_strategy(CollapseBasicStrategy::Mean);
201 tmp->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
202 op_collapse->set_new_attribute_strategy(p, tmp);
205 op_collapse->add_invariant(
207 for (
auto& p : positions) {
208 op_collapse->set_new_attribute_strategy(p, CollapseBasicStrategy::Mean);
211 for (
auto& p : positions) {
212 op_collapse->set_new_attribute_strategy(p, CollapseBasicStrategy::Mean);
217 for (
const auto& attr : pass_through_attributes) {
218 op_collapse->set_new_attribute_strategy(attr);
220 assert(op_collapse->attribute_new_all_configured());
221 ops.push_back(op_collapse);
226 wmtk::logger().debug(
"Configure isotropic remeshing swap");
227 auto op_swap = std::make_shared<composite::TriEdgeSwap>(mesh);
228 op_swap->add_invariant(invariant_interior_edge);
232 op_swap->add_invariant(
233 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
236 op_swap->add_invariant(invariant_valence_improve);
237 op_swap->collapse().add_invariant(invariant_link_condition);
238 op_swap->collapse().add_invariant(invariant_mm_map);
239 for (
auto& p : positions) {
240 op_swap->split().set_new_attribute_strategy(
242 SplitBasicStrategy::None,
243 SplitRibBasicStrategy::Mean);
245 if (position_for_inversion) {
247 position_for_inversion.value().mesh(),
248 position_for_inversion.value().as<
double>()));
251 for (
auto& p : positions)
252 op_swap->collapse().set_new_attribute_strategy(p, CollapseBasicStrategy::CopyOther);
253 for (
const auto& attr : pass_through_attributes) {
254 op_swap->split().set_new_attribute_strategy(attr);
255 op_swap->collapse().set_new_attribute_strategy(attr);
257 assert(op_swap->split().attribute_new_all_configured());
258 assert(op_swap->collapse().attribute_new_all_configured());
259 ops.push_back(op_swap);
264 auto op_smooth = std::make_shared<AttributesUpdateWithFunction>(mesh);
265 if (position.dimension() == 3) {
272 op_smooth->add_invariant(invariant_interior_vertex);
277 op_smooth->add_invariant(
278 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
281 if (position_for_inversion) {
283 position_for_inversion.value().mesh(),
284 position_for_inversion.value().as<
double>()));
287 if (update_position) op_smooth->add_transfer_strategy(update_position);
288 ops.push_back(op_smooth);
293 for (
long i = 0; i < options.
iterations; ++i) {
297 for (
size_t j = 0; j < ops.size(); ++j) {
298 const auto& op = ops[j];
305 "Executed {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, executing: {}",