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