extract explicit mesh with topology information from implicit surfaces with boolean operations, and do surface/volume integrating on them.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
14 KiB

#include <prim_gen.hpp>
#include <helper.hpp>
void extract_iso_mesh(const std::array<uint32_t, 3>& tet_active_subface_counts,
const stl_vector_mp<arrangement_t>& tetrahedron_arrangements,
const scene_bg_mesh_info_t& scene_bg_mesh_info,
const stl_vector_mp<std::array<uint32_t, 4>>& tetrahedrons,
const stl_vector_mp<uint32_t>& tetrahedron_active_subface_start_index,
const stl_vector_mp<uint32_t>& active_subface_indices,
const Eigen::MatrixXd& vertex_infos,
const flat_hash_map_mp<uint32_t, uint32_t>& vertex_indices_mapping,
stl_vector_mp<Eigen::Vector3d>& iso_pts,
stl_vector_mp<iso_vertex_t>& iso_verts,
stl_vector_mp<polygon_face_t>& iso_faces)
{
// estimate number of iso-verts and iso-faces
const auto& [num_1_func, num_2_func, num_more_func] = tet_active_subface_counts;
uint32_t max_num_face = num_1_func + 4 * num_2_func + 8 * num_more_func;
uint32_t max_num_vert = max_num_face;
iso_pts.reserve(max_num_vert);
iso_verts.reserve(max_num_vert);
iso_faces.reserve(max_num_face);
// hash table for vertices on the boundary of tetrahedron
flat_hash_map_mp<uint32_t, uint32_t> vert_on_tetVert{};
flat_hash_map_mp<pod_key_t<3>, uint32_t> vert_on_tetEdge{};
vert_on_tetEdge.reserve(num_1_func + 3 * num_2_func + num_more_func);
flat_hash_map_mp<pod_key_t<5>, uint32_t> vert_on_tetFace{};
vert_on_tetFace.reserve(num_2_func + 6 * num_more_func);
// hash table for faces on the boundary of tetrahedron
flat_hash_map_mp<pod_key_t<3>, uint32_t> face_on_tetFace{};
//
stl_vector_mp<bool> is_iso_vert{};
is_iso_vert.reserve(8);
stl_vector_mp<bool> is_iso_face{};
is_iso_face.reserve(9);
stl_vector_mp<uint32_t> iso_vId_of_vert{};
iso_vId_of_vert.reserve(8);
stl_vector_mp<uint32_t> face_verts{};
face_verts.reserve(4);
pod_key_t<3> key3;
pod_key_t<5> key5;
std::array<bool, 4> used_pId;
std::array<uint32_t, 2> vIds2;
std::array<uint32_t, 3> vIds3;
std::array<uint16_t, 3> implicit_pIds;
std::array<uint32_t, 3> boundary_pIds;
//
for (uint32_t i = 0; i < tetrahedrons.size(); i++) {
const auto& arrangement = tetrahedron_arrangements[i];
const auto& vertices = arrangement.vertices;
const auto& faces = arrangement.faces;
auto start_index = tetrahedron_active_subface_start_index[i];
// find vertices and faces on isosurface
is_iso_vert.assign(vertices.size(), false);
is_iso_face.clear();
is_iso_face.reserve(faces.size());
if (arrangement.unique_planes.empty()) { // all planes are unique
for (const auto& face : faces) {
is_iso_face.emplace_back(false);
if (face.supporting_plane > 3) { // plane 0,1,2,3 are tet boundaries
is_iso_face.back() = true;
for (const auto& vid : face.vertices) { is_iso_vert[vid] = true; }
}
}
} else {
for (const auto& face : faces) {
is_iso_face.emplace_back(false);
auto pid = face.supporting_plane;
auto uid = arrangement.unique_plane_indices[pid];
for (const auto& plane_id : arrangement.unique_planes[uid]) {
if (plane_id > 3) { // plane 0,1,2,3 are tet boundaries
is_iso_face.back() = true;
for (const auto& vid : face.vertices) { is_iso_vert[vid] = true; }
break;
}
}
}
}
// map: local vert index --> iso-vert index
iso_vId_of_vert.clear();
iso_vId_of_vert.reserve(vertices.size());
// create iso-vertices
for (uint32_t j = 0; j < vertices.size(); j++) {
iso_vId_of_vert.emplace_back(invalid_index);
if (is_iso_vert[j]) {
uint32_t num_boundary_planes = 0;
uint32_t num_impl_planes = 0;
for (const auto& vertex_plane : vertices[j]) {
if (vertex_plane >= 4) { // plane 0,1,2,3 are tet boundaries
implicit_pIds[num_impl_planes++] =
static_cast<uint16_t>(active_subface_indices[vertex_plane - 4 + start_index]);
} else {
boundary_pIds[num_boundary_planes++] = vertex_plane;
}
}
switch (num_boundary_planes) {
case 2: // on tet edge
{
used_pId.fill(false);
used_pId[boundary_pIds[0]] = true;
used_pId[boundary_pIds[1]] = true;
uint32_t num_vIds = 0;
for (uint32_t k = 0; k < 4; k++) {
if (!used_pId[k]) vIds2[num_vIds++] = tetrahedrons[i][k];
}
uint32_t vId1 = vIds2[0];
uint32_t vId2 = vIds2[1];
if (vId1 > vId2) std::swap(vId1, vId2);
key3 = {vId1, vId2, implicit_pIds[0]};
auto iter_inserted = vert_on_tetEdge.try_emplace(key3, static_cast<uint32_t>(iso_verts.size()));
if (iter_inserted.second) {
auto& iso_vert = iso_verts.emplace_back();
iso_vert.header = {i, j, 2};
iso_vert.simplex_vertex_indices = {vId1, vId2};
iso_vert.subface_indices = {implicit_pIds[0]};
const auto f1 = vertex_infos(vertex_indices_mapping.at(vId1), implicit_pIds[0]);
const auto f2 = vertex_infos(vertex_indices_mapping.at(vId2), implicit_pIds[0]);
const auto coord = compute_barycentric_coords(f1, f2);
iso_pts.emplace_back(coord[0] * get_vert_pos(vId1, scene_bg_mesh_info)
+ coord[1] * get_vert_pos(vId2, scene_bg_mesh_info));
}
iso_vId_of_vert.back() = iter_inserted.first->second;
break;
}
case 1: // on tet face
{
uint32_t pId = boundary_pIds[0];
uint32_t num_vIds = 0;
for (uint32_t k = 0; k < 4; k++) {
if (k != pId) vIds3[num_vIds++] = tetrahedrons[i][k];
}
std::sort(vIds3.begin(), vIds3.end());
key5 = {vIds3[0], vIds3[1], vIds3[2], implicit_pIds[0], implicit_pIds[1]};
auto iter_inserted = vert_on_tetFace.try_emplace(key5, static_cast<uint32_t>(iso_verts.size()));
if (iter_inserted.second) {
auto& iso_vert = iso_verts.emplace_back();
iso_vert.header = {i, j, 3};
iso_vert.simplex_vertex_indices = {vIds3[0], vIds3[1], vIds3[2]};
iso_vert.subface_indices = {implicit_pIds[0], implicit_pIds[1]};
//
const auto &vert_face0 = vertex_infos.row(vertex_indices_mapping.at(vIds3[0])),
vert_face1 = vertex_infos.row(vertex_indices_mapping.at(vIds3[1])),
vert_face2 = vertex_infos.row(vertex_indices_mapping.at(vIds3[2]));
const auto f1 = std::array{vert_face0(implicit_pIds[0]),
vert_face1(implicit_pIds[0]),
vert_face2(implicit_pIds[0])};
const auto f2 = std::array{vert_face0(implicit_pIds[1]),
vert_face1(implicit_pIds[1]),
vert_face2(implicit_pIds[1])};
const auto coord = compute_barycentric_coords(f1, f2);
iso_pts.emplace_back(coord[0] * get_vert_pos(vIds3[0], scene_bg_mesh_info)
+ coord[1] * get_vert_pos(vIds3[1], scene_bg_mesh_info)
+ coord[2] * get_vert_pos(vIds3[2], scene_bg_mesh_info));
}
iso_vId_of_vert.back() = iter_inserted.first->second;
break;
}
case 0: // in tet cell
{
iso_vId_of_vert.back() = static_cast<uint32_t>(iso_verts.size());
auto& iso_vert = iso_verts.emplace_back();
iso_vert.header = {i, j, 4};
iso_vert.simplex_vertex_indices = tetrahedrons[i];
iso_vert.subface_indices = implicit_pIds;
const auto &vert_face0 = vertex_infos.row(vertex_indices_mapping.at(tetrahedrons[i][0])),
vert_face1 = vertex_infos.row(vertex_indices_mapping.at(tetrahedrons[i][1])),
vert_face2 = vertex_infos.row(vertex_indices_mapping.at(tetrahedrons[i][2])),
vert_face3 = vertex_infos.row(vertex_indices_mapping.at(tetrahedrons[i][3]));
const auto f1 = std::array{vert_face0(implicit_pIds[0]),
vert_face1(implicit_pIds[0]),
vert_face2(implicit_pIds[0]),
vert_face3(implicit_pIds[0])};
const auto f2 = std::array{vert_face0(implicit_pIds[1]),
vert_face1(implicit_pIds[1]),
vert_face2(implicit_pIds[1]),
vert_face3(implicit_pIds[1])};
const auto f3 = std::array{vert_face0(implicit_pIds[2]),
vert_face1(implicit_pIds[2]),
vert_face2(implicit_pIds[2]),
vert_face3(implicit_pIds[2])};
const auto coord = compute_barycentric_coords(f1, f2, f3);
iso_pts.emplace_back(coord[0] * get_vert_pos(tetrahedrons[i][0], scene_bg_mesh_info)
+ coord[1] * get_vert_pos(tetrahedrons[i][1], scene_bg_mesh_info)
+ coord[2] * get_vert_pos(tetrahedrons[i][2], scene_bg_mesh_info)
+ coord[3] * get_vert_pos(tetrahedrons[i][3], scene_bg_mesh_info));
break;
}
case 3: // on tet vertex
{
used_pId.fill(false);
for (const auto& pId : boundary_pIds) { used_pId[pId] = true; }
uint32_t vId;
for (uint32_t k = 0; k < 4; k++) {
if (!used_pId[k]) {
vId = k;
break;
}
}
auto key = tetrahedrons[i][vId];
auto iter_inserted = vert_on_tetVert.try_emplace(key, static_cast<uint32_t>(iso_verts.size()));
if (iter_inserted.second) {
auto& iso_vert = iso_verts.emplace_back();
iso_vert.header = {i, j, 1};
iso_vert.subface_indices = {static_cast<uint16_t>(tetrahedrons[i][vId])};
iso_pts.emplace_back(get_vert_pos(iso_vert.simplex_vertex_indices[0], scene_bg_mesh_info));
}
iso_vId_of_vert.back() = iter_inserted.first->second;
break;
}
default: break;
}
}
}
// create iso-faces
for (uint32_t j = 0; j < faces.size(); j++) {
if (is_iso_face[j]) {
face_verts.clear();
for (unsigned long vId : faces[j].vertices) { face_verts.emplace_back(iso_vId_of_vert[vId]); }
//
// face is on tet boundary if face.negative_cell is NONE
bool face_on_tet_boundary = (faces[j].negative_cell == invalid_index);
//
if (face_on_tet_boundary) {
compute_iso_face_key(face_verts, key3);
auto iter_inserted = face_on_tetFace.try_emplace(key3, static_cast<uint32_t>(iso_faces.size()));
if (iter_inserted.second) {
auto& face = iso_faces.emplace_back();
face.vertex_indices = face_verts;
face.headers.emplace_back(face_header_t{i, j});
face.subface_index = active_subface_indices[faces[j].supporting_plane - 4 + start_index];
} else { // iso_face inserted before
uint32_t iso_face_id = (iter_inserted.first)->second;
iso_faces[iso_face_id].headers.emplace_back(face_header_t{i, j});
}
} else { // face not on tet boundary
auto& face = iso_faces.emplace_back();
face.vertex_indices = face_verts;
face.headers.emplace_back(face_header_t{i, j});
face.subface_index = active_subface_indices[faces[j].supporting_plane - 4 + start_index];
}
}
}
}
//
}