32 static constexpr double kZeroValueReplacement = 1e-10;
35 std::vector<cell_vector> nodes_to_evaluate_;
36 std::unordered_set<cell_vector> added_cells_;
37 std::vector<cell_vector> last_added_cells_;
39 std::vector<geometry::point3d> vertices_;
40 std::unordered_map<vertex_index, vertex_index> cluster_map_;
43 return a !=
nullptr && b !=
nullptr && a->value_sign() != b->value_sign();
47 void add_cell(
const cell_vector& cv) {
48 if (added_cells_.contains(cv)) {
53 add_node(cv + NeighborCellVectors[4]);
54 add_node(cv + NeighborCellVectors[9]);
55 add_node(cv + NeighborCellVectors[3]);
56 add_node(cv + NeighborCellVectors[13]);
57 add_node(cv + NeighborCellVectors[1]);
58 add_node(cv + NeighborCellVectors[12]);
59 add_node(cv + NeighborCellVectors[0]);
61 added_cells_.insert(cv);
62 last_added_cells_.push_back(cv);
65 bool add_node(
const cell_vector& cv) {
66 if (node_list_.contains(cv)) {
70 return add_node_unchecked(cv);
73 bool add_node_unchecked(
const cell_vector& cv) {
74 auto p = cell_node_point(cv);
79 auto unit = resolution() / 100.0;
80 p = unit * (p.array() / unit).round();
82 if (!extended_bbox().contains(p)) {
86 node_list_.emplace(cv,
rmt_node{clamp_to_bbox(p)});
88 nodes_to_evaluate_.push_back(cv);
93 return p.array().max(bbox().min().array()).min(bbox().max().array());
96 vertex_index clustered_vertex_index(vertex_index vi)
const {
97 return cluster_map_.contains(vi) ? cluster_map_.at(vi) : vi;
101 void evaluate_field(
const field_function& field_fn,
double isovalue) {
102 if (nodes_to_evaluate_.empty()) {
108 auto point_it = points.rowwise().begin();
109 for (
const auto& cv : nodes_to_evaluate_) {
110 *point_it++ = node_list_.at(cv).position();
113 valuesd values = field_fn(points).array() - isovalue;
116 for (
const auto& cv : nodes_to_evaluate_) {
117 auto value = values(i);
119 value = kZeroValueReplacement;
122 node_list_.at(cv).set_value(value);
126 nodes_to_evaluate_.clear();
130 void remove_free_nodes(
const std::vector<cell_vector>& node_cvs) {
131 for (
const auto& cv : node_cvs) {
132 auto it = node_list_.find(cv);
133 if (it->second.is_free()) {
134 node_list_.erase(it->first);
139 void track_surface() {
140 std::unordered_set<cell_vector> cells_to_add;
144 for (
const auto& cv : last_added_cells_) {
146 auto iaab = cv + NeighborCellVectors[4];
147 auto iaba = cv + NeighborCellVectors[9];
148 auto iabb = cv + NeighborCellVectors[3];
149 auto ibaa = cv + NeighborCellVectors[13];
150 auto ibab = cv + NeighborCellVectors[1];
151 auto ibba = cv + NeighborCellVectors[12];
152 auto ibbb = cv + NeighborCellVectors[0];
154 const auto* aaa = node_list_.node_ptr(iaaa);
155 const auto* aab = node_list_.node_ptr(iaab);
156 const auto* aba = node_list_.node_ptr(iaba);
157 const auto* abb = node_list_.node_ptr(iabb);
158 const auto* baa = node_list_.node_ptr(ibaa);
159 const auto* bab = node_list_.node_ptr(ibab);
160 const auto* bba = node_list_.node_ptr(ibba);
161 const auto* bbb = node_list_.node_ptr(ibbb);
164 if (has_intersection(aaa, aab)) {
165 cells_to_add.insert(iaaa + NeighborCellVectors[2]);
166 cells_to_add.insert(iaaa + NeighborCellVectors[5]);
167 cells_to_add.insert(iaaa + NeighborCellVectors[6]);
169 if (has_intersection(aba, abb)) {
170 cells_to_add.insert(iaba);
171 cells_to_add.insert(iaba + NeighborCellVectors[5]);
172 cells_to_add.insert(iaba + NeighborCellVectors[6]);
174 if (has_intersection(baa, bab)) {
175 cells_to_add.insert(ibaa);
176 cells_to_add.insert(ibaa + NeighborCellVectors[2]);
177 cells_to_add.insert(ibaa + NeighborCellVectors[5]);
179 if (has_intersection(bba, bbb)) {
180 cells_to_add.insert(ibba);
181 cells_to_add.insert(ibba + NeighborCellVectors[2]);
182 cells_to_add.insert(ibba + NeighborCellVectors[6]);
186 if (has_intersection(aaa, aba)) {
187 cells_to_add.insert(iaaa + NeighborCellVectors[6]);
188 cells_to_add.insert(iaaa + NeighborCellVectors[8]);
189 cells_to_add.insert(iaaa + NeighborCellVectors[11]);
191 if (has_intersection(aab, abb)) {
192 cells_to_add.insert(iaab);
193 cells_to_add.insert(iaab + NeighborCellVectors[6]);
194 cells_to_add.insert(iaab + NeighborCellVectors[8]);
196 if (has_intersection(baa, bba)) {
197 cells_to_add.insert(ibaa);
198 cells_to_add.insert(ibaa + NeighborCellVectors[8]);
199 cells_to_add.insert(ibaa + NeighborCellVectors[11]);
201 if (has_intersection(bab, bbb)) {
202 cells_to_add.insert(ibab);
203 cells_to_add.insert(ibab + NeighborCellVectors[6]);
204 cells_to_add.insert(ibab + NeighborCellVectors[11]);
208 if (has_intersection(aaa, baa)) {
209 cells_to_add.insert(iaaa + NeighborCellVectors[2]);
210 cells_to_add.insert(iaaa + NeighborCellVectors[10]);
211 cells_to_add.insert(iaaa + NeighborCellVectors[11]);
213 if (has_intersection(aab, bab)) {
214 cells_to_add.insert(iaab);
215 cells_to_add.insert(iaab + NeighborCellVectors[2]);
216 cells_to_add.insert(iaab + NeighborCellVectors[10]);
218 if (has_intersection(aba, bba)) {
219 cells_to_add.insert(iaba);
220 cells_to_add.insert(iaba + NeighborCellVectors[10]);
221 cells_to_add.insert(iaba + NeighborCellVectors[11]);
223 if (has_intersection(abb, bbb)) {
224 cells_to_add.insert(iabb);
225 cells_to_add.insert(iabb + NeighborCellVectors[2]);
226 cells_to_add.insert(iabb + NeighborCellVectors[11]);
230 last_added_cells_.clear();
232 for (
const auto& cv : cells_to_add) {
237 void update_neighbor_cache() {
238 for (
auto& cv_node : node_list_) {
239 const auto& cv = cv_node.first;
240 auto& node = cv_node.second;
242 auto neighbors = std::make_unique<std::array<rmt_node*, 14>>();
244 for (edge_index ei = 0; ei < 14; ei++) {
245 neighbors->at(ei) = node_list_.neighbor_node_ptr(cv, ei);
248 node.set_neighbors(std::move(neighbors));
256 void add_all_nodes(
const field_function& field_fn,
double isovalue) {
257 std::vector<cell_vector> new_nodes;
258 std::vector<cell_vector> prev_nodes;
260 for (
auto cv2 = cv_min(2); cv2 <= cv_max(2); cv2++) {
261 for (
auto cv1 = cv_min(1); cv1 <= cv_max(1); cv1++) {
262 for (
auto cv0 = cv_min(0); cv0 <= cv_max(0); cv0++) {
263 cell_vector cv(cv0, cv1, cv2);
264 if (add_node_unchecked(cv)) {
265 new_nodes.push_back(cv);
270 if (cv2 > cv_min(2)) {
271 evaluate_field(field_fn, isovalue);
272 generate_vertices(prev_nodes);
273 remove_free_nodes(prev_nodes);
276 prev_nodes.swap(new_nodes);
280 remove_free_nodes(prev_nodes);
282 update_neighbor_cache();
285 void add_nodes_by_tracking(
const field_function& field_fm,
double isovalue) {
286 evaluate_field(field_fm, isovalue);
287 while (!last_added_cells_.empty()) {
289 evaluate_field(field_fm, isovalue);
292 std::vector<cell_vector> all_nodes;
293 for (
const auto& cv_node : node_list_) {
294 all_nodes.push_back(cv_node.first);
297 generate_vertices(all_nodes);
298 remove_free_nodes(all_nodes);
300 update_neighbor_cache();
304 if (!extended_bbox().contains(p)) {
308 add_cell(cell_vector_from_point(p));
313 nodes_to_evaluate_.clear();
314 cluster_map_.clear();
318 void cluster_vertices() {
319 for (
auto& ci_node : node_list_) {
320 auto& node = ci_node.second;
321 const auto& p = node.position();
322 if ((p.array() == bbox().min().array() || p.array() == bbox().max().array()).any()) {
326 node.cluster(vertices_, cluster_map_);
330 void generate_vertices(
const std::vector<cell_vector>& node_cvs) {
331 static constexpr std::array<edge_index, 7> CellEdgeIndices{0, 1, 3, 4, 9, 12, 13};
333#pragma omp parallel for
335 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(node_cvs.size()); i++) {
336 const auto& cv = node_cvs.at(i);
337 auto& node = node_list_.at(cv);
340 auto d = std::abs(node.value());
341 const auto& p = node.position();
343 for (
auto ei : CellEdgeIndices) {
344 auto* node2_ptr = node_list_.neighbor_node_ptr(cv, ei);
345 if (node2_ptr ==
nullptr) {
350 auto& node2 = *node2_ptr;
351 if (node.value_sign() == node2.value_sign()) {
357 auto d2 = std::abs(node2.value());
358 const auto& p2 = node2.position();
363 (p.array() == p2.array()).select(p, (d2 * p + d * p2) / (d + d2));
367 auto vi =
static_cast<vertex_index
>(vertices_.size());
368 vertices_.emplace_back(vertex);
371 node.insert_vertex(vi, ei);
373 node2.insert_vertex(vi, OppositeEdge.at(ei));
376 node.set_intersection(ei);
377 node2.set_intersection(OppositeEdge.at(ei));
385 auto it = vertices.rowwise().begin();
386 for (
const auto& v : vertices_) {
392 void uncluster_vertices(
const std::unordered_set<vertex_index>& vis) {
393 auto it = cluster_map_.begin();
394 while (it != cluster_map_.end()) {
395 if (vis.contains(it->second)) {
397 it = cluster_map_.erase(it);