#[allow(unused_imports)]
use super::functions::*;
#[allow(unused_imports)]
use super::functions_2::*;
use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone)]
pub struct HalfEdgeMesh {
pub vertices: Vec<[f64; 3]>,
pub half_edges: Vec<HalfEdge>,
pub vertex_half_edge: Vec<usize>,
pub face_half_edge: Vec<usize>,
pub vertex_deleted: Vec<bool>,
pub face_deleted: Vec<bool>,
pub he_deleted: Vec<bool>,
}
impl HalfEdgeMesh {
pub fn from_triangles(vertices: Vec<[f64; 3]>, triangles: &[[usize; 3]]) -> Self {
let n_verts = vertices.len();
let n_faces = triangles.len();
let n_he = n_faces * 3;
let mut half_edges = Vec::with_capacity(n_he);
let mut vertex_half_edge = vec![usize::MAX; n_verts];
let mut face_half_edge = Vec::with_capacity(n_faces);
let mut edge_map: HashMap<(usize, usize), usize> = HashMap::new();
for (fi, tri) in triangles.iter().enumerate() {
let base = half_edges.len();
face_half_edge.push(base);
for k in 0..3 {
let v_from = tri[k];
let v_to = tri[(k + 1) % 3];
let he_idx = base + k;
half_edges.push(HalfEdge {
vertex: v_to,
face: fi,
twin: usize::MAX,
next: base + (k + 1) % 3,
prev: base + (k + 2) % 3,
});
if vertex_half_edge[v_from] == usize::MAX {
vertex_half_edge[v_from] = he_idx;
}
edge_map.insert((v_from, v_to), he_idx);
}
}
let keys: Vec<(usize, usize)> = edge_map.keys().copied().collect();
for (v_from, v_to) in keys {
if let Some(&twin_idx) = edge_map.get(&(v_to, v_from)) {
let he_idx = edge_map[&(v_from, v_to)];
half_edges[he_idx].twin = twin_idx;
half_edges[twin_idx].twin = he_idx;
}
}
let vertex_deleted = vec![false; n_verts];
let face_deleted = vec![false; n_faces];
let he_deleted = vec![false; n_he];
Self {
vertices,
half_edges,
vertex_half_edge,
face_half_edge,
vertex_deleted,
face_deleted,
he_deleted,
}
}
pub fn active_vertex_count(&self) -> usize {
self.vertex_deleted.iter().filter(|&&d| !d).count()
}
pub fn active_face_count(&self) -> usize {
self.face_deleted.iter().filter(|&&d| !d).count()
}
pub fn is_boundary_half_edge(&self, he_idx: usize) -> bool {
self.half_edges[he_idx].twin == usize::MAX
}
pub fn is_boundary_vertex(&self, v: usize) -> bool {
let start = self.vertex_half_edge[v];
if start == usize::MAX {
return false;
}
let mut he = start;
loop {
if self.is_boundary_half_edge(he) {
return true;
}
let twin = self.half_edges[he].twin;
if twin == usize::MAX {
return true;
}
he = self.half_edges[twin].next;
if he == start {
break;
}
}
false
}
pub fn vertex_faces(&self, v: usize) -> Vec<usize> {
let mut faces = Vec::new();
let start = self.vertex_half_edge[v];
if start == usize::MAX {
return faces;
}
let mut he = start;
loop {
let f = self.half_edges[he].face;
if f != usize::MAX && !self.face_deleted[f] {
faces.push(f);
}
let twin = self.half_edges[he].twin;
if twin == usize::MAX {
break;
}
he = self.half_edges[twin].next;
if he == start {
break;
}
}
faces
}
pub fn vertex_neighbors(&self, v: usize) -> Vec<usize> {
let mut neighbors = Vec::new();
let start = self.vertex_half_edge[v];
if start == usize::MAX {
return neighbors;
}
let mut he = start;
loop {
let target = self.half_edges[he].vertex;
if !self.vertex_deleted[target] {
neighbors.push(target);
}
let twin = self.half_edges[he].twin;
if twin == usize::MAX {
break;
}
he = self.half_edges[twin].next;
if he == start {
break;
}
}
neighbors
}
pub fn face_normal(&self, fi: usize) -> [f64; 3] {
let he0 = self.face_half_edge[fi];
let he1 = self.half_edges[he0].next;
let he2 = self.half_edges[he1].next;
let v0_idx = self.half_edges[self.half_edges[he0].prev].vertex;
let v1_idx = self.half_edges[he0].vertex;
let v2_idx = self.half_edges[he1].vertex;
let _ = v2_idx;
let _ = he2;
let va = self.vertices[v0_idx];
let vb = self.vertices[v1_idx];
let vc = self.vertices[self.half_edges[he1].vertex];
let ab = sub3(vb, va);
let ac = sub3(vc, va);
normalize3(cross3(ab, ac))
}
pub fn face_area(&self, fi: usize) -> f64 {
let he0 = self.face_half_edge[fi];
let he1 = self.half_edges[he0].next;
let v0_idx = self.half_edges[self.half_edges[he0].prev].vertex;
let v1_idx = self.half_edges[he0].vertex;
let v2_idx = self.half_edges[he1].vertex;
let va = self.vertices[v0_idx];
let vb = self.vertices[v1_idx];
let vc = self.vertices[v2_idx];
let ab = sub3(vb, va);
let ac = sub3(vc, va);
0.5 * len3(cross3(ab, ac))
}
pub fn extract_triangles(&self) -> Vec<[usize; 3]> {
let mut tris = Vec::new();
for (fi, &he0) in self.face_half_edge.iter().enumerate() {
if self.face_deleted[fi] {
continue;
}
let he1 = self.half_edges[he0].next;
let he2 = self.half_edges[he1].next;
let v0 = self.half_edges[he2].vertex;
let v1 = self.half_edges[he0].vertex;
let v2 = self.half_edges[he1].vertex;
tris.push([v0, v1, v2]);
}
tris
}
}
#[derive(Debug, Clone)]
pub struct MeshStats {
pub n_vertices: usize,
pub n_triangles: usize,
pub n_edges: usize,
pub avg_edge_length: f64,
pub min_edge_length: f64,
pub max_edge_length: f64,
pub avg_quality: f64,
pub min_quality: f64,
}
#[derive(Debug, Clone)]
pub struct QemConfig {
pub target_triangles: usize,
pub max_error: f64,
pub preserve_boundary: bool,
pub max_normal_deviation: f64,
pub preserve_texture_seams: bool,
pub boundary_weight: f64,
}
impl QemConfig {
pub fn default_config(current_tris: usize) -> Self {
Self {
target_triangles: current_tris / 2,
max_error: 0.0,
preserve_boundary: true,
max_normal_deviation: std::f64::consts::FRAC_PI_4,
preserve_texture_seams: false,
boundary_weight: 100.0,
}
}
pub fn with_error_threshold(max_error: f64) -> Self {
Self {
target_triangles: 0,
max_error,
preserve_boundary: true,
max_normal_deviation: 0.0,
preserve_texture_seams: false,
boundary_weight: 100.0,
}
}
}
#[derive(Debug, Clone)]
pub struct CollapseRecord {
pub removed: usize,
pub kept: usize,
pub removed_pos: [f64; 3],
pub kept_pos: [f64; 3],
pub collapsed_pos: [f64; 3],
pub removed_triangles: Vec<[usize; 3]>,
pub modified_triangles: Vec<[usize; 3]>,
}
#[derive(Debug, Clone)]
pub struct ProgressiveMesh {
pub base_vertices: Vec<[f64; 3]>,
pub base_triangles: Vec<[usize; 3]>,
pub collapses: Vec<CollapseRecord>,
}
impl ProgressiveMesh {
pub fn build(vertices: &[[f64; 3]], triangles: &[[usize; 3]], target_triangles: usize) -> Self {
let config = QemConfig {
target_triangles,
max_error: 0.0,
preserve_boundary: true,
max_normal_deviation: 0.0,
preserve_texture_seams: false,
boundary_weight: 100.0,
};
let (base_verts, base_tris) = qem_simplify(vertices, triangles, &config);
Self {
base_vertices: base_verts,
base_triangles: base_tris,
collapses: Vec::new(),
}
}
pub fn base_mesh(&self) -> (&[[f64; 3]], &[[usize; 3]]) {
(&self.base_vertices, &self.base_triangles)
}
pub fn num_collapses(&self) -> usize {
self.collapses.len()
}
}
#[derive(Debug, Clone, Copy)]
pub struct SymMat4 {
pub m: [f64; 10],
}
impl SymMat4 {
pub fn zero() -> Self {
Self { m: [0.0; 10] }
}
pub fn from_plane(a: f64, b: f64, c: f64, d: f64) -> Self {
Self {
m: [
a * a,
a * b,
a * c,
a * d,
b * b,
b * c,
b * d,
c * c,
c * d,
d * d,
],
}
}
pub fn add(&self, other: &Self) -> Self {
let mut result = Self::zero();
for i in 0..10 {
result.m[i] = self.m[i] + other.m[i];
}
result
}
pub fn scale(&self, s: f64) -> Self {
let mut result = *self;
for v in &mut result.m {
*v *= s;
}
result
}
pub fn evaluate(&self, v: [f64; 3]) -> f64 {
let x = v[0];
let y = v[1];
let z = v[2];
self.m[0] * x * x
+ 2.0 * self.m[1] * x * y
+ 2.0 * self.m[2] * x * z
+ 2.0 * self.m[3] * x
+ self.m[4] * y * y
+ 2.0 * self.m[5] * y * z
+ 2.0 * self.m[6] * y
+ self.m[7] * z * z
+ 2.0 * self.m[8] * z
+ self.m[9]
}
pub fn optimal_point(&self) -> Option<[f64; 3]> {
let a = [
[self.m[0], self.m[1], self.m[2]],
[self.m[1], self.m[4], self.m[5]],
[self.m[2], self.m[5], self.m[7]],
];
let b = [-self.m[3], -self.m[6], -self.m[8]];
solve_3x3(a, b)
}
}
#[derive(Debug, Clone)]
pub struct HalfEdge {
pub vertex: usize,
pub face: usize,
pub twin: usize,
pub next: usize,
pub prev: usize,
}
#[derive(Debug, Clone)]
pub struct TextureSeamFlags {
pub seam_edges: HashSet<(usize, usize)>,
}
impl TextureSeamFlags {
pub fn new() -> Self {
Self {
seam_edges: HashSet::new(),
}
}
pub fn mark_seam(&mut self, v0: usize, v1: usize) {
let (lo, hi) = if v0 < v1 { (v0, v1) } else { (v1, v0) };
self.seam_edges.insert((lo, hi));
}
pub fn is_seam(&self, v0: usize, v1: usize) -> bool {
let (lo, hi) = if v0 < v1 { (v0, v1) } else { (v1, v0) };
self.seam_edges.contains(&(lo, hi))
}
pub fn count(&self) -> usize {
self.seam_edges.len()
}
}
#[derive(Debug, Clone)]
pub struct TopologyValidation {
pub is_valid: bool,
pub non_manifold_edges: usize,
pub isolated_vertices: usize,
pub degenerate_triangles: usize,
}
#[derive(Debug, Clone)]
pub(super) struct CollapseCandidate {
pub(super) v0: usize,
pub(super) v1: usize,
pub(super) optimal_pos: [f64; 3],
pub(super) cost: f64,
}