pub fn find_adjacent_face_index(
vtxs_i: &[usize; 4],
i_face: usize,
j_tet: usize,
tet2vtx: &[usize],
face2idx: &[usize],
idx2node: &[usize],
) -> usize {
let iv0 = vtxs_i[idx2node[face2idx[i_face]]];
let iv1 = vtxs_i[idx2node[face2idx[i_face] + 1]];
let iv2 = vtxs_i[idx2node[face2idx[i_face] + 2]];
let i_sum = iv0 + iv1 + iv2;
assert_ne!(iv0, iv1);
assert_ne!(iv0, iv2);
let vtxs_j = arrayref::array_ref![tet2vtx, j_tet * 4, 4];
for j_face in 0..4 {
let jv0 = vtxs_j[idx2node[face2idx[j_face]]];
let jv1 = vtxs_j[idx2node[face2idx[j_face] + 1]];
let jv2 = vtxs_j[idx2node[face2idx[j_face] + 2]];
let j_sum = jv0 + jv1 + jv2;
if i_sum == j_sum {
return j_face;
}
}
dbg!(iv0, iv1, iv2, &vtxs_j);
panic!();
}
pub fn remove(i_tet: usize, tet2tet: &mut [usize], tet2vtx: &mut [usize]) {
for i2_node in 0..4 {
let k_tet = tet2tet[i_tet * 4 + i2_node];
if k_tet == usize::MAX {
continue;
}
let k2_node = find_adjacent_face_index(
arrayref::array_ref![tet2vtx, i_tet * 4, 4],
i2_node,
k_tet,
tet2vtx,
&del_geo_core::tet::FACE2IDX,
&del_geo_core::tet::IDX2NODE,
);
tet2tet[i_tet * 4 + i2_node] = usize::MAX;
tet2tet[k_tet * 4 + k2_node] = usize::MAX;
}
for i2_node in 0..4 {
tet2vtx[i_tet * 4 + i2_node] = usize::MAX;
}
}
#[derive(Debug, Clone)]
struct MergeTwoTetsIntoPrm {
i_tet: usize,
i0_node: usize,
i1_node: usize,
j_tet: usize,
j0_node: usize,
}
impl MergeTwoTetsIntoPrm {
fn prism_vtxs(&self, tet2vtx: &[usize]) -> [usize; 5] {
use del_geo_core::tet::{FACE2IDX, IDX2NODE};
let (i_tet, j_tet, i0_node, i1_node, j0_node) = (
self.i_tet,
self.j_tet,
self.i0_node,
self.i1_node,
self.j0_node,
);
let k4_vtx = tet2vtx[i_tet * 4 + i0_node];
assert_eq!(tet2vtx[j_tet * 4 + j0_node], k4_vtx);
let k0_vtx = tet2vtx[i_tet * 4 + i1_node];
let i0_nofa = (0..3)
.find(|i| IDX2NODE[FACE2IDX[i0_node] + i] == i1_node)
.unwrap();
let i2_node = IDX2NODE[FACE2IDX[i0_node] + (i0_nofa + 1) % 3];
let i3_node = IDX2NODE[FACE2IDX[i0_node] + (i0_nofa + 2) % 3];
let j1_node = find_adjacent_face_index(
arrayref::array_ref![tet2vtx, i_tet * 4, 4],
i1_node,
j_tet,
tet2vtx,
&FACE2IDX,
&IDX2NODE,
);
let k1_vtx = tet2vtx[i_tet * 4 + i2_node];
let k2_vtx = tet2vtx[j_tet * 4 + j1_node];
let k3_vtx = tet2vtx[i_tet * 4 + i3_node];
[k0_vtx, k3_vtx, k2_vtx, k1_vtx, k4_vtx]
}
}
pub fn make_pyramids_on_boundary(
tet2vtx: &[usize],
tet2tet: &[usize],
vtx2xyz: &[f64],
) -> (Vec<usize>, Vec<usize>) {
let num_tet = tet2vtx.len() / 4;
let mut cands: Vec<MergeTwoTetsIntoPrm> = vec![];
for i_tet in 0..num_tet {
let cands_i: Vec<MergeTwoTetsIntoPrm> = (0..4)
.flat_map(|i0_node| {
if tet2tet[i_tet * 4 + i0_node] != usize::MAX {
return None;
}
let i0_vtx = tet2vtx[i_tet * 4 + i0_node];
let res = (0..3)
.filter_map(|i| {
let i1_node = (i0_node + i) % 4;
let j_tet = tet2tet[i_tet * 4 + i1_node];
if j_tet == usize::MAX {
return None;
}
let j0_node = (0..4).find(|&i| tet2vtx[j_tet * 4 + i] == i0_vtx).unwrap();
if tet2tet[j_tet * 4 + j0_node] != usize::MAX {
return None;
}
Some(MergeTwoTetsIntoPrm {
i_tet,
i0_node,
i1_node,
j_tet,
j0_node,
})
})
.collect::<Vec<MergeTwoTetsIntoPrm>>();
Some(res)
})
.flatten()
.collect();
cands.extend_from_slice(&cands_i);
}
let cands: Vec<_> = cands
.into_iter()
.filter(|cand| {
let ci = {
let i_tet = cand.i_tet;
let p0i = arrayref::array_ref![vtx2xyz, tet2vtx[i_tet * 4] * 3, 3];
let p1i = arrayref::array_ref![vtx2xyz, tet2vtx[i_tet * 4 + 1] * 3, 3];
let p2i = arrayref::array_ref![vtx2xyz, tet2vtx[i_tet * 4 + 2] * 3, 3];
let p3i = arrayref::array_ref![vtx2xyz, tet2vtx[i_tet * 4 + 3] * 3, 3];
1.0 / del_geo_core::tet::condition_number(p0i, p1i, p2i, p3i).unwrap()
};
let cj = {
let j_tet = cand.j_tet;
let p0j = arrayref::array_ref![vtx2xyz, tet2vtx[j_tet * 4] * 3, 3];
let p1j = arrayref::array_ref![vtx2xyz, tet2vtx[j_tet * 4 + 1] * 3, 3];
let p2j = arrayref::array_ref![vtx2xyz, tet2vtx[j_tet * 4 + 2] * 3, 3];
let p3j = arrayref::array_ref![vtx2xyz, tet2vtx[j_tet * 4 + 3] * 3, 3];
1.0 / del_geo_core::tet::condition_number(p0j, p1j, p2j, p3j).unwrap()
};
let c_new = {
let pnode2vtx = cand.prism_vtxs(tet2vtx);
let p0 = arrayref::array_ref![vtx2xyz, pnode2vtx[0] * 3, 3];
let p1 = arrayref::array_ref![vtx2xyz, pnode2vtx[1] * 3, 3];
let p2 = arrayref::array_ref![vtx2xyz, pnode2vtx[2] * 3, 3];
let p3 = arrayref::array_ref![vtx2xyz, pnode2vtx[3] * 3, 3];
let p4 = arrayref::array_ref![vtx2xyz, pnode2vtx[4] * 3, 3];
use del_geo_core::pyramid::jacobian_determinant_and_conditiona_number as djac_cnd;
let (d0, c0) = djac_cnd(p0, p1, p2, p3, p4, &[0.5, 0.5, 0.5]).unwrap();
let (d1, c1) = djac_cnd(p0, p1, p2, p3, p4, &[0.5, 0.5, 0.0]).unwrap();
let (d2, c2) = djac_cnd(p0, p1, p2, p3, p4, &[0.0, 0.0, 0.0]).unwrap();
let (d3, c3) = djac_cnd(p0, p1, p2, p3, p4, &[1.0, 0.0, 0.0]).unwrap();
let (d4, c4) = djac_cnd(p0, p1, p2, p3, p4, &[1.0, 1.0, 0.0]).unwrap();
let (d5, c5) = djac_cnd(p0, p1, p2, p3, p4, &[0.0, 1.0, 0.0]).unwrap();
let (c0, c1, c2, c3, c4, c5) =
(1.0 / c0, 1.0 / c1, 1.0 / c2, 1.0 / c3, 1.0 / c4, 1.0 / c5);
let dmin = [d0, d1, d2, d3, d4, d5]
.iter()
.copied()
.min_by(|x, y| x.total_cmp(y));
dmin.filter(|&d| d > 0.0).and_then(|_| {
[c0, c1, c2, c3, c4, c5]
.iter()
.copied()
.min_by(|x, y| x.total_cmp(y))
})
};
let c_old = ci.min(cj);
c_new.is_some_and(|c| c > c_old * 1.3)
})
.collect();
dbg!(cands.len());
let mut tets = std::collections::HashSet::<usize>::new();
let mut pyrmd2vtx = vec![0usize; 0];
for cand in &cands {
let i_tet = cand.i_tet;
let j_tet = cand.j_tet;
if tets.contains(&i_tet) || tets.contains(&j_tet) {
continue;
}
let pnode2vtx = cand.prism_vtxs(tet2vtx);
pyrmd2vtx.extend_from_slice(&pnode2vtx);
tets.insert(i_tet);
tets.insert(j_tet);
}
(pyrmd2vtx, tets.into_iter().collect())
}