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.

270 lines
12 KiB

#include <queue>
#include <container/hashmap.hpp>
#include <patch_connectivity.hpp>
ISNP_API void compute_patch_edges(const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face,
stl_vector_mp<iso_edge_t>& patch_edges)
{
uint32_t max_num_edge = 0;
for (const auto& iso_face : patch_faces) { max_num_edge += static_cast<uint32_t>(iso_face.vertex_indices.size()); }
patch_edges.reserve(max_num_edge / 2);
edges_of_face.reserve(patch_faces.size());
uint32_t num_iso_edge{};
// map: (v1, v2) -> iso-edge index
flat_hash_map_mp<std::pair<uint32_t, uint32_t>, uint32_t> edge_id{};
for (uint32_t i = 0; i < patch_faces.size(); i++) {
auto& face = patch_faces[i];
const uint32_t num_edge = static_cast<uint32_t>(face.vertex_indices.size());
// emplace at back of edges_of_face a vector<uint32_t> of size num_edge
auto& face_edges = edges_of_face.emplace_back(num_edge);
for (uint32_t j = 0; j < num_edge; j++) {
auto v1 = face.vertex_indices[j];
auto v2 = (j + 1 == num_edge) ? face.vertex_indices[0] : face.vertex_indices[j + 1];
// swap if v1 > v2
if (v1 > v2) std::swap(v1, v2);
//
num_iso_edge = static_cast<uint32_t>(patch_edges.size());
auto iter_inserted = edge_id.try_emplace(std::make_pair(v1, v2), num_iso_edge);
if (iter_inserted.second) { // new iso-edge
auto& edge = patch_edges.emplace_back();
edge.v1 = v1;
edge.v2 = v2;
edge.headers.emplace_back(i, j);
face_edges[j] = num_iso_edge;
} else { // existing iso-edge
uint32_t eId = iter_inserted.first->second;
patch_edges[eId].headers.emplace_back(i, j);
face_edges[j] = eId;
}
}
}
}
ISNP_API void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face,
const stl_vector_mp<iso_edge_t>& patch_edges,
const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
8 months ago
stl_vector_mp<uint32_t>& patch_of_face_mapping)
{
stl_vector_mp<bool> visited_face(edges_of_face.size(), false);
for (uint32_t i = 0; i < edges_of_face.size(); i++) {
if (!visited_face[i]) {
// new patch
auto& patch = patches.emplace_back();
const auto patch_id = static_cast<uint32_t>(patches.size() - 1);
std::queue<uint32_t> Q{};
Q.emplace(i);
patch.emplace_back(i);
visited_face[i] = true;
patch_of_face_mapping[i] = patch_id;
while (!Q.empty()) {
const auto fId = Q.front();
Q.pop();
for (const auto eId : edges_of_face[fId]) {
if (patch_edges[eId].headers.size() == 2) { // manifold edge
const auto other_fId = (patch_edges[eId].headers[0].face_index == fId)
? patch_edges[eId].headers[1].face_index
: patch_edges[eId].headers[0].face_index;
if (!visited_face[other_fId]) {
Q.emplace(other_fId);
patch.emplace_back(other_fId);
patch_of_face_mapping[other_fId] = patch_id;
8 months ago
visited_face[other_fId] = true;
}
}
}
}
}
}
}
ISNP_API void compute_chains(const stl_vector_mp<iso_edge_t>& patch_edges,
const stl_vector_mp<stl_vector_mp<uint32_t>>& non_manifold_edges_of_vert,
stl_vector_mp<stl_vector_mp<uint32_t>>& chains)
{
stl_vector_mp<bool> visited_edge(patch_edges.size(), false);
for (uint32_t i = 0; i < patch_edges.size(); i++) {
if (!visited_edge[i] && patch_edges[i].headers.size() > 2) {
// unvisited non-manifold iso-edge (not a boundary edge)
// new chain
auto& chain = chains.emplace_back();
std::queue<uint32_t> Q{};
Q.emplace(i);
chain.emplace_back(i);
visited_edge[i] = true;
while (!Q.empty()) {
const auto eId = Q.front();
Q.pop();
// v1
auto v = patch_edges[eId].v1;
if (non_manifold_edges_of_vert[v].size() == 2) {
const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1]
: non_manifold_edges_of_vert[v][0];
if (!visited_edge[other_eId]) {
Q.emplace(other_eId);
chain.emplace_back(other_eId);
visited_edge[other_eId] = true;
}
}
// v2
v = patch_edges[eId].v2;
if (non_manifold_edges_of_vert[v].size() == 2) {
const auto other_eId = (non_manifold_edges_of_vert[v][0] == eId) ? non_manifold_edges_of_vert[v][1]
: non_manifold_edges_of_vert[v][0];
if (!visited_edge[other_eId]) {
Q.emplace(other_eId);
chain.emplace_back(other_eId);
visited_edge[other_eId] = true;
}
}
}
}
}
}
ISNP_API void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& half_patch_adj_list,
stl_vector_mp<stl_vector_mp<uint32_t>>& shells,
stl_vector_mp<uint32_t>& shell_of_half_patch,
stl_vector_mp<stl_vector_mp<uint32_t>>& components,
stl_vector_mp<uint32_t>& component_of_patch)
{
8 months ago
const auto num_patch = half_patch_adj_list.size() / 2;
// find connected component of half-patch adjacency graph
// each component is a shell
stl_vector_mp<bool> visited_flags(2 * num_patch, false);
shells.clear();
shell_of_half_patch.resize(2 * num_patch);
for (uint32_t i = 0; i < 2 * num_patch; i++) {
if (!visited_flags[i]) {
// create new component
const uint32_t shell_Id = static_cast<uint32_t>(shells.size());
auto& shell = shells.emplace_back();
std::queue<uint32_t> Q{};
Q.emplace(i);
shell.emplace_back(i);
shell_of_half_patch[i] = shell_Id;
visited_flags[i] = true;
while (!Q.empty()) {
auto half_patch = Q.front();
Q.pop();
for (auto hp : half_patch_adj_list[half_patch]) {
if (!visited_flags[hp]) {
shell.emplace_back(hp);
shell_of_half_patch[hp] = shell_Id;
Q.emplace(hp);
visited_flags[hp] = true;
}
}
}
}
}
// find connected component of patch-adjacency graph
// each component is an iso-surface component
visited_flags.clear();
visited_flags.resize(num_patch, false);
components.clear();
component_of_patch.resize(num_patch);
for (uint32_t i = 0; i < num_patch; i++) {
if (!visited_flags[i]) {
// create new component
const uint32_t component_Id = static_cast<uint32_t>(components.size());
auto& component = components.emplace_back();
std::queue<uint32_t> Q{};
Q.emplace(i);
component.emplace_back(i);
component_of_patch[i] = component_Id;
visited_flags[i] = true;
while (!Q.empty()) {
auto patch = Q.front();
Q.pop();
// 1-side of patch
for (auto hp : half_patch_adj_list[2 * patch]) {
if (!visited_flags[hp / 2]) {
const auto p = hp / 2;
component.emplace_back(p);
component_of_patch[p] = component_Id;
Q.emplace(p);
visited_flags[p] = true;
}
}
// -1-side of patch
for (auto hp : half_patch_adj_list[2 * patch + 1]) {
if (!visited_flags[hp / 2]) {
const auto p = hp / 2;
component.emplace_back(p);
component_of_patch[p] = component_Id;
Q.emplace(p);
visited_flags[p] = true;
}
}
}
}
}
// get shells as list of patch indices
// for (auto& shell : shells) {
// for (auto& pId : shell) {
// pId /= 2; // get patch index of half-patch
// }
// }
}
ISNP_API void compute_arrangement_cells(uint32_t num_shell,
const stl_vector_mp<std::pair<uint32_t, uint32_t>>& shell_links,
stl_vector_mp<stl_vector_mp<uint32_t>>& arrangement_cells)
{
// build shell adjacency list
uint32_t sink_shell = num_shell;
flat_hash_map_mp<uint32_t, std::vector<uint32_t>> adjacent_shells{};
for (const auto& link : shell_links) {
if (link.first == invalid_index) {
adjacent_shells[sink_shell].emplace_back(link.second);
adjacent_shells[link.second].emplace_back(sink_shell);
} else if (link.second == invalid_index) {
adjacent_shells[sink_shell].emplace_back(link.first);
adjacent_shells[link.first].emplace_back(sink_shell);
} else {
adjacent_shells[link.first].emplace_back(link.second);
adjacent_shells[link.second].emplace_back(link.first);
}
}
// find connected components of shell adjacency graph
// each component is an arrangement cells
stl_vector_mp<bool> visited_shell(num_shell + 1, false);
// arrangement_cells.clear();
for (uint32_t i = 0; i < num_shell + 1; ++i) {
if (!visited_shell[i]) {
// create new component
auto& arr_cell = arrangement_cells.emplace_back();
std::queue<uint32_t> Q{};
Q.emplace(i);
arr_cell.emplace_back(i);
visited_shell[i] = true;
while (!Q.empty()) {
const auto shell_id = Q.front();
Q.pop();
for (const auto s : adjacent_shells[shell_id]) {
if (!visited_shell[s]) {
arr_cell.emplace_back(s);
Q.emplace(s);
visited_shell[s] = true;
}
}
}
}
}
// remove sink shell from arrangement cells
stl_vector_mp<uint32_t> sink_free_shell_list{};
for (auto& arr_cell : arrangement_cells) {
sink_free_shell_list.clear();
for (const auto s : arr_cell) {
if (s < num_shell) { sink_free_shell_list.emplace_back(s); }
}
// arr_cell = sink_free_shell_list;
std::swap(arr_cell, sink_free_shell_list);
}
}