diff --git a/network_process/include/connect_by_topo/pair_faces.hpp b/network_process/include/connect_by_topo/pair_faces.hpp index 6c6c36f..0a3f668 100644 --- a/network_process/include/connect_by_topo/pair_faces.hpp +++ b/network_process/include/connect_by_topo/pair_faces.hpp @@ -8,7 +8,7 @@ // output: // half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 void compute_patch_order(const stl_vector_mp> &tetrahedrons, - const iso_edge_t &iso_edge, + const chain_header_t &iso_edge, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, const stl_vector_mp &tetrahedron_arrangements, @@ -22,7 +22,7 @@ void compute_patch_order(const stl_vector_mp> // half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, const stl_vector_mp &iso_faces, - const iso_edge_t &iso_edge, + const chain_header_t &iso_edge, const stl_vector_mp &patch_of_face_mapping, stl_vector_mp> &half_patch_adj_list); @@ -31,7 +31,7 @@ void pair_patches_in_one_tet(const arrangement_t &tet_cut_res void pair_patches_in_tets(const stl_vector_mp &containing_simplex, const stl_vector_mp &containing_tetIds, const stl_vector_mp> &tetrahedrons, - const iso_edge_t &iso_edge, + const chain_header_t &iso_edge, const stl_vector_mp &iso_faces, const stl_vector_mp &tetrahedron_arrangements, const stl_vector_mp &tetrahedron_active_subface_start_index, diff --git a/network_process/include/connect_by_topo/patch_connectivity.hpp b/network_process/include/connect_by_topo/patch_connectivity.hpp index 2e12f90..af17617 100644 --- a/network_process/include/connect_by_topo/patch_connectivity.hpp +++ b/network_process/include/connect_by_topo/patch_connectivity.hpp @@ -6,11 +6,11 @@ * @brief Compute iso-edges and edge-face connectivity * @param[in] patch_faces Patch faces taken from the kernel * @param[out] edges_of_face A list of face edges containing global edge index - * @param[out] patch_edges Edges of the patch; containing two vertices, global face index, and local edge index + * @param[out] patch_edges Edges of the patch; containing two vertices, global face index */ -void compute_patch_edges(const stl_vector_mp &patch_faces, - stl_vector_mp> &edges_of_face, - stl_vector_mp &patch_edges); +void compute_patch_edges(const stl_vector_mp &patch_faces, + stl_vector_mp> &edges_of_face, + flat_hash_map_mp &patch_edges); /** * @brief Group `iso_faces` into patches @@ -18,26 +18,30 @@ 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 map: face index --> patch index + * @param[out] patch_boundary_edges the set of boundary edges of the patches */ -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, - stl_vector_mp &patch_of_face_mapping); +void compute_patches(const stl_vector_mp> &edges_of_face, + const flat_hash_map_mp &patch_edges, + const stl_vector_mp &patch_faces, + stl_vector_mp> &patches, + stl_vector_mp &patch_of_face_mapping, + flat_hash_set_mp &patch_boundary_edges); /** * @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] chain_vertices the list of chains which contain a list of vertices' indices. + * @param[out] chain_edge_headers the list of chains' edge headers which contain a list of infos. * @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> &chain_vertices, - stl_vector_mp &chain_headers, - flat_hash_map_mp> &chain_of_mid_face); +void compute_chains(const flat_hash_map_mp &patch_edges, + const flat_hash_set_mp &patch_boundary_edges, + const stl_vector_mp &iso_faces, + stl_vector_mp> &chain_vertices, + stl_vector_mp &chain_edge_headers, + stl_vector_mp &chain_headers); /** * @brief compute shells and connected components of isosurfaces, and build maps: half-patch --> shell, patch --> component diff --git a/network_process/include/post_topo/chain_post_processing.hpp b/network_process/include/post_topo/chain_post_processing.hpp index 8db189d..632f9af 100644 --- a/network_process/include/post_topo/chain_post_processing.hpp +++ b/network_process/include/post_topo/chain_post_processing.hpp @@ -9,7 +9,7 @@ struct parametric_plane_t; 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, + const stl_vector_mp& chain_edge_headers, flat_hash_map_mp>& chain_of_patch); // return: is chain end vertices signular dynamic_bitset_mp<> identify_chain_signular(const stl_vector_mp& faces, @@ -23,7 +23,9 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& const stl_vector_mp& faces, const stl_vector_mp>& patches, const stl_vector_mp>& chains, + const stl_vector_mp& chain_edge_headers, 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 + flat_hash_map_mp& parameteric_planes); +void remap_parameteric_plane_vertices(flat_hash_map_mp& parameteric_planes); \ No newline at end of file diff --git a/network_process/interface/fwd_types.hpp b/network_process/interface/fwd_types.hpp index dbb6be1..9e52f7e 100644 --- a/network_process/interface/fwd_types.hpp +++ b/network_process/interface/fwd_types.hpp @@ -119,16 +119,34 @@ static void compute_iso_face_key(const stl_vector_mp& face_verts, pod_ // ============================================================================== +// struct edge_header_t { +// uint32_t face_index{}; /// face index in the global list of faces +// uint32_t local_edge_index{}; /// edge index in the face +// }; + +// /// Edge of the isosurface +// struct iso_edge_t { +// /// Two end-vertics' indices +// uint32_t v1{}, v2{}; +// stl_vector_mp headers{}; +// }; + +struct edge_key_t { + uint32_t v1{}, v2{}; +}; + struct edge_header_t { - uint32_t face_index{}; /// face index in the global list of faces - uint32_t local_edge_index{}; /// edge index in the face + stl_vector_mp face_indices{}; }; -/// Edge of the isosurface -struct iso_edge_t { - /// Two end-vertics' indices - uint32_t v1{}, v2{}; - stl_vector_mp headers{}; +struct boundary_edge_header_t { + stl_vector_mp subface_indices{}; +}; + +struct chain_header_t { + uint32_t v1{}, v2{}; + stl_vector_mp face_indices{}; + stl_vector_mp volume_indices{}; }; // ============================================================================== @@ -169,8 +187,8 @@ struct hash { }; template <> -struct hash { - size_t operator()(const edge_header_t& e) const { return XXH3_64bits(&e, sizeof(edge_header_t)); } +struct hash { + size_t operator()(const edge_key_t& e) const { return XXH3_64bits(&e, sizeof(edge_key_t)); } }; template @@ -196,11 +214,8 @@ struct equal_to { }; template <> -struct equal_to { - bool operator()(const edge_header_t& e1, const edge_header_t& e2) const - { - return e1.face_index == e2.face_index && e1.local_edge_index == e2.local_edge_index; - } +struct equal_to { + bool operator()(const edge_key_t& e1, const edge_key_t& e2) const { return e1.v1 == e2.v1 && e1.v2 == e2.v2; } }; template diff --git a/network_process/interface/process.hpp b/network_process/interface/process.hpp index e9d8111..bbd2701 100644 --- a/network_process/interface/process.hpp +++ b/network_process/interface/process.hpp @@ -4,13 +4,17 @@ #include "settings.h" -struct parametric_plane_t { +struct parameteric_plane_t { + /// plane associated properties + Eigen::AlignedBox2d uv_bounds{}; /// chain associated properties stl_vector_mp> chain_vertices{}; // 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{}; + // the other subface index (except the subface of the parameteric plane) of the chain + stl_vector_mp chain_other_subface_indices{}; /// chain group (by neighboring patch) associated properties stl_vector_mp> chain_group_indices{}; }; diff --git a/network_process/src/connect_by_topo/pair_faces.cpp b/network_process/src/connect_by_topo/pair_faces.cpp index ac22818..2b4b244 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 chain_header_t &character_edge, const stl_vector_mp &iso_verts, const stl_vector_mp &iso_faces, const stl_vector_mp &tetrahedron_arrangements, @@ -11,25 +11,25 @@ void compute_patch_order(const stl_vector_mp> const stl_vector_mp &patch_of_face_mapping, stl_vector_mp> &half_patch_adj_list) { - // collect all iso-faces incident to the iso-edge - const auto &face_edge_indices = iso_edge.headers; - // collect all tets containing the incident iso-faces - flat_hash_set_mp containing_tets{}; - for (const auto &face_edge : face_edge_indices) { - for (const auto &tetrahedron : iso_faces[face_edge.face_index].headers) - containing_tets.emplace(tetrahedron.volume_index); - } + // // collect all iso-faces incident to the iso-edge + // const auto &face_edge_indices = character_edge.headers; + // // collect all tets containing the incident iso-faces + // flat_hash_set_mp containing_tets{}; + // for (const auto &face_edge : face_edge_indices) { + // for (const auto &tetrahedron : iso_faces[face_edge.face_index].headers) + // containing_tets.emplace(tetrahedron.volume_index); + // } // pair faces - if (containing_tets.size() == 1) { - auto tet_id = *containing_tets.begin(); + if (character_edge.volume_indices.size() == 1) { + auto tet_id = character_edge.volume_indices.front(); pair_patches_in_one_tet(tetrahedron_arrangements[tet_id], iso_faces, - iso_edge, + character_edge, patch_of_face_mapping, half_patch_adj_list); } else { - const auto v1 = iso_edge.v1; - const auto v2 = iso_edge.v2; + const auto v1 = character_edge.v1; + const auto v2 = character_edge.v2; const auto &iso_v1 = iso_verts[v1]; const auto &iso_v2 = iso_verts[v2]; bool on_tet_edge = false; @@ -55,7 +55,7 @@ void compute_patch_order(const stl_vector_mp> on_tet_edge = (vId1 == iso_v2.simplex_vertex_indices[0] && vId2 == iso_v2.simplex_vertex_indices[1]); } if (on_tet_edge) { - // iso_edge lies on tet edge (vId1, vId2) + // character_edge lies on tet edge (vId1, vId2) // tet vertices vId1, vId2 must be degenerate vertices // find all tets incident to edge (vId1, vId2) const auto &tet_ids = zero_vertex_to_incident_tet_mapping.at(vId1); @@ -68,7 +68,7 @@ void compute_patch_order(const stl_vector_mp> pair_patches_in_tets({vId1, vId2}, common_tetIds, tetrahedrons, - iso_edge, + character_edge, iso_faces, tetrahedron_arrangements, tetrahedron_active_subface_start_index, @@ -76,12 +76,10 @@ void compute_patch_order(const stl_vector_mp> patch_of_face_mapping, half_patch_adj_list); } else { - // iso_edge lies on a tet boundary face + // character_edge lies on a tet boundary face // assert: containing_tets.size() == 2 - auto iter = containing_tets.begin(); - const auto tet_id1 = *iter; - std::advance(iter, containing_tets.size() - 1); - const auto tet_id2 = *iter; + const auto tet_id1 = character_edge.volume_indices.front(); + const auto tet_id2 = character_edge.volume_indices.back(); flat_hash_set_mp tet1_vIds(tetrahedrons[tet_id1].begin(), tetrahedrons[tet_id1].end()); stl_vector_mp common_vIds{}; common_vIds.reserve(3); @@ -92,7 +90,7 @@ void compute_patch_order(const stl_vector_mp> pair_patches_in_tets(common_vIds, {tet_id1, tet_id2}, tetrahedrons, - iso_edge, + character_edge, iso_faces, tetrahedron_arrangements, tetrahedron_active_subface_start_index, @@ -108,16 +106,15 @@ void compute_patch_order(const stl_vector_mp> // half-patch adjacency list : (patch i, 1) <--> 2i, (patch i, -1) <--> 2i+1 void pair_patches_in_one_tet(const arrangement_t &tet_cut_result, const stl_vector_mp &iso_faces, - const iso_edge_t &iso_edge, + const chain_header_t &character_edge, const stl_vector_mp &patch_of_face_mapping, stl_vector_mp> &half_patch_adj_list) { - // find tet faces that are incident to the iso_edge + // find tet faces that are incident to the character_edge stl_vector_mp is_incident_faces(tet_cut_result.faces.size(), false); // map: tet face id --> iso face id stl_vector_mp iso_face_Id_of_face(tet_cut_result.faces.size(), invalid_index); - for (const auto &fId_eId_pair : iso_edge.headers) { - const auto iso_face_id = fId_eId_pair.face_index; + for (const auto &iso_face_id : character_edge.face_indices) { const auto face_id = iso_faces[iso_face_id].headers[0].local_face_index; is_incident_faces[face_id] = true; iso_face_Id_of_face[face_id] = iso_face_id; @@ -179,17 +176,14 @@ void pair_patches_in_one_tet(const arrangement_t &tet_cut_res } }; + const auto character_face_index = character_edge.face_indices.front(); // start from the first incident face, and travel to its positive cell - travel_info_t info1{iso_edge.headers[0].face_index, - iso_faces[iso_edge.headers[0].face_index].headers[0].local_face_index, - 1}; + travel_info_t info1{character_face_index, iso_faces[character_face_index].headers[0].local_face_index, 1}; travel_info_t info2{}; auto cell_id = tet_cut_result.faces[info1.face_id].positive_cell; travel_func(cell_id, info1, info2); // travel in a different direction - info1 = {iso_edge.headers[0].face_index, // - iso_faces[iso_edge.headers[0].face_index].headers[0].local_face_index, // - -1}; + info1 = {character_face_index, iso_faces[character_face_index].headers[0].local_face_index, -1}; info2.clear(); cell_id = tet_cut_result.faces[info1.face_id].negative_cell; travel_func(cell_id, info1, info2); @@ -201,7 +195,7 @@ void pair_patches_in_one_tet(const arrangement_t &tet_cut_res void pair_patches_in_tets(const stl_vector_mp &containing_simplex, const stl_vector_mp &containing_tetIds, const stl_vector_mp> &tetrahedrons, - const iso_edge_t &iso_edge, + const chain_header_t &character_edge, const stl_vector_mp &iso_faces, const stl_vector_mp &tetrahedron_arrangements, const stl_vector_mp &tetrahedron_active_subface_start_index, @@ -213,14 +207,14 @@ void pair_patches_in_tets(const stl_vector_mp &containi // collect all iso-faces incident to the iso-edge // map: (tet_id, tet_face_id) -> iso_face_id flat_hash_map_mp iso_face_Id_of_face{}; - for (const auto &[iso_face_id, _] : iso_edge.headers) { + for (const auto &iso_face_id : character_edge.face_indices) { for (const auto &t : iso_faces[iso_face_id].headers) { iso_face_Id_of_face[t] = iso_face_id; } } // find identical tet boundary planes incident to iso-edge // map: (tet_Id, tet_plane_Id) -> (oppo_tet_Id, oppo_tet_plane_Id) flat_hash_map_mp identical_tet_planes{}; if (containing_simplex.size() == 3) { - // iso_edge contained in a tet boundary triangle + // character_edge contained in a tet boundary triangle const auto vId1 = containing_simplex[0]; const auto vId2 = containing_simplex[1]; const auto vId3 = containing_simplex[2]; @@ -248,7 +242,7 @@ void pair_patches_in_tets(const stl_vector_mp &containi identical_tet_planes[{tId1, pId1}] = {tId2, pId2}; identical_tet_planes[{tId2, pId2}] = {tId1, pId1}; } else { - // iso_edge contained in a tet edge + // character_edge contained in a tet edge uint32_t vId1 = containing_simplex[0]; uint32_t vId2 = containing_simplex[1]; flat_hash_map_mp, face_header_t> tet_plane_of_tri{}; @@ -459,7 +453,7 @@ void pair_patches_in_tets(const stl_vector_mp &containi //// face pairing algorithm - const auto iso_face_0 = iso_edge.headers[0].face_index; + const auto iso_face_0 = character_edge.face_indices.front(); // pair (tet_id, tet_face_id) auto face_curr = iso_faces[iso_face_0].headers[0]; int8_t orient_curr = 1; // orientation: 1 for Positive, -1 for Negative diff --git a/network_process/src/connect_by_topo/patch_connectivity.cpp b/network_process/src/connect_by_topo/patch_connectivity.cpp index 5237215..bd2e75e 100644 --- a/network_process/src/connect_by_topo/patch_connectivity.cpp +++ b/network_process/src/connect_by_topo/patch_connectivity.cpp @@ -3,9 +3,9 @@ #include -void compute_patch_edges(const stl_vector_mp& patch_faces, - stl_vector_mp>& edges_of_face, - stl_vector_mp& patch_edges) +void compute_patch_edges(const stl_vector_mp& patch_faces, + stl_vector_mp>& edges_of_face, + flat_hash_map_mp& patch_edges) { uint32_t max_num_edge = 0; for (const auto& iso_face : patch_faces) { max_num_edge += static_cast(iso_face.vertex_indices.size()); } @@ -24,29 +24,29 @@ void compute_patch_edges(const stl_vector_mp& patch_faces, auto v2 = face.vertex_indices[(j + 1) % num_edge]; // swap if v1 > v2 if (v1 > v2) std::swap(v1, v2); - // - num_iso_edge = static_cast(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(edge_header_t{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(edge_header_t{i, j}); - face_edges[j] = eId; - } + patch_edges[{v1, v2}].face_indices.emplace_back(i); + face_edges[j] = {v1, v2}; + // // + // num_iso_edge = static_cast(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 + // patch_edges[{v1, v2}].face_indices.emplace_back(i); + // face_edges[j] = {v1, v2}; + // } else { // existing iso-edge + // uint32_t eId = iter_inserted.first->second; + // patch_edges[eId].headers.emplace_back(edge_header_t{i, j}); + // face_edges[j] = {v1, v2}; + // } } } } -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, - stl_vector_mp& patch_of_face_mapping) +void compute_patches(const stl_vector_mp>& edges_of_face, + const flat_hash_map_mp& patch_edges, + const stl_vector_mp& patch_faces, + stl_vector_mp>& patches, + stl_vector_mp& patch_of_face_mapping, + flat_hash_set_mp& patch_boundary_edges) { stl_vector_mp visited_face(edges_of_face.size(), false); for (uint32_t i = 0; i < edges_of_face.size(); i++) { @@ -63,16 +63,18 @@ void compute_patches(const stl_vector_mp>& edges_of_face 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; + const auto& edge_header = patch_edges.at(eId); + if (edge_header.face_indices.size() == 2) { // manifold edge + const auto other_fId = + (edge_header.face_indices[0] == fId) ? edge_header.face_indices[1] : edge_header.face_indices[0]; if (!visited_face[other_fId]) { Q.emplace(other_fId); patch.emplace_back(other_fId); patch_of_face_mapping[other_fId] = patch_id; visited_face[other_fId] = true; } + } else if (edge_header.face_indices.size() > 2) { // non-manifold edge + patch_boundary_edges.emplace(eId); } } } @@ -80,57 +82,71 @@ void compute_patches(const stl_vector_mp>& edges_of_face } } -void compute_chains(size_t iso_vert_count, - stl_vector_mp& patch_edges, +void compute_chains(const flat_hash_map_mp& patch_edges, + const flat_hash_set_mp& patch_boundary_edges, + const stl_vector_mp& iso_faces, stl_vector_mp>& chain_vertices, - stl_vector_mp& chain_headers, - flat_hash_map_mp>& chain_of_mid_face) + stl_vector_mp& chain_edge_headers, + stl_vector_mp& chain_headers) { - stl_vector_mp> non_manifold_edges_of_vert{}; - stl_vector_mp non_manifold_edges{}; - non_manifold_edges_of_vert.resize(iso_vert_count); - non_manifold_edges.reserve(patch_edges.size() / 2); + flat_hash_map_mp> non_manifold_edges_of_vert{}; + non_manifold_edges_of_vert.reserve(patch_boundary_edges.size() / 2); // get incident non-manifold edges for iso-vertices - for (uint32_t i = 0; i < patch_edges.size(); i++) { - if (patch_edges[i].headers.size() > 2) { // non-manifold edge (not a boundary edge) - // there is only one patch incident to a boundary edge, so there is no need to figure out the "order" of patches - // around a boundary edge - non_manifold_edges_of_vert[patch_edges[i].v1].emplace_back(i); - non_manifold_edges_of_vert[patch_edges[i].v2].emplace_back(i); - non_manifold_edges.emplace_back(i); - } + for (const auto& eId : patch_boundary_edges) { + // there is only one patch incident to a boundary edge, so there is no need to figure out the "order" of patches + // around a boundary edge + non_manifold_edges_of_vert[eId.v1].emplace_back(eId.v2); + non_manifold_edges_of_vert[eId.v2].emplace_back(eId.v1); } - stl_vector_mp visited_edge(patch_edges.size(), false); + flat_hash_map_mp visited_edge{}; + visited_edge.reserve(patch_boundary_edges.size()); stl_list_mp chain{}; - for (const auto& i : non_manifold_edges) { - if (!visited_edge[i]) { + for (const auto& start_eId : patch_boundary_edges) { + if (!visited_edge[start_eId]) { // unvisited non-manifold iso-edge (not a boundary edge) // new chain - auto& new_chain_vertices = chain_vertices.emplace_back(); - auto& new_chain_headers = chain_headers.emplace_back(); + auto& new_chain_vertices = chain_vertices.emplace_back(); + auto& new_chain_headers = chain_headers.emplace_back(); + auto& new_chain_edge_headers = chain_edge_headers.emplace_back(); chain.clear(); - std::queue Q{}; - Q.emplace(i); - chain.emplace_back(patch_edges[i].v1); - chain.emplace_back(patch_edges[i].v2); - new_chain_headers = patch_edges[i]; - visited_edge[i] = true; + new_chain_headers.v1 = start_eId.v1; + new_chain_headers.v2 = start_eId.v2; + new_chain_headers.face_indices = std::move(patch_edges.at(start_eId).face_indices); + flat_hash_set_mp unique_volume_indices{}; + new_chain_edge_headers.subface_indices.reserve(new_chain_headers.face_indices.size()); + for (const auto& face_index : new_chain_headers.face_indices) { + std::transform(iso_faces[face_index].headers.begin(), + iso_faces[face_index].headers.end(), + std::back_inserter(unique_volume_indices), + [](const face_header_t& header) { return header.volume_index; }); + new_chain_edge_headers.subface_indices.emplace_back(iso_faces[face_index].subface_index); + } + std::move(unique_volume_indices.begin(), + unique_volume_indices.end(), + std::back_inserter(new_chain_headers.volume_indices)); + new_chain_edge_headers.subface_indices.shrink_to_fit(); + + std::queue Q{}; + Q.emplace(start_eId); + chain.emplace_back(start_eId.v1); + chain.emplace_back(start_eId.v2); + visited_edge[start_eId] = true; while (!Q.empty()) { const auto eId = Q.front(); Q.pop(); + const auto v1 = eId.v1; + const auto v2 = eId.v2; // 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]; - const auto other_vId = - (patch_edges[other_eId].v1 == v) ? patch_edges[other_eId].v2 : patch_edges[other_eId].v1; + if (non_manifold_edges_of_vert[v1].size() == 2) { + const auto other_vId = (non_manifold_edges_of_vert[v1][0] == v2) ? non_manifold_edges_of_vert[v1][1] + : non_manifold_edges_of_vert[v1][0]; + const edge_key_t other_eId = v1 < other_vId ? edge_key_t{v1, other_vId} : edge_key_t{other_vId, v1}; if (!visited_edge[other_eId]) { Q.emplace(other_eId); visited_edge[other_eId] = true; - if (v == chain.front()) { + if (v1 == chain.front()) { chain.emplace_front(other_vId); } else { chain.emplace_back(other_vId); @@ -138,16 +154,14 @@ void compute_chains(size_t iso_ver } } // 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]; - const auto other_vId = - (patch_edges[other_eId].v1 == v) ? patch_edges[other_eId].v2 : patch_edges[other_eId].v1; + if (non_manifold_edges_of_vert[v2].size() == 2) { + const auto other_vId = (non_manifold_edges_of_vert[v2][0] == v1) ? non_manifold_edges_of_vert[v2][1] + : non_manifold_edges_of_vert[v2][0]; + const edge_key_t other_eId = v2 < other_vId ? edge_key_t{v2, other_vId} : edge_key_t{other_vId, v2}; if (!visited_edge[other_eId]) { Q.emplace(other_eId); visited_edge[other_eId] = true; - if (v == chain.front()) { + if (v2 == chain.front()) { chain.emplace_front(other_vId); } else { chain.emplace_back(other_vId); @@ -157,43 +171,43 @@ void compute_chains(size_t iso_ver } 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); - } + // 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(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)); - } + // 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 index 01014c0..703bb97 100644 --- a/network_process/src/post_topo/filter_chains.cpp +++ b/network_process/src/post_topo/filter_chains.cpp @@ -3,7 +3,7 @@ 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, + const stl_vector_mp& chain_edge_headers, flat_hash_map_mp>& chain_of_patch) { flat_hash_map_mp> filtered_chain_of_patch{}; @@ -16,16 +16,11 @@ dynamic_bitset_mp<> filter_chains(const stl_vector_mp& } } - dynamic_bitset_mp<> active_chain_label(chain_size); + dynamic_bitset_mp<> active_chain_label(chain_edge_headers.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; + // valid chain should only have 2 indent subfaces + if (patch_indices.size() > 2 && chain_edge_headers[chain_index].subface_indices.size() == 2) label = true; } stl_vector_mp temp_filtered_chain_indices{}; diff --git a/network_process/src/post_topo/map_chains.cpp b/network_process/src/post_topo/map_chains.cpp index ba0713e..9416c99 100644 --- a/network_process/src/post_topo/map_chains.cpp +++ b/network_process/src/post_topo/map_chains.cpp @@ -6,6 +6,7 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& const stl_vector_mp& faces, const stl_vector_mp>& patches, const stl_vector_mp>& chains, + const stl_vector_mp& chain_edge_headers, 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, @@ -22,12 +23,13 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& flat_hash_map_mp old_chain_index_to_unique_index{}; auto unique_end_iter = unique_chain_indices.begin(); for (const auto& [subface_index, patch_indices] : patch_of_subface) { - const auto& subface = subfaces[subface_index].object_ptr.get(); - 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_indices = parameteric_plane.chain_group_indices; - auto& chain_vertex_flags = parameteric_plane.vertex_special_flags; + const auto& subface = subfaces[subface_index].object_ptr.get(); + 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_indices = parameteric_plane.chain_group_indices; + auto& chain_vertex_flags = parameteric_plane.vertex_special_flags; + auto& chain_other_subface_indices = parameteric_plane.chain_other_subface_indices; chain_group_indices.reserve(patch_indices.size()); unique_chain_indices.clear(); @@ -41,8 +43,10 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& for (auto iter = unique_chain_indices.begin(); iter != unique_end_iter; ++iter) old_chain_index_to_unique_index[*iter] = std::distance(unique_chain_indices.begin(), iter); - chain_vertices.reserve(unique_chain_indices.size()); - chain_vertex_flags.reserve(unique_chain_indices.size()); + const auto unique_chain_count = std::distance(unique_chain_indices.begin(), unique_end_iter); + chain_vertices.reserve(unique_chain_count); + chain_vertex_flags.reserve(unique_chain_count); + chain_other_subface_indices.reserve(unique_chain_count); for (const auto& chain_index : unique_chain_indices) { const auto& chain = chains[chain_index]; @@ -57,6 +61,8 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& 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]; + + chain_other_subface_indices.emplace_back(chain_edge_headers[chain_index].subface_indices); } for (const auto& patch_index : patch_indices) { @@ -68,4 +74,22 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t& [&](uint32_t chain_index) { return old_chain_index_to_unique_index[chain_index]; }); } } +} + +void remap_parameteric_plane_vertices(flat_hash_map_mp& parameteric_planes) +{ + for (auto& [_, parameteric_plane] : parameteric_planes) { + auto& uv_bounds = parameteric_plane.uv_bounds; + for (auto& chain_vertices : parameteric_plane.chain_vertices) { + for (auto& vertex : chain_vertices) uv_bounds = uv_bounds.extend(vertex); + } + assert(uv_bounds.sizes().minCoeff() > epsilon); + const auto uv_bounds_rpc = uv_bounds.sizes().cwiseInverse().array(); + for (auto& chain_vertices : parameteric_plane.chain_vertices) { + std::transform(chain_vertices.begin(), + chain_vertices.end(), + chain_vertices.begin(), + [&](const Eigen::Vector2d& uv) { return (uv - uv_bounds.min()).array() * uv_bounds_rpc; }); + } + } } \ No newline at end of file diff --git a/network_process/src/process.cpp b/network_process/src/process.cpp index 756fd26..d5f09d0 100644 --- a/network_process/src/process.cpp +++ b/network_process/src/process.cpp @@ -5,7 +5,7 @@ #include #include - +#include "post_topo/chain_post_processing.hpp" void export_halfpatch_obj( const stl_vector_mp& iso_pts, @@ -166,38 +166,37 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& stl_vector_mp> components{}; stl_vector_mp> arrangement_cells{}; stl_vector_mp shell_to_cell{}; + stl_vector_mp chain_edge_headers{}; { - stl_vector_mp chain_headers{}; + stl_vector_mp> half_patch_adj_list(2 * patches.size()); { - 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, chain_vertices, chain_headers, chain_of_mid_face); - export_halfpatch_obj(iso_pts, iso_faces, patches, "halfpatch_before_connect"); - for (auto &subface : tree.subfaces) { - std::cout << subface.object_ptr->data_center << std::endl; - } - 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 chain_headers{}; + { + stl_vector_mp> edges_of_iso_face{}; + flat_hash_map_mp iso_edges{}; + flat_hash_set_mp boundary_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, boundary_edges); + compute_chains(iso_edges, boundary_edges, iso_faces, chain_vertices, chain_edge_headers, chain_headers); + for (size_t i = 0; i < chain_headers.size(); ++i) { + for (const auto& face_index : chain_headers[i].face_indices) { + chain_of_patch[patch_of_face[face_index]].emplace_back(static_cast(i)); + } + } + // should we take unique part of chain_of_patch? } + for (size_t i = 0; i < chain_headers.size(); ++i) + compute_patch_order(tetrahedrons, + chain_headers[i], + iso_verts, + iso_faces, + tetrahedron_arrangements, + tetrahedron_active_subface_start_index, + active_subface_indices, + zero_vertex_to_incident_tet_mapping, + patch_of_face, + half_patch_adj_list); } - stl_vector_mp> half_patch_adj_list(2 * patches.size()); - for (size_t i = 0; i < chain_headers.size(); ++i) - compute_patch_order(tetrahedrons, - chain_headers[i], - iso_verts, - iso_faces, - tetrahedron_arrangements, - tetrahedron_active_subface_start_index, - active_subface_indices, - 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 @@ -262,7 +261,7 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& 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); + filter_chains(iso_faces, patches, active_patch_label, chain_edge_headers, 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, @@ -270,11 +269,13 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings& iso_faces, patches, chain_vertices, + chain_edge_headers, chain_of_patch, vertex_old_index_to_unique_index, is_chain_end_vertices_signular, output_parameteric_planes); identify_chain_near_parallel(output_parameteric_planes); + remap_parameteric_plane_vertices(output_parameteric_planes); } } export_halfpatch_obj(iso_pts, iso_faces, patches, "halfpatch_final");