use crate::ids::HalfEdgeId;
use crate::storage::MeshStorage;
use super::helpers::TopologyError;
pub fn validate_mesh(mesh: &MeshStorage) -> Result<(), TopologyError> {
let all_he: Vec<HalfEdgeId> = mesh.halfedge_ids().collect();
for he_id in &all_he {
let he = match mesh.get_halfedge(*he_id) {
Some(h) => h,
None => continue,
};
if let Some(twin_id) = he.twin {
let twin = match mesh.get_halfedge(twin_id) {
Some(t) => t,
None => {
return Err(TopologyError::Inconsistent(format!(
"半边 {:?} 的 twin {:?} 不存在",
he_id, twin_id
)));
}
};
if twin.twin != Some(*he_id) {
return Err(TopologyError::Inconsistent(format!(
"twin 不互指:{:?}.twin={:?}, 但 {:?}.twin={:?}",
he_id, twin_id, twin_id, twin.twin
)));
}
if twin.vertex == he.vertex {
return Err(TopologyError::Inconsistent(format!(
"半边 {:?} 与其 twin 顶点相同(自环)",
he_id
)));
}
}
if let Some(next_id) = he.next {
match mesh.get_halfedge(next_id) {
Some(next) if next.prev == Some(*he_id) => {}
Some(next) => {
return Err(TopologyError::Inconsistent(format!(
"next/prev 不一致:{:?}.next={:?}, 但 {:?}.prev={:?}",
he_id, next_id, next_id, next.prev
)));
}
None => {
return Err(TopologyError::Inconsistent(format!(
"半边 {:?} 的 next {:?} 不存在",
he_id, next_id
)));
}
}
}
if let Some(prev_id) = he.prev {
match mesh.get_halfedge(prev_id) {
Some(prev) if prev.next == Some(*he_id) => {}
Some(prev) => {
return Err(TopologyError::Inconsistent(format!(
"prev/next 不一致:{:?}.prev={:?}, 但 {:?}.next={:?}",
he_id, prev_id, prev_id, prev.next
)));
}
None => {
return Err(TopologyError::Inconsistent(format!(
"半边 {:?} 的 prev {:?} 不存在",
he_id, prev_id
)));
}
}
}
}
for f_id in mesh.face_ids() {
let f = match mesh.get_face(f_id) {
Some(f) => f,
None => continue,
};
if let Some(start) = f.halfedge {
let mut count = 0usize;
let mut cur = start;
let max_iter = mesh.halfedge_count() + 1;
for _ in 0..max_iter {
count += 1;
match mesh.get_halfedge(cur).and_then(|h| h.next) {
Some(n) if n != start => cur = n,
_ => break,
}
}
if count != 3 {
return Err(TopologyError::Inconsistent(format!(
"面 {:?} 的边界环长度为 {},非三角面",
f_id, count
)));
}
}
}
Ok(())
}