use std::collections::HashSet;
use crate::ids::{FaceId, HalfEdgeId, VertexId};
use crate::storage::{Face, HalfEdge, MeshStorage, Vertex};
use crate::traversal::{FaceHalfEdges, VertexAdjacentVerts, VertexRing};
use super::helpers::TopologyError;
use super::validate::validate_mesh;
pub fn split_edge(mesh: &mut MeshStorage, he: HalfEdgeId) -> Result<VertexId, TopologyError> {
let data = collect_split_edge_data(mesh, he)?;
let new_he = create_split_elements(mesh, &data)?;
reconnect_split_f1_side(mesh, &data, &new_he);
reconnect_split_twin_side(mesh, &data, &new_he);
finalize_split_edge(mesh, &data, &new_he);
Ok(new_he.m)
}
struct SplitEdgeData {
h_id: HalfEdgeId,
twin_id: HalfEdgeId,
a: VertexId,
b: VertexId,
c: VertexId,
f1: FaceId,
n1: HalfEdgeId,
p1: HalfEdgeId,
has_f2: bool,
f2: Option<FaceId>,
n2: Option<HalfEdgeId>,
p2: Option<HalfEdgeId>,
d: Option<VertexId>,
}
struct SplitHalfedges {
m: VertexId,
a_to_m: HalfEdgeId,
m_to_a: HalfEdgeId,
m_to_b: HalfEdgeId,
b_to_m: HalfEdgeId,
m_to_c: HalfEdgeId,
c_to_m: HalfEdgeId,
m_to_d: Option<HalfEdgeId>,
d_to_m: Option<HalfEdgeId>,
}
fn collect_split_edge_data(
mesh: &MeshStorage,
he: HalfEdgeId,
) -> Result<SplitEdgeData, TopologyError> {
let h_data = mesh
.get_halfedge(he)
.ok_or(TopologyError::InvalidHalfEdge(he))?
.clone();
let (h_id, h) = if h_data.face.is_none() {
let twin_id = h_data.twin.ok_or(TopologyError::NoTwin(he))?;
let twin_data = mesh
.get_halfedge(twin_id)
.ok_or(TopologyError::InvalidHalfEdge(twin_id))?
.clone();
if twin_data.face.is_none() {
return Err(TopologyError::NoFace(he));
}
(twin_id, twin_data)
} else {
(he, h_data)
};
let twin_id = h.twin.ok_or(TopologyError::NoTwin(h_id))?;
let twin = mesh
.get_halfedge(twin_id)
.ok_or(TopologyError::InvalidHalfEdge(twin_id))?
.clone();
let a = twin.vertex; let b = h.vertex; let f1 = h.face.ok_or(TopologyError::NoFace(h_id))?;
let n1 = h
.next
.ok_or_else(|| TopologyError::Inconsistent("h.next 为 None".into()))?;
let p1 = h
.prev
.ok_or_else(|| TopologyError::Inconsistent("h.prev 为 None".into()))?;
let c = mesh
.get_halfedge(n1)
.ok_or(TopologyError::InvalidHalfEdge(n1))?
.vertex;
let has_f2 = twin.face.is_some();
let (f2, n2, p2, d) = if has_f2 {
let f2 = twin.face.expect("has_f2 guarantees twin.face is Some");
let n2 = twin
.next
.ok_or_else(|| TopologyError::Inconsistent("twin.next 为 None".into()))?;
let p2 = twin
.prev
.ok_or_else(|| TopologyError::Inconsistent("twin.prev 为 None".into()))?;
let d = mesh
.get_halfedge(n2)
.ok_or(TopologyError::InvalidHalfEdge(n2))?
.vertex;
(Some(f2), Some(n2), Some(p2), Some(d))
} else {
(None, None, None, None)
};
Ok(SplitEdgeData {
h_id,
twin_id,
a,
b,
c,
f1,
n1,
p1,
has_f2,
f2,
n2,
p2,
d,
})
}
fn create_split_elements(
mesh: &mut MeshStorage,
data: &SplitEdgeData,
) -> Result<SplitHalfedges, TopologyError> {
let pos_a = mesh
.get_vertex(data.a)
.ok_or_else(|| TopologyError::Inconsistent("顶点 A 不存在".into()))?
.position;
let pos_b = mesh
.get_vertex(data.b)
.ok_or_else(|| TopologyError::Inconsistent("顶点 B 不存在".into()))?
.position;
let mid = [
(pos_a[0] + pos_b[0]) * 0.5,
(pos_a[1] + pos_b[1]) * 0.5,
(pos_a[2] + pos_b[2]) * 0.5,
];
let m = mesh.add_vertex(Vertex::new(mid));
let a_to_m = mesh.add_halfedge(HalfEdge::new(m)); let m_to_a = mesh.add_halfedge(HalfEdge::new(data.a)); let m_to_b = mesh.add_halfedge(HalfEdge::new(data.b)); let b_to_m = mesh.add_halfedge(HalfEdge::new(m)); let m_to_c = mesh.add_halfedge(HalfEdge::new(data.c)); let c_to_m = mesh.add_halfedge(HalfEdge::new(m));
let (m_to_d, d_to_m) = if data.has_f2 {
let d = data.d.expect("d is Some when has_f2");
(
Some(mesh.add_halfedge(HalfEdge::new(d))), Some(mesh.add_halfedge(HalfEdge::new(m))), )
} else {
(None, None)
};
Ok(SplitHalfedges {
m,
a_to_m,
m_to_a,
m_to_b,
b_to_m,
m_to_c,
c_to_m,
m_to_d,
d_to_m,
})
}
fn reconnect_split_f1_side(mesh: &mut MeshStorage, data: &SplitEdgeData, he: &SplitHalfedges) {
{
let am = mesh
.get_halfedge_mut(he.a_to_m)
.expect("a_to_m just created");
am.twin = Some(he.m_to_a);
am.next = Some(he.m_to_c);
am.prev = Some(data.p1);
am.face = Some(data.f1);
let mc = mesh
.get_halfedge_mut(he.m_to_c)
.expect("m_to_c just created");
mc.twin = Some(he.c_to_m);
mc.next = Some(data.p1);
mc.prev = Some(he.a_to_m);
mc.face = Some(data.f1);
let p1h = mesh
.get_halfedge_mut(data.p1)
.expect("p1 validated earlier");
p1h.next = Some(he.a_to_m);
p1h.prev = Some(he.m_to_c);
}
let f_new1 = mesh.add_face(Face::new());
{
let mb = mesh
.get_halfedge_mut(he.m_to_b)
.expect("m_to_b just created");
mb.twin = Some(he.b_to_m);
mb.next = Some(data.n1);
mb.prev = Some(he.c_to_m);
mb.face = Some(f_new1);
let n1h = mesh
.get_halfedge_mut(data.n1)
.expect("n1 validated earlier");
n1h.next = Some(he.c_to_m);
n1h.prev = Some(he.m_to_b);
n1h.face = Some(f_new1);
let cm = mesh
.get_halfedge_mut(he.c_to_m)
.expect("c_to_m just created");
cm.twin = Some(he.m_to_c);
cm.next = Some(he.m_to_b);
cm.prev = Some(data.n1);
cm.face = Some(f_new1);
}
mesh.get_face_mut(f_new1)
.expect("f_new1 just created")
.halfedge = Some(he.m_to_b);
}
fn reconnect_split_twin_side(mesh: &mut MeshStorage, data: &SplitEdgeData, he: &SplitHalfedges) {
if data.has_f2 {
let f2 = data.f2.expect("f2 is Some when has_f2");
let n2 = data.n2.expect("n2 is Some when has_f2");
let p2 = data.p2.expect("p2 is Some when has_f2");
let m_to_d = he.m_to_d.expect("m_to_d is Some when has_f2");
let d_to_m = he.d_to_m.expect("d_to_m is Some when has_f2");
{
let bm = mesh
.get_halfedge_mut(he.b_to_m)
.expect("b_to_m just created");
bm.twin = Some(he.m_to_b);
bm.next = Some(m_to_d);
bm.prev = Some(p2);
bm.face = Some(f2);
let md = mesh.get_halfedge_mut(m_to_d).expect("m_to_d just created");
md.twin = Some(d_to_m);
md.next = Some(p2);
md.prev = Some(he.b_to_m);
md.face = Some(f2);
let p2h = mesh.get_halfedge_mut(p2).expect("p2 validated earlier");
p2h.next = Some(he.b_to_m);
p2h.prev = Some(m_to_d);
}
let f_new2 = mesh.add_face(Face::new());
{
let ma = mesh
.get_halfedge_mut(he.m_to_a)
.expect("m_to_a just created");
ma.twin = Some(he.a_to_m);
ma.next = Some(n2);
ma.prev = Some(d_to_m);
ma.face = Some(f_new2);
let n2h = mesh.get_halfedge_mut(n2).expect("n2 validated earlier");
n2h.next = Some(d_to_m);
n2h.prev = Some(he.m_to_a);
n2h.face = Some(f_new2);
let dm = mesh.get_halfedge_mut(d_to_m).expect("d_to_m just created");
dm.twin = Some(m_to_d);
dm.next = Some(he.m_to_a);
dm.prev = Some(n2);
dm.face = Some(f_new2);
}
mesh.get_face_mut(f_new2)
.expect("f_new2 just created")
.halfedge = Some(he.m_to_a);
mesh.get_face_mut(f2)
.expect("f2 validated earlier")
.halfedge = Some(he.b_to_m);
} else {
let bm = mesh
.get_halfedge_mut(he.b_to_m)
.expect("b_to_m just created");
bm.twin = Some(he.m_to_b);
bm.face = None;
let ma = mesh
.get_halfedge_mut(he.m_to_a)
.expect("m_to_a just created");
ma.twin = Some(he.a_to_m);
ma.face = None;
}
}
fn finalize_split_edge(mesh: &mut MeshStorage, data: &SplitEdgeData, he: &SplitHalfedges) {
mesh.get_face_mut(data.f1)
.expect("f1 validated earlier")
.halfedge = Some(he.a_to_m);
if mesh
.get_vertex(data.a)
.expect("vertex a validated earlier")
.halfedge
== Some(data.h_id)
{
mesh.get_vertex_mut(data.a)
.expect("vertex a validated earlier")
.halfedge = Some(he.a_to_m);
}
if mesh
.get_vertex(data.b)
.expect("vertex b validated earlier")
.halfedge
== Some(data.twin_id)
{
mesh.get_vertex_mut(data.b)
.expect("vertex b validated earlier")
.halfedge = Some(he.b_to_m);
}
mesh.get_vertex_mut(he.m).expect("m just created").halfedge = Some(he.m_to_a);
mesh.remove_halfedge(data.h_id);
mesh.remove_halfedge(data.twin_id);
}
pub fn flip_edge(mesh: &mut MeshStorage, he: HalfEdgeId) -> Result<(), TopologyError> {
let h = mesh
.get_halfedge(he)
.ok_or(TopologyError::InvalidHalfEdge(he))?
.clone();
let twin_id = h.twin.ok_or(TopologyError::NoTwin(he))?;
let twin = mesh
.get_halfedge(twin_id)
.ok_or(TopologyError::InvalidHalfEdge(twin_id))?
.clone();
let f1 = h.face.ok_or(TopologyError::FlipOnBoundaryEdge(he))?;
let f2 = twin.face.ok_or(TopologyError::FlipOnBoundaryEdge(he))?;
let a = twin.vertex; let b = h.vertex;
let n1 = h
.next
.ok_or_else(|| TopologyError::Inconsistent("h.next 为 None".into()))?;
let p1 = h
.prev
.ok_or_else(|| TopologyError::Inconsistent("h.prev 为 None".into()))?;
let n2 = twin
.next
.ok_or_else(|| TopologyError::Inconsistent("twin.next 为 None".into()))?;
let p2 = twin
.prev
.ok_or_else(|| TopologyError::Inconsistent("twin.prev 为 None".into()))?;
let c = mesh
.get_halfedge(n1)
.ok_or(TopologyError::InvalidHalfEdge(n1))?
.vertex;
let d = mesh
.get_halfedge(n2)
.ok_or(TopologyError::InvalidHalfEdge(n2))?
.vertex;
if c == d {
return Err(TopologyError::DegenerateTriangle);
}
{
let h_mut = mesh
.get_halfedge_mut(he)
.expect("he validated at function start");
h_mut.vertex = c;
h_mut.next = Some(p1);
h_mut.prev = Some(n2);
h_mut.face = Some(f1);
let twin_mut = mesh
.get_halfedge_mut(twin_id)
.expect("twin_id validated earlier");
twin_mut.vertex = d;
twin_mut.next = Some(p2);
twin_mut.prev = Some(n1);
twin_mut.face = Some(f2);
}
{
let p1_mut = mesh.get_halfedge_mut(p1).expect("p1 validated earlier");
p1_mut.next = Some(n2);
p1_mut.prev = Some(he);
let n2_mut = mesh.get_halfedge_mut(n2).expect("n2 validated earlier");
n2_mut.next = Some(he);
n2_mut.prev = Some(p1);
n2_mut.face = Some(f1);
}
{
let p2_mut = mesh.get_halfedge_mut(p2).expect("p2 validated earlier");
p2_mut.next = Some(n1);
p2_mut.prev = Some(twin_id);
let n1_mut = mesh.get_halfedge_mut(n1).expect("n1 validated earlier");
n1_mut.next = Some(twin_id);
n1_mut.prev = Some(p2);
n1_mut.face = Some(f2);
}
mesh.get_face_mut(f1)
.expect("f1 validated earlier")
.halfedge = Some(he);
mesh.get_face_mut(f2)
.expect("f2 validated earlier")
.halfedge = Some(twin_id);
if mesh
.get_vertex(a)
.expect("vertex a is twin.vertex, validated")
.halfedge
== Some(he)
{
mesh.get_vertex_mut(a)
.expect("vertex a is twin.vertex, validated")
.halfedge = Some(n2);
}
if mesh
.get_vertex(b)
.expect("vertex b is h.vertex, validated")
.halfedge
== Some(twin_id)
{
mesh.get_vertex_mut(b)
.expect("vertex b is h.vertex, validated")
.halfedge = Some(n1);
}
Ok(())
}
pub fn collapse_edge(mesh: &mut MeshStorage, he: HalfEdgeId) -> Result<VertexId, TopologyError> {
collapse_edge_impl(mesh, he, None)
}
pub fn collapse_edge_at(
mesh: &mut MeshStorage,
he: HalfEdgeId,
target_pos: [f64; 3],
) -> Result<VertexId, TopologyError> {
collapse_edge_impl(mesh, he, Some(target_pos))
}
fn collapse_edge_impl(
mesh: &mut MeshStorage,
he: HalfEdgeId,
target_pos: Option<[f64; 3]>,
) -> Result<VertexId, TopologyError> {
let data = collect_collapse_data(mesh, he)?;
let to_update = collect_halfedges_to_update(mesh, &data);
let new_pos = compute_collapse_position(mesh, &data, target_pos)?;
let k = mesh.add_vertex(Vertex::new(new_pos));
sew_collapse_twins(mesh, &data);
update_collapse_vertex_refs(mesh, &data, &to_update, k);
remove_collapse_elements(mesh, &data);
Ok(k)
}
struct CollapseData {
he: HalfEdgeId,
twin_id: HalfEdgeId,
a: VertexId,
b: VertexId,
c: VertexId,
d: VertexId,
f1: FaceId,
f2: FaceId,
n1: HalfEdgeId,
p1: HalfEdgeId,
n2: HalfEdgeId,
p2: HalfEdgeId,
p1_twin: HalfEdgeId,
n1_twin: HalfEdgeId,
n2_twin: HalfEdgeId,
p2_twin: HalfEdgeId,
}
fn collect_collapse_data(
mesh: &MeshStorage,
he: HalfEdgeId,
) -> Result<CollapseData, TopologyError> {
let h = mesh
.get_halfedge(he)
.ok_or(TopologyError::InvalidHalfEdge(he))?
.clone();
let twin_id = h.twin.ok_or(TopologyError::NoTwin(he))?;
let twin = mesh
.get_halfedge(twin_id)
.ok_or(TopologyError::InvalidHalfEdge(twin_id))?
.clone();
let f1 = h.face.ok_or(TopologyError::CollapseOnBoundaryEdge(he))?;
let f2 = twin.face.ok_or(TopologyError::CollapseOnBoundaryEdge(he))?;
let a = twin.vertex;
let b = h.vertex;
let n1 = h
.next
.ok_or_else(|| TopologyError::Inconsistent("h.next 为 None".into()))?;
let p1 = h
.prev
.ok_or_else(|| TopologyError::Inconsistent("h.prev 为 None".into()))?;
let n2 = twin
.next
.ok_or_else(|| TopologyError::Inconsistent("twin.next 为 None".into()))?;
let p2 = twin
.prev
.ok_or_else(|| TopologyError::Inconsistent("twin.prev 为 None".into()))?;
let c = mesh
.get_halfedge(n1)
.ok_or(TopologyError::InvalidHalfEdge(n1))?
.vertex;
let d = mesh
.get_halfedge(n2)
.ok_or(TopologyError::InvalidHalfEdge(n2))?
.vertex;
if c == d {
return Err(TopologyError::DegenerateTriangle);
}
if !check_link_condition(mesh, a, b, c, d) {
return Err(TopologyError::LinkConditionViolated { a, b });
}
let p1_twin = mesh
.get_halfedge(p1)
.ok_or(TopologyError::InvalidHalfEdge(p1))?
.twin
.ok_or_else(|| TopologyError::Inconsistent("p1.twin 为 None".into()))?;
let n1_twin = mesh
.get_halfedge(n1)
.ok_or(TopologyError::InvalidHalfEdge(n1))?
.twin
.ok_or_else(|| TopologyError::Inconsistent("n1.twin 为 None".into()))?;
let n2_twin = mesh
.get_halfedge(n2)
.ok_or(TopologyError::InvalidHalfEdge(n2))?
.twin
.ok_or_else(|| TopologyError::Inconsistent("n2.twin 为 None".into()))?;
let p2_twin = mesh
.get_halfedge(p2)
.ok_or(TopologyError::InvalidHalfEdge(p2))?
.twin
.ok_or_else(|| TopologyError::Inconsistent("p2.twin 为 None".into()))?;
Ok(CollapseData {
he,
twin_id,
a,
b,
c,
d,
f1,
f2,
n1,
p1,
n2,
p2,
p1_twin,
n1_twin,
n2_twin,
p2_twin,
})
}
fn collect_halfedges_to_update(mesh: &MeshStorage, data: &CollapseData) -> Vec<HalfEdgeId> {
let deleted = [data.he, data.twin_id, data.n1, data.p1, data.n2, data.p2];
let deleted_set: HashSet<HalfEdgeId> = deleted.iter().copied().collect();
let mut to_update: Vec<HalfEdgeId> = Vec::new();
for out_he in VertexRing::new(mesh, data.a).collect::<Vec<_>>() {
if let Some(t_id) = mesh.get_halfedge(out_he).and_then(|h| h.twin)
&& !deleted_set.contains(&t_id)
{
to_update.push(t_id);
}
}
for out_he in VertexRing::new(mesh, data.b).collect::<Vec<_>>() {
if let Some(t_id) = mesh.get_halfedge(out_he).and_then(|h| h.twin)
&& !deleted_set.contains(&t_id)
{
to_update.push(t_id);
}
}
to_update
}
fn compute_collapse_position(
mesh: &MeshStorage,
data: &CollapseData,
target_pos: Option<[f64; 3]>,
) -> Result<[f64; 3], TopologyError> {
match target_pos {
Some(p) => Ok(p),
None => {
let pos_a = mesh
.get_vertex(data.a)
.ok_or_else(|| TopologyError::Inconsistent("顶点 A 不存在".into()))?
.position;
let pos_b = mesh
.get_vertex(data.b)
.ok_or_else(|| TopologyError::Inconsistent("顶点 B 不存在".into()))?
.position;
Ok([
(pos_a[0] + pos_b[0]) * 0.5,
(pos_a[1] + pos_b[1]) * 0.5,
(pos_a[2] + pos_b[2]) * 0.5,
])
}
}
}
fn sew_collapse_twins(mesh: &mut MeshStorage, data: &CollapseData) {
{
let p1t = mesh
.get_halfedge_mut(data.p1_twin)
.expect("p1_twin validated earlier");
p1t.twin = Some(data.n1_twin);
let n1t = mesh
.get_halfedge_mut(data.n1_twin)
.expect("n1_twin validated earlier");
n1t.twin = Some(data.p1_twin);
}
{
let n2t = mesh
.get_halfedge_mut(data.n2_twin)
.expect("n2_twin validated earlier");
n2t.twin = Some(data.p2_twin);
let p2t = mesh
.get_halfedge_mut(data.p2_twin)
.expect("p2_twin validated earlier");
p2t.twin = Some(data.n2_twin);
}
}
fn update_collapse_vertex_refs(
mesh: &mut MeshStorage,
data: &CollapseData,
to_update: &[HalfEdgeId],
k: VertexId,
) {
for he_id in to_update {
let h_mut = mesh
.get_halfedge_mut(*he_id)
.expect("he_id collected from valid halfedges");
if h_mut.vertex == data.a || h_mut.vertex == data.b {
h_mut.vertex = k;
}
}
mesh.get_vertex_mut(k).expect("k just created").halfedge = Some(data.p1_twin);
let c_out = mesh
.get_vertex(data.c)
.expect("vertex c validated earlier")
.halfedge;
if c_out == Some(data.n1) || c_out == Some(data.p1) || c_out.is_none() {
mesh.get_vertex_mut(data.c)
.expect("vertex c validated earlier")
.halfedge = Some(data.n1_twin);
}
let d_out = mesh
.get_vertex(data.d)
.expect("vertex d validated earlier")
.halfedge;
if d_out == Some(data.n2) || d_out == Some(data.p2) || d_out.is_none() {
mesh.get_vertex_mut(data.d)
.expect("vertex d validated earlier")
.halfedge = Some(data.n2_twin);
}
}
fn remove_collapse_elements(mesh: &mut MeshStorage, data: &CollapseData) {
mesh.remove_halfedge(data.he);
mesh.remove_halfedge(data.twin_id);
mesh.remove_halfedge(data.n1);
mesh.remove_halfedge(data.p1);
mesh.remove_halfedge(data.n2);
mesh.remove_halfedge(data.p2);
mesh.remove_face(data.f1);
mesh.remove_face(data.f2);
mesh.remove_vertex(data.a);
mesh.remove_vertex(data.b);
}
pub(super) fn check_link_condition(
mesh: &MeshStorage,
a: VertexId,
b: VertexId,
c: VertexId,
d: VertexId,
) -> bool {
let neighbors_a: HashSet<VertexId> = VertexAdjacentVerts::new(mesh, a).collect();
let neighbors_b: HashSet<VertexId> = VertexAdjacentVerts::new(mesh, b).collect();
let common: HashSet<&VertexId> = neighbors_a.intersection(&neighbors_b).collect();
common.len() == 2 && common.contains(&c) && common.contains(&d)
}
pub fn split_face(mesh: &mut MeshStorage, face: FaceId) -> Result<VertexId, TopologyError> {
let face_data = mesh
.get_face(face)
.ok_or_else(|| TopologyError::Inconsistent("面不存在".into()))?;
let _start_he = face_data
.halfedge
.ok_or_else(|| TopologyError::Inconsistent("面无半边".into()))?;
let he_ids: Vec<HalfEdgeId> = FaceHalfEdges::new(mesh, face).collect();
if he_ids.len() != 3 {
return Err(TopologyError::Inconsistent("仅支持三角面".into()));
}
let he_data: Vec<_> = he_ids
.iter()
.map(|&h| {
mesh.get_halfedge(h)
.expect("h from FaceHalfEdges, validated")
.clone()
})
.collect();
let verts: Vec<VertexId> = he_data.iter().map(|h| h.vertex).collect();
let [v0, v1, v2] = [verts[0], verts[1], verts[2]];
let [_he0, _he1, _he2] = [he_ids[0], he_ids[1], he_ids[2]];
let old_twins = [he_data[0].twin, he_data[1].twin, he_data[2].twin];
let pos: Vec<[f64; 3]> = verts
.iter()
.map(|&v| {
mesh.get_vertex(v)
.expect("v from he_data, validated")
.position
})
.collect();
let center = [
(pos[0][0] + pos[1][0] + pos[2][0]) / 3.0,
(pos[0][1] + pos[1][1] + pos[2][1]) / 3.0,
(pos[0][2] + pos[1][2] + pos[2][2]) / 3.0,
];
let m = mesh.add_vertex(Vertex::new(center));
mesh.remove_face(face);
for &he in &he_ids {
mesh.remove_halfedge(he);
}
let mut new_faces = Vec::new();
for (i, &(_, src, dst)) in [(0, v0, v1), (1, v1, v2), (2, v2, v0)].iter().enumerate() {
let spoke_out = mesh.add_halfedge(HalfEdge::new(src)); let spoke_in = mesh.add_halfedge(HalfEdge::new(m));
mesh.get_halfedge_mut(spoke_out)
.expect("spoke_out just created")
.twin = Some(spoke_in);
mesh.get_halfedge_mut(spoke_in)
.expect("spoke_in just created")
.twin = Some(spoke_out);
let outer = mesh.add_halfedge(HalfEdge::new(dst));
if let Some(old_twin) = old_twins[(i + 1) % 3] {
mesh.get_halfedge_mut(outer)
.expect("outer just created")
.twin = Some(old_twin);
if let Some(t) = mesh.get_halfedge_mut(old_twin) {
t.twin = Some(outer);
}
}
mesh.get_halfedge_mut(spoke_out)
.expect("spoke_out just created")
.next = Some(outer);
mesh.get_halfedge_mut(spoke_out)
.expect("spoke_out just created")
.prev = Some(spoke_in);
mesh.get_halfedge_mut(outer)
.expect("outer just created")
.next = Some(spoke_in);
mesh.get_halfedge_mut(outer)
.expect("outer just created")
.prev = Some(spoke_out);
mesh.get_halfedge_mut(spoke_in)
.expect("spoke_in just created")
.next = Some(spoke_out);
mesh.get_halfedge_mut(spoke_in)
.expect("spoke_in just created")
.prev = Some(outer);
let new_f = mesh.add_face(Face::new());
mesh.get_face_mut(new_f)
.expect("new_f just created")
.halfedge = Some(spoke_out);
for &he in &[spoke_out, outer, spoke_in] {
mesh.get_halfedge_mut(he).expect("he just created").face = Some(new_f);
}
new_faces.push(new_f);
}
mesh.get_vertex_mut(m).expect("m just created").halfedge = Some(
mesh.get_face(new_faces[0])
.and_then(|f| f.halfedge)
.expect("face halfedge just set"),
);
validate_mesh(mesh)?;
Ok(m)
}