oxiphysics_geometry/geodesic_geometry/
types.rs1use super::functions::*;
6#[derive(Debug, Clone, Copy, PartialEq)]
8pub(super) enum FmmStatus {
9 Far,
11 Trial,
13 Known,
15}
16#[derive(Debug, Clone)]
18pub struct HeatMethodParams {
19 pub time_factor: f64,
21}
22#[derive(Debug, Clone)]
24pub struct GeodesicVoronoiCell {
25 pub site: usize,
27 pub vertices: Vec<usize>,
29 pub area: f64,
31}
32#[derive(Debug, Clone)]
34pub struct ExpMapResult {
35 pub vertex: usize,
37 pub position: [f64; 3],
39 pub face: usize,
41 pub bary: [f64; 3],
43}
44#[derive(Debug, Clone)]
46pub struct LogMapResult {
47 pub coords: [f64; 2],
49 pub distance: f64,
51 pub angle: f64,
53}
54#[derive(Debug, Clone)]
56pub(super) struct DistNode {
57 pub(super) vertex: usize,
59 pub(super) dist: f64,
61}
62#[derive(Debug, Clone)]
67pub struct GeodesicMesh {
68 pub vertices: Vec<[f64; 3]>,
70 pub faces: Vec<[usize; 3]>,
72}
73impl GeodesicMesh {
74 pub fn new(vertices: Vec<[f64; 3]>, faces: Vec<[usize; 3]>) -> Self {
76 Self { vertices, faces }
77 }
78 pub fn num_vertices(&self) -> usize {
80 self.vertices.len()
81 }
82 pub fn num_faces(&self) -> usize {
84 self.faces.len()
85 }
86 pub fn vertex_adjacency(&self) -> Vec<Vec<usize>> {
88 let n = self.num_vertices();
89 let mut adj: Vec<Vec<usize>> = vec![Vec::new(); n];
90 for f in &self.faces {
91 for i in 0..3 {
92 let a = f[i];
93 let b = f[(i + 1) % 3];
94 if !adj[a].contains(&b) {
95 adj[a].push(b);
96 }
97 if !adj[b].contains(&a) {
98 adj[b].push(a);
99 }
100 }
101 }
102 adj
103 }
104 pub fn vertex_to_faces(&self) -> Vec<Vec<usize>> {
106 let n = self.num_vertices();
107 let mut v2f: Vec<Vec<usize>> = vec![Vec::new(); n];
108 for (fi, f) in self.faces.iter().enumerate() {
109 for &vi in f {
110 v2f[vi].push(fi);
111 }
112 }
113 v2f
114 }
115 pub fn face_normal(&self, fi: usize) -> [f64; 3] {
117 let f = self.faces[fi];
118 let e1 = sub3(self.vertices[f[1]], self.vertices[f[0]]);
119 let e2 = sub3(self.vertices[f[2]], self.vertices[f[0]]);
120 cross3(e1, e2)
121 }
122 pub fn vertex_normal(&self, vi: usize) -> [f64; 3] {
124 let v2f = self.vertex_to_faces();
125 let mut n = [0.0; 3];
126 for &fi in &v2f[vi] {
127 let fn_ = self.face_normal(fi);
128 n = add3(n, fn_);
129 }
130 normalize3(n)
131 }
132 pub fn face_area(&self, fi: usize) -> f64 {
134 0.5 * len3(self.face_normal(fi))
135 }
136 pub fn total_area(&self) -> f64 {
138 (0..self.num_faces()).map(|fi| self.face_area(fi)).sum()
139 }
140 pub fn tangent_frame(&self, vi: usize) -> ([f64; 3], [f64; 3], [f64; 3]) {
142 let n = self.vertex_normal(vi);
143 let adj = self.vertex_adjacency();
144 let t = if !adj[vi].is_empty() {
145 let edge = sub3(self.vertices[adj[vi][0]], self.vertices[vi]);
146 let proj = sub3(edge, scale3(n, dot3(edge, n)));
147 normalize3(proj)
148 } else {
149 let candidate = if n[0].abs() < 0.9 {
150 [1.0, 0.0, 0.0]
151 } else {
152 [0.0, 1.0, 0.0]
153 };
154 let proj = sub3(candidate, scale3(n, dot3(candidate, n)));
155 normalize3(proj)
156 };
157 let b = cross3(n, t);
158 (t, b, n)
159 }
160 pub fn cotangent_weight(&self, i: usize, j: usize) -> f64 {
163 let mut cot_sum = 0.0;
164 for f in &self.faces {
165 let mut found = false;
166 let mut opposite = 0;
167 for k in 0..3 {
168 let a = f[k];
169 let b = f[(k + 1) % 3];
170 let c = f[(k + 2) % 3];
171 if (a == i && b == j) || (a == j && b == i) {
172 found = true;
173 opposite = c;
174 break;
175 }
176 }
177 if found {
178 let pi = self.vertices[i];
179 let pj = self.vertices[j];
180 let po = self.vertices[opposite];
181 let ei = sub3(pi, po);
182 let ej = sub3(pj, po);
183 let cos_a = dot3(ei, ej) / (len3(ei) * len3(ej) + 1e-30);
184 let sin_a = len3(cross3(ei, ej)) / (len3(ei) * len3(ej) + 1e-30);
185 if sin_a.abs() > 1e-15 {
186 cot_sum += cos_a / sin_a;
187 }
188 }
189 }
190 cot_sum
191 }
192 pub fn voronoi_area(&self, vi: usize) -> f64 {
194 let v2f = self.vertex_to_faces();
195 let mut area = 0.0;
196 for &fi in &v2f[vi] {
197 let f = self.faces[fi];
198 let local_idx = f.iter().position(|&v| v == vi).expect("element must exist");
199 let a = self.vertices[f[local_idx]];
200 let b = self.vertices[f[(local_idx + 1) % 3]];
201 let c = self.vertices[f[(local_idx + 2) % 3]];
202 let angle_a = angle_at_vertex(b, a, c);
203 let angle_b = angle_at_vertex(a, b, c);
204 let angle_c = angle_at_vertex(a, c, b);
205 if angle_a > std::f64::consts::FRAC_PI_2 {
206 area += self.face_area(fi) * 0.5;
207 } else if angle_b > std::f64::consts::FRAC_PI_2 || angle_c > std::f64::consts::FRAC_PI_2
208 {
209 area += self.face_area(fi) * 0.25;
210 } else {
211 let ab2 = dot3(sub3(b, a), sub3(b, a));
212 let ac2 = dot3(sub3(c, a), sub3(c, a));
213 let cot_b = angle_b.cos() / (angle_b.sin() + 1e-30);
214 let cot_c = angle_c.cos() / (angle_c.sin() + 1e-30);
215 area += 0.125 * (cot_b * ac2 + cot_c * ab2);
216 }
217 }
218 area.max(1e-30)
219 }
220}