From ac6f039f1773767447428c9c7c3a4462cf5e35e0 Mon Sep 17 00:00:00 2001 From: Zhicheng Wang <1627343141@qq.com> Date: Fri, 3 Oct 2025 18:23:43 +0800 Subject: [PATCH] first valid version of chain post processing --- .../connect_by_topo/patch_connectivity.hpp | 12 ++- network_process/include/post_topo.hpp | 3 +- .../post_topo/chain_post_processing.hpp | 29 +++++++ .../post_topo/filter_polygon_faces.hpp | 9 +- network_process/interface/process.hpp | 20 +++-- .../src/connect_by_topo/pair_faces.cpp | 2 +- .../connect_by_topo/patch_connectivity.cpp | 78 +++++++++++++++-- .../src/post_topo/filter_chains.cpp | 43 ++++++++++ .../src/post_topo/filter_polygon_faces.cpp | 39 ++++----- .../post_topo/identify_chain_properties.cpp | 77 +++++++++++++++++ network_process/src/post_topo/map_chains.cpp | 53 ++++++++++++ network_process/src/process.cpp | 86 ++++++++++++------- primitive_process/interface/base/subface.hpp | 1 + .../subface/simple/cylinder_face.hpp | 1 + .../interface/subface/simple/plane.hpp | 1 + .../interface/subface/simple/sphere_face.hpp | 1 + .../src/subface/simple/cylinder_face.cpp | 10 +++ .../src/subface/simple/plane.cpp | 10 +++ .../src/subface/simple/sphere_face.cpp | 12 +++ .../container/wrapper/flat_index_group.hpp | 39 +++++++++ 20 files changed, 451 insertions(+), 75 deletions(-) create mode 100644 network_process/include/post_topo/chain_post_processing.hpp create mode 100644 network_process/src/post_topo/filter_chains.cpp create mode 100644 network_process/src/post_topo/identify_chain_properties.cpp create mode 100644 network_process/src/post_topo/map_chains.cpp create mode 100644 shared_module/container/wrapper/flat_index_group.hpp diff --git a/network_process/include/connect_by_topo/patch_connectivity.hpp b/network_process/include/connect_by_topo/patch_connectivity.hpp index 7ab198c..2e12f90 100644 --- a/network_process/include/connect_by_topo/patch_connectivity.hpp +++ b/network_process/include/connect_by_topo/patch_connectivity.hpp @@ -29,11 +29,15 @@ void compute_patches(const stl_vector_mp> &edges_of_face * @brief Group non-manifold iso-edges into chains * @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] chain_vertices the list of chains which contain a list of vertices' indices. + * @param[out] chain_headers the list of chains' headers which contain a list of infos. + * @param[out] chain_of_mid_face map: face index --> list of chain indices (the chain passes through the face) */ -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, + stl_vector_mp> &chain_vertices, + stl_vector_mp &chain_headers, + flat_hash_map_mp> &chain_of_mid_face); /** * @brief compute shells and connected components of isosurfaces, and build maps: half-patch --> shell, patch --> component diff --git a/network_process/include/post_topo.hpp b/network_process/include/post_topo.hpp index 058adfe..1e0f78f 100644 --- a/network_process/include/post_topo.hpp +++ b/network_process/include/post_topo.hpp @@ -1,4 +1,5 @@ #pragma once #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/network_process/include/post_topo/chain_post_processing.hpp b/network_process/include/post_topo/chain_post_processing.hpp new file mode 100644 index 0000000..cb5b967 --- /dev/null +++ b/network_process/include/post_topo/chain_post_processing.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +struct baked_blobtree_t; +struct parameteric_plane_t; + +// return: active chain label +dynamic_bitset_mp<> filter_chains(const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const dynamic_bitset_mp<>& active_patch_label, + size_t chain_size, + flat_hash_map_mp>& chain_of_patch); +// return: is chain end vertices signular +dynamic_bitset_mp<> identify_chain_signular(const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const stl_vector_mp>& chains, + const flat_hash_map_mp>& chain_of_patch, + size_t chain_size); +void identify_chain_near_parallel(flat_hash_map_mp& parameteric_planes); +void map_chain_to_parameteric_plane(const baked_blobtree_t& tree, + const stl_vector_mp& vertices, + const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const stl_vector_mp>& chains, + const flat_hash_map_mp>& chain_of_patch, + const flat_hash_map_mp& vertex_old_index_to_unique_index, + const dynamic_bitset_mp<>& chain_end_vertex_signular_flag, + flat_hash_map_mp& parameteric_planes); \ 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 f6a73ad..ef8fedf 100644 --- a/network_process/include/post_topo/filter_polygon_faces.hpp +++ b/network_process/include/post_topo/filter_polygon_faces.hpp @@ -2,7 +2,7 @@ #include -// return: active face label +// return: active patch label dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, const stl_vector_mp>& patches, const stl_vector_mp>& arrangement_cells, @@ -13,6 +13,7 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& stl_vector_mp& output_polygon_faces, stl_vector_mp& output_vertex_counts_of_face); -void filter_active_vertices(stl_vector_mp& iso_pts, - stl_vector_mp& vertices, - stl_vector_mp& output_polygon_faces); \ No newline at end of file +void calculate_vertex_mapping(stl_vector_mp& iso_pts, + stl_vector_mp& output_vertices, + stl_vector_mp& output_polygon_faces, + flat_hash_map_mp& vertex_old_index_to_unique_index); \ No newline at end of file diff --git a/network_process/interface/process.hpp b/network_process/interface/process.hpp index 5efbbd3..1ca8fab 100644 --- a/network_process/interface/process.hpp +++ b/network_process/interface/process.hpp @@ -4,8 +4,18 @@ #include "settings.h" -ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, - const baked_blobtree_t& tree, - stl_vector_mp& output_vertices, - stl_vector_mp& output_polygon_faces, - stl_vector_mp& output_vertex_counts_of_face); \ No newline at end of file +struct parameteric_plane_t { + stl_vector_mp> chain_vertices{}; + stl_vector_mp chain_group_start_indices{}; + // iff start/end vertex, then this is signular or not; else this is polar or not + stl_vector_mp> vertex_special_flags{}; + // format: total length is N - 1, and i identifies whether edge [i, i+1) is near parallel or not + stl_vector_mp> edge_near_parallel_flags{}; +}; + +ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, + const baked_blobtree_t& tree, + stl_vector_mp& output_vertices, + stl_vector_mp& output_polygon_faces, + stl_vector_mp& output_vertex_counts_of_face, + flat_hash_map_mp& output_parameteric_planes); \ No newline at end of file diff --git a/network_process/src/connect_by_topo/pair_faces.cpp b/network_process/src/connect_by_topo/pair_faces.cpp index ac22818..d70b471 100644 --- a/network_process/src/connect_by_topo/pair_faces.cpp +++ b/network_process/src/connect_by_topo/pair_faces.cpp @@ -1,7 +1,7 @@ #include void compute_patch_order(const stl_vector_mp> &tetrahedrons, - const iso_edge_t &iso_edge, + const stl_vector_mp &iso_edge, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, const stl_vector_mp &tetrahedron_arrangements, diff --git a/network_process/src/connect_by_topo/patch_connectivity.cpp b/network_process/src/connect_by_topo/patch_connectivity.cpp index 7039186..5237215 100644 --- a/network_process/src/connect_by_topo/patch_connectivity.cpp +++ b/network_process/src/connect_by_topo/patch_connectivity.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -79,9 +80,11 @@ void compute_patches(const stl_vector_mp>& edges_of_face } } -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, + stl_vector_mp>& chain_vertices, + stl_vector_mp& chain_headers, + flat_hash_map_mp>& chain_of_mid_face) { stl_vector_mp> non_manifold_edges_of_vert{}; stl_vector_mp non_manifold_edges{}; @@ -98,16 +101,22 @@ void compute_chains(size_t iso_vert_count, } } - stl_vector_mp visited_edge(patch_edges.size(), false); + stl_vector_mp visited_edge(patch_edges.size(), false); + stl_list_mp chain{}; 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(); + auto& new_chain_vertices = chain_vertices.emplace_back(); + auto& new_chain_headers = chain_headers.emplace_back(); + chain.clear(); + std::queue Q{}; Q.emplace(i); - chain.emplace_back(std::move(patch_edges[i])); - visited_edge[i] = true; + chain.emplace_back(patch_edges[i].v1); + chain.emplace_back(patch_edges[i].v2); + new_chain_headers = patch_edges[i]; + visited_edge[i] = true; while (!Q.empty()) { const auto eId = Q.front(); Q.pop(); @@ -116,10 +125,16 @@ 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]; + const auto other_vId = + (patch_edges[other_eId].v1 == v) ? patch_edges[other_eId].v2 : patch_edges[other_eId].v1; if (!visited_edge[other_eId]) { Q.emplace(other_eId); - chain.emplace_back(std::move(patch_edges[other_eId])); visited_edge[other_eId] = true; + if (v == chain.front()) { + chain.emplace_front(other_vId); + } else { + chain.emplace_back(other_vId); + } } } // v2 @@ -127,13 +142,58 @@ 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]; + const auto other_vId = + (patch_edges[other_eId].v1 == v) ? patch_edges[other_eId].v2 : patch_edges[other_eId].v1; if (!visited_edge[other_eId]) { Q.emplace(other_eId); - chain.emplace_back(std::move(patch_edges[other_eId])); visited_edge[other_eId] = true; + if (v == chain.front()) { + chain.emplace_front(other_vId); + } else { + chain.emplace_back(other_vId); + } } } } + + new_chain_vertices.insert(new_chain_vertices.end(), chain.begin(), chain.end()); + if (new_chain_vertices.size() > 2) { + const auto mid_vert = *(new_chain_vertices.begin() + 1); + stl_vector_mp face_indices{}; + face_indices.reserve(non_manifold_edges_of_vert[mid_vert].size() * 2); + for (const auto& eId : non_manifold_edges_of_vert[mid_vert]) { + for (const auto& header : patch_edges[eId].headers) face_indices.emplace_back(header.face_index); + } + + std::sort(face_indices.begin(), face_indices.end()); + auto iter = std::unique(face_indices.begin(), face_indices.end()); + for (auto it = face_indices.begin(); it != iter; ++it) + chain_of_mid_face[*it].emplace_back(static_cast(chain_vertices.size() - 1)); + } else { + stl_vector_mp start_face_indices{}; + stl_vector_mp end_face_indices{}; + start_face_indices.reserve(non_manifold_edges_of_vert[new_chain_vertices.front()].size() * 2); + end_face_indices.reserve(non_manifold_edges_of_vert[new_chain_vertices.back()].size() * 2); + for (const auto& eId : non_manifold_edges_of_vert[new_chain_vertices.front()]) { + for (const auto& header : patch_edges[eId].headers) start_face_indices.emplace_back(header.face_index); + } + for (const auto& eId : non_manifold_edges_of_vert[new_chain_vertices.back()]) { + for (const auto& header : patch_edges[eId].headers) end_face_indices.emplace_back(header.face_index); + } + + std::sort(start_face_indices.begin(), start_face_indices.end()); + std::sort(end_face_indices.begin(), end_face_indices.end()); + auto iter_start = std::unique(start_face_indices.begin(), start_face_indices.end()); + auto iter_end = std::unique(end_face_indices.begin(), end_face_indices.end()); + stl_vector_mp unique_face_indices{}; + std::set_intersection(start_face_indices.begin(), + iter_start, + end_face_indices.begin(), + iter_end, + std::back_inserter(unique_face_indices)); + for (auto it = unique_face_indices.begin(); it != unique_face_indices.end(); ++it) + chain_of_mid_face[*it].emplace_back(static_cast(chain_vertices.size() - 1)); + } } } } diff --git a/network_process/src/post_topo/filter_chains.cpp b/network_process/src/post_topo/filter_chains.cpp new file mode 100644 index 0000000..01014c0 --- /dev/null +++ b/network_process/src/post_topo/filter_chains.cpp @@ -0,0 +1,43 @@ +#include + +dynamic_bitset_mp<> filter_chains(const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const dynamic_bitset_mp<>& active_patch_label, + size_t chain_size, + flat_hash_map_mp>& chain_of_patch) +{ + flat_hash_map_mp> filtered_chain_of_patch{}; + flat_hash_map_mp> active_prim_of_chain{}; + for (uint32_t i = 0; i < chain_of_patch.size(); ++i) { + if (active_patch_label[i]) { + auto& cIds_of_patch = filtered_chain_of_patch[i]; + cIds_of_patch = std::move(chain_of_patch.at(i)); + for (auto chain_index : cIds_of_patch) { active_prim_of_chain[chain_index].emplace_back(i); } + } + } + + dynamic_bitset_mp<> active_chain_label(chain_size); + for (auto& [chain_index, patch_indices] : active_prim_of_chain) { + auto label = active_chain_label[chain_index]; + if (patch_indices.size() > 2) label = true; + // transform patch index to subface index + for (auto& patch_index : patch_indices) patch_index = faces[patches[patch_index][0]].subface_index; + std::sort(patch_indices.begin(), patch_indices.end()); + auto iter = std::unique(patch_indices.begin(), patch_indices.end()); + // turn it off iff only one subface is incident + if (std::distance(patch_indices.begin(), iter) <= 1) label = false; + } + + stl_vector_mp temp_filtered_chain_indices{}; + chain_of_patch.clear(); + for (auto& [patch_index, chain_indices] : filtered_chain_of_patch) { + temp_filtered_chain_indices.clear(); + for (auto chain_index : chain_indices) { + if (active_chain_label[chain_index]) temp_filtered_chain_indices.emplace_back(chain_index); + } + temp_filtered_chain_indices.shrink_to_fit(); + if (!temp_filtered_chain_indices.empty()) chain_of_patch[patch_index] = std::move(temp_filtered_chain_indices); + } + + return active_chain_label; +} \ No newline at end of file diff --git a/network_process/src/post_topo/filter_polygon_faces.cpp b/network_process/src/post_topo/filter_polygon_faces.cpp index b84950e..28bf84c 100644 --- a/network_process/src/post_topo/filter_polygon_faces.cpp +++ b/network_process/src/post_topo/filter_polygon_faces.cpp @@ -12,7 +12,7 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& stl_vector_mp& output_polygon_faces, stl_vector_mp& output_vertex_counts_of_face) { - dynamic_bitset_mp<> active_face_label(faces.size(), false); + dynamic_bitset_mp<> active_patch_label(patches.size(), false); output_polygon_faces.reserve(faces.size() * 3); output_vertex_counts_of_face.reserve(faces.size()); @@ -37,6 +37,7 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& 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)]]; + active_patch_label[half_patch / 2] = true; // iff not interior patch, we do surface propagation if (!active_cell_label[oppose_cell]) { @@ -51,7 +52,6 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& // outside of that surface, so it is also right if (!sign) { for (const auto face_index : patches[half_patch / 2]) { - 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(), @@ -60,7 +60,6 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& } } else { for (const auto face_index : patches[half_patch / 2]) { - 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(), @@ -79,31 +78,27 @@ dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& output_polygon_faces.shrink_to_fit(); output_vertex_counts_of_face.shrink_to_fit(); - return active_face_label; + return active_patch_label; } -void filter_active_vertices(stl_vector_mp& iso_pts, - stl_vector_mp& output_vertices, - stl_vector_mp& output_polygon_faces) +void calculate_vertex_mapping(stl_vector_mp& iso_pts, + stl_vector_mp& output_vertices, + stl_vector_mp& output_polygon_faces, + flat_hash_map_mp& vertex_old_index_to_unique_index) { - stl_vector_mp unique_vertex_indices{}; - dynamic_bitset_mp<> vertex_visited(iso_pts.size(), false); - for (const auto& vertex_index : output_polygon_faces) { - if (!vertex_visited[vertex_index]) { - unique_vertex_indices.emplace_back(vertex_index); - vertex_visited[vertex_index] = true; - } - } + auto unique_vertex_indices = output_polygon_faces; + std::sort(unique_vertex_indices.begin(), unique_vertex_indices.end()); + auto iter = std::unique(unique_vertex_indices.begin(), unique_vertex_indices.end()); - flat_hash_map_mp vertex_old_index_to_unique_index{}; - for (uint32_t i = 0; i < unique_vertex_indices.size(); ++i) { - vertex_old_index_to_unique_index[unique_vertex_indices[i]] = i; + stl_vector_mp unique_vertices{}; + unique_vertices.reserve(unique_vertex_indices.size()); + for (uint32_t i = 0; i < std::distance(unique_vertex_indices.begin(), iter); ++i) { + auto vertex_index = unique_vertex_indices[i]; + vertex_old_index_to_unique_index[vertex_index] = i; + unique_vertices.emplace_back(iso_pts[vertex_index]); } - for (auto& vertex_index : output_polygon_faces) { vertex_index = vertex_old_index_to_unique_index[vertex_index]; } + for (auto& vertex_index : output_polygon_faces) vertex_index = vertex_old_index_to_unique_index[vertex_index]; - stl_vector_mp unique_vertices{}; - unique_vertices.reserve(unique_vertex_indices.size()); - for (const auto& vertex_index : unique_vertex_indices) { unique_vertices.emplace_back(iso_pts[vertex_index]); } std::swap(output_vertices, unique_vertices); } \ No newline at end of file diff --git a/network_process/src/post_topo/identify_chain_properties.cpp b/network_process/src/post_topo/identify_chain_properties.cpp new file mode 100644 index 0000000..da976bc --- /dev/null +++ b/network_process/src/post_topo/identify_chain_properties.cpp @@ -0,0 +1,77 @@ +#include +#include + +dynamic_bitset_mp<> identify_chain_signular(const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const stl_vector_mp>& chains, + const flat_hash_map_mp>& chain_of_patch, + size_t chain_size) +{ + dynamic_bitset_mp<> chain_end_vertex_signular_flag(chain_size * 2); + + flat_hash_map_mp> vertex_subface_indices{}; + flat_hash_map_mp> start_vertex_to_chain_indices{}; + flat_hash_map_mp> end_vertex_to_chain_indices{}; + for (const auto& [patch_index, chain_indices] : chain_of_patch) { + const auto subface_index = faces[patches[patch_index][0]].subface_index; + for (const auto& face_index : patches[patch_index]) { + const auto& face = faces[face_index]; + for (const auto& vertex_index : face.vertex_indices) { + for (const auto& chain_index : chain_indices) { + const auto start_vertex = chains[chain_index].front(); + const auto end_vertex = chains[chain_index].back(); + if (vertex_index == start_vertex) { + vertex_subface_indices[vertex_index].emplace(subface_index); + start_vertex_to_chain_indices[vertex_index].emplace_back(chain_index); + break; + } else if (vertex_index == end_vertex) { + vertex_subface_indices[vertex_index].emplace(subface_index); + end_vertex_to_chain_indices[vertex_index].emplace_back(chain_index); + break; + } + } + } + } + } + for (const auto& [vertex_index, subface_set] : vertex_subface_indices) { + if (subface_set.size() >= 3) { + if (auto iter = start_vertex_to_chain_indices.find(vertex_index); iter != start_vertex_to_chain_indices.end()) { + for (const auto& chain_index : iter->second) chain_end_vertex_signular_flag[chain_index * 2] = true; + } + if (auto iter = end_vertex_to_chain_indices.find(vertex_index); iter != end_vertex_to_chain_indices.end()) { + for (const auto& chain_index : iter->second) chain_end_vertex_signular_flag[chain_index * 2 + 1] = true; + } + } + } + + return chain_end_vertex_signular_flag; +} + +void identify_chain_near_parallel(flat_hash_map_mp& parameteric_planes) +{ + for (auto& [_, parameteric_plane] : parameteric_planes) { + parameteric_plane.edge_near_parallel_flags.reserve(parameteric_plane.chain_vertices.size()); + for (size_t i = 0; i < parameteric_plane.chain_vertices.size(); ++i) { + const auto& vertices = parameteric_plane.chain_vertices[i]; + auto& vertex_flags = parameteric_plane.vertex_special_flags[i]; + auto& edge_flags = parameteric_plane.edge_near_parallel_flags.emplace_back(); + edge_flags.resize(vertices.size() - 1); + + // identify edge near parallel first + for (auto iter = vertices.begin(); iter != vertices.end() - 1; ++iter) { + if (std::abs(iter->x() - (iter + 1)->x()) <= epsilon || // + std::abs(iter->y() - (iter + 1)->y()) <= epsilon) + edge_flags[std::distance(vertices.begin(), iter)] = true; + } + + // then identify polar vertex + if (vertices.size() >= 3) { + for (auto iter = vertices.begin() + 1; iter != vertices.end() - 1; ++iter) { + auto vec1 = *iter - *(iter - 1); + auto vec2 = *(iter + 1) - *iter; + if (vec1.dot(vec2) < 0) vertex_flags[std::distance(vertices.begin(), iter)] = true; + } + } + } + } +} \ No newline at end of file diff --git a/network_process/src/post_topo/map_chains.cpp b/network_process/src/post_topo/map_chains.cpp new file mode 100644 index 0000000..d2c6680 --- /dev/null +++ b/network_process/src/post_topo/map_chains.cpp @@ -0,0 +1,53 @@ +#include +#include + +void map_chain_to_parameteric_plane(const baked_blobtree_t& tree, + const stl_vector_mp& vertices, + const stl_vector_mp& faces, + const stl_vector_mp>& patches, + const stl_vector_mp>& chains, + const flat_hash_map_mp>& chain_of_patch, + const flat_hash_map_mp& vertex_old_index_to_unique_index, + const dynamic_bitset_mp<>& chain_end_vertex_signular_flag, + flat_hash_map_mp& parameteric_planes) +{ + flat_hash_map_mp> patch_of_subface{}; + for (const auto& [patch_index, _] : chain_of_patch) { + const auto& subface_index = faces[patches[patch_index][0]].subface_index; + patch_of_subface[subface_index].emplace_back(patch_index); + } + + const auto& subfaces = tree.subfaces; + for (const auto& [subface_index, patch_indices] : patch_of_subface) { + const auto& subface = *subfaces[subface_index].object_ptr; + auto mapping_func = subface.fetch_param_mapping_evaluator(); + auto& parameteric_plane = parameteric_planes[subface_index]; + auto& chain_vertices = parameteric_plane.chain_vertices; + auto& chain_group_start_indices = parameteric_plane.chain_group_start_indices; + auto& chain_vertex_flags = parameteric_plane.vertex_special_flags; + chain_group_start_indices.reserve(patch_indices.size()); + chain_group_start_indices.emplace_back(0); + + for (const auto& patch_index : patch_indices) { + const auto& chain_indices = chain_of_patch.at(patch_index); + chain_group_start_indices.emplace_back(chain_indices.size() + chain_group_start_indices.back()); + chain_vertices.reserve(chain_vertices.size() + chain_indices.size()); + chain_vertex_flags.reserve(chain_vertex_flags.size() + chain_indices.size()); + for (const auto& chain_index : chain_indices) { + const auto& chain = chains[chain_index]; + + auto& chain_vertices_ = chain_vertices.emplace_back(); + chain_vertices_.resize(chain.size()); + std::transform(chain.begin(), chain.end(), chain_vertices_.begin(), [&](uint32_t vertex_index) { + auto mapped_vertex_index = vertex_old_index_to_unique_index.at(vertex_index); + return mapping_func(vertices[mapped_vertex_index]); + }); + + auto& chain_vertex_flags_ = chain_vertex_flags.emplace_back(); + chain_vertex_flags_.resize(chain.size()); + chain_vertex_flags_[0] = chain_end_vertex_signular_flag[2 * chain_index]; + chain_vertex_flags_[chain.size() - 1] = chain_end_vertex_signular_flag[2 * chain_index + 1]; + } + } + } +} \ No newline at end of file diff --git a/network_process/src/process.cpp b/network_process/src/process.cpp index fa4ca85..6fa9ca8 100644 --- a/network_process/src/process.cpp +++ b/network_process/src/process.cpp @@ -4,11 +4,12 @@ #include #include -ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, - const baked_blobtree_t& tree, - stl_vector_mp& output_vertices, - stl_vector_mp& output_polygon_faces, - stl_vector_mp& output_vertex_counts_of_face) +ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, + const baked_blobtree_t& tree, + stl_vector_mp& output_vertices, + stl_vector_mp& output_polygon_faces, + stl_vector_mp& output_vertex_counts_of_face, + flat_hash_map_mp& output_parameteric_planes) { // load LUT for implicit arrangement load_lut(); @@ -71,27 +72,36 @@ 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{}; + stl_vector_mp patch_of_face(iso_faces.size()); + stl_vector_mp shell_of_half_patch{}; + stl_vector_mp component_of_patch{}; + flat_hash_map_mp> chain_of_patch{}; + stl_vector_mp> patches{}; + stl_vector_mp> chain_vertices{}; + stl_vector_mp> shells{}; + stl_vector_mp> components{}; + stl_vector_mp> arrangement_cells{}; + stl_vector_mp shell_to_cell{}; { + stl_vector_mp chain_headers{}; { - stl_vector_mp> edges_of_iso_face{}; - stl_vector_mp iso_edges{}; + stl_vector_mp> edges_of_iso_face{}; + flat_hash_map_mp> chain_of_mid_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, chain_vertices, chain_headers, chain_of_mid_face); + for (const auto& [face_index, chain_indices] : chain_of_mid_face) { + auto& chain_indices_ = chain_of_patch[patch_of_face[face_index]]; + chain_indices_ = std::move(chain_indices); + std::sort(chain_indices_.begin(), chain_indices_.end()); + chain_indices_.erase(std::unique(chain_indices_.begin(), chain_indices_.end()), chain_indices_.end()); + } } stl_vector_mp> half_patch_adj_list(2 * patches.size()); - for (size_t i = 0; i < chains.size(); ++i) + for (size_t i = 0; i < chain_headers.size(); ++i) compute_patch_order(tetrahedrons, - chains[i].front(), + chain_headers[i], iso_verts, iso_faces, tetrahedron_arrangements, @@ -150,16 +160,34 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& } active_cell_label = filter_cells_by_boolean(tree, cell_primitive_signs); } - filter_polygon_faces(iso_faces, - patches, - arrangement_cells, - shell_of_half_patch, - shells, - shell_to_cell, - active_cell_label, - output_polygon_faces, - output_vertex_counts_of_face); - filter_active_vertices(iso_pts, output_vertices, output_polygon_faces); + { + auto active_patch_label = filter_polygon_faces(iso_faces, + patches, + arrangement_cells, + shell_of_half_patch, + shells, + shell_to_cell, + active_cell_label, + output_polygon_faces, + output_vertex_counts_of_face); + flat_hash_map_mp vertex_old_index_to_unique_index{}; + calculate_vertex_mapping(iso_pts, output_vertices, output_polygon_faces, vertex_old_index_to_unique_index); + // chain postprocessing + auto active_chain_label = + filter_chains(iso_faces, patches, active_patch_label, chain_vertices.size(), chain_of_patch); + auto is_chain_end_vertices_signular = + identify_chain_signular(iso_faces, patches, chain_vertices, chain_of_patch, chain_vertices.size()); + map_chain_to_parameteric_plane(tree, + iso_pts, + iso_faces, + patches, + chain_vertices, + chain_of_patch, + vertex_old_index_to_unique_index, + is_chain_end_vertices_signular, + output_parameteric_planes); + identify_chain_near_parallel(output_parameteric_planes); + } } } } \ No newline at end of file diff --git a/primitive_process/interface/base/subface.hpp b/primitive_process/interface/base/subface.hpp index 4eb3df4..5b4228f 100644 --- a/primitive_process/interface/base/subface.hpp +++ b/primitive_process/interface/base/subface.hpp @@ -57,6 +57,7 @@ EXTERN_C struct PE_API subface { virtual std::function fetch_sdf_evaluator() const = 0; virtual std::function fetch_sdf_grad_evaluator() const = 0; virtual std::function fetch_point_by_param_evaluator() const = 0; + virtual std::function fetch_param_mapping_evaluator() const = 0; virtual std::function fetch_curve_constraint_evaluator( internal::parameter_u_t constraint_var_type, diff --git a/primitive_process/interface/subface/simple/cylinder_face.hpp b/primitive_process/interface/subface/simple/cylinder_face.hpp index 5f20cb4..675572d 100644 --- a/primitive_process/interface/subface/simple/cylinder_face.hpp +++ b/primitive_process/interface/subface/simple/cylinder_face.hpp @@ -15,6 +15,7 @@ struct cylinder_face_t final : subface { // u: planar angle from x-axis to z-axis // v: depth/height from xz-plane to y-axis std::function fetch_point_by_param_evaluator() const override; + std::function fetch_param_mapping_evaluator() const override; std::function fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const override; diff --git a/primitive_process/interface/subface/simple/plane.hpp b/primitive_process/interface/subface/simple/plane.hpp index f0b2d0c..84e0d36 100644 --- a/primitive_process/interface/subface/simple/plane.hpp +++ b/primitive_process/interface/subface/simple/plane.hpp @@ -15,6 +15,7 @@ struct plane_t final : subface { // u: planar local x-axis // v: planar local y-axis std::function fetch_point_by_param_evaluator() const override; + std::function fetch_param_mapping_evaluator() const override; std::function fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const override; diff --git a/primitive_process/interface/subface/simple/sphere_face.hpp b/primitive_process/interface/subface/simple/sphere_face.hpp index 60e4c9b..410a80f 100644 --- a/primitive_process/interface/subface/simple/sphere_face.hpp +++ b/primitive_process/interface/subface/simple/sphere_face.hpp @@ -15,6 +15,7 @@ struct sphere_face_t final : subface { // u: planar angle from x-axis to z-axis // v: polar angle from xz-plane to y-axis std::function fetch_point_by_param_evaluator() const override; + std::function fetch_param_mapping_evaluator() const override; std::function fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const override; diff --git a/primitive_process/src/subface/simple/cylinder_face.cpp b/primitive_process/src/subface/simple/cylinder_face.cpp index d243913..ff9cb4a 100644 --- a/primitive_process/src/subface/simple/cylinder_face.cpp +++ b/primitive_process/src/subface/simple/cylinder_face.cpp @@ -41,6 +41,16 @@ auto cylinder_face_t::fetch_point_by_param_evaluator() const -> std::functionraw_local_to_world())); } +auto cylinder_face_t::fetch_param_mapping_evaluator() const -> std::function +{ + auto functor = [](Eigen::Vector3d p, const transform_block* _world_to_local) { + Eigen::Vector4d local_p = *_world_to_local * Eigen::Vector4d{p.x(), p.y(), p.z(), 1.0}; + return Eigen::Vector2d(std::atan2(local_p.y(), local_p.x()), local_p.z()); + }; + + return std::bind(functor, std::placeholders::_1, &this->raw_world_to_local()); +} + auto cylinder_face_t::fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const -> std::function { diff --git a/primitive_process/src/subface/simple/plane.cpp b/primitive_process/src/subface/simple/plane.cpp index 79e3b68..469d7b9 100644 --- a/primitive_process/src/subface/simple/plane.cpp +++ b/primitive_process/src/subface/simple/plane.cpp @@ -30,6 +30,16 @@ auto plane_t::fetch_point_by_param_evaluator() const -> std::functionraw_local_to_world())); } +auto plane_t::fetch_param_mapping_evaluator() const -> std::function +{ + auto functor = [](Eigen::Vector3d p, const transform_block* _world_to_local) { + Eigen::Vector4d local_p = *_world_to_local * Eigen::Vector4d{p.x(), p.y(), p.z(), 1.0}; + return Eigen::Vector2d{local_p.y(), local_p.z()}; + }; + + return std::bind(functor, std::placeholders::_1, &this->raw_world_to_local()); +} + auto plane_t::fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const -> std::function { diff --git a/primitive_process/src/subface/simple/sphere_face.cpp b/primitive_process/src/subface/simple/sphere_face.cpp index 9e46996..68c528d 100644 --- a/primitive_process/src/subface/simple/sphere_face.cpp +++ b/primitive_process/src/subface/simple/sphere_face.cpp @@ -43,6 +43,18 @@ auto sphere_face_t::fetch_point_by_param_evaluator() const -> std::functionraw_local_to_world())); } +auto sphere_face_t::fetch_param_mapping_evaluator() const -> std::function +{ + auto functor = [](Eigen::Vector3d p, const transform_block* _world_to_local) { + Eigen::Vector4d local_p = (*_world_to_local * Eigen::Vector4d{p.x(), p.y(), p.z(), 1.0}).normalized(); + const auto u = std::atan2(local_p.z(), local_p.x()); + const auto v = std::asin(local_p.y()); + return Eigen::Vector2d{u, v}; + }; + + return std::bind(functor, std::placeholders::_1, &this->raw_world_to_local()); +} + auto sphere_face_t::fetch_curve_constraint_evaluator(parameter_u_t constraint_var_type, double u) const -> std::function { diff --git a/shared_module/container/wrapper/flat_index_group.hpp b/shared_module/container/wrapper/flat_index_group.hpp new file mode 100644 index 0000000..f9494d2 --- /dev/null +++ b/shared_module/container/wrapper/flat_index_group.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "../stl_alias.hpp" + +struct flat_index_group { + 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; } + + // f(group_index, element_index_in_group, elemenet) + 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]); + } + } + } + + // f(group_index, group_start_index, group_end_index) + 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]); + } + } + + // f(element_index_in_group, element) + 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