use std::collections::{HashMap, HashSet};
use crate::ids::{FaceId, HalfEdgeId, VertexId};
use crate::storage::{Face, HalfEdge, MeshStorage, Vertex};
use crate::traversal::{FaceHalfEdges, VertexAdjacentFaces};
use super::helpers::TopologyError;
pub fn extrude_face(
mesh: &mut MeshStorage,
face: FaceId,
offset: [f64; 3],
) -> Result<Vec<FaceId>, TopologyError> {
let data = validate_extrude_face_input(mesh, face, offset)?;
let elements = create_extrude_face_elements(mesh, &data, offset);
setup_extrude_face_top(mesh, &elements);
setup_extrude_face_sides(mesh, &data, &elements);
update_extrude_face_vertex_outgoing(mesh, &elements);
let errors = crate::validate::validate_topology(mesh);
if !errors.is_empty() {
return Err(TopologyError::Inconsistent(format!(
"extrude_face 后校验失败:{:?}",
errors
)));
}
Ok(vec![
elements.f_top,
elements.f_t1[0],
elements.f_t2[0],
elements.f_t1[1],
elements.f_t2[1],
elements.f_t1[2],
elements.f_t2[2],
])
}
struct ExtrudeFaceData {
h_arr: [HalfEdgeId; 3],
t: [HalfEdgeId; 3],
v: [VertexId; 3],
pos: [[f64; 3]; 3],
}
struct ExtrudeFaceElements {
vp: [VertexId; 3],
tp: [HalfEdgeId; 3],
a: [HalfEdgeId; 3],
b: [HalfEdgeId; 3],
c: [HalfEdgeId; 3],
d: [HalfEdgeId; 3],
e: [HalfEdgeId; 3],
f_top: FaceId,
f_t1: [FaceId; 3],
f_t2: [FaceId; 3],
}
fn validate_extrude_face_input(
mesh: &MeshStorage,
face: FaceId,
offset: [f64; 3],
) -> Result<ExtrudeFaceData, TopologyError> {
let offset_len = (offset[0].powi(2) + offset[1].powi(2) + offset[2].powi(2)).sqrt();
if offset_len < 1e-12 {
return Err(TopologyError::DegenerateTriangle);
}
if !mesh.contains_face(face) {
return Err(TopologyError::Inconsistent(format!("面 {:?} 不存在", face)));
}
let hs: Vec<HalfEdgeId> = FaceHalfEdges::new(mesh, face).collect();
if hs.len() != 3 {
return Err(TopologyError::Inconsistent(format!(
"面 {:?} 边界环长度={}, 非三角面",
face,
hs.len()
)));
}
let h_arr: [HalfEdgeId; 3] = [hs[0], hs[1], hs[2]];
let h0d = mesh
.get_halfedge(h_arr[0])
.ok_or(TopologyError::InvalidHalfEdge(h_arr[0]))?
.clone();
let h1d = mesh
.get_halfedge(h_arr[1])
.ok_or(TopologyError::InvalidHalfEdge(h_arr[1]))?
.clone();
let h2d = mesh
.get_halfedge(h_arr[2])
.ok_or(TopologyError::InvalidHalfEdge(h_arr[2]))?
.clone();
let v: [VertexId; 3] = [h2d.vertex, h0d.vertex, h1d.vertex];
let pos: [[f64; 3]; 3] = {
let mut arr = [[0.0f64; 3]; 3];
for i in 0..3 {
arr[i] = mesh
.get_vertex(v[i])
.ok_or_else(|| TopologyError::Inconsistent(format!("顶点 {:?} 不存在", v[i])))?
.position;
}
arr
};
let t: [HalfEdgeId; 3] = [
h0d.twin.ok_or(TopologyError::NoTwin(h_arr[0]))?,
h1d.twin.ok_or(TopologyError::NoTwin(h_arr[1]))?,
h2d.twin.ok_or(TopologyError::NoTwin(h_arr[2]))?,
];
for &item in &t {
let td = mesh
.get_halfedge(item)
.ok_or(TopologyError::InvalidHalfEdge(item))?;
if td.face.is_some() {
return Err(TopologyError::Inconsistent(
"extrude_face 仅支持所有边为边界边的面".into(),
));
}
}
for i in 0..3 {
let a = pos[(i + 1) % 3];
let b = pos[i];
let c = [
pos[i][0] + offset[0],
pos[i][1] + offset[1],
pos[i][2] + offset[2],
];
if crate::predicates::is_triangle_degenerate_3d(a, b, c) {
return Err(TopologyError::DegenerateTriangle);
}
}
Ok(ExtrudeFaceData { h_arr, t, v, pos })
}
fn create_extrude_face_elements(
mesh: &mut MeshStorage,
data: &ExtrudeFaceData,
offset: [f64; 3],
) -> ExtrudeFaceElements {
let v = &data.v;
let pos = &data.pos;
let vp: [VertexId; 3] = [
mesh.add_vertex(Vertex::new([
pos[0][0] + offset[0],
pos[0][1] + offset[1],
pos[0][2] + offset[2],
])),
mesh.add_vertex(Vertex::new([
pos[1][0] + offset[0],
pos[1][1] + offset[1],
pos[1][2] + offset[2],
])),
mesh.add_vertex(Vertex::new([
pos[2][0] + offset[0],
pos[2][1] + offset[1],
pos[2][2] + offset[2],
])),
];
let tp: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(vp[1])),
mesh.add_halfedge(HalfEdge::new(vp[0])),
mesh.add_halfedge(HalfEdge::new(vp[2])),
];
let a: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(vp[0])),
mesh.add_halfedge(HalfEdge::new(vp[1])),
mesh.add_halfedge(HalfEdge::new(vp[2])),
];
let b: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(v[1])),
mesh.add_halfedge(HalfEdge::new(v[2])),
mesh.add_halfedge(HalfEdge::new(v[0])),
];
let c: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(vp[0])),
mesh.add_halfedge(HalfEdge::new(vp[1])),
mesh.add_halfedge(HalfEdge::new(vp[2])),
];
let d: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(vp[1])),
mesh.add_halfedge(HalfEdge::new(vp[2])),
mesh.add_halfedge(HalfEdge::new(vp[0])),
];
let e: [HalfEdgeId; 3] = [
mesh.add_halfedge(HalfEdge::new(v[1])),
mesh.add_halfedge(HalfEdge::new(v[2])),
mesh.add_halfedge(HalfEdge::new(v[0])),
];
let f_top = mesh.add_face(Face::new());
let f_t1: [FaceId; 3] = [
mesh.add_face(Face::new()),
mesh.add_face(Face::new()),
mesh.add_face(Face::new()),
];
let f_t2: [FaceId; 3] = [
mesh.add_face(Face::new()),
mesh.add_face(Face::new()),
mesh.add_face(Face::new()),
];
ExtrudeFaceElements {
vp,
tp,
a,
b,
c,
d,
e,
f_top,
f_t1,
f_t2,
}
}
fn setup_extrude_face_top(mesh: &mut MeshStorage, el: &ExtrudeFaceElements) {
let tp_twin: [HalfEdgeId; 3] = [el.d[1], el.d[0], el.d[2]];
for (i, &twin) in tp_twin.iter().enumerate() {
let he = mesh.get_halfedge_mut(el.tp[i]).expect("tp[i] just created");
he.twin = Some(twin);
he.next = Some(el.tp[(i + 1) % 3]);
he.prev = Some(el.tp[(i + 2) % 3]);
he.face = Some(el.f_top);
}
mesh.get_face_mut(el.f_top)
.expect("f_top just created")
.halfedge = Some(el.tp[0]);
}
fn setup_extrude_face_sides(
mesh: &mut MeshStorage,
data: &ExtrudeFaceData,
el: &ExtrudeFaceElements,
) {
let d_twin: [HalfEdgeId; 3] = [el.tp[1], el.tp[0], el.tp[2]];
for (i, &dt) in d_twin.iter().enumerate() {
{
let he = mesh
.get_halfedge_mut(data.t[i])
.expect("t[i] validated earlier");
he.twin = Some(data.h_arr[i]); he.next = Some(el.a[i]);
he.prev = Some(el.b[i]);
he.face = Some(el.f_t1[i]);
let he = mesh.get_halfedge_mut(el.a[i]).expect("a[i] just created");
he.twin = Some(el.e[(i + 2) % 3]); he.next = Some(el.b[i]);
he.prev = Some(data.t[i]);
he.face = Some(el.f_t1[i]);
let he = mesh.get_halfedge_mut(el.b[i]).expect("b[i] just created");
he.twin = Some(el.c[i]); he.next = Some(data.t[i]);
he.prev = Some(el.a[i]);
he.face = Some(el.f_t1[i]);
}
mesh.get_face_mut(el.f_t1[i])
.expect("f_t1[i] just created")
.halfedge = Some(data.t[i]);
{
let he = mesh.get_halfedge_mut(el.c[i]).expect("c[i] just created");
he.twin = Some(el.b[i]); he.next = Some(el.d[i]);
he.prev = Some(el.e[i]);
he.face = Some(el.f_t2[i]);
let he = mesh.get_halfedge_mut(el.d[i]).expect("d[i] just created");
he.twin = Some(dt); he.next = Some(el.e[i]);
he.prev = Some(el.c[i]);
he.face = Some(el.f_t2[i]);
let he = mesh.get_halfedge_mut(el.e[i]).expect("e[i] just created");
he.twin = Some(el.a[(i + 1) % 3]); he.next = Some(el.c[i]);
he.prev = Some(el.d[i]);
he.face = Some(el.f_t2[i]);
}
mesh.get_face_mut(el.f_t2[i])
.expect("f_t2[i] just created")
.halfedge = Some(el.c[i]);
}
}
fn update_extrude_face_vertex_outgoing(mesh: &mut MeshStorage, el: &ExtrudeFaceElements) {
for i in 0..3 {
mesh.get_vertex_mut(el.vp[i])
.expect("vp[i] just created")
.halfedge = Some(el.d[i]);
}
}
pub fn extrude_faces(
mesh: &mut MeshStorage,
faces: &[FaceId],
offset: [f64; 3],
) -> Result<Vec<FaceId>, TopologyError> {
let mut all_new = Vec::new();
for &f in faces {
let new = extrude_face(mesh, f, offset)?;
all_new.extend(new);
}
Ok(all_new)
}
pub fn extrude_region(
mesh: &mut MeshStorage,
faces: &[FaceId],
offset: [f64; 3],
) -> Result<Vec<FaceId>, TopologyError> {
let region_set = validate_extrude_region_input(mesh, faces, offset)?;
let topo = collect_region_topology(mesh, faces, ®ion_set)?;
let vert_map = classify_region_vertices(mesh, &topo.verts, ®ion_set, offset)?;
let classification = classify_region_halfedges(mesh, &topo.face_hes, ®ion_set, offset)?;
let maps = setup_region_halfedges(
mesh,
&classification.boundary_hes,
&classification.interior_hes,
&vert_map,
);
rebuild_region_face_rings(mesh, &topo.face_hes, &maps.top_he_map);
let new_faces = create_region_side_faces(mesh, &classification.boundary_hes, &vert_map, &maps);
fix_region_vertex_outgoing(mesh, &classification.boundary_hes, &maps.vert_he, &vert_map);
let errors = crate::validate::validate_topology(mesh);
if !errors.is_empty() {
return Err(TopologyError::Inconsistent(format!(
"extrude_region 后校验失败:{:?}",
errors
)));
}
Ok(new_faces)
}
struct RegionHalfedgeClassification {
boundary_hes: Vec<(HalfEdgeId, VertexId, VertexId, FaceId)>,
interior_hes: HashSet<HalfEdgeId>,
}
struct RegionHalfedgeMaps {
vert_he: HashMap<VertexId, (HalfEdgeId, HalfEdgeId)>,
top_he_map: HashMap<HalfEdgeId, HalfEdgeId>,
s_top_map: HashMap<HalfEdgeId, HalfEdgeId>,
}
fn validate_extrude_region_input(
mesh: &MeshStorage,
faces: &[FaceId],
offset: [f64; 3],
) -> Result<HashSet<FaceId>, TopologyError> {
let offset_len = (offset[0].powi(2) + offset[1].powi(2) + offset[2].powi(2)).sqrt();
if offset_len < 1e-12 {
return Err(TopologyError::DegenerateTriangle);
}
if faces.is_empty() {
return Err(TopologyError::Inconsistent("挤出区域为空".into()));
}
let region_set: HashSet<FaceId> = faces.iter().copied().collect();
if region_set.len() != faces.len() {
return Err(TopologyError::Inconsistent("挤出区域包含重复面".into()));
}
for &f in faces {
if !mesh.contains_face(f) {
return Err(TopologyError::Inconsistent(format!("面 {:?} 不存在", f)));
}
}
Ok(region_set)
}
struct RegionTopology {
face_hes: Vec<(FaceId, [HalfEdgeId; 3])>,
verts: HashSet<VertexId>,
}
fn collect_region_topology(
mesh: &MeshStorage,
faces: &[FaceId],
_region_set: &HashSet<FaceId>,
) -> Result<RegionTopology, TopologyError> {
let mut face_hes: Vec<(FaceId, [HalfEdgeId; 3])> = Vec::new();
let mut verts: HashSet<VertexId> = HashSet::new();
for &f in faces {
let hes: Vec<HalfEdgeId> = FaceHalfEdges::new(mesh, f).collect();
if hes.len() != 3 {
return Err(TopologyError::Inconsistent(format!(
"面 {:?} 边界环长度={}, 非三角面",
f,
hes.len()
)));
}
for &h in &hes {
let v_t = mesh
.get_halfedge(h)
.ok_or(TopologyError::InvalidHalfEdge(h))?
.vertex;
verts.insert(v_t);
}
face_hes.push((f, [hes[0], hes[1], hes[2]]));
}
Ok(RegionTopology { face_hes, verts })
}
fn classify_region_vertices(
mesh: &mut MeshStorage,
region_verts_set: &HashSet<VertexId>,
region_set: &HashSet<FaceId>,
offset: [f64; 3],
) -> Result<HashMap<VertexId, VertexId>, TopologyError> {
let mut vert_map: HashMap<VertexId, VertexId> = HashMap::new();
for &v in region_verts_set {
let adj_faces: Vec<FaceId> = VertexAdjacentFaces::new(mesh, v).collect();
let all_in_region =
!adj_faces.is_empty() && adj_faces.iter().all(|f| region_set.contains(f));
if all_in_region {
let pos = mesh
.get_vertex(v)
.ok_or_else(|| TopologyError::Inconsistent(format!("顶点 {:?} 不存在", v)))?
.position;
mesh.get_vertex_mut(v)
.expect("vertex v validated above")
.position = [pos[0] + offset[0], pos[1] + offset[1], pos[2] + offset[2]];
vert_map.insert(v, v);
} else {
let pos = mesh
.get_vertex(v)
.ok_or_else(|| TopologyError::Inconsistent(format!("顶点 {:?} 不存在", v)))?
.position;
let v_new = mesh.add_vertex(Vertex::new([
pos[0] + offset[0],
pos[1] + offset[1],
pos[2] + offset[2],
]));
vert_map.insert(v, v_new);
}
}
Ok(vert_map)
}
fn classify_region_halfedges(
mesh: &MeshStorage,
region_face_hes: &[(FaceId, [HalfEdgeId; 3])],
region_set: &HashSet<FaceId>,
offset: [f64; 3],
) -> Result<RegionHalfedgeClassification, TopologyError> {
let mut boundary_hes: Vec<(HalfEdgeId, VertexId, VertexId, FaceId)> = Vec::new();
let mut interior_hes: HashSet<HalfEdgeId> = HashSet::new();
for &(f, hes) in region_face_hes {
for &h in &hes {
let h_data = mesh
.get_halfedge(h)
.ok_or(TopologyError::InvalidHalfEdge(h))?;
let twin_id = h_data
.twin
.ok_or_else(|| TopologyError::Inconsistent(format!("半边 {:?} 无 twin", h)))?;
let twin_data = mesh
.get_halfedge(twin_id)
.ok_or(TopologyError::InvalidHalfEdge(twin_id))?;
let v_t = h_data.vertex;
let v_o = twin_data.vertex;
match twin_data.face {
Some(twin_face) if region_set.contains(&twin_face) => {
interior_hes.insert(h);
}
_ => {
boundary_hes.push((h, v_o, v_t, f));
}
}
}
}
for &(_h, v_o, v_t, _f) in &boundary_hes {
let pos_o = mesh
.get_vertex(v_o)
.ok_or_else(|| TopologyError::Inconsistent(format!("顶点 {:?} 不存在", v_o)))?
.position;
let pos_t = mesh
.get_vertex(v_t)
.ok_or_else(|| TopologyError::Inconsistent(format!("顶点 {:?} 不存在", v_t)))?
.position;
let pos_o_up = [
pos_o[0] + offset[0],
pos_o[1] + offset[1],
pos_o[2] + offset[2],
];
if crate::predicates::is_triangle_degenerate_3d(pos_o, pos_t, pos_o_up) {
return Err(TopologyError::DegenerateTriangle);
}
}
Ok(RegionHalfedgeClassification {
boundary_hes,
interior_hes,
})
}
fn setup_region_halfedges(
mesh: &mut MeshStorage,
boundary_hes: &[(HalfEdgeId, VertexId, VertexId, FaceId)],
interior_hes: &HashSet<HalfEdgeId>,
vert_map: &HashMap<VertexId, VertexId>,
) -> RegionHalfedgeMaps {
let mut vert_he: HashMap<VertexId, (HalfEdgeId, HalfEdgeId)> = HashMap::new();
for &(_h, v_o, v_t, _f) in boundary_hes {
for &v in &[v_o, v_t] {
vert_he.entry(v).or_insert_with(|| {
let v_new = vert_map[&v];
let up = mesh.add_halfedge(HalfEdge::new(v_new)); let down = mesh.add_halfedge(HalfEdge::new(v)); mesh.get_halfedge_mut(up).expect("up just created").twin = Some(down);
mesh.get_halfedge_mut(down).expect("down just created").twin = Some(up);
(up, down)
});
}
}
for &h in interior_hes {
let v_t = mesh
.get_halfedge(h)
.expect("h from interior_hes, validated")
.vertex;
let new_v = vert_map[&v_t];
mesh.get_halfedge_mut(h)
.expect("h from interior_hes, validated")
.vertex = new_v;
}
let mut top_he_map: HashMap<HalfEdgeId, HalfEdgeId> = HashMap::new();
let mut s_top_map: HashMap<HalfEdgeId, HalfEdgeId> = HashMap::new();
for &(h, v_o, v_t, _f) in boundary_hes {
let v_t_new = vert_map[&v_t];
let v_o_new = vert_map[&v_o];
let h_top = mesh.add_halfedge(HalfEdge::new(v_t_new)); let s_top = mesh.add_halfedge(HalfEdge::new(v_o_new)); mesh.get_halfedge_mut(h_top)
.expect("h_top just created")
.twin = Some(s_top);
mesh.get_halfedge_mut(s_top)
.expect("s_top just created")
.twin = Some(h_top);
top_he_map.insert(h, h_top);
s_top_map.insert(h, s_top);
}
RegionHalfedgeMaps {
vert_he,
top_he_map,
s_top_map,
}
}
fn rebuild_region_face_rings(
mesh: &mut MeshStorage,
region_face_hes: &[(FaceId, [HalfEdgeId; 3])],
top_he_map: &HashMap<HalfEdgeId, HalfEdgeId>,
) {
for &(f, hes) in region_face_hes {
let [h0, h1, h2] = hes;
let r0 = *top_he_map.get(&h0).unwrap_or(&h0);
let r1 = *top_he_map.get(&h1).unwrap_or(&h1);
let r2 = *top_he_map.get(&h2).unwrap_or(&h2);
let r0_he = mesh
.get_halfedge_mut(r0)
.expect("r0 from top_he_map or original, validated");
r0_he.next = Some(r1);
r0_he.prev = Some(r2);
r0_he.face = Some(f);
let r1_he = mesh
.get_halfedge_mut(r1)
.expect("r1 from top_he_map or original, validated");
r1_he.next = Some(r2);
r1_he.prev = Some(r0);
r1_he.face = Some(f);
let r2_he = mesh
.get_halfedge_mut(r2)
.expect("r2 from top_he_map or original, validated");
r2_he.next = Some(r0);
r2_he.prev = Some(r1);
r2_he.face = Some(f);
mesh.get_face_mut(f).expect("f validated earlier").halfedge = Some(r0);
for &h in &hes {
if top_he_map.contains_key(&h) {
let h_he = mesh
.get_halfedge_mut(h)
.expect("h from region_face_hes, validated");
h_he.next = None;
h_he.prev = None;
h_he.face = None;
}
}
}
}
fn create_region_side_faces(
mesh: &mut MeshStorage,
boundary_hes: &[(HalfEdgeId, VertexId, VertexId, FaceId)],
vert_map: &HashMap<VertexId, VertexId>,
maps: &RegionHalfedgeMaps,
) -> Vec<FaceId> {
let mut new_faces = Vec::new();
for &(h, v_o, v_t, _f) in boundary_hes {
let v_t_new = vert_map[&v_t];
let s_top = maps.s_top_map[&h];
let (up_t, _down_t) = maps.vert_he[&v_t]; let (_up_o, down_o) = maps.vert_he[&v_o];
let diag = mesh.add_halfedge(HalfEdge::new(v_t_new)); let diag_rev = mesh.add_halfedge(HalfEdge::new(v_o)); mesh.get_halfedge_mut(diag).expect("diag just created").twin = Some(diag_rev);
mesh.get_halfedge_mut(diag_rev)
.expect("diag_rev just created")
.twin = Some(diag);
let f_t1 = mesh.add_face(Face::new());
{
let he = mesh
.get_halfedge_mut(h)
.expect("h from boundary_hes, validated");
he.next = Some(up_t);
he.prev = Some(diag_rev);
he.face = Some(f_t1);
let he = mesh
.get_halfedge_mut(up_t)
.expect("up_t from vert_he, just created");
he.next = Some(diag_rev);
he.prev = Some(h);
he.face = Some(f_t1);
let he = mesh
.get_halfedge_mut(diag_rev)
.expect("diag_rev just created");
he.next = Some(h);
he.prev = Some(up_t);
he.face = Some(f_t1);
}
mesh.get_face_mut(f_t1).expect("f_t1 just created").halfedge = Some(h);
let f_t2 = mesh.add_face(Face::new());
{
let he = mesh.get_halfedge_mut(diag).expect("diag just created");
he.next = Some(s_top);
he.prev = Some(down_o);
he.face = Some(f_t2);
let he = mesh.get_halfedge_mut(s_top).expect("s_top just created");
he.next = Some(down_o);
he.prev = Some(diag);
he.face = Some(f_t2);
let he = mesh
.get_halfedge_mut(down_o)
.expect("down_o from vert_he, just created");
he.next = Some(diag);
he.prev = Some(s_top);
he.face = Some(f_t2);
}
mesh.get_face_mut(f_t2).expect("f_t2 just created").halfedge = Some(diag);
new_faces.push(f_t1);
new_faces.push(f_t2);
}
new_faces
}
fn fix_region_vertex_outgoing(
mesh: &mut MeshStorage,
boundary_hes: &[(HalfEdgeId, VertexId, VertexId, FaceId)],
vert_he: &HashMap<VertexId, (HalfEdgeId, HalfEdgeId)>,
vert_map: &HashMap<VertexId, VertexId>,
) {
for &(_h, v_o, v_t, _f) in boundary_hes {
for &v in &[v_o, v_t] {
let (up, down) = vert_he[&v];
mesh.get_vertex_mut(v)
.expect("v from boundary_hes, validated")
.halfedge = Some(up);
let v_new = vert_map[&v];
mesh.get_vertex_mut(v_new)
.expect("v_new from vert_map, validated")
.halfedge = Some(down);
}
}
}