|
|
@ -44,18 +44,18 @@ void compute_patch_edges(const stl_vector_mp<polygon_face_t>& patch_faces, |
|
|
|
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, |
|
|
|
flat_index_group_t& patches, |
|
|
|
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); |
|
|
|
const auto patch_id = static_cast<uint32_t>(patches.size()); |
|
|
|
patches.start_indices.emplace_back(patch_id); |
|
|
|
std::queue<uint32_t> Q{}; |
|
|
|
Q.emplace(i); |
|
|
|
patch.emplace_back(i); |
|
|
|
patches.index_group.emplace_back(i); |
|
|
|
visited_face[i] = true; |
|
|
|
patch_of_face_mapping[i] = patch_id; |
|
|
|
while (!Q.empty()) { |
|
|
@ -68,7 +68,7 @@ void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face |
|
|
|
: patch_edges[eId].headers[0].face_index; |
|
|
|
if (!visited_face[other_fId]) { |
|
|
|
Q.emplace(other_fId); |
|
|
|
patch.emplace_back(other_fId); |
|
|
|
patches.index_group.emplace_back(other_fId); |
|
|
|
patch_of_face_mapping[other_fId] = patch_id; |
|
|
|
visited_face[other_fId] = true; |
|
|
|
} |
|
|
@ -77,11 +77,13 @@ void compute_patches(const stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
patches.start_indices.emplace_back(static_cast<uint32_t>(patches.index_group.size())); |
|
|
|
} |
|
|
|
|
|
|
|
void compute_chains(size_t iso_vert_count, |
|
|
|
stl_vector_mp<iso_edge_t>& patch_edges, |
|
|
|
stl_vector_mp<stl_list_mp<iso_edge_t>>& chains) |
|
|
|
void compute_chains(size_t iso_vert_count, |
|
|
|
stl_vector_mp<iso_edge_t>& patch_edges, |
|
|
|
flat_index_group_t& chains, |
|
|
|
stl_vector_mp<iso_edge_t>& chain_representative_headers) |
|
|
|
{ |
|
|
|
stl_vector_mp<stl_vector_mp<uint32_t>> non_manifold_edges_of_vert{}; |
|
|
|
stl_vector_mp<uint32_t> non_manifold_edges{}; |
|
|
@ -98,16 +100,32 @@ void compute_chains(size_t iso_vert_count, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// NOTE: the rule of building chains here in brief:
|
|
|
|
// HINT: the chains can be seen as intersection edges of patches
|
|
|
|
// CONCEPT: the non-manifold edges where vertices do not have branches are called 'trivial';
|
|
|
|
// the non-manifold edges where vertices have branches (i.e. intersection of chains) are called 'singular', and the
|
|
|
|
// vertices are also called 'singular'.
|
|
|
|
// 1. each chain can start from arbitary vertex of a non-manifold edge, and end at visited edge (i.e. a ring is built) or
|
|
|
|
// singular vertex;
|
|
|
|
// 2. along each chain, the neighboring patch does not change, otherwise a new chain is raised.
|
|
|
|
stl_vector_mp<bool> visited_edge(patch_edges.size(), false); |
|
|
|
std::list<uint32_t> chain_edges{}; |
|
|
|
chains.index_group.reserve(non_manifold_edges.size() * 2); |
|
|
|
chains.start_indices.reserve(8); |
|
|
|
chain_representative_headers.reserve(8); |
|
|
|
for (const auto& i : non_manifold_edges) { |
|
|
|
if (!visited_edge[i]) { |
|
|
|
// unvisited non-manifold iso-edge (not a boundary edge)
|
|
|
|
// new chain
|
|
|
|
auto& chain = chains.emplace_back(); |
|
|
|
chains.start_indices.emplace_back(static_cast<uint32_t>(chains.index_group.size())); |
|
|
|
auto& edge = patch_edges[i]; |
|
|
|
std::queue<uint32_t> Q{}; |
|
|
|
Q.emplace(i); |
|
|
|
chain.emplace_back(std::move(patch_edges[i])); |
|
|
|
chain_edges.emplace_back(edge.v1); |
|
|
|
chain_edges.emplace_back(edge.v2); |
|
|
|
chain_representative_headers.emplace_back(edge); |
|
|
|
visited_edge[i] = true; |
|
|
|
chain_edges.clear(); |
|
|
|
while (!Q.empty()) { |
|
|
|
const auto eId = Q.front(); |
|
|
|
Q.pop(); |
|
|
@ -116,9 +134,21 @@ void compute_chains(size_t iso_vert_count, |
|
|
|
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]; |
|
|
|
|
|
|
|
edge = patch_edges[other_eId]; |
|
|
|
if (!visited_edge[other_eId]) { |
|
|
|
Q.emplace(other_eId); |
|
|
|
chain.emplace_back(std::move(patch_edges[other_eId])); |
|
|
|
if (v == chain_edges.front()) { |
|
|
|
if (v == edge.v1) |
|
|
|
chain_edges.emplace_front(edge.v2); |
|
|
|
else |
|
|
|
chain_edges.emplace_front(edge.v1); |
|
|
|
} else { |
|
|
|
if (v == edge.v1) |
|
|
|
chain_edges.emplace_front(edge.v2); |
|
|
|
else |
|
|
|
chain_edges.emplace_front(edge.v1); |
|
|
|
} |
|
|
|
visited_edge[other_eId] = true; |
|
|
|
} |
|
|
|
} |
|
|
@ -127,21 +157,40 @@ void compute_chains(size_t iso_vert_count, |
|
|
|
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]; |
|
|
|
edge = patch_edges[other_eId]; |
|
|
|
if (!visited_edge[other_eId]) { |
|
|
|
Q.emplace(other_eId); |
|
|
|
chain.emplace_back(std::move(patch_edges[other_eId])); |
|
|
|
if (v == chain_edges.front()) { |
|
|
|
if (v == edge.v1) |
|
|
|
chain_edges.emplace_front(edge.v2); |
|
|
|
else |
|
|
|
chain_edges.emplace_front(edge.v1); |
|
|
|
} else { |
|
|
|
if (v == edge.v1) |
|
|
|
chain_edges.emplace_front(edge.v2); |
|
|
|
else |
|
|
|
chain_edges.emplace_front(edge.v1); |
|
|
|
} |
|
|
|
visited_edge[other_eId] = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// add chain edges to chains.index_group
|
|
|
|
chains.index_group.insert(chains.index_group.end(), |
|
|
|
std::make_move_iterator(chain_edges.begin()), |
|
|
|
std::make_move_iterator(chain_edges.end())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
chains.start_indices.emplace_back(static_cast<uint32_t>(chains.index_group.size())); |
|
|
|
chains.start_indices.shrink_to_fit(); |
|
|
|
chains.index_group.shrink_to_fit(); |
|
|
|
} |
|
|
|
|
|
|
|
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, |
|
|
|
flat_index_group_t& shells, |
|
|
|
stl_vector_mp<uint32_t>& shell_of_half_patch, |
|
|
|
stl_vector_mp<stl_vector_mp<uint32_t>>& components, |
|
|
|
flat_index_group_t& components, |
|
|
|
stl_vector_mp<uint32_t>& component_of_patch) |
|
|
|
{ |
|
|
|
const auto num_patch = half_patch_adj_list.size() / 2; |
|
|
@ -152,11 +201,11 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
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(); |
|
|
|
const auto shell_Id = static_cast<uint32_t>(shells.size()); |
|
|
|
shells.start_indices.emplace_back(shell_Id); |
|
|
|
std::queue<uint32_t> Q{}; |
|
|
|
Q.emplace(i); |
|
|
|
shell.emplace_back(i); |
|
|
|
shells.index_group.emplace_back(i); |
|
|
|
shell_of_half_patch[i] = shell_Id; |
|
|
|
visited_flags[i] = true; |
|
|
|
while (!Q.empty()) { |
|
|
@ -164,7 +213,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
Q.pop(); |
|
|
|
for (auto hp : half_patch_adj_list[half_patch]) { |
|
|
|
if (!visited_flags[hp]) { |
|
|
|
shell.emplace_back(hp); |
|
|
|
shells.index_group.emplace_back(hp); |
|
|
|
shell_of_half_patch[hp] = shell_Id; |
|
|
|
Q.emplace(hp); |
|
|
|
visited_flags[hp] = true; |
|
|
@ -173,20 +222,21 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
shells.start_indices.emplace_back(static_cast<uint32_t>(shells.index_group.size())); |
|
|
|
|
|
|
|
// 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(); |
|
|
|
const auto component_Id = static_cast<uint32_t>(components.size()); |
|
|
|
components.start_indices.emplace_back(component_Id); |
|
|
|
std::queue<uint32_t> Q{}; |
|
|
|
Q.emplace(i); |
|
|
|
component.emplace_back(i); |
|
|
|
components.index_group.emplace_back(i); |
|
|
|
component_of_patch[i] = component_Id; |
|
|
|
visited_flags[i] = true; |
|
|
|
while (!Q.empty()) { |
|
|
@ -196,7 +246,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
for (auto hp : half_patch_adj_list[2 * patch]) { |
|
|
|
if (!visited_flags[hp / 2]) { |
|
|
|
const auto p = hp / 2; |
|
|
|
component.emplace_back(p); |
|
|
|
components.index_group.emplace_back(p); |
|
|
|
component_of_patch[p] = component_Id; |
|
|
|
Q.emplace(p); |
|
|
|
visited_flags[p] = true; |
|
|
@ -206,7 +256,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
for (auto hp : half_patch_adj_list[2 * patch + 1]) { |
|
|
|
if (!visited_flags[hp / 2]) { |
|
|
|
const auto p = hp / 2; |
|
|
|
component.emplace_back(p); |
|
|
|
components.index_group.emplace_back(p); |
|
|
|
component_of_patch[p] = component_Id; |
|
|
|
Q.emplace(p); |
|
|
|
visited_flags[p] = true; |
|
|
@ -215,6 +265,8 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
components.start_indices.emplace_back(static_cast<uint32_t>(components.index_group.size())); |
|
|
|
|
|
|
|
// get shells as list of patch indices
|
|
|
|
// for (auto& shell : shells) {
|
|
|
|
// for (auto& pId : shell) {
|
|
|
@ -225,7 +277,7 @@ void compute_shells_and_components(const stl_vector_mp<stl_vector_mp<uint32_t>>& |
|
|
|
|
|
|
|
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) |
|
|
|
flat_index_group_t& arrangement_cells) |
|
|
|
{ |
|
|
|
// build shell adjacency list
|
|
|
|
uint32_t sink_shell = num_shell; |
|
|
@ -250,17 +302,17 @@ void compute_arrangement_cells(uint32_t |
|
|
|
for (uint32_t i = 0; i < num_shell + 1; ++i) { |
|
|
|
if (!visited_shell[i]) { |
|
|
|
// create new component
|
|
|
|
auto& arr_cell = arrangement_cells.emplace_back(); |
|
|
|
arrangement_cells.start_indices.emplace_back(static_cast<uint32_t>(arrangement_cells.size())); |
|
|
|
std::queue<uint32_t> Q{}; |
|
|
|
Q.emplace(i); |
|
|
|
arr_cell.emplace_back(i); |
|
|
|
arrangement_cells.index_group.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); |
|
|
|
arrangement_cells.index_group.emplace_back(s); |
|
|
|
Q.emplace(s); |
|
|
|
visited_shell[s] = true; |
|
|
|
} |
|
|
@ -270,13 +322,21 @@ void compute_arrangement_cells(uint32_t |
|
|
|
} |
|
|
|
|
|
|
|
// 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); } |
|
|
|
flat_index_group_t sink_free_cells{}; |
|
|
|
sink_free_cells.index_group.reserve(arrangement_cells.index_group.size()); |
|
|
|
sink_free_cells.start_indices.reserve(arrangement_cells.size() + 1); |
|
|
|
sink_free_cells.start_indices.emplace_back(0); |
|
|
|
sink_free_cells.group_foreach([&](uint32_t group_idx, uint32_t range_start, uint32_t range_end) { |
|
|
|
if (sink_free_cells.index_group.size() > sink_free_cells.start_indices.back()) { |
|
|
|
sink_free_cells.start_indices.emplace_back(static_cast<uint32_t>(sink_free_cells.index_group.size())); |
|
|
|
} |
|
|
|
// arr_cell = sink_free_shell_list;
|
|
|
|
std::swap(arr_cell, sink_free_shell_list); |
|
|
|
} |
|
|
|
for (auto i = range_start; i < range_end; ++i) { |
|
|
|
if (arrangement_cells.index_group[i] < num_shell) { |
|
|
|
sink_free_cells.index_group.emplace_back(arrangement_cells.index_group[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
sink_free_cells.index_group.shrink_to_fit(); |
|
|
|
sink_free_cells.start_indices.shrink_to_fit(); |
|
|
|
std::swap(arrangement_cells, sink_free_cells); |
|
|
|
} |