1use glam::Vec4;
2
3use crate::polytope::Polytope4;
4
5#[derive(Clone, Copy, Debug, PartialEq)]
7pub struct SchlegelParams {
8 pub cell_index: u32,
9 pub cell_normal: Vec4,
10 pub cell_basis: [Vec4; 3],
11 pub cell_offset: f32,
12 pub viewpoint_distance: f32,
13}
14
15impl SchlegelParams {
16 pub fn new(polytope: Polytope4, cell_index: u32, eye_margin: f32) -> Option<Self> {
17 if !eye_margin.is_finite() || eye_margin <= 0.0 {
18 return None;
19 }
20 let topology = polytope.topology();
21 let cell = topology.cells.get(cell_index as usize)?;
22 let anchor = topology.vertices[*cell.first()? as usize];
23 let centroid = cell
24 .iter()
25 .map(|&index| topology.vertices[index as usize])
26 .sum::<Vec4>()
27 / cell.len() as f32;
28 let cell_offset = centroid.length();
29 let cell_normal = centroid.try_normalize()?;
30 let mut cell_basis = [Vec4::ZERO; 3];
31 let mut count = 0;
32
33 for &index in cell.iter().skip(1) {
34 let delta = topology.vertices[index as usize] - anchor;
35 let mut axis = delta - delta.dot(cell_normal) * cell_normal;
36 for &previous in cell_basis.iter().take(count) {
37 axis -= axis.dot(previous) * previous;
38 }
39 let length = axis.length();
40 if length > 1e-6 {
41 cell_basis[count] = axis / length;
42 count += 1;
43 if count == cell_basis.len() {
44 break;
45 }
46 }
47 }
48 if count != cell_basis.len() {
49 return None;
50 }
51
52 let support = topology
54 .vertices
55 .iter()
56 .map(|vertex| cell_normal.dot(*vertex))
57 .fold(f32::NEG_INFINITY, f32::max);
58 let viewpoint_distance = support + eye_margin;
59 if !viewpoint_distance.is_finite() || viewpoint_distance <= support {
60 return None;
61 }
62 Some(Self {
63 cell_index,
64 cell_normal,
65 cell_basis,
66 cell_offset,
67 viewpoint_distance,
68 })
69 }
70}