#include #include #include std::vector> propagate_subface_labels(size_t subface_count, const std::vector& faces, const std::vector>& patches, const std::vector>& arrangement_cells, const std::vector& shell_of_half_patch, const std::vector>& shells, const std::vector& shell_to_cell) { // in turn: [subface_index][cell_index] = sign std::vector> cell_subface_signs(subface_count, dynamic_bitset<>(arrangement_cells.size())); std::vector visited_cells(arrangement_cells.size(), false); std::vector visited_subfaces(subface_count, false); std::vector> cell_indices_of_inactive_subfaces(subface_count); std::queue Q{}; dynamic_bitset<> opposed_cells(arrangement_cells.size()); std::vector 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>& cell_primitive_signs) { struct compact_node_info { dynamic_bitset<> cell_signs{}; uint32_t parent_index{}; }; std::stack 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; }