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.
 
 
 
 
 
 

145 lines
7.3 KiB

#include <stack>
#include <queue>
#include <post_topo.hpp>
std::vector<dynamic_bitset<>> propagate_subface_labels(size_t subface_count,
const std::vector<polygon_face_t>& faces,
const std::vector<std::vector<uint32_t>>& patches,
const std::vector<std::vector<uint32_t>>& arrangement_cells,
const std::vector<uint32_t>& shell_of_half_patch,
const std::vector<std::vector<uint32_t>>& shells,
const std::vector<uint32_t>& shell_to_cell)
{
// in turn: [subface_index][cell_index] = sign
std::vector<dynamic_bitset<>> cell_subface_signs(subface_count, dynamic_bitset<>(arrangement_cells.size()));
std::vector<bool> visited_cells(arrangement_cells.size(), false);
std::vector<bool> visited_subfaces(subface_count, false);
std::vector<std::vector<uint32_t>> cell_indices_of_inactive_subfaces(subface_count);
std::queue<uint32_t> Q{};
dynamic_bitset<> opposed_cells(arrangement_cells.size());
std::vector<uint32_t> unique_opposed_cells{};
Q.emplace(0);
while (!Q.empty()) {
const auto cell_index = Q.front();
const auto cell = arrangement_cells[cell_index];
Q.pop();
if (!visited_cells[cell_index]) {
visited_cells[cell_index] = true;
opposed_cells.reset();
unique_opposed_cells.clear();
for (auto shell : cell) {
for (auto half_patch : shells[shell]) {
auto subface_label = faces[patches[half_patch / 2][0]].subface_index;
// CAUTION: we assume that the sign is 1 when the surface is inside the sdf before
// but in blobtree we assume that the sign is 0 when the surface is inside the sdf
// so we need to flip the sign here
// EDIT: to keep sign operation nice and easy, we'll just keep the sign being 1 when the surface is inside
// the sdf
bool sign = (half_patch % 2 == 0) ? 1 : 0;
auto oppose_cell = shell_to_cell[shell_of_half_patch[sign ? (half_patch + 1) : (half_patch - 1)]];
// bool sign = (half_patch % 2 == 0) ? 0 : 1;
// auto oppose_cell = shell_to_cell[shell_of_half_patch[!sign ? (half_patch + 1) : (half_patch - 1)]];
// sign broadcast
if (oppose_cell != cell_index) {
if (!opposed_cells[oppose_cell]) {
for (uint32_t si = 0; si < subface_count; ++si)
cell_subface_signs[si][oppose_cell] = cell_subface_signs[si][cell_index];
opposed_cells[oppose_cell] = true;
unique_opposed_cells.emplace_back(oppose_cell);
if (!visited_cells[oppose_cell]) Q.emplace(oppose_cell);
}
cell_subface_signs[subface_label][oppose_cell] = !sign;
}
#ifndef RELEASE_BRANCH
if (visited_subfaces[subface_label] != false && cell_subface_signs[subface_label][cell_index] != sign) {
throw std::runtime_error("ERROR: Inconsistent Cell Function Labels.");
}
#endif
cell_subface_signs[subface_label][cell_index] = sign;
visited_subfaces[subface_label] = true;
// propagate the function signs to all previously inactive cells
if (cell_indices_of_inactive_subfaces[subface_label].size() > 0) {
for (const auto cell_index : cell_indices_of_inactive_subfaces[subface_label]) {
cell_subface_signs[subface_label][cell_index] = sign;
}
cell_indices_of_inactive_subfaces[subface_label].clear();
}
}
}
// fetch inactive subface index
for (uint32_t subface_index = 0; subface_index < subface_count; subface_index++) {
if (visited_subfaces[subface_index] == false) {
cell_indices_of_inactive_subfaces[subface_index].emplace_back(cell_index);
for (const auto& other_cell_index : unique_opposed_cells) {
cell_indices_of_inactive_subfaces[subface_index].emplace_back(other_cell_index);
}
}
}
}
}
#ifndef RELEASE_BRANCH
for (size_t i = 0; i < subface_count; ++i) {
if (visited_subfaces[i] == false) { throw std::logic_error("ERROR: Still have sign-unknown subfaces."); }
}
#endif
return cell_subface_signs;
}
dynamic_bitset<> filter_cells_by_boolean(const baked_blobtree_t& tree, std::vector<dynamic_bitset<>>& cell_primitive_signs)
{
struct compact_node_info {
dynamic_bitset<> cell_signs{};
uint32_t parent_index{};
};
std::stack<compact_node_info> stacked_nodes{};
auto iter = tree.nodes.begin();
stacked_nodes.emplace(compact_node_info{std::move(cell_primitive_signs[iter->primitive_index]), iter->parent_index});
iter++;
while (iter != tree.nodes.end()) {
// each out iteration must start with leaf node, only 1 leaf node is absorbed in one iteration
assert(iter->is_primitive_node());
compact_node_info temp_info{std::move(cell_primitive_signs[iter->primitive_index]), iter->parent_index};
iter++; // to parent or neighboring node
while (!stacked_nodes.empty() && temp_info.parent_index == stacked_nodes.top().parent_index) {
// do bool operation, util meet next primitive node.
assert(iter->is_operation_node());
// HINT: other_cell_signs here should always be left nodes
const auto& other_cell_sign = stacked_nodes.top().cell_signs;
switch (iter->get_operation()) {
case internal::eNodeOperation::unionOp: temp_info.cell_signs |= other_cell_sign; break;
case internal::eNodeOperation::intersectionOp: temp_info.cell_signs &= other_cell_sign; break;
case internal::eNodeOperation::differenceOp:
// stacked nodes are always left childs
temp_info.cell_signs = other_cell_sign & ~temp_info.cell_signs;
break;
default: throw std::runtime_error("ERROR: baked blobtree with unknown type operation node"); break;
}
temp_info.parent_index = iter->parent_index;
stacked_nodes.pop();
iter++; // to parent or neighboring node
}
stacked_nodes.emplace(std::move(temp_info));
}
assert(stacked_nodes.size() == 1);
assert(stacked_nodes.top().parent_index == 0xFFFFFFFF);
// sign 0 in blobtree means inside, so we need to flip the sign
// EDIT: no need to flip signs here
return stacked_nodes.top().cell_signs;
}