use cgmath::EuclideanSpace;
use cgmath::Point3;
use iterator::FaceHalfedgeIterator;
use iterator::FaceIterator;
use mesh::Id;
use mesh::Mesh;
#[derive(Clone)]
struct FaceData {
average_of_points: Point3<f32>,
generated_vertex_id: Id,
}
#[derive(Clone)]
struct EdgeData {
mid_point: Point3<f32>,
generated_vertex_id: Id,
}
#[derive(Copy, Clone)]
struct VertexData {
generated_vertex_id: Id,
}
impl VertexData {
pub fn new() -> Self {
VertexData {
generated_vertex_id: 0,
}
}
}
fn face_data_mut<'a>(
input: &Mesh,
id: Id,
face_data_set: &'a mut Vec<Option<FaceData>>,
output: &mut Mesh,
) -> &'a mut FaceData {
if face_data_set[id].is_some() {
return face_data_set[id].as_mut().unwrap();
}
let average_of_points = input.face_center(id);
face_data_set[id] = Some(FaceData {
average_of_points,
generated_vertex_id: output.add_vertex(average_of_points),
});
face_data_set[id].as_mut().unwrap()
}
fn edge_data_mut<'a>(
input: &Mesh,
id: Id,
face_data_set: &mut Vec<Option<FaceData>>,
edge_data_set: &'a mut Vec<Option<EdgeData>>,
output: &mut Mesh,
) -> &'a mut EdgeData {
let id = input.peek_same_halfedge(id);
if edge_data_set[id].is_some() {
return edge_data_set[id].as_mut().unwrap();
}
let mid_point = input.edge_center(id);
let (
halfedge_face_id,
opposite_face_id,
next_halfedge_vertex_id,
start_vertex_position,
) = {
let halfedge = input.halfedge(id).unwrap();
(
halfedge.face,
input.halfedge(halfedge.opposite).unwrap().face,
input.halfedge(halfedge.next).unwrap().vertex,
input.vertex(halfedge.vertex).unwrap().position,
)
};
let stop_vertex_position =
input.vertex(next_halfedge_vertex_id).unwrap().position;
let f1_data_average =
face_data_mut(input, halfedge_face_id, face_data_set, output)
.average_of_points;
let f2_data_average =
face_data_mut(input, opposite_face_id, face_data_set, output)
.average_of_points;
let center = Point3::centroid(&[
f1_data_average,
f2_data_average,
start_vertex_position,
stop_vertex_position,
]);
edge_data_set[id] = Some(EdgeData {
mid_point,
generated_vertex_id: output.add_vertex(center),
});
edge_data_set[id].as_mut().unwrap()
}
pub struct CatmullClarkSubdivider<'a> {
edge_data_set: Vec<Option<EdgeData>>,
face_data_set: Vec<Option<FaceData>>,
output: Mesh,
input: &'a Mesh,
tmp_avg_of_faces: Vec<Point3<f32>>,
tmp_avg_of_edge_mids: Vec<Point3<f32>>,
vertex_data_set: Vec<Option<VertexData>>,
}
impl<'a> CatmullClarkSubdivider<'a> {
pub fn new(input: &'a Mesh) -> Self {
let mut output = Mesh::new();
let halfedge_prediction = input.halfedge_count * 4;
output.halfedges.reserve(halfedge_prediction);
output.vertices.reserve(
input.vertex_count + input.halfedge_count / 2 + input.face_count, );
output.faces.reserve(
input.face_count * 4, );
output.edges.reserve(halfedge_prediction / 2);
let face_data_set = vec![None; input.faces.len() + 1];
let edge_data_set = vec![None; input.halfedges.len() + 1];
let vertex_data_set = vec![None; input.vertices.len() + 1];
CatmullClarkSubdivider {
input,
output,
tmp_avg_of_edge_mids: Vec::new(),
tmp_avg_of_faces: Vec::new(),
face_data_set,
edge_data_set,
vertex_data_set,
}
}
pub fn generate(mut self) -> Mesh {
for face_id in FaceIterator::new(self.input) {
let face_vertex_id = face_data_mut(
&self.input,
face_id,
&mut self.face_data_set,
&mut self.output,
).generated_vertex_id;
let face_halfedge = self.input.face(face_id).unwrap().halfedge;
let face_halfedge_id_vec =
FaceHalfedgeIterator::new(self.input, face_halfedge).into_vec();
for halfedge_id in face_halfedge_id_vec {
let (next_halfedge_id, vertex_id) = {
let halfedge = self.input.halfedge(halfedge_id).unwrap();
let next_halfedge_id = halfedge.next;
let next_halfedge_start =
self.input.halfedge(next_halfedge_id).unwrap().vertex;
(next_halfedge_id, next_halfedge_start)
};
let e1_vertex_id =
self.edge_data_mut(halfedge_id).generated_vertex_id;
let e2_vertex_id =
self.edge_data_mut(next_halfedge_id).generated_vertex_id;
let vertex_generated_id =
self.vertex_data_mut(vertex_id).generated_vertex_id;
let added_face_id = self.output.add_face();
let mut added_halfedges = [
(self.output.add_halfedge(), face_vertex_id),
(self.output.add_halfedge(), e1_vertex_id),
(self.output.add_halfedge(), vertex_generated_id),
(self.output.add_halfedge(), e2_vertex_id),
];
for &(added_halfedge_id, added_vertex_id) in
added_halfedges.iter()
{
{
let vert = self.output
.vertex_mut(added_vertex_id)
.unwrap();
if !vert.halfedges.contains(&added_halfedge_id) {
vert.halfedges.push(added_halfedge_id);
}
}
self.output.halfedge_mut(added_halfedge_id).unwrap().face =
added_face_id;
self.output
.halfedge_mut(added_halfedge_id)
.unwrap()
.vertex = added_vertex_id;
}
self.output.face_mut(added_face_id).unwrap().halfedge =
added_halfedges[0].0;
for i in 0..added_halfedges.len() {
let first = added_halfedges[i].0;
let second =
added_halfedges[(i + 1) % added_halfedges.len()].0;
self.output.link_halfedges(first, second);
}
}
}
self.output
}
fn edge_data_mut(&mut self, halfedge_id: Id) -> &EdgeData {
edge_data_mut(
&self.input,
halfedge_id,
&mut self.face_data_set,
&mut self.edge_data_set,
&mut self.output,
)
}
fn vertex_data_mut(&mut self, vertex_id: Id) -> VertexData {
if let Some(data) = self.vertex_data_set[vertex_id] {
return data;
}
self.tmp_avg_of_faces.clear();
self.tmp_avg_of_edge_mids.clear();
let vertex = self.input.vertex(vertex_id).unwrap();
for halfedge_id in vertex.halfedges.iter() {
let halfedge_face_id =
self.input.halfedge(*halfedge_id).unwrap().face;
self.tmp_avg_of_faces.push(
face_data_mut(
&self.input,
halfedge_face_id,
&mut self.face_data_set,
&mut self.output,
).average_of_points,
);
self.tmp_avg_of_edge_mids.push(
edge_data_mut(
&self.input,
*halfedge_id,
&mut self.face_data_set,
&mut self.edge_data_set,
&mut self.output,
).mid_point,
);
}
let barycenter = Point3::centroid(&self.tmp_avg_of_faces);
let average_of_edge = Point3::centroid(&self.tmp_avg_of_edge_mids);
let position = (((average_of_edge * 2.0) + barycenter.to_vec())
+ (vertex.position.to_vec()
* ((self.tmp_avg_of_faces.len() as i32 - 3).abs() as f32)))
/ (self.tmp_avg_of_faces.len() as f32);
let mut data = VertexData::new();
data.generated_vertex_id = self.output.add_vertex(position);
self.vertex_data_set[vertex_id] = Some(data);
data
}
}
pub trait Subdivide {
fn subdivide(&self) -> Self;
}
impl Subdivide for Mesh {
fn subdivide(&self) -> Self {
CatmullClarkSubdivider::new(self).generate()
}
}