extract explicit mesh with topology information from implicit surfaces with boolean operations, and do surface/volume integrating on them.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
7.5 KiB

#include <container/hashmap.hpp>
#include <algorithm/glue_algorithm.hpp>
#include "ia_cut_face.hpp"
#include "implicit_arrangement.hpp"
#include "robust_assert.hpp"
std::array<uint32_t, 3> ia_cut_3_face(ia_complex_t& ia_complex,
uint32_t cid,
uint32_t plane_index,
const stl_vector_mp<std::array<uint32_t, 3>>& subfaces)
{
auto& edges = ia_complex.edges;
auto& faces = ia_complex.faces;
auto& cells = ia_complex.cells;
const auto& cell = cells[cid];
const auto num_boundary_faces = cell.faces.size();
uint32_t cut_face_id = INVALID_INDEX;
stl_vector_mp<uint32_t> positive_subfaces{};
stl_vector_mp<uint32_t> negative_subfaces{};
stl_vector_mp<uint32_t> cut_edges{};
stl_vector_mp<bool> cut_edge_orientations{};
positive_subfaces.reserve(num_boundary_faces + 1);
negative_subfaces.reserve(num_boundary_faces + 1);
cut_edges.reserve(num_boundary_faces);
cut_edge_orientations.reserve(num_boundary_faces);
auto compute_cut_edge_orientation = [&](uint32_t fid, const std::array<uint32_t, 3>& subface) -> bool {
ROBUST_ASSERT(subface[2] != INVALID_INDEX);
const auto& f = faces[fid];
bool s = cell.signs[f.supporting_plane];
if (subface[0] == INVALID_INDEX || subface[1] == INVALID_INDEX) {
// Intersection edge is on the boundary of the face.
auto itr =
algorithm::find<algorithm::ExecutionPolicySelector::simd_only>(f.edges.begin(), f.edges.end(), subface[2]);
ROBUST_ASSERT(itr != f.edges.end());
size_t curr_i = itr - f.edges.begin();
size_t next_i = (curr_i + 1) % f.edges.size();
const auto& curr_e = edges[f.edges[curr_i]];
const auto& next_e = edges[f.edges[next_i]];
bool edge_is_consistent_with_face =
(curr_e.vertices[1] == next_e.vertices[0] || curr_e.vertices[1] == next_e.vertices[1]);
bool on_positive_side = subface[0] != INVALID_INDEX;
uint8_t key = static_cast<uint8_t>(s) + static_cast<uint8_t>(edge_is_consistent_with_face)
+ static_cast<uint8_t>(on_positive_side);
return key % 2 == 0;
} else {
// Intersection edge is a cross cut.
return !s;
}
};
for (auto fid : cell.faces) {
const auto& subface = subfaces[fid];
if (subface[0] == INVALID_INDEX && subface[1] == INVALID_INDEX) { cut_face_id = fid; }
if (subface[0] != INVALID_INDEX) { positive_subfaces.emplace_back(subface[0]); }
if (subface[1] != INVALID_INDEX) { negative_subfaces.emplace_back(subface[1]); }
if (subface[2] != INVALID_INDEX) {
cut_edges.emplace_back(subface[2]);
cut_edge_orientations.emplace_back(compute_cut_edge_orientation(fid, subface));
}
}
if (positive_subfaces.empty() && negative_subfaces.empty()) {
// The implicit function is identical over the whole cell.
return {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
} else if (positive_subfaces.empty()) {
cells[cid].signs[plane_index] = false;
return {INVALID_INDEX, cid, cut_face_id};
} else if (negative_subfaces.empty()) {
cells[cid].signs[plane_index] = true;
return {cid, INVALID_INDEX, cut_face_id};
}
// Chain cut edges into a loop.
{
size_t num_cut_edges = cut_edges.size();
ROBUST_ASSERT(num_cut_edges >= 3);
flat_hash_map_mp<uint32_t, uint32_t> v2e{};
v2e.reserve(num_cut_edges);
for (size_t i = 0; i < num_cut_edges; i++) {
const auto eid = cut_edges[i];
const auto& e = edges[eid];
if (cut_edge_orientations[i]) {
v2e[e.vertices[0]] = i;
} else {
v2e[e.vertices[1]] = i;
}
}
stl_vector_mp<uint32_t> chained_cut_edges{};
chained_cut_edges.reserve(num_cut_edges);
chained_cut_edges.emplace_back(0u);
while (chained_cut_edges.size() < num_cut_edges) {
const uint32_t i = chained_cut_edges.back();
const auto& e = edges[cut_edges[i]];
const auto vid = cut_edge_orientations[i] ? e.vertices[1] : e.vertices[0];
const auto itr = v2e.find(vid);
ROBUST_ASSERT(itr != v2e.end());
const auto next_i = itr->second;
if (cut_edges[next_i] == cut_edges[chained_cut_edges.front()]) { break; }
chained_cut_edges.emplace_back(next_i);
}
algorithm::transform<algorithm::ExecutionPolicySelector::simd_only>(chained_cut_edges.begin(),
chained_cut_edges.end(),
chained_cut_edges.begin(),
[&](auto i) { return cut_edges[i]; });
std::swap(cut_edges, chained_cut_edges);
}
// Cross cut.
ROBUST_ASSERT(!cut_edges.empty());
ia_face_t cut_face;
cut_face.edges = std::move(cut_edges);
cut_face.supporting_plane = plane_index;
faces.emplace_back(std::move(cut_face));
cut_face_id = faces.size() - 1;
// Generate positive and negative subcell.
ia_cell_t positive_cell, negative_cell;
positive_cell.faces.reserve(positive_subfaces.size() + 1);
negative_cell.faces.reserve(negative_subfaces.size() + 1);
positive_subfaces.emplace_back(cut_face_id);
positive_cell.faces = std::move(positive_subfaces);
positive_cell.signs = cell.signs;
positive_cell.signs[plane_index] = true;
negative_subfaces.emplace_back(cut_face_id);
negative_cell.faces = std::move(negative_subfaces);
negative_cell.signs = cell.signs;
negative_cell.signs[plane_index] = false;
cells.emplace_back(std::move(positive_cell));
cells.emplace_back(std::move(negative_cell));
uint32_t positive_cell_id = static_cast<uint32_t>(cells.size() - 2);
uint32_t negative_cell_id = static_cast<uint32_t>(cells.size() - 1);
// Update cell id on each side of involved faces.
{
// cut face
ROBUST_ASSERT(cut_face_id != INVALID_INDEX);
auto& cut_f = faces[cut_face_id];
cut_f.positive_cell = positive_cell_id;
cut_f.negative_cell = negative_cell_id;
auto& positive_c = cells[positive_cell_id];
auto& negative_c = cells[negative_cell_id];
for (auto fid : positive_c.faces) {
if (fid == cut_face_id) continue;
auto& f = faces[fid];
ROBUST_ASSERT(f.positive_cell == cid || f.negative_cell == cid);
if (f.positive_cell == cid) {
f.positive_cell = positive_cell_id;
} else {
f.negative_cell = positive_cell_id;
}
}
for (auto fid : negative_c.faces) {
if (fid == cut_face_id) continue;
auto& f = faces[fid];
ROBUST_ASSERT(f.positive_cell == cid || f.negative_cell == cid);
if (f.positive_cell == cid) {
f.positive_cell = negative_cell_id;
} else {
f.negative_cell = negative_cell_id;
}
}
}
return {positive_cell_id, negative_cell_id, cut_face_id};
}