diff --git a/network_process/interface/fwd_types.hpp b/network_process/interface/fwd_types.hpp index 9639bca..1dcf575 100644 --- a/network_process/interface/fwd_types.hpp +++ b/network_process/interface/fwd_types.hpp @@ -206,6 +206,17 @@ struct polygon_face_t { // ============================================================================== +// each active subface should have one structure as below +struct parametric_plane { + stl_vector_mp chain_vertices{}; + flat_index_group chains{}; + stl_vector_mp singularity_vertices{}; // i.e. intersection of chains + stl_vector_mp polar_vertices{}; // i.e. min/max x/y around 2 connecting vertices + stl_vector_mp parallel_start_vertices{}; // i.e. edge {v, v + 1} is parallel to x/y axis +}; + +// ============================================================================== + namespace std { template <> diff --git a/network_process/interface/process.hpp b/network_process/interface/process.hpp index cd54347..5efbbd3 100644 --- a/network_process/interface/process.hpp +++ b/network_process/interface/process.hpp @@ -4,15 +4,6 @@ #include "settings.h" -// each active subface should have one structure as below -struct parametric_plane { - stl_vector_mp chain_vertices{}; - flat_index_group chains{}; - stl_vector_mp singularity_vertices{}; // i.e. intersection of chains - stl_vector_mp polar_vertices{}; // i.e. min/max x/y around 2 connecting vertices - stl_vector_mp parallel_start_vertices{}; // i.e. edge {v, v + 1} is parallel to x/y axis -}; - ISNP_API void build_implicit_network_by_blobtree(const s_settings& settings, const baked_blobtree_t& tree, stl_vector_mp& output_vertices, diff --git a/network_process/src/post_topo/filter_polygon_faces.cpp b/network_process/src/post_topo/filter_polygon_faces.cpp index af9ec15..2653764 100644 --- a/network_process/src/post_topo/filter_polygon_faces.cpp +++ b/network_process/src/post_topo/filter_polygon_faces.cpp @@ -4,16 +4,15 @@ // =========================================================================================================== -void collect_active_prims(const flat_index_group& patches, - const flat_index_group& chain_of_patch, - const flat_index_group& arrangement_cells, +void collect_active_prims(const flat_index_group& patches, + const flat_index_group& chain_of_patch, + const flat_index_group& arrangement_cells, const stl_vector_mp& shell_of_half_patch, - const flat_index_group& shells, + const flat_index_group& shells, const stl_vector_mp& shell_to_cell, const dynamic_bitset_mp<>& active_cell_label, dynamic_bitset_mp<>& active_patch_label, - dynamic_bitset_mp<>& patch_sign_label, - dynamic_bitset_mp<>& active_chain_label) + dynamic_bitset_mp<>& patch_sign_label) { stl_vector_mp visited_cells(arrangement_cells.size(), false); std::queue Q{}; @@ -36,10 +35,6 @@ void collect_active_prims(const flat_index_group& patches, active_patch_label[patch_index].flip(); patch_sign_label[patch_index] = ((half_patch_index & 1) == 0); - chain_of_patch.loop_on_group(patch_index, [&](uint32_t _, uint32_t chain_index) { - active_chain_label[chain_index].set(); - }); - auto oppose_cell = shell_to_cell[shell_of_half_patch[(half_patch_index & 1) == 1 ? (half_patch_index + 1) : (half_patch_index - 1)]]; if (active_cell_label[oppose_cell] && !visited_cells[oppose_cell]) Q.emplace(oppose_cell); @@ -49,89 +44,140 @@ void collect_active_prims(const flat_index_group& patches, } } -// =========================================================================================================== - -dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, - const flat_index_group& patches, - const flat_index_group& arrangement_cells, - const stl_vector_mp& shell_of_half_patch, - const flat_index_group& shells, - const stl_vector_mp& shell_to_cell, - const dynamic_bitset_mp<>& active_cell_label, - stl_vector_mp& output_polygon_faces, - stl_vector_mp& output_vertex_counts_of_face) +void transfer_active_prims(const stl_vector_mp& faces, + const flat_index_group& patches, + const flat_index_group& chain_of_patch, + const dynamic_bitset_mp<>& active_patch_label, + const dynamic_bitset_mp<>& patch_sign_label, + stl_vector_mp& output_polygon_faces, + stl_vector_mp& output_vertex_counts_of_face, + stl_vector_mp& output_parametric_planes) { - dynamic_bitset_mp<> active_face_label(faces.size(), false); - dynamic_bitset_mp<> active_patch_label(patches.size(), false); - dynamic_bitset_mp<> patch_sign_label(patches.size(), false); - output_polygon_faces.reserve(faces.size() * 3); - output_vertex_counts_of_face.reserve(faces.size()); + auto active_patch_index = active_patch_label.find_first(); + if (active_patch_index != dynamic_bitset_mp<>::npos) { + do { + // NOTE: since patch inside the sdf should be oriented counterclockwise when viewed from inside + // i.e. it is viewed to be clockwise when viewed from outside + // so we need to flip its vertex order here + // NOTE: as for the integral, surface integral is always positive so we just add them up + // however for the partial volume integral, the right one should be corresponding to the normal which + // points outside. Here's a simple prove that the partial volume integral always have right sign: If the + // surface is outside (i.e. counterclockwise), then it is obviously right; If the surface is inside + // (i.e. clockwise), then its normal should point to the other side of that surface, which is the + // outside of that surface, so it is also right + if (!patch_sign_label[active_patch_index]) { + patches.loop_on_group(active_patch_index, [&](uint32_t _, uint32_t face_index) { + const auto& face_vertices = faces[face_index].vertex_indices; + output_vertex_counts_of_face.emplace_back(face_vertices.size()); + output_polygon_faces.insert(output_polygon_faces.end(), + std::make_move_iterator(face_vertices.rbegin()), + std::make_move_iterator(face_vertices.rend())); + }); + } else { + patches.loop_on_group(active_patch_index, [&](uint32_t _, uint32_t face_index) { + const auto& face_vertices = faces[face_index].vertex_indices; + output_vertex_counts_of_face.emplace_back(face_vertices.size()); + output_polygon_faces.insert(output_polygon_faces.end(), + std::make_move_iterator(face_vertices.begin()), + std::make_move_iterator(face_vertices.end())); + }); + } - stl_vector_mp visited_cells(arrangement_cells.size(), false); - std::queue Q{}; - for (uint32_t i = 0; i < arrangement_cells.size(); ++i) { - if (active_cell_label[i]) { - Q.emplace(i); - break; - } - } - while (!Q.empty()) { - const auto cell_index = Q.front(); - Q.pop(); + chain_of_patch.loop_on_group(active_patch_index, + [&](uint32_t _, uint32_t chain_index) { active_chain_label[chain_index].set(); }); - if (!visited_cells[cell_index] && active_cell_label[cell_index]) { - visited_cells[cell_index] = true; - arrangement_cells.loop_on_group(cell_index, [&](uint32_t _, uint32_t shell_index) { - // it is secured that one shell cell cannot have a pair of half patches with same patch index - shells.loop_on_group(shell_index, [&](uint32_t _, uint32_t half_patch_index) { - bool sign = (half_patch_index % 2 == 0) ? 0 : 1; - auto oppose_cell = - shell_to_cell[shell_of_half_patch[!sign ? (half_patch_index + 1) : (half_patch_index - 1)]]; - - // iff not interior patch, we do surface propagation - if (!active_cell_label[oppose_cell]) { - // NOTE: since patch inside the sdf should be oriented counterclockwise when viewed from inside - // i.e. it is viewed to be clockwise when viewed from outside - // so we need to flip its vertex order here - // NOTE: as for the integral, surface integral is always positive so we just add them up - // however for the partial volume integral, the right one should be corresponding to the normal which - // points outside. Here's a simple prove that the partial volume integral always have right sign: If the - // surface is outside (i.e. counterclockwise), then it is obviously right; If the surface is inside - // (i.e. clockwise), then its normal should point to the other side of that surface, which is the - // outside of that surface, so it is also right - if (!sign) { - patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { - active_face_label[face_index] = true; - const auto& face_vertices = faces[face_index].vertex_indices; - output_vertex_counts_of_face.emplace_back(face_vertices.size()); - output_polygon_faces.insert(output_polygon_faces.end(), - std::make_move_iterator(face_vertices.rbegin()), - std::make_move_iterator(face_vertices.rend())); - }); - } else { - patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { - active_face_label[face_index] = true; - const auto& face_vertices = faces[face_index].vertex_indices; - output_vertex_counts_of_face.emplace_back(face_vertices.size()); - output_polygon_faces.insert(output_polygon_faces.end(), - std::make_move_iterator(face_vertices.begin()), - std::make_move_iterator(face_vertices.end())); - }); - } - } else if (!visited_cells[oppose_cell]) { - // active and not visited cell, enqueue it - Q.emplace(oppose_cell); - } - }); - }); - } + active_patch_index = active_patch_label.find_next(active_patch_index); + } while (active_patch_index != dynamic_bitset_mp<>::npos); } output_polygon_faces.shrink_to_fit(); output_vertex_counts_of_face.shrink_to_fit(); - return active_face_label; } +// =========================================================================================================== + +// dynamic_bitset_mp<> filter_polygon_faces(const stl_vector_mp& faces, +// const flat_index_group& patches, +// const flat_index_group& arrangement_cells, +// const stl_vector_mp& shell_of_half_patch, +// const flat_index_group& shells, +// const stl_vector_mp& shell_to_cell, +// const dynamic_bitset_mp<>& active_cell_label, +// stl_vector_mp& output_polygon_faces, +// stl_vector_mp& output_vertex_counts_of_face) +// { +// dynamic_bitset_mp<> active_face_label(faces.size(), false); +// dynamic_bitset_mp<> active_patch_label(patches.size(), false); +// dynamic_bitset_mp<> patch_sign_label(patches.size(), false); +// output_polygon_faces.reserve(faces.size() * 3); +// output_vertex_counts_of_face.reserve(faces.size()); + +// stl_vector_mp visited_cells(arrangement_cells.size(), false); +// std::queue Q{}; +// for (uint32_t i = 0; i < arrangement_cells.size(); ++i) { +// if (active_cell_label[i]) { +// Q.emplace(i); +// break; +// } +// } +// while (!Q.empty()) { +// const auto cell_index = Q.front(); +// Q.pop(); + +// if (!visited_cells[cell_index] && active_cell_label[cell_index]) { +// visited_cells[cell_index] = true; +// arrangement_cells.loop_on_group(cell_index, [&](uint32_t _, uint32_t shell_index) { +// // it is secured that one shell cell cannot have a pair of half patches with same patch index +// shells.loop_on_group(shell_index, [&](uint32_t _, uint32_t half_patch_index) { +// bool sign = (half_patch_index % 2 == 0) ? 0 : 1; +// auto oppose_cell = +// shell_to_cell[shell_of_half_patch[!sign ? (half_patch_index + 1) : (half_patch_index - 1)]]; + +// // iff not interior patch, we do surface propagation +// if (!active_cell_label[oppose_cell]) { +// // NOTE: since patch inside the sdf should be oriented counterclockwise when viewed from inside +// // i.e. it is viewed to be clockwise when viewed from outside +// // so we need to flip its vertex order here +// // NOTE: as for the integral, surface integral is always positive so we just add them up +// // however for the partial volume integral, the right one should be corresponding to the normal which +// // points outside. Here's a simple prove that the partial volume integral always have right sign: If +// the +// // surface is outside (i.e. counterclockwise), then it is obviously right; If the surface is inside +// // (i.e. clockwise), then its normal should point to the other side of that surface, which is the +// // outside of that surface, so it is also right +// if (!sign) { +// patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { +// active_face_label[face_index] = true; +// const auto& face_vertices = faces[face_index].vertex_indices; +// output_vertex_counts_of_face.emplace_back(face_vertices.size()); +// output_polygon_faces.insert(output_polygon_faces.end(), +// std::make_move_iterator(face_vertices.rbegin()), +// std::make_move_iterator(face_vertices.rend())); +// }); +// } else { +// patches.loop_on_group(half_patch_index / 2, [&](uint32_t _, uint32_t face_index) { +// active_face_label[face_index] = true; +// const auto& face_vertices = faces[face_index].vertex_indices; +// output_vertex_counts_of_face.emplace_back(face_vertices.size()); +// output_polygon_faces.insert(output_polygon_faces.end(), +// std::make_move_iterator(face_vertices.begin()), +// std::make_move_iterator(face_vertices.end())); +// }); +// } +// } else if (!visited_cells[oppose_cell]) { +// // active and not visited cell, enqueue it +// Q.emplace(oppose_cell); +// } +// }); +// }); +// } +// } + +// output_polygon_faces.shrink_to_fit(); +// output_vertex_counts_of_face.shrink_to_fit(); +// return active_face_label; +// } + void filter_active_vertices(stl_vector_mp& vertices, stl_vector_mp& output_polygon_faces) { stl_vector_mp unique_vertex_indices{};