use num_traits::AsPrimitive;
pub fn from_vtx2vtx<Index>(vtx2idx: &[Index], idx2vtx: &[Index], edge2vtx: &mut [[Index; 2]])
where
Index: AsPrimitive<usize>,
usize: AsPrimitive<Index>,
{
assert_eq!(edge2vtx.len(), idx2vtx.len());
let mut icnt = 0usize;
for i_vtx in 0..vtx2idx.len() - 1 {
let idx0 = vtx2idx[i_vtx].as_();
let idx1 = vtx2idx[i_vtx + 1].as_();
for &j_vtx in &idx2vtx[idx0..idx1] {
edge2vtx[icnt] = [i_vtx.as_(), j_vtx];
icnt += 1;
}
}
}
pub fn from_uniform_mesh_with_specific_edges<Index, const NNODE: usize>(
elem2vtx: &[[Index; NNODE]],
edge2node: &[usize],
num_vtx: usize,
) -> Vec<[Index; 2]>
where
Index: num_traits::PrimInt + std::ops::AddAssign + AsPrimitive<usize>,
usize: AsPrimitive<Index>,
{
let vtx2elem = crate::vtx2elem::from_uniform_mesh::<Index, NNODE>(elem2vtx, num_vtx);
let vtx2vtx = crate::vtx2vtx::from_specific_edges_of_uniform_mesh::<Index, NNODE>(
elem2vtx,
edge2node.as_chunks::<2>().0,
&vtx2elem.0,
&vtx2elem.1,
false,
);
let mut edge2vtx = vec![[Index::zero(); 2]; vtx2vtx.1.len()];
from_vtx2vtx(&vtx2vtx.0, &vtx2vtx.1, &mut edge2vtx);
edge2vtx
}
pub fn from_triangle_mesh<INDEX>(tri2vtx: &[[INDEX; 3]], num_vtx: usize) -> Vec<[INDEX; 2]>
where
INDEX: num_traits::PrimInt + std::ops::AddAssign + num_traits::AsPrimitive<usize>,
usize: AsPrimitive<INDEX>,
{
from_uniform_mesh_with_specific_edges::<_, 3>(tri2vtx, &[0, 1, 1, 2, 2, 0], num_vtx)
}
pub fn from_polygon_mesh<INDEX>(
elem2idx_offset: &[INDEX],
idx2vtx: &[INDEX],
num_vtx: usize,
) -> Vec<[INDEX; 2]>
where
INDEX: num_traits::PrimInt + num_traits::AsPrimitive<usize>,
usize: AsPrimitive<INDEX>,
{
let vtx2elem = crate::vtx2elem::from_polygon_mesh(elem2idx_offset, idx2vtx, num_vtx);
let vtx2vtx = crate::vtx2vtx::from_polygon_mesh_edges_with_vtx2elem(
elem2idx_offset,
idx2vtx,
&vtx2elem.0,
&vtx2elem.1,
false, );
let mut edge2vtx = vec![[INDEX::zero(); 2]; vtx2vtx.1.len()];
from_vtx2vtx(&vtx2vtx.0, &vtx2vtx.1, &mut edge2vtx);
edge2vtx
}
pub fn from_polyloop(num_vtx: usize) -> Vec<[usize; 2]> {
let mut edge2vtx = Vec::<[usize; 2]>::with_capacity(num_vtx);
for i in 0..num_vtx {
edge2vtx.push([i, (i + 1) % num_vtx]);
}
edge2vtx
}
pub fn from_polyline(num_vtx: usize) -> Vec<[usize; 2]> {
let mut edge2vtx = Vec::<[usize; 2]>::with_capacity(num_vtx - 1);
for i in 0..num_vtx - 1 {
edge2vtx.push([i, i + 1]);
}
edge2vtx
}
pub fn contour_for_triangle_mesh<INDEX>(
tri2vtx: &[[INDEX; 3]],
vtx2xyz: &[[f32; 3]],
transform_world2ndc: &[f32; 16],
edge2vtx: &[[INDEX; 2]],
edge2tri: &[[INDEX; 2]],
) -> Vec<[INDEX; 2]>
where
INDEX: num_traits::PrimInt + num_traits::AsPrimitive<usize> + std::fmt::Display,
usize: AsPrimitive<INDEX>,
{
use del_geo_core::{mat4_col_major, vec3};
let num_tri = tri2vtx.len();
let transform_ndc2world = mat4_col_major::try_inverse(transform_world2ndc).unwrap();
let mut edge2vtx_contour: Vec<[INDEX; 2]> = vec![];
for (i_edge, node2vtx) in edge2vtx.iter().enumerate() {
let (i0_vtx, i1_vtx) = (node2vtx[0].as_(), node2vtx[1].as_());
let pos_mid: [f32; 3] =
std::array::from_fn(|i| (vtx2xyz[i0_vtx][i] + vtx2xyz[i1_vtx][i]) * 0.5);
let (_ray_org, ray_dir) = mat4_col_major::ray_from_transform_world2ndc(
transform_world2ndc,
&pos_mid,
&transform_ndc2world,
);
let i0_tri = edge2tri[i_edge][0];
let i1_tri = edge2tri[i_edge][1];
assert!(i0_tri.as_() < num_tri, "{} {}", i0_tri, tri2vtx.len());
assert!(i1_tri.as_() < num_tri, "{} {}", i1_tri, tri2vtx.len());
let nrm0_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i0_tri.as_()).unit_normal();
let nrm1_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i1_tri.as_()).unit_normal();
let flg0 = vec3::dot(&nrm0_world, &ray_dir) > 0.; let flg1 = vec3::dot(&nrm1_world, &ray_dir) > 0.;
if flg0 == flg1 {
continue; }
edge2vtx_contour.push([i0_vtx.as_(), i1_vtx.as_()]);
}
edge2vtx_contour
}
pub fn occluding_contour_for_triangle_mesh(
tri2vtx: &[[usize; 3]],
vtx2xyz: &[[f32; 3]],
transform_world2ndc: &[f32; 16],
edge2vtx: &[[usize; 2]],
edge2tri: &[[usize; 2]],
bvhnode2tri_tree: &[[usize; 3]],
bvhnode2aabb: &[[f32; 6]],
) -> Vec<[usize; 2]> {
use del_geo_core::{mat4_col_major, vec3};
let transform_ndc2world = mat4_col_major::try_inverse(transform_world2ndc).unwrap();
let mut edge2vtx_contour = vec![];
for (i_edge, node2vtx) in edge2vtx.iter().enumerate() {
let (i0_vtx, i1_vtx) = (node2vtx[0], node2vtx[1]);
let pos_mid: [f32; 3] =
std::array::from_fn(|i| (vtx2xyz[i0_vtx][i] + vtx2xyz[i1_vtx][i]) * 0.5);
let (_ray_org, ray_dir) = mat4_col_major::ray_from_transform_world2ndc(
transform_world2ndc,
&pos_mid,
&transform_ndc2world,
);
let i0_tri = edge2tri[i_edge][0];
let i1_tri = edge2tri[i_edge][1];
assert!(i0_tri < tri2vtx.len(), "{} {}", i0_tri, tri2vtx.len());
assert!(i1_tri < tri2vtx.len(), "{} {}", i1_tri, tri2vtx.len());
let nrm0_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i0_tri).unit_normal();
let nrm1_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i1_tri).unit_normal();
{
let flg0 = vec3::dot(&nrm0_world, &ray_dir) > 0.;
let flg1 = vec3::dot(&nrm1_world, &ray_dir) > 0.;
if flg0 == flg1 {
continue; }
}
let ray_org = {
let nrm = vec3::normalize(&vec3::add(&nrm0_world, &nrm1_world));
vec3::axpy(0.001, &nrm, &pos_mid) };
let res = crate::search_bvh3::first_intersection_ray(
&ray_org,
&ray_dir,
&crate::search_bvh3::TriMesh3WithBvhRef {
bvhnode2tri_btree: bvhnode2tri_tree,
bvhnode2aabb,
tri2vtx,
vtx2xyz,
},
0,
f32::MAX,
);
if res.is_some() {
continue; }
edge2vtx_contour.push([i0_vtx, i1_vtx]);
}
edge2vtx_contour
}
pub fn silhouette_for_triangle_mesh(
tri2vtx: &[[usize; 3]],
vtx2xyz: &[[f32; 3]],
transform_world2ndc: &[f32; 16],
edge2vtx: &[[usize; 2]],
edge2tri: &[[usize; 2]],
bvhnode2tri_tree: &[[usize; 3]],
bvhnode2aabb: &[[f32; 6]],
) -> Vec<[usize; 2]> {
use del_geo_core::{mat4_col_major, vec3};
let transform_ndc2world = mat4_col_major::try_inverse(transform_world2ndc).unwrap();
let mut edge2vtx_contour = vec![];
for (i_edge, node2vtx) in edge2vtx.iter().enumerate() {
let (i0_vtx, i1_vtx) = (node2vtx[0], node2vtx[1]);
let pos_mid: [f32; 3] =
std::array::from_fn(|i| (vtx2xyz[i0_vtx][i] + vtx2xyz[i1_vtx][i]) * 0.5);
let (_ray_org, ray_dir) = mat4_col_major::ray_from_transform_world2ndc(
transform_world2ndc,
&pos_mid,
&transform_ndc2world,
);
let i0_tri = edge2tri[i_edge][0];
let i1_tri = edge2tri[i_edge][1];
assert!(i0_tri < tri2vtx.len(), "{} {}", i0_tri, tri2vtx.len());
assert!(i1_tri < tri2vtx.len(), "{} {}", i1_tri, tri2vtx.len());
let nrm0_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i0_tri).unit_normal();
let nrm1_world = crate::trimesh3::to_tri3(tri2vtx, vtx2xyz, i1_tri).unit_normal();
{
let flg0 = vec3::dot(&nrm0_world, &ray_dir) > 0.;
let flg1 = vec3::dot(&nrm1_world, &ray_dir) > 0.;
if flg0 == flg1 {
continue; }
}
let ray_org = {
let nrm = vec3::normalize(&vec3::add(&nrm0_world, &nrm1_world));
vec3::axpy(0.001, &nrm, &pos_mid) };
let mut res: Vec<(f32, usize)> = vec![];
crate::search_bvh3::intersections_line(
&mut res,
&ray_org,
&ray_dir,
&crate::search_bvh3::TriMesh3WithBvhRef {
bvhnode2tri_btree: bvhnode2tri_tree,
bvhnode2aabb,
tri2vtx,
vtx2xyz,
},
0,
);
if !res.is_empty() {
continue; }
edge2vtx_contour.push([i0_vtx, i1_vtx]);
}
edge2vtx_contour
}
#[test]
pub fn test_contour() {
let path_dir = std::path::Path::new("../target/out_del_msh_cpu");
std::fs::create_dir_all(path_dir).unwrap();
let (tri2vtx, vtx2xyz): (Vec<[usize; 3]>, Vec<[f32; 3]>)
= crate::trimesh3_primitive::torus_zup(2.0, 0.5, 32, 32);
let dir = del_geo_core::vec3::normalize(&[1f32, 1.0, 0.1]);
let transform_world2ndc = {
let ez = dir;
let (ex, ey) = del_geo_core::vec3::basis_xy_from_basis_z(&ez);
let m3 = del_geo_core::mat3_col_major::from_columns(&ex, &ey, &ez);
let t = del_geo_core::mat4_col_major::from_mat3_col_major_adding_w(&m3, 1.0);
del_geo_core::mat4_col_major::transpose(&t)
};
let bvhnode2tri_tree = crate::bvhnodes_morton::from_triangle_mesh(&tri2vtx, &vtx2xyz);
let bvhnode2aabb = crate::bvhnode2aabb3::from_uniform_mesh_with_bvh(
0,
&bvhnode2tri_tree,
&tri2vtx,
&vtx2xyz,
None,
);
let edge2vtx = crate::edge2vtx::from_triangle_mesh(&tri2vtx, vtx2xyz.len());
let edge2tri = crate::edge2elem::from_edge2vtx_of_tri2vtx(&edge2vtx, &tri2vtx, vtx2xyz.len());
{
let edge2vtx_contour = occluding_contour_for_triangle_mesh(
&tri2vtx,
&vtx2xyz,
&transform_world2ndc,
&edge2vtx,
&edge2tri,
&bvhnode2tri_tree,
&bvhnode2aabb,
);
crate::io_wavefront_obj::save_edge2vtx_vtx2xyz(
"../target/edge2vtx_countour.obj",
&edge2vtx_contour,
&vtx2xyz,
)
.unwrap();
}
{
let edge2vtx_contour = silhouette_for_triangle_mesh(
&tri2vtx,
&vtx2xyz,
&transform_world2ndc,
&edge2vtx,
&edge2tri,
&bvhnode2tri_tree,
&bvhnode2aabb,
);
crate::io_wavefront_obj::save_edge2vtx_vtx2xyz(
"../target/edge2vtx_silhouette.obj",
&edge2vtx_contour,
&vtx2xyz,
)
.unwrap();
}
crate::io_wavefront_obj::save_tri2vtx_vtx2xyz(
"../target/edge2vtx_trimsh.obj",
&tri2vtx,
&vtx2xyz,
)
.unwrap();
}