diff --git a/network_process/include/connect_by_topo/patch_connectivity.hpp b/network_process/include/connect_by_topo/patch_connectivity.hpp index 7ab198c..28bc754 100644 --- a/network_process/include/connect_by_topo/patch_connectivity.hpp +++ b/network_process/include/connect_by_topo/patch_connectivity.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include /** @@ -18,35 +19,39 @@ void compute_patch_edges(const stl_vector_mp &patch_faces, * @param[in] patch_edges the list of edges on the patch. * @param[in] patch_faces the list of faces on the patch. Each face contains an implicit function label. * @param[out] patches the list of patches which contain a list of faces' indices. + * @param[out] patch_of_face_mapping the mapping from face index to patch index. */ void compute_patches(const stl_vector_mp> &edges_of_face, const stl_vector_mp &patch_edges, const stl_vector_mp &patch_faces, - stl_vector_mp> &patches, + flat_index_group_t &patches, stl_vector_mp &patch_of_face_mapping); /** * @brief Group non-manifold iso-edges into chains - * @param[in] iso_vert_count the count of iso-vertices + * @param[in] iso_vert_count the count of iso-vertices. * @param[in] patch_edges the list of edges on the patch. - * @param[out] chains Chains of non-manifold edges; encoded by a vector of edge indices. + * @param[out] chains non-manifold edges. + * @param[out] chain_representative_headers the headers of edges in chains. */ -void compute_chains(size_t iso_vert_count, - stl_vector_mp &patch_edges, - stl_vector_mp> &chains); +void compute_chains(size_t iso_vert_count, + stl_vector_mp &patch_edges, + flat_index_group_t &chains, + stl_vector_mp &chain_representative_headers); /** * @brief compute shells and connected components of isosurfaces, and build maps: half-patch --> shell, patch --> component * @param[in] half_patch_adj_list The adjacency list of half-patches + * @param[out] shells List of shells, each shell is a list of half-patches * @param[out] shell_of_patch Map: half-patch --> shell * @param[out] component Connected componeent represented as a list of patches * @param[out] component_of_patch Map: patch --> component * @note each shell is a list of half-patches, each component is a list of patches */ void compute_shells_and_components(const stl_vector_mp> &half_patch_adj_list, - stl_vector_mp> &shells, + flat_index_group_t &shells, stl_vector_mp &shell_of_half_patch, - stl_vector_mp> &components, + flat_index_group_t &components, stl_vector_mp &component_of_patch); /** @@ -57,4 +62,4 @@ void compute_shells_and_components(const stl_vector_mp> */ void compute_arrangement_cells(uint32_t num_shell, const stl_vector_mp> &shell_links, - stl_vector_mp> &arrangement_cells); \ No newline at end of file + flat_index_group_t &arrangement_cells); \ No newline at end of file diff --git a/network_process/include/connect_by_topo/topology_ray_shooting.hpp b/network_process/include/connect_by_topo/topology_ray_shooting.hpp index 5ad646f..846858a 100644 --- a/network_process/include/connect_by_topo/topology_ray_shooting.hpp +++ b/network_process/include/connect_by_topo/topology_ray_shooting.hpp @@ -15,10 +15,10 @@ void topo_ray_shooting(const scene_bg_mesh_info_t const stl_vector_mp &tetrahedron_arrangements, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, - const stl_vector_mp> &patches, + const flat_index_group_t &patches, const stl_vector_mp &patch_of_face, - const stl_vector_mp> &shells, + const flat_index_group_t &shells, const stl_vector_mp &shell_of_half_patch, - const stl_vector_mp> &components, + const flat_index_group_t &components, const stl_vector_mp &component_of_patch, stl_vector_mp> &shell_links); \ No newline at end of file diff --git a/network_process/include/post_topo/filter_polygon_faces.hpp b/network_process/include/post_topo/filter_polygon_faces.hpp index fb76e4e..2c0c241 100644 --- a/network_process/include/post_topo/filter_polygon_faces.hpp +++ b/network_process/include/post_topo/filter_polygon_faces.hpp @@ -3,14 +3,14 @@ #include // return: active face label -dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, - const stl_vector_mp>& patches, - const stl_vector_mp>& arrangement_cells, - const stl_vector_mp& shell_of_half_patch, - const stl_vector_mp>& shells, - const stl_vector_mp& shell_to_cell, - const dynamic_bitset_mp<>& active_cell_label, - stl_vector_mp& output_polygon_faces, - stl_vector_mp& output_vertex_counts_of_face); +dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, + const flat_index_group_t& patches, + const flat_index_group_t& arrangement_cells, + const stl_vector_mp& shell_of_half_patch, + const flat_index_group_t& shells, + const stl_vector_mp& shell_to_cell, + const dynamic_bitset_mp<>& active_cell_label, + stl_vector_mp& output_polygon_faces, + stl_vector_mp& output_vertex_counts_of_face); void filter_active_vertices(stl_vector_mp& vertices, stl_vector_mp& output_polygon_faces); \ No newline at end of file diff --git a/network_process/include/post_topo/patch_propagation.hpp b/network_process/include/post_topo/patch_propagation.hpp index 7cb5b39..80bef52 100644 --- a/network_process/include/post_topo/patch_propagation.hpp +++ b/network_process/include/post_topo/patch_propagation.hpp @@ -4,19 +4,19 @@ #include -void propagate_subface_labels(const baked_blobtree_t& tree, - const stl_vector_mp& faces, - const stl_vector_mp>& patches, - const stl_vector_mp>& arrangement_cells, - const stl_vector_mp& shell_of_half_patch, - const stl_vector_mp>& shells, - const stl_vector_mp& shell_to_cell, +void propagate_subface_labels(const baked_blobtree_t& tree, + const stl_vector_mp& faces, + const flat_index_group_t& patches, + const flat_index_group_t& arrangement_cells, + const stl_vector_mp& shell_of_half_patch, + const flat_index_group_t& shells, + const stl_vector_mp& shell_to_cell, // in turn: [subface_index][cell_index] = sign - stl_vector_mp>& cell_subface_signs); + stl_vector_mp>& cell_subface_signs); void transform_subface_to_primitive_labels(const baked_blobtree_t& tree, const stl_vector_mp>& cell_subface_signs, stl_vector_mp>& cell_primitive_signs); -dynamic_bitset_mp<> filter_cells_by_boolean(const baked_blobtree_t& tree, +dynamic_bitset_mp<> filter_cells_by_boolean(const baked_blobtree_t& tree, stl_vector_mp>& cell_primitive_signs); \ No newline at end of file diff --git a/network_process/interface/fwd_types.hpp b/network_process/interface/fwd_types.hpp index 94cc6db..42df6a1 100644 --- a/network_process/interface/fwd_types.hpp +++ b/network_process/interface/fwd_types.hpp @@ -259,4 +259,39 @@ struct equal_to> { return static_cast>(k1) == static_cast>(k2); } }; -} // namespace std \ No newline at end of file +} // namespace std + +// ============================================================================== + +struct flat_index_group_t { + stl_vector_mp index_group{}; /// a list of indices in the group + stl_vector_mp start_indices{}; /// a list of start indices for each group in the flat index group + + inline size_t size() const { return start_indices.size() - 1; } + + template + inline void foreach (F&& f) const + { + for (uint32_t group_idx = 0; group_idx < size(); ++group_idx) { + for (uint32_t elem_idx = 0; elem_idx < start_indices[group_idx + 1] - start_indices[group_idx]; ++elem_idx) { + f(group_idx, elem_idx, index_group[start_indices[group_idx] + elem_idx]); + } + } + } + + template + inline void group_foreach(F&& f) const + { + for (uint32_t group_idx = 0; group_idx < size(); ++group_idx) { + f(group_idx, start_indices[group_idx], start_indices[group_idx + 1]); + } + } + + template + inline void loop_on_group(uint32_t group_idx, F&& f) const + { + for (uint32_t elem_idx = 0; elem_idx < start_indices[group_idx + 1] - start_indices[group_idx]; ++elem_idx) { + f(elem_idx, index_group[start_indices[group_idx] + elem_idx]); + } + } +}; \ No newline at end of file diff --git a/network_process/src/connect_by_topo/patch_connectivity.cpp b/network_process/src/connect_by_topo/patch_connectivity.cpp index 8e9c395..ef6eea6 100644 --- a/network_process/src/connect_by_topo/patch_connectivity.cpp +++ b/network_process/src/connect_by_topo/patch_connectivity.cpp @@ -44,18 +44,18 @@ void compute_patch_edges(const stl_vector_mp& patch_faces, void compute_patches(const stl_vector_mp>& edges_of_face, const stl_vector_mp& patch_edges, const stl_vector_mp& patch_faces, - stl_vector_mp>& patches, + flat_index_group_t& patches, stl_vector_mp& patch_of_face_mapping) { stl_vector_mp 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(patches.size() - 1); + const auto patch_id = static_cast(patches.size()); + patches.start_indices.emplace_back(patch_id); std::queue 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>& 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>& edges_of_face } } } + patches.start_indices.emplace_back(static_cast(patches.index_group.size())); } -void compute_chains(size_t iso_vert_count, - stl_vector_mp& patch_edges, - stl_vector_mp>& chains) +void compute_chains(size_t iso_vert_count, + stl_vector_mp& patch_edges, + flat_index_group_t& chains, + stl_vector_mp& chain_representative_headers) { stl_vector_mp> non_manifold_edges_of_vert{}; stl_vector_mp 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 visited_edge(patch_edges.size(), false); + std::list 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(chains.index_group.size())); + auto& edge = patch_edges[i]; std::queue 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(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>& half_patch_adj_list, - stl_vector_mp>& shells, + flat_index_group_t& shells, stl_vector_mp& shell_of_half_patch, - stl_vector_mp>& components, + flat_index_group_t& components, stl_vector_mp& 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>& for (uint32_t i = 0; i < 2 * num_patch; i++) { if (!visited_flags[i]) { // create new component - const uint32_t shell_Id = static_cast(shells.size()); - auto& shell = shells.emplace_back(); + const auto shell_Id = static_cast(shells.size()); + shells.start_indices.emplace_back(shell_Id); std::queue 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>& 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>& } } } + shells.start_indices.emplace_back(static_cast(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(components.size()); - auto& component = components.emplace_back(); + const auto component_Id = static_cast(components.size()); + components.start_indices.emplace_back(component_Id); std::queue 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>& 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>& 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>& } } } + components.start_indices.emplace_back(static_cast(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>& void compute_arrangement_cells(uint32_t num_shell, const stl_vector_mp>& shell_links, - stl_vector_mp>& 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(arrangement_cells.size())); std::queue 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 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(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); } \ No newline at end of file diff --git a/network_process/src/connect_by_topo/topo_ray_shooting/find_extermal_edges.hpp b/network_process/src/connect_by_topo/topo_ray_shooting/find_extermal_edges.hpp index 03963a6..f8e4aa3 100644 --- a/network_process/src/connect_by_topo/topo_ray_shooting/find_extermal_edges.hpp +++ b/network_process/src/connect_by_topo/topo_ray_shooting/find_extermal_edges.hpp @@ -7,8 +7,8 @@ static inline void find_extremal_edges( const scene_bg_mesh_info_t &scene_bg_mesh_info, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, - const stl_vector_mp> &patches, - const stl_vector_mp> &components, + const flat_index_group_t &patches, + const flat_index_group_t &components, const stl_vector_mp &component_of_patch, const flat_hash_map_mp &next_vert, // extremal edge of component i is stored at position [2*i], [2*i+1] @@ -26,11 +26,12 @@ static inline void find_extremal_edges( iso_vId_compId_of_tet_vert.reserve(iso_faces.size() / 2); // stl_vector_mp is_iso_vert_visited(iso_verts.size(), false); - for (uint32_t i = 0; i < patches.size(); ++i) { - uint32_t component_id = component_of_patch[i]; + patches.group_foreach([&](uint32_t patch_index, uint32_t range_start, uint32_t range_end) { + uint32_t component_id = component_of_patch[patch_index]; auto &u1 = extremal_edge_of_component[2 * component_id]; auto &u2 = extremal_edge_of_component[2 * component_id + 1]; - for (auto fId : patches[i]) { + for (uint32_t i = range_start; i < range_end; ++i) { + const auto &fId = patches.index_group[i]; for (const auto &tet_face : iso_faces[fId].headers) iso_face_id_of_tet_face.try_emplace(tet_face, fId); for (const auto vId : iso_faces[fId].vertex_indices) { if (!is_iso_vert_visited[vId]) { @@ -82,5 +83,5 @@ static inline void find_extremal_edges( } } } - } + }); } \ No newline at end of file diff --git a/network_process/src/connect_by_topo/topology_ray_shooting.cpp b/network_process/src/connect_by_topo/topology_ray_shooting.cpp index 5073f96..f402995 100644 --- a/network_process/src/connect_by_topo/topology_ray_shooting.cpp +++ b/network_process/src/connect_by_topo/topology_ray_shooting.cpp @@ -10,11 +10,11 @@ void topo_ray_shooting(const scene_bg_mesh_info_t const stl_vector_mp &tetrahedron_arrangements, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, - const stl_vector_mp> &patches, + const flat_index_group_t &patches, const stl_vector_mp &patch_of_face, - const stl_vector_mp> &shells, + const flat_index_group_t &shells, const stl_vector_mp &shell_of_half_patch, - const stl_vector_mp> &components, + const flat_index_group_t &components, const stl_vector_mp &component_of_patch, stl_vector_mp> &shell_links) { diff --git a/network_process/src/post_topo/filter_polygon_faces.cpp b/network_process/src/post_topo/filter_polygon_faces.cpp index 1e2c020..54e12e9 100644 --- a/network_process/src/post_topo/filter_polygon_faces.cpp +++ b/network_process/src/post_topo/filter_polygon_faces.cpp @@ -2,15 +2,15 @@ #include -dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, - const stl_vector_mp>& patches, - const stl_vector_mp>& arrangement_cells, - const stl_vector_mp& shell_of_half_patch, - const stl_vector_mp>& shells, - const stl_vector_mp& shell_to_cell, - const dynamic_bitset_mp<>& active_cell_label, - stl_vector_mp& output_polygon_faces, - stl_vector_mp& output_vertex_counts_of_face) +dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, + const flat_index_group_t& patches, + const flat_index_group_t& arrangement_cells, + const stl_vector_mp& shell_of_half_patch, + const flat_index_group_t& shells, + const stl_vector_mp& shell_to_cell, + const dynamic_bitset_mp<>& active_cell_label, + stl_vector_mp& output_polygon_faces, + stl_vector_mp& output_vertex_counts_of_face) { dynamic_bitset_mp<> active_face_label(faces.size(), false); output_polygon_faces.reserve(faces.size() * 3); @@ -18,7 +18,6 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& stl_vector_mp visited_cells(arrangement_cells.size(), false); std::queue Q{}; - for (uint32_t i = 0; i < arrangement_cells.size(); ++i) { if (active_cell_label[i]) { Q.emplace(i); @@ -27,16 +26,16 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& } while (!Q.empty()) { const auto cell_index = Q.front(); - const auto cell = arrangement_cells[cell_index]; Q.pop(); if (!visited_cells[cell_index] && active_cell_label[cell_index]) { visited_cells[cell_index] = true; - for (auto shell : cell) { + arrangement_cells.loop_on_group(cell_index, [&](uint32_t _, uint32_t shell_index) { // it is secured that one shell cell cannot have a pair of half patches with same patch index - for (auto half_patch : shells[shell]) { - 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)]]; + shells.loop_on_group(shell_index, [&](uint32_t _, uint32_t half_patch_index) { + bool sign = (half_patch_index % 2 == 0) ? 0 : 1; + auto oppose_cell = + shell_to_cell[shell_of_half_patch[!sign ? (half_patch_index + 1) : (half_patch_index - 1)]]; // iff not interior patch, we do surface propagation if (!active_cell_label[oppose_cell]) { @@ -50,30 +49,30 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& // (i.e. clockwise), then its normal should point to the other side of that surface, which is the // outside of that surface, so it is also right if (!sign) { - for (const auto face_index : patches[half_patch / 2]) { + patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { active_face_label[face_index] = true; const auto& face_vertices = faces[face_index].vertex_indices; output_vertex_counts_of_face.emplace_back(face_vertices.size()); output_polygon_faces.insert(output_polygon_faces.end(), std::make_move_iterator(face_vertices.rbegin()), std::make_move_iterator(face_vertices.rend())); - } + }); } else { - for (const auto face_index : patches[half_patch / 2]) { + patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { active_face_label[face_index] = true; const auto& face_vertices = faces[face_index].vertex_indices; output_vertex_counts_of_face.emplace_back(face_vertices.size()); output_polygon_faces.insert(output_polygon_faces.end(), std::make_move_iterator(face_vertices.begin()), std::make_move_iterator(face_vertices.end())); - } + }); } } else if (!visited_cells[oppose_cell]) { // active and not visited cell, enqueue it Q.emplace(oppose_cell); } - } - } + }); + }); } } diff --git a/network_process/src/post_topo/patch_propagation.cpp b/network_process/src/post_topo/patch_propagation.cpp index d7574ad..8cd21c0 100644 --- a/network_process/src/post_topo/patch_propagation.cpp +++ b/network_process/src/post_topo/patch_propagation.cpp @@ -3,14 +3,14 @@ #include -void propagate_subface_labels(const baked_blobtree_t& tree, - const stl_vector_mp& faces, - const stl_vector_mp>& patches, - const stl_vector_mp>& arrangement_cells, - const stl_vector_mp& shell_of_half_patch, - const stl_vector_mp>& shells, - const stl_vector_mp& shell_to_cell, - stl_vector_mp>& cell_subface_signs) +void propagate_subface_labels(const baked_blobtree_t& tree, + const stl_vector_mp& faces, + const flat_index_group_t& patches, + const flat_index_group_t& arrangement_cells, + const stl_vector_mp& shell_of_half_patch, + const flat_index_group_t& shells, + const stl_vector_mp& shell_to_cell, + stl_vector_mp>& cell_subface_signs) { const auto num_subface = tree.subfaces.size(); @@ -23,23 +23,23 @@ void propagate_subface_labels(const baked_blobtree_t& tree 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; cell_neighbors_map.clear(); - for (auto shell : cell) { - for (auto half_patch : shells[shell]) { - auto subface_label = faces[patches[half_patch / 2][0]].subface_index; + arrangement_cells.loop_on_group(cell_index, [&](uint32_t _, uint32_t shell_index) { + shells.loop_on_group(shell_index, [&](uint32_t _, uint32_t half_patch_index) { + auto subface_label = faces[patches.index_group[patches.start_indices[half_patch_index / 2]]].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 // 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)]]; + bool sign = (half_patch_index % 2 == 0) ? 0 : 1; + auto oppose_cell = + shell_to_cell[shell_of_half_patch[!sign ? (half_patch_index + 1) : (half_patch_index - 1)]]; cell_neighbors_map[oppose_cell] = std::make_pair(subface_label, sign); #ifndef RELEASE_BRANCH @@ -57,8 +57,8 @@ void propagate_subface_labels(const baked_blobtree_t& tree } cell_indices_of_inactive_subfaces[subface_label].clear(); } - } - } + }); + }); // fetch inactive subface index for (uint32_t subface_index = 0; subface_index < num_subface; subface_index++) { diff --git a/network_process/src/process.cpp b/network_process/src/process.cpp index e7b9964..2221944 100644 --- a/network_process/src/process.cpp +++ b/network_process/src/process.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -66,27 +68,29 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& iso_faces); } // connect components by topology - stl_vector_mp patch_of_face(iso_faces.size()); - stl_vector_mp shell_of_half_patch{}; - stl_vector_mp component_of_patch{}; - stl_vector_mp> patches{}; - stl_vector_mp> chains{}; - stl_vector_mp> shells{}; - stl_vector_mp> components{}; - stl_vector_mp> arrangement_cells{}; - stl_vector_mp shell_to_cell{}; + // TODO: split headers of chains out, because it should not change during the chain + stl_vector_mp chain_representative_headers{}; + stl_vector_mp patch_of_face(iso_faces.size()); + stl_vector_mp shell_of_half_patch{}; + stl_vector_mp component_of_patch{}; + flat_index_group_t patches{}; + flat_index_group_t chains{}; + flat_index_group_t shells{}; + flat_index_group_t components{}; + flat_index_group_t arrangement_cells{}; + stl_vector_mp shell_to_cell{}; { { stl_vector_mp> edges_of_iso_face{}; stl_vector_mp iso_edges{}; compute_patch_edges(iso_faces, edges_of_iso_face, iso_edges); compute_patches(edges_of_iso_face, iso_edges, iso_faces, patches, patch_of_face); - compute_chains(iso_verts.size(), iso_edges, chains); + compute_chains(iso_verts.size(), iso_edges, chains, chain_representative_headers); } - stl_vector_mp> half_patch_adj_list(2 * patches.size()); - for (size_t i = 0; i < chains.size(); ++i) + stl_vector_mp> half_patch_adj_list(2 * chains.size()); + chains.group_foreach([&](uint32_t chain_index, uint32_t _, uint32_t __) { compute_patch_order(tetrahedrons, - chains[i].front(), + chain_representative_headers[chain_index], iso_verts, iso_faces, tetrahedron_arrangements, @@ -95,12 +99,14 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& zero_vertex_to_incident_tet_mapping, patch_of_face, half_patch_adj_list); + }); compute_shells_and_components(half_patch_adj_list, shells, shell_of_half_patch, components, component_of_patch); if (components.size() == 1) // no nesting problem, each shell is an arrangement cell { - arrangement_cells.reserve(shells.size()); - for (uint32_t i = 0; i < shells.size(); ++i) { arrangement_cells.emplace_back(std::vector{i}); } + arrangement_cells.index_group.resize(shells.size(), 0u); + arrangement_cells.start_indices.resize(shells.size() + 1); + std::iota(arrangement_cells.start_indices.begin(), arrangement_cells.start_indices.end(), 0u); } else { { stl_vector_mp> shell_links{}; @@ -117,14 +123,14 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& components, component_of_patch, shell_links); - compute_arrangement_cells(static_cast(shells.size()), shell_links, arrangement_cells); + compute_arrangement_cells(shells.size(), shell_links, arrangement_cells); } } - shell_to_cell.resize(shells.size()); - for (uint32_t i = 0; i < arrangement_cells.size(); i++) { - for (auto shell : arrangement_cells[i]) shell_to_cell[shell] = i; - } + shell_to_cell.resize(arrangement_cells.size()); + arrangement_cells.foreach ([&shell_to_cell](uint32_t cell_index, uint32_t _, uint32_t shell_index) { + shell_to_cell[shell_index] = cell_index; + }); } // post process diff --git a/shared_module/xmake.lua b/shared_module/xmake.lua index 0e5c828..3c39255 100644 --- a/shared_module/xmake.lua +++ b/shared_module/xmake.lua @@ -1,4 +1,4 @@ -add_requires("mimalloc-adjust") +add_requires("mimalloc", {configs = {shared = false}}) add_requires("parallel-hashmap") add_requires("range-v3") add_requires("eigen-latest") @@ -8,6 +8,6 @@ add_requires("xxhash") target("shared_module") set_kind("headeronly") add_includedirs("./", {public = true}) - add_packages("mimalloc-adjust", "parallel-hashmap", "range-v3", "eigen-latest", "xxhash", {public = true}) + add_packages("mimalloc", "parallel-hashmap", "range-v3", "eigen-latest", "xxhash", {public = true}) add_rules("library.force.distribute.header", {headers = path.join(os.scriptdir(), "math", "math_defs.h")}) target_end() \ No newline at end of file