31 #include <Eigen/Geometry>
39 const double length_rel)
43 Eigen::AlignedBox<double, Eigen::Dynamic>
bbox(pos.dimension());
47 bbox.extend(pos.const_vector_attribute(v));
50 const double diag_length =
bbox.sizes().norm();
52 return length_rel * diag_length;
65 "isotropic remeshing works only for triangle meshes: {}",
75 throw std::runtime_error(
"Either absolute or relative length must be set!");
81 std::vector<attribute::MeshAttributeHandle> keeps = pass_through_attributes;
82 keeps.emplace_back(position);
83 keeps.insert(keeps.end(), other_positions.begin(), other_positions.end());
94 std::optional<attribute::MeshAttributeHandle> position_for_inversion =
98 assert(
dynamic_cast<TriMesh*
>(&position.mesh()) !=
nullptr);
102 const double length_min = (4. / 5.) * length;
103 const double length_max = (4. / 3.) * length;
105 std::vector<attribute::MeshAttributeHandle> positions = other_positions;
106 positions.push_back(position);
108 auto invariant_link_condition =
109 std::make_shared<wmtk::invariants::MultiMeshLinkConditionInvariant>(mesh);
111 auto invariant_min_edge_length = std::make_shared<MinEdgeLengthInvariant>(
113 position.as<
double>(),
114 length_max * length_max);
116 auto invariant_max_edge_length = std::make_shared<MaxEdgeLengthInvariant>(
118 position.as<
double>(),
119 length_min * length_min);
121 auto invariant_interior_edge = std::make_shared<invariants::InvariantCollection>(mesh);
122 auto invariant_interior_vertex = std::make_shared<invariants::InvariantCollection>(mesh);
124 auto set_all_invariants = [&](
auto&& m) {
125 invariant_interior_edge->add(
127 invariant_interior_vertex->add(
133 auto invariant_valence_improve =
134 std::make_shared<invariants::ValenceImprovementInvariant>(mesh);
136 auto invariant_mm_map = std::make_shared<MultiMeshMapValidInvariant>(mesh);
138 auto update_position_func = [](
const Eigen::MatrixXd& P) -> Eigen::VectorXd {
141 std::shared_ptr<wmtk::operations::SingleAttributeTransferStrategy<double, double>>
146 std::make_shared<wmtk::operations::SingleAttributeTransferStrategy<double, double>>(
147 other_positions.front(),
149 update_position_func);
152 using namespace operations;
156 std::vector<std::shared_ptr<Operation>> ops;
159 wmtk::logger().debug(
"Configure isotropic remeshing split");
160 auto op_split = std::make_shared<EdgeSplit>(mesh);
161 op_split->add_invariant(invariant_min_edge_length);
163 op_split->add_invariant(invariant_interior_edge);
165 for (
auto& p : positions) {
166 op_split->set_new_attribute_strategy(
168 SplitBasicStrategy::None,
169 SplitRibBasicStrategy::Mean);
171 for (
const auto& attr : pass_through_attributes) {
172 op_split->set_new_attribute_strategy(attr);
174 assert(op_split->attribute_new_all_configured());
175 ops.push_back(op_split);
181 wmtk::logger().debug(
"Configure isotropic remeshing collapse");
182 auto op_collapse = std::make_shared<EdgeCollapse>(mesh);
183 op_collapse->add_invariant(invariant_link_condition);
184 if (position_for_inversion) {
186 position_for_inversion.value().mesh(),
187 position_for_inversion.value().as<
double>()));
190 op_collapse->add_invariant(invariant_max_edge_length);
191 op_collapse->add_invariant(invariant_mm_map);
195 op_collapse->add_invariant(
196 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
200 op_collapse->add_invariant(invariant_interior_edge);
202 for (
auto& p : positions) {
203 auto tmp = std::make_shared<CollapseNewAttributeStrategy<double>>(p);
204 tmp->set_strategy(CollapseBasicStrategy::Mean);
205 tmp->set_simplex_predicate(BasicSimplexPredicate::IsInterior);
206 op_collapse->set_new_attribute_strategy(p, tmp);
209 op_collapse->add_invariant(
211 for (
auto& p : positions) {
212 op_collapse->set_new_attribute_strategy(p, CollapseBasicStrategy::Mean);
215 for (
auto& p : positions) {
216 op_collapse->set_new_attribute_strategy(p, CollapseBasicStrategy::Mean);
221 for (
const auto& attr : pass_through_attributes) {
222 op_collapse->set_new_attribute_strategy(attr);
224 assert(op_collapse->attribute_new_all_configured());
225 ops.push_back(op_collapse);
230 wmtk::logger().debug(
"Configure isotropic remeshing swap");
231 auto op_swap = std::make_shared<composite::TriEdgeSwap>(mesh);
232 op_swap->add_invariant(invariant_interior_edge);
236 op_swap->add_invariant(
237 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
240 op_swap->add_invariant(invariant_valence_improve);
241 op_swap->collapse().add_invariant(invariant_link_condition);
242 op_swap->collapse().add_invariant(invariant_mm_map);
243 for (
auto& p : positions) {
244 op_swap->split().set_new_attribute_strategy(
246 SplitBasicStrategy::None,
247 SplitRibBasicStrategy::Mean);
249 if (position_for_inversion) {
251 position_for_inversion.value().mesh(),
252 position_for_inversion.value().as<
double>()));
255 for (
auto& p : positions)
256 op_swap->collapse().set_new_attribute_strategy(p, CollapseBasicStrategy::CopyOther);
257 for (
const auto& attr : pass_through_attributes) {
258 op_swap->split().set_new_attribute_strategy(attr);
259 op_swap->collapse().set_new_attribute_strategy(attr);
261 assert(op_swap->split().attribute_new_all_configured());
262 assert(op_swap->collapse().attribute_new_all_configured());
263 ops.push_back(op_swap);
268 auto op_smooth = std::make_shared<AttributesUpdateWithFunction>(mesh);
269 if (position.dimension() == 3) {
276 op_smooth->add_invariant(invariant_interior_vertex);
281 op_smooth->add_invariant(
282 std::make_shared<invariants::uvEdgeInvariant>(mesh, other_positions.front().mesh()));
285 if (position_for_inversion) {
287 position_for_inversion.value().mesh(),
288 position_for_inversion.value().as<
double>()));
291 if (update_position) op_smooth->add_transfer_strategy(update_position);
292 ops.push_back(op_smooth);
297 for (
long i = 0; i < options.
iterations; ++i) {
301 for (
size_t j = 0; j < ops.size(); ++j) {
302 const auto& op = ops[j];
309 "Executed {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, executing: {}",
const attribute::Accessor< T, Mesh, D > create_const_accessor(const attribute::MeshAttributeHandle &handle) const
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Mesh & get_multi_mesh_root()
returns a reference to the root of a multimesh tree
SchedulerStats run_operation_on_all(operations::Operation &op)
int64_t number_of_failed_operations() const
Returns the number of failed operations performed by the scheduler.
int64_t number_of_performed_operations() const
Returns the number of performed operations performed by the scheduler.
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
bool is_connectivity_valid() const final override
void execute_from_root(Mesh &mesh)
double relative_to_absolute_length(const attribute::MeshAttributeHandle &position, const double length_rel)
void isotropic_remeshing(const IsotropicRemeshingOptions &options)
void consolidate(Mesh &mesh)
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
std::string_view primitive_type_name(PrimitiveType t)
void log_and_throw_error(const std::string &msg)
spdlog::logger & logger()
Retrieves the current logger.
wmtk::attribute::MeshAttributeHandle position_attribute
std::vector< wmtk::attribute::MeshAttributeHandle > other_position_attributes
std::optional< wmtk::attribute::MeshAttributeHandle > inversion_position_attribute
std::vector< wmtk::attribute::MeshAttributeHandle > pass_through_attributes