Browse Source

Merge branch 'V2-integral' into feat-integrator

feat-integrator
mckay 1 month ago
parent
commit
645d80d2a4
  1. 6
      network_process/include/connect_by_topo/pair_faces.hpp
  2. 34
      network_process/include/connect_by_topo/patch_connectivity.hpp
  3. 6
      network_process/include/post_topo/chain_post_processing.hpp
  4. 43
      network_process/interface/fwd_types.hpp
  5. 6
      network_process/interface/process.hpp
  6. 68
      network_process/src/connect_by_topo/pair_faces.cpp
  7. 218
      network_process/src/connect_by_topo/patch_connectivity.cpp
  8. 13
      network_process/src/post_topo/filter_chains.cpp
  9. 40
      network_process/src/post_topo/map_chains.cpp
  10. 61
      network_process/src/process.cpp

6
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<std::array<uint32_t, 4>> &tetrahedrons,
const iso_edge_t &iso_edge,
const chain_header_t &iso_edge,
const stl_vector_mp<iso_vertex_t> &iso_verts,
const stl_vector_mp<polygon_face_t> &iso_faces,
const stl_vector_mp<arrangement_t> &tetrahedron_arrangements,
@ -22,7 +22,7 @@ void compute_patch_order(const stl_vector_mp<std::array<uint32_t, 4>>
// 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<polygon_face_t> &iso_faces,
const iso_edge_t &iso_edge,
const chain_header_t &iso_edge,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<stl_vector_mp<uint32_t>> &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<uint32_t> &containing_simplex,
const stl_vector_mp<uint32_t> &containing_tetIds,
const stl_vector_mp<std::array<uint32_t, 4>> &tetrahedrons,
const iso_edge_t &iso_edge,
const chain_header_t &iso_edge,
const stl_vector_mp<polygon_face_t> &iso_faces,
const stl_vector_mp<arrangement_t> &tetrahedron_arrangements,
const stl_vector_mp<uint32_t> &tetrahedron_active_subface_start_index,

34
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<polygon_face_t> &patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>> &edges_of_face,
stl_vector_mp<iso_edge_t> &patch_edges);
void compute_patch_edges(const stl_vector_mp<polygon_face_t> &patch_faces,
stl_vector_mp<stl_vector_mp<edge_key_t>> &edges_of_face,
flat_hash_map_mp<edge_key_t, edge_header_t> &patch_edges);
/**
* @brief Group `iso_faces` into patches
@ -18,26 +18,30 @@ void compute_patch_edges(const stl_vector_mp<polygon_face_t> &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<stl_vector_mp<uint32_t>> &edges_of_face,
const stl_vector_mp<iso_edge_t> &patch_edges,
const stl_vector_mp<polygon_face_t> &patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>> &patches,
stl_vector_mp<uint32_t> &patch_of_face_mapping);
void compute_patches(const stl_vector_mp<stl_vector_mp<edge_key_t>> &edges_of_face,
const flat_hash_map_mp<edge_key_t, edge_header_t> &patch_edges,
const stl_vector_mp<polygon_face_t> &patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>> &patches,
stl_vector_mp<uint32_t> &patch_of_face_mapping,
flat_hash_set_mp<edge_key_t> &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<iso_edge_t> &patch_edges,
stl_vector_mp<stl_vector_mp<uint32_t>> &chain_vertices,
stl_vector_mp<iso_edge_t> &chain_headers,
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> &chain_of_mid_face);
void compute_chains(const flat_hash_map_mp<edge_key_t, edge_header_t> &patch_edges,
const flat_hash_set_mp<edge_key_t> &patch_boundary_edges,
const stl_vector_mp<polygon_face_t> &iso_faces,
stl_vector_mp<stl_vector_mp<uint32_t>> &chain_vertices,
stl_vector_mp<boundary_edge_header_t> &chain_edge_headers,
stl_vector_mp<chain_header_t> &chain_headers);
/**
* @brief compute shells and connected components of isosurfaces, and build maps: half-patch --> shell, patch --> component

6
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<polygon_face_t>& faces,
const stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
const dynamic_bitset_mp<>& active_patch_label,
size_t chain_size,
const stl_vector_mp<boundary_edge_header_t>& chain_edge_headers,
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>>& chain_of_patch);
// return: is chain end vertices signular
dynamic_bitset_mp<> identify_chain_signular(const stl_vector_mp<polygon_face_t>& faces,
@ -23,7 +23,9 @@ void map_chain_to_parameteric_plane(const baked_blobtree_t&
const stl_vector_mp<polygon_face_t>& faces,
const stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
const stl_vector_mp<stl_vector_mp<uint32_t>>& chains,
const stl_vector_mp<boundary_edge_header_t>& chain_edge_headers,
const flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>>& chain_of_patch,
const flat_hash_map_mp<uint32_t, uint32_t>& vertex_old_index_to_unique_index,
const dynamic_bitset_mp<>& chain_end_vertex_signular_flag,
flat_hash_map_mp<uint32_t, parametric_plane_t>& parameteric_planes);
flat_hash_map_mp<uint32_t, parameteric_plane_t>& parameteric_planes);
void remap_parameteric_plane_vertices(flat_hash_map_mp<uint32_t, parameteric_plane_t>& parameteric_planes);

43
network_process/interface/fwd_types.hpp

@ -119,16 +119,34 @@ static void compute_iso_face_key(const stl_vector_mp<uint32_t>& 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<edge_header_t> 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<uint32_t> face_indices{};
};
/// Edge of the isosurface
struct iso_edge_t {
/// Two end-vertics' indices
uint32_t v1{}, v2{};
stl_vector_mp<edge_header_t> headers{};
struct boundary_edge_header_t {
stl_vector_mp<uint32_t> subface_indices{};
};
struct chain_header_t {
uint32_t v1{}, v2{};
stl_vector_mp<uint32_t> face_indices{};
stl_vector_mp<uint32_t> volume_indices{};
};
// ==============================================================================
@ -169,8 +187,8 @@ struct hash<face_header_t> {
};
template <>
struct hash<edge_header_t> {
size_t operator()(const edge_header_t& e) const { return XXH3_64bits(&e, sizeof(edge_header_t)); }
struct hash<edge_key_t> {
size_t operator()(const edge_key_t& e) const { return XXH3_64bits(&e, sizeof(edge_key_t)); }
};
template <size_t N>
@ -196,11 +214,8 @@ struct equal_to<face_header_t> {
};
template <>
struct equal_to<edge_header_t> {
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<edge_key_t> {
bool operator()(const edge_key_t& e1, const edge_key_t& e2) const { return e1.v1 == e2.v1 && e1.v2 == e2.v2; }
};
template <size_t N>

6
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<stl_vector_mp<Eigen::Vector2d>> chain_vertices{};
// iff start/end vertex, then this is signular or not; else this is polar or not
stl_vector_mp<dynamic_bitset_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<dynamic_bitset_mp<>> edge_near_parallel_flags{};
// the other subface index (except the subface of the parameteric plane) of the chain
stl_vector_mp<uint32_t> chain_other_subface_indices{};
/// chain group (by neighboring patch) associated properties
stl_vector_mp<stl_vector_mp<uint16_t>> chain_group_indices{};
};

68
network_process/src/connect_by_topo/pair_faces.cpp

@ -1,7 +1,7 @@
#include <connect_by_topo.hpp>
void compute_patch_order(const stl_vector_mp<std::array<uint32_t, 4>> &tetrahedrons,
const iso_edge_t &iso_edge,
const chain_header_t &character_edge,
const stl_vector_mp<iso_vertex_t> &iso_verts,
const stl_vector_mp<polygon_face_t> &iso_faces,
const stl_vector_mp<arrangement_t> &tetrahedron_arrangements,
@ -11,25 +11,25 @@ void compute_patch_order(const stl_vector_mp<std::array<uint32_t, 4>>
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<stl_vector_mp<uint32_t>> &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<uint32_t> 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<uint32_t> 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<std::array<uint32_t, 4>>
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<std::array<uint32_t, 4>>
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<std::array<uint32_t, 4>>
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<uint32_t> tet1_vIds(tetrahedrons[tet_id1].begin(), tetrahedrons[tet_id1].end());
stl_vector_mp<uint32_t> common_vIds{};
common_vIds.reserve(3);
@ -92,7 +90,7 @@ void compute_patch_order(const stl_vector_mp<std::array<uint32_t, 4>>
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<std::array<uint32_t, 4>>
// 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<polygon_face_t> &iso_faces,
const iso_edge_t &iso_edge,
const chain_header_t &character_edge,
const stl_vector_mp<uint32_t> &patch_of_face_mapping,
stl_vector_mp<stl_vector_mp<uint32_t>> &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<bool> is_incident_faces(tet_cut_result.faces.size(), false);
// map: tet face id --> iso face id
stl_vector_mp<uint32_t> 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<uint32_t> &containing_simplex,
const stl_vector_mp<uint32_t> &containing_tetIds,
const stl_vector_mp<std::array<uint32_t, 4>> &tetrahedrons,
const iso_edge_t &iso_edge,
const chain_header_t &character_edge,
const stl_vector_mp<polygon_face_t> &iso_faces,
const stl_vector_mp<arrangement_t> &tetrahedron_arrangements,
const stl_vector_mp<uint32_t> &tetrahedron_active_subface_start_index,
@ -213,14 +207,14 @@ void pair_patches_in_tets(const stl_vector_mp<uint32_t> &containi
// collect all iso-faces incident to the iso-edge
// map: (tet_id, tet_face_id) -> iso_face_id
flat_hash_map_mp<face_header_t, uint32_t> 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<face_header_t, face_header_t> 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<uint32_t> &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<pod_key_t<3>, face_header_t> tet_plane_of_tri{};
@ -459,7 +453,7 @@ void pair_patches_in_tets(const stl_vector_mp<uint32_t> &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

218
network_process/src/connect_by_topo/patch_connectivity.cpp

@ -3,9 +3,9 @@
#include <connect_by_topo.hpp>
void compute_patch_edges(const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& edges_of_face,
stl_vector_mp<iso_edge_t>& patch_edges)
void compute_patch_edges(const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<edge_key_t>>& edges_of_face,
flat_hash_map_mp<edge_key_t, edge_header_t>& patch_edges)
{
uint32_t max_num_edge = 0;
for (const auto& iso_face : patch_faces) { max_num_edge += static_cast<uint32_t>(iso_face.vertex_indices.size()); }
@ -24,29 +24,29 @@ void compute_patch_edges(const stl_vector_mp<polygon_face_t>& 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<uint32_t>(patch_edges.size());
auto iter_inserted = edge_id.try_emplace(std::make_pair(v1, v2), num_iso_edge);
if (iter_inserted.second) { // new iso-edge
auto& edge = patch_edges.emplace_back();
edge.v1 = v1;
edge.v2 = v2;
edge.headers.emplace_back(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<uint32_t>(patch_edges.size());
// auto iter_inserted = edge_id.try_emplace(std::make_pair(v1, v2), num_iso_edge);
// if (iter_inserted.second) { // new iso-edge
// 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<stl_vector_mp<uint32_t>>& edges_of_face,
const stl_vector_mp<iso_edge_t>& patch_edges,
const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
stl_vector_mp<uint32_t>& patch_of_face_mapping)
void compute_patches(const stl_vector_mp<stl_vector_mp<edge_key_t>>& edges_of_face,
const flat_hash_map_mp<edge_key_t, edge_header_t>& patch_edges,
const stl_vector_mp<polygon_face_t>& patch_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
stl_vector_mp<uint32_t>& patch_of_face_mapping,
flat_hash_set_mp<edge_key_t>& patch_boundary_edges)
{
stl_vector_mp<bool> 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<stl_vector_mp<uint32_t>>& 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<stl_vector_mp<uint32_t>>& edges_of_face
}
}
void compute_chains(size_t iso_vert_count,
stl_vector_mp<iso_edge_t>& patch_edges,
void compute_chains(const flat_hash_map_mp<edge_key_t, edge_header_t>& patch_edges,
const flat_hash_set_mp<edge_key_t>& patch_boundary_edges,
const stl_vector_mp<polygon_face_t>& iso_faces,
stl_vector_mp<stl_vector_mp<uint32_t>>& chain_vertices,
stl_vector_mp<iso_edge_t>& chain_headers,
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>>& chain_of_mid_face)
stl_vector_mp<boundary_edge_header_t>& chain_edge_headers,
stl_vector_mp<chain_header_t>& chain_headers)
{
stl_vector_mp<stl_vector_mp<uint32_t>> non_manifold_edges_of_vert{};
stl_vector_mp<uint32_t> non_manifold_edges{};
non_manifold_edges_of_vert.resize(iso_vert_count);
non_manifold_edges.reserve(patch_edges.size() / 2);
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> 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<bool> visited_edge(patch_edges.size(), false);
flat_hash_map_mp<edge_key_t, bool> visited_edge{};
visited_edge.reserve(patch_boundary_edges.size());
stl_list_mp<uint32_t> 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<uint32_t> 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<uint32_t> 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<edge_key_t> 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<uint32_t> 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<uint32_t> 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<uint32_t>(chain_vertices.size() - 1));
} else {
stl_vector_mp<uint32_t> start_face_indices{};
stl_vector_mp<uint32_t> 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<uint32_t>(chain_vertices.size() - 1));
// } else {
// stl_vector_mp<uint32_t> start_face_indices{};
// stl_vector_mp<uint32_t> 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<uint32_t> 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<uint32_t>(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<uint32_t> 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<uint32_t>(chain_vertices.size() - 1));
// }
}
}
}

13
network_process/src/post_topo/filter_chains.cpp

@ -3,7 +3,7 @@
dynamic_bitset_mp<> filter_chains(const stl_vector_mp<polygon_face_t>& faces,
const stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
const dynamic_bitset_mp<>& active_patch_label,
size_t chain_size,
const stl_vector_mp<boundary_edge_header_t>& chain_edge_headers,
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>>& chain_of_patch)
{
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> filtered_chain_of_patch{};
@ -16,16 +16,11 @@ dynamic_bitset_mp<> filter_chains(const stl_vector_mp<polygon_face_t>&
}
}
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<uint32_t> temp_filtered_chain_indices{};

40
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<polygon_face_t>& faces,
const stl_vector_mp<stl_vector_mp<uint32_t>>& patches,
const stl_vector_mp<stl_vector_mp<uint32_t>>& chains,
const stl_vector_mp<boundary_edge_header_t>& chain_edge_headers,
const flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>>& chain_of_patch,
const flat_hash_map_mp<uint32_t, uint32_t>& 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<uint32_t, uint32_t> 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<uint32_t, parameteric_plane_t>& 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; });
}
}
}

61
network_process/src/process.cpp

@ -5,7 +5,7 @@
#include <post_topo.hpp>
#include <fstream>
#include "post_topo/chain_post_processing.hpp"
void export_halfpatch_obj(
const stl_vector_mp<Eigen::Vector3d>& iso_pts,
@ -166,38 +166,37 @@ ISNP_API void build_implicit_network_by_blobtree(const s_settings&
stl_vector_mp<stl_vector_mp<uint32_t>> components{};
stl_vector_mp<stl_vector_mp<uint32_t>> arrangement_cells{};
stl_vector_mp<uint32_t> shell_to_cell{};
stl_vector_mp<boundary_edge_header_t> chain_edge_headers{};
{
stl_vector_mp<iso_edge_t> chain_headers{};
stl_vector_mp<stl_vector_mp<uint32_t>> half_patch_adj_list(2 * patches.size());
{
stl_vector_mp<stl_vector_mp<uint32_t>> edges_of_iso_face{};
flat_hash_map_mp<uint32_t, stl_vector_mp<uint32_t>> chain_of_mid_face{};
stl_vector_mp<iso_edge_t> 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_header_t> chain_headers{};
{
stl_vector_mp<stl_vector_mp<edge_key_t>> edges_of_iso_face{};
flat_hash_map_mp<edge_key_t, edge_header_t> iso_edges{};
flat_hash_set_mp<edge_key_t> 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<uint32_t>(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<stl_vector_mp<uint32_t>> 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");

Loading…
Cancel
Save