Wildmeshing Toolkit
Loading...
Searching...
No Matches
Marching.cpp
Go to the documentation of this file.
1#include "Marching.hpp"
2
3#include <deque>
4#include <optional>
5#include <wmtk/Scheduler.hpp>
13#include <wmtk/utils/Logger.hpp>
14
15namespace wmtk::components {
16
18{
19public:
22 int64_t m_val;
23
25 Mesh& m,
26 const attribute::MeshAttributeHandle& attribute,
27 PrimitiveType ptype,
28 int64_t val)
29 : m_accessor(m.create_accessor<int64_t>(attribute))
30 , m_ptype(ptype)
31 , m_val(val)
32 {}
33
35};
36
39 std::map<PrimitiveType, attribute::MeshAttributeHandle>& label_handles,
40 const std::vector<int64_t>& input_values,
41 const int64_t output_value)
42 : m_mesh(pos_handle.mesh())
43 , m_pos_handle(pos_handle)
44 , m_input_values(input_values)
45 , m_output_value(output_value)
46{
47 assert(label_handles.count(PrimitiveType::Vertex));
48
50
51 if (label_handles.count(PrimitiveType::Edge)) {
53 }
54
55 if (label_handles.count(PrimitiveType::Triangle)) {
57 }
58}
59
61{
62 using namespace operations;
63
64 auto todo_attribute = m_mesh.register_attribute_typed<int64_t>(
65 "todo_edgesplit_in_marching_component",
67 1);
68 auto splitted_edges_attribute = m_mesh.register_attribute_typed<int64_t>(
69 "splitted_edges_in_marching_component",
71 1);
72
73 assert(m_input_values.size() == 1 || m_input_values.size() == 2);
74
75 if (m_input_values.size() == 1) {
76 logger().info(
77 "Only one input value was given. Perform marching in between value {} and any other "
78 "value.",
80 }
81
84
85 std::deque<TagAttribute> filters;
86 for (size_t i = 0; i < m_filter_labels.size(); ++i) {
87 filters.emplace_back(m_mesh, m_filter_labels[i], PrimitiveType::Edge, m_filter_values[i]);
88 }
89
90 // compute the todo list for the split edge
92 wmtk::attribute::Accessor<int64_t> acc_splitted_edges =
93 m_mesh.create_accessor(splitted_edges_attribute);
94 for (const Tuple& edge : m_mesh.get_all(PrimitiveType::Edge)) {
95 bool is_of_interest = true;
96 for (const TagAttribute& filter : filters) {
97 if ((filter.m_accessor.const_scalar_attribute(edge) == filter.m_val) ==
99 is_of_interest = false;
100 break;
101 }
102 }
103
104 if (!is_of_interest) {
105 continue;
106 }
107
108 const int64_t vt0 = acc_vertex_tag.scalar_attribute(edge);
109 const int64_t vt1 =
111 if (m_input_values.size() == 2) {
112 if ((vt0 == m_input_values[0] && vt1 == m_input_values[1]) ||
113 (vt1 == m_input_values[0] && vt0 == m_input_values[1])) {
114 acc_todo.scalar_attribute(edge) = 1;
115 acc_splitted_edges.scalar_attribute(edge) = 1;
116 }
117 } else {
118 assert(m_input_values.size() == 1);
119 if ((vt0 == m_input_values[0] && vt1 != m_input_values[0]) ||
120 (vt1 == m_input_values[0] && vt0 != m_input_values[0])) {
121 acc_todo.scalar_attribute(edge) = 1;
122 acc_splitted_edges.scalar_attribute(edge) = 1;
123 }
124 }
125 }
126
127 EdgeSplit op_split(m_mesh);
128 op_split.add_invariant(std::make_shared<TodoInvariant>(m_mesh, todo_attribute));
129
130 // position
132
133 // labels
134 {
135 /**************************edge tag******************************/
136 if (m_edge_tag_handle.has_value()) {
137 auto compute_edge_label =
138 [this](
139 const Eigen::MatrixX<int64_t>& labels,
140 const std::vector<Tuple>& tuples) -> Eigen::VectorX<int64_t> {
141 assert(labels.cols() == 2);
142 assert(labels.rows() == 1);
143 assert(tuples.size() == 2);
144 if (labels(0, 0) == m_output_value && labels(0, 1) == m_output_value) {
145 return Eigen::VectorX<int64_t>::Constant(1, m_output_value);
146 }
147
148 // do not change the current value
149 auto acc = m_mesh.create_const_accessor<int64_t>(m_edge_tag_handle.value());
150 const int64_t val = acc.const_scalar_attribute(tuples[0]);
151 return Eigen::VectorX<int64_t>::Constant(1, val);
152 };
153
154 std::shared_ptr edge_tag_strategy = std::make_shared<
156 m_edge_tag_handle.value(),
158 compute_edge_label);
159
161 m_edge_tag_handle.value(),
162 SplitBasicStrategy::Copy,
163 SplitRibBasicStrategy::None);
164 op_split.add_transfer_strategy(edge_tag_strategy);
165 }
166
167 /**************************face tag******************************/
168 if (m_face_tag_handle.has_value() && m_edge_tag_handle.has_value()) {
169 auto compute_face_label =
170 [this](
171 const Eigen::MatrixX<int64_t>& labels,
172 const std::vector<Tuple>& tuples) -> Eigen::VectorX<int64_t> {
173 assert(labels.cols() == 3);
174 assert(labels.rows() == 1);
175 assert(tuples.size() == 3);
176 if (labels(0, 0) == m_output_value && labels(0, 1) == m_output_value &&
177 labels(0, 2) == m_output_value) {
178 return Eigen::VectorX<int64_t>::Constant(1, m_output_value);
179 }
180
181 // do not change the current value
182 auto acc = m_mesh.create_const_accessor<int64_t>(m_face_tag_handle.value());
183 const int64_t val = acc.const_scalar_attribute(tuples[0]);
184 return Eigen::VectorX<int64_t>::Constant(1, val);
185 };
186
187 std::shared_ptr face_tag_strategy = std::make_shared<
189 m_face_tag_handle.value(),
190 m_edge_tag_handle.value(),
191 compute_face_label);
192
194 m_face_tag_handle.value(),
195 SplitBasicStrategy::Copy,
196 SplitRibBasicStrategy::None);
197 op_split.add_transfer_strategy(face_tag_strategy);
198 }
199
200
201 auto tmp = std::make_shared<SplitNewAttributeStrategy<int64_t>>(m_vertex_tag_handle);
202 tmp->set_strategy(SplitBasicStrategy::None);
203 tmp->set_rib_strategy(
204 [this](const VectorX<int64_t>&, const VectorX<int64_t>&, const std::bitset<2>&) {
205 VectorX<int64_t> ret(1);
206 ret(0) = m_output_value;
207 return ret;
208 });
210
212 attribute::MeshAttributeHandle(m_mesh, splitted_edges_attribute),
213 SplitBasicStrategy::Copy,
214 SplitRibBasicStrategy::None);
215 }
216
217 // filters
218 for (const auto& edge_filter_handle : m_filter_labels) {
220 edge_filter_handle,
221 SplitBasicStrategy::None,
222 SplitRibBasicStrategy::None);
223 }
224 // todo_attribute
226 attribute::MeshAttributeHandle(m_mesh, todo_attribute),
227 SplitBasicStrategy::None,
228 SplitRibBasicStrategy::None);
229 // scalar field
230 if (m_scalar_field.has_value()) {
232 m_scalar_field.value(),
233 SplitBasicStrategy::None,
234 SplitRibBasicStrategy::None);
235 }
236 // pass_through
237 for (const auto& attr : m_pass_through_attributes) {
238 op_split.set_new_attribute_strategy(attr);
239 }
240
241 Scheduler scheduler;
242 while (true) {
243 const auto stats = scheduler.run_operation_on_all(op_split);
244 if (stats.number_of_successful_operations() == 0) {
245 break;
246 }
247 }
248
249 if (m_scalar_field.has_value()) {
250 // move vertices according to isovalue
251 auto sf_acc = m_mesh.create_accessor<double>(m_scalar_field.value());
252
253 auto pos_acc = m_mesh.create_accessor<double>(m_pos_handle);
254
255 auto inversion_invariant =
257
258 for (const Tuple& v_tuple : m_mesh.get_all(PrimitiveType::Vertex)) {
260
261 if (acc_vertex_tag.const_scalar_attribute(v) != m_output_value) {
262 continue;
263 }
264 // get the two input positions
265 Tuple v0;
266 Tuple v1;
267 auto incident_edges =
269 for (Tuple e : incident_edges) {
270 if (acc_splitted_edges.const_scalar_attribute(e) == 0) {
271 continue;
272 }
273 if (acc_vertex_tag.const_scalar_attribute(e) == m_output_value) {
275 }
276 if (acc_vertex_tag.const_scalar_attribute(e) == m_input_values[0]) {
277 v0 = e;
278 }
279 if (m_input_values.size() == 2) {
280 if (acc_vertex_tag.const_scalar_attribute(e) == m_input_values[1]) {
281 v1 = e;
282 }
283 } else {
284 if (acc_vertex_tag.const_scalar_attribute(e) != m_input_values[0]) {
285 v1 = e;
286 }
287 }
288 }
289 assert(m_mesh.is_valid(v0));
290 assert(m_mesh.is_valid(v1));
291 const auto p0 = pos_acc.const_vector_attribute(v0);
292 const auto p1 = pos_acc.const_vector_attribute(v1);
293 const double sf0 = sf_acc.const_scalar_attribute(v0);
294 const double sf1 = sf_acc.const_scalar_attribute(v1);
295
296 auto p = pos_acc.vector_attribute(v);
297
298 const double u = (m_isovalue - sf0) / (sf1 - sf0);
299
300 const Eigen::VectorXd p_opt = (1. - u) * p0 + u * p1;
301 const Eigen::VectorXd p_mid = p;
302
303
304 const auto tets = simplex::top_dimension_cofaces_tuples(m_mesh, v);
305
306 // make sure that the current position is valid
307 if (!inversion_invariant.after({}, tets)) {
308 log_and_throw_error("Midpoint split im Marching component caused inversions.");
309 }
310
311 // sf_acc.scalar_attribute(v) = m_isovalue;
312 // continue;
313
314 // test position on the isovalue
315 p = p_opt;
316 if (u > 0 && u < 1 && inversion_invariant.after({}, tets)) {
317 sf_acc.scalar_attribute(v) = m_isovalue;
318 continue;
319 }
320
321 Eigen::VectorXd p_valid = p_mid;
322 Eigen::VectorXd p_target = p_opt;
323
324 // line search
325 bool found_valid_position = false;
326 for (size_t i = 0; i < m_linesearch_iterations; ++i) {
327 p = 0.5 * (p_valid + p_target);
328
329
330 if (inversion_invariant.after({}, tets)) {
331 p_valid = p;
332 } else {
333 p_target = p;
334 }
335 }
336
337 if (p_valid == p_mid) {
338 logger().trace(
339 "Could not find a solution in the linesearch. Using the mid point: {}",
340 p_mid.transpose());
341 }
342
343 p = p_valid;
344 {
345 // compute isovalue
346 const double l = (p1 - p0).norm();
347 const double u_0 = (p - p0).norm() / l;
348 const double u_1 = (p1 - p).norm() / l;
349 const double sf_p = u_0 * sf0 + u_1 * sf1;
350 sf_acc.scalar_attribute(v) = sf_p;
351 }
352 }
353 }
354}
355
356void Marching::add_filter(const attribute::MeshAttributeHandle& label, const int64_t value)
357{
358 assert(label.primitive_type() == PrimitiveType::Edge);
359 m_filter_labels.emplace_back(label);
360 m_filter_values.emplace_back(value);
361}
362
364{
365 m_pass_through_attributes.emplace_back(pass_through);
366}
367
368void Marching::add_pass_through(const std::vector<attribute::MeshAttributeHandle>& pass_through)
369{
372 pass_through.begin(),
373 pass_through.end());
374}
375
377 const attribute::MeshAttributeHandle& scalar_field,
378 const double isovalue)
379{
380 m_scalar_field = scalar_field;
381 m_isovalue = isovalue;
382}
383
384void Marching::set_isovalue_linesearch_iterations(const int64_t linesearch_iterations)
385{
386 m_linesearch_iterations = linesearch_iterations;
387}
388
390{
391 m_invert_filter = true;
392}
393
394
395} // namespace wmtk::components
attribute::TypedAttributeHandle< T > register_attribute_typed(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
const attribute::Accessor< T, Mesh, attribute::CachingAttribute< T >, 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.
Definition Mesh.cpp:18
virtual bool is_valid(const Tuple &tuple) const
check validity of tuple including its hash
Definition Mesh.cpp:113
virtual Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const =0
switch the orientation of the Tuple of the given dimension
attribute::Accessor< T, Mesh, attribute::CachingAttribute< T >, D > create_accessor(const attribute::MeshAttributeHandle &handle)
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition Scheduler.cpp:33
The Tuple is the basic navigation tool in our mesh data structure.
Definition Tuple.hpp:19
An Accessor that uses tuples for accessing attributes instead of indices.
Definition Accessor.hpp:28
const Scalar & const_scalar_attribute(const ArgType &t) const
Scalar & scalar_attribute(const ArgType &t)
auto as() const -> const held_handle_type< held_type_from_primitive< T >()> &
std::vector< attribute::MeshAttributeHandle > m_pass_through_attributes
Definition Marching.hpp:92
void add_filter(const attribute::MeshAttributeHandle &label, const int64_t value)
Add an edge filter to marching.
Definition Marching.cpp:356
std::vector< int64_t > m_input_values
Definition Marching.hpp:86
Marching(attribute::MeshAttributeHandle &pos_handle, std::map< PrimitiveType, attribute::MeshAttributeHandle > &label_handles, const std::vector< int64_t > &input_values, const int64_t output_value)
Initialize the marching method.
Definition Marching.cpp:37
std::optional< attribute::MeshAttributeHandle > m_face_tag_handle
Definition Marching.hpp:85
std::vector< attribute::MeshAttributeHandle > m_filter_labels
Definition Marching.hpp:89
attribute::MeshAttributeHandle m_vertex_tag_handle
Definition Marching.hpp:83
void set_isovalue_linesearch_iterations(const int64_t linesearch_iterations)
Set the number of iterations for the linesearch when trying to match the isovalue.
Definition Marching.cpp:384
attribute::MeshAttributeHandle m_pos_handle
Definition Marching.hpp:82
void invert_filter()
Invert the filter such that everything covered by the filter is ignored.
Definition Marching.cpp:389
void add_isovalue(const attribute::MeshAttributeHandle &scalar_field, const double isovalue)
Position the new vertices along an edge according to an isovalue in a scalar field.
Definition Marching.cpp:376
void process()
Perform the actual marching.
Definition Marching.cpp:60
void add_pass_through(const attribute::MeshAttributeHandle &pass_through)
Add pass through attributes.
Definition Marching.cpp:363
std::optional< attribute::MeshAttributeHandle > m_edge_tag_handle
Definition Marching.hpp:84
std::optional< attribute::MeshAttributeHandle > m_scalar_field
Definition Marching.hpp:94
std::vector< int64_t > m_filter_values
Definition Marching.hpp:90
wmtk::attribute::Accessor< int64_t > m_accessor
Definition Marching.cpp:20
TagAttribute(Mesh &m, const attribute::MeshAttributeHandle &attribute, PrimitiveType ptype, int64_t val)
Definition Marching.cpp:24
TagAttribute(TagAttribute &)=delete
void set_new_attribute_strategy(const attribute::MeshAttributeHandle &attribute, const std::shared_ptr< const operations::BaseSplitNewAttributeStrategy > &other)
Definition EdgeSplit.cpp:85
void add_invariant(std::shared_ptr< Invariant > invariant)
Definition Operation.hpp:48
void add_transfer_strategy(const std::shared_ptr< const operations::AttributeTransferStrategyBase > &other)
Definition Operation.cpp:59
void top_dimension_cofaces_tuples(const PointMesh &mesh, const Simplex &simplex, SimplexCollection &collection)
std::vector< Tuple > cofaces_single_dimension_tuples(const Mesh &mesh, const Simplex &my_simplex, PrimitiveType cofaces_type)
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:101
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
Vector< T, Eigen::Dynamic > VectorX
Definition Types.hpp:19