use crate::{
math::{Scalar, Transformable},
mesh::{
DefaultEdgePayload, DefaultFacePayload, EdgeBasics, EuclideanMeshType, FaceBasics,
HalfEdge, MeshTypeHalfEdge, VertexBasics,
},
operations::MeshLoft,
};
use itertools::Itertools;
pub trait MeshExtrude<T: MeshTypeHalfEdge<Mesh = Self>>: MeshLoft<T>
where
T::EP: DefaultEdgePayload,
T::FP: DefaultFacePayload,
{
fn extrude_boundary<const D: usize>(&mut self, transform: T::Trans)
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
let faces = self.face_ids().collect_vec();
for f in faces {
let e = self.face(f).edge(self).twin_id();
if self.edge(e).is_boundary_self() {
self.extrude(e, transform);
}
}
}
fn extrude<const D: usize>(&mut self, e: T::E, transform: T::Trans) -> T::E
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
assert!(self.edge(e).is_boundary_self());
let vps: Vec<_> = self
.edges_back_from(self.edge(e).next_id())
.map(|v| v.origin(self).payload().transformed(&transform))
.collect();
let start = self.loft_polygon_back(e, 2, 2, vps);
self.close_hole(start, Default::default(), false);
start
}
fn extrude_face<const D: usize>(&mut self, f: T::F, transform: T::Trans) -> T::E
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
let e = self.face(f).edge_id();
self.remove_face(f);
return self.extrude(e, transform);
}
fn extrude_tri_face<const D: usize>(&mut self, f: T::F, transform: T::Trans) -> T::E
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
let e = self.face(f).edge_id();
self.remove_face(f);
return self.extrude_tri(e, transform);
}
fn extrude_tri<const D: usize>(&mut self, e: T::E, transform: T::Trans) -> T::E
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
assert!(self.edge(e).is_boundary_self());
let vps: Vec<_> = self
.edges_from(self.edge(e).next_id())
.map(|v| v.origin(self).payload().transformed(&transform))
.collect();
let start = self.loft_tri_closed(e, vps);
self.close_hole(start, Default::default(), false);
start
}
fn extrude_tri2<const D: usize>(&mut self, e: T::E, transform: T::Trans) -> T::E
where
T::VP: Transformable<D, Trans = T::Trans, S = T::S>,
T: EuclideanMeshType<D, Mesh = Self>,
{
assert!(self.edge(e).is_boundary_self());
let mut vps: Vec<_> = self
.edges_from(self.edge(e).next_id())
.map(|v| v.origin(self).payload().transformed(&transform))
.collect::<Vec<_>>()
.iter()
.circular_tuple_windows()
.map(|(a, b)| a.lerped(&b, T::S::HALF))
.collect();
vps.rotate_right(1);
let start = self.loft_tri_closed(e, vps);
self.close_hole(start, Default::default(), false);
start
}
fn fill_hole_apex(&mut self, start: T::E, apex: T::VP) -> T::V {
let e0 = self.edge(start);
let origin = e0.origin_id();
let mut input = self.edge(start).prev_id();
let (v, _, _) = self.add_vertex_via_edge_default(input, start, apex);
loop {
let e = self.edge(input);
if e.origin_id() == origin {
break;
}
input = e.prev_id();
self.close_face_default(self.edge(input).next(&self).next_id(), input, false);
}
self.close_hole(input, Default::default(), false);
v
}
}