use crate::mesh::{
DefaultEdgePayload, EdgeBasics, FaceBasics, HalfEdge, HalfEdgeSemiBuilder, MeshTypeHalfEdge,
VertexInterpolator,
};
#[derive(Debug, Clone, Copy)]
pub struct SubdivisionDescription {
b: usize,
c: usize,
}
impl SubdivisionDescription {
pub fn new(b: usize, c: usize) -> Self {
assert!(b >= 1);
Self { b, c }
}
pub fn b(&self) -> usize {
self.b
}
pub fn c(&self) -> usize {
self.c
}
pub fn frequency(&self) -> usize {
self.b + self.c
}
pub fn triangulation_number(&self) -> usize {
self.b * self.b + self.b * self.c + self.c * self.c
}
}
pub trait MeshSubdivision<T: MeshTypeHalfEdge<Mesh = Self>>
where
T::EP: DefaultEdgePayload,
{
fn loop_subdivision(&mut self, vp_builder: &impl VertexInterpolator<3, T>) -> &mut Self
where
T::Mesh: HalfEdgeSemiBuilder<T>,
{
let fs = self.faces().map(|f| f.id()).collect::<Vec<_>>();
for face in &fs {
let edges = self.face(*face).edges(self).collect::<Vec<_>>();
let vs = edges.iter().map(|e| e.origin_id()).collect::<Vec<_>>();
assert!(edges.len() == 3);
for i in 0..3 {
if self
.subdivide_unsafe_try_fixup(edges[i].id(), Default::default())
.is_some()
{
continue;
}
let vp = vp_builder.call(
self,
[
(
if vs[0] == edges[i].origin_id() || vs[0] == edges[i].target_id(self) {
1
} else {
0
},
vs[0],
),
(
if vs[1] == edges[i].origin_id() || vs[1] == edges[i].target_id(self) {
1
} else {
0
},
vs[1],
),
(
if vs[2] == edges[i].origin_id() || vs[2] == edges[i].target_id(self) {
1
} else {
0
},
vs[2],
),
],
);
self.subdivide_unsafe(edges[i].id(), vp, Default::default());
}
let fp = self.remove_face(*face);
for e in &edges {
self.insert_edge_no_check(
e.id(),
Default::default(),
self.edge(e.id()).prev(self).prev_id(),
Default::default(),
);
self.close_hole(e.id(), fp, false);
}
self.close_hole(self.edge(edges[0].id()).next(self).twin_id(), fp, false);
}
self
}
fn subdivision_frequency(
&mut self,
des: SubdivisionDescription,
vp_builder: impl VertexInterpolator<3, T>,
) -> &mut Self
where
T::Mesh: HalfEdgeSemiBuilder<T>,
{
assert!(des.c == 0);
assert!(des.b & (des.b - 1) == 0, "todo: odd subdivision frequency");
let num_faces = self.num_faces();
let mut b = des.b;
while b > 1 {
self.loop_subdivision(&vp_builder);
if b == 1 {
break;
}
assert!(b % 2 == 0, "todo: odd subdivision frequency");
b = b / 2
}
debug_assert_eq!(self.num_faces(), num_faces * des.triangulation_number());
self
}
}