1use num_traits::AsPrimitive;
4
5pub fn vtx2framex<T>(vtx2xyz: &[T]) -> Vec<T>
6where
7 T: num_traits::Float + 'static + Copy,
8 f64: AsPrimitive<T>,
9{
10 use del_geo_core::vec3::Vec3;
11 let num_vtx = vtx2xyz.len() / 3;
12 let mut vtx2bin = vec![T::zero(); num_vtx * 3];
13 {
14 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, 0);
16 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, 1);
17 let v01 = p1.sub(p0);
18 let (x, _) = del_geo_core::vec3::basis_xy_from_basis_z(&v01);
19 crate::vtx2xyz::to_vec3_mut(&mut vtx2bin, 0).copy_from_slice(&x);
20 }
21 for iseg1 in 1..num_vtx {
22 let iv0 = iseg1 - 1;
24 let iv1 = iseg1;
25 let iv2 = (iseg1 + 1) % num_vtx;
26 let iseg0 = iseg1 - 1;
27 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, iv0);
28 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, iv1);
29 let p2 = crate::vtx2xyz::to_vec3(vtx2xyz, iv2);
30 let v01 = p1.sub(p0);
31 let v12 = p2.sub(p1);
32 let rot = del_geo_core::mat3_col_major::minimum_rotation_matrix(&v01, &v12);
33 let b01 = crate::vtx2xyz::to_vec3(&vtx2bin, iseg0);
34 let b12 = del_geo_core::mat3_col_major::mult_vec(&rot, b01);
35 crate::vtx2xyz::to_vec3_mut(&mut vtx2bin, iseg1).copy_from_slice(&b12);
36 }
37 vtx2bin
38}
39
40pub fn framez<T>(vtx2xyz: &[T], i_vtx: usize) -> [T; 3]
41where
42 T: num_traits::Float + Copy,
43{
44 let num_vtx = vtx2xyz.len() / 3;
45 assert!(i_vtx < num_vtx);
46 let i0_vtx = (i_vtx + num_vtx - 1) % num_vtx;
47 let i2_vtx = (i_vtx + 1) % num_vtx;
49 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, i0_vtx);
50 let p2 = crate::vtx2xyz::to_vec3(vtx2xyz, i2_vtx);
51 use del_geo_core::vec3::Vec3;
52 p2.sub(p0).normalize()
53}
54
55fn match_frames_of_two_ends<T>(vtx2xyz: &[T], vtx2bin0: &[T]) -> Vec<T>
56where
57 T: num_traits::Float + Copy + 'static + std::fmt::Display,
58 f64: AsPrimitive<T>,
59 usize: AsPrimitive<T>,
60{
61 use del_geo_core::vec3::Vec3;
62 let num_vtx = vtx2xyz.len() / 3;
63 let theta = {
64 let x0 = crate::vtx2xyz::to_vec3(vtx2bin0, 0);
65 let p0 = &crate::vtx2xyz::to_vec3(vtx2xyz, 0);
66 let p1 = &crate::vtx2xyz::to_vec3(vtx2xyz, 1);
67 let v01 = p1.sub(p0).normalize();
68 assert!(x0.dot(&v01).abs() < 1.0e-6_f64.as_());
69 let xn = crate::vtx2xyz::to_vec3(vtx2bin0, num_vtx - 1);
70 let pn = &crate::vtx2xyz::to_vec3(vtx2xyz, num_vtx - 1);
71 let vn0 = p0.sub(pn).normalize();
72 let rot = del_geo_core::mat3_col_major::minimum_rotation_matrix(&vn0, &v01);
73 let x1a = del_geo_core::mat3_col_major::mult_vec(&rot, xn);
74 let y0 = v01.cross(x0);
75 assert!(
76 x1a.dot(&v01).abs() < 1.0e-4f64.as_(),
77 "{}",
78 x1a.dot(&v01).abs()
79 );
80 assert!((y0.norm() - 1.0_f64.as_()).abs() < 1.0e-6_f64.as_());
81 let c0 = x1a.dot(x0);
82 let s0 = x1a.dot(&y0);
83 T::atan2(s0, c0)
84 };
85 let theta_step = theta / num_vtx.as_();
86 let mut vtx2bin1 = vec![T::zero(); num_vtx * 3];
87 for iseg in 0..num_vtx {
88 let dtheta = theta_step * iseg.as_();
89 let x0 = crate::vtx2xyz::to_vec3(vtx2bin0, iseg);
90 let ivtx0 = iseg;
91 let ivtx1 = (iseg + 1) % num_vtx;
92 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, ivtx1);
93 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, ivtx0);
94 let v01 = p1.sub(p0).normalize();
95 let y0 = v01.cross(x0);
96 assert!(
97 (x0.cross(&y0).dot(&v01) - 1.as_()).abs() < 1.0e-3_f64.as_(),
98 "{}",
99 x0.cross(&y0).dot(&v01)
100 );
101 let x0 = x0.scale(dtheta.sin());
102 let y0 = y0.scale(dtheta.cos());
103 let x1 = x0.add(&y0);
104 crate::vtx2xyz::to_vec3_mut(&mut vtx2bin1, iseg).copy_from_slice(&x1);
105 }
106 vtx2bin1
107}
108
109pub fn smooth_frame<T>(vtx2xyz: &[T]) -> Vec<T>
110where
111 T: num_traits::Float + 'static + Copy + std::fmt::Display,
112 f64: AsPrimitive<T>,
113 usize: AsPrimitive<T>,
114{
115 let vtx2bin0 = vtx2framex(vtx2xyz);
116 match_frames_of_two_ends(vtx2xyz, &vtx2bin0)
118}
119
120pub fn normal_binormal<T>(vtx2xyz: &[T]) -> (Vec<T>, Vec<T>)
121where
122 T: num_traits::Float + Copy,
123{
124 use del_geo_core::vec3::Vec3;
125 let num_vtx = vtx2xyz.len() / 3;
126 let mut vtx2bin = vec![T::zero(); num_vtx * 3];
127 let mut vtx2nrm = vec![T::zero(); num_vtx * 3];
128 for ivtx1 in 0..num_vtx {
129 let ivtx0 = (ivtx1 + num_vtx - 1) % num_vtx;
130 let ivtx2 = (ivtx1 + 1) % num_vtx;
131 let v0 = crate::vtx2xyz::to_vec3(vtx2xyz, ivtx0);
132 let v1 = crate::vtx2xyz::to_vec3(vtx2xyz, ivtx1);
133 let v2 = crate::vtx2xyz::to_vec3(vtx2xyz, ivtx2);
134 let v01 = v1.sub(v0);
135 let v12 = v2.sub(v1);
136 let binormal = v12.cross(&v01).normalize();
137 crate::vtx2xyz::to_vec3_mut(&mut vtx2bin, ivtx1).copy_from_slice(&binormal);
138 let norm = v01.add(&v12).cross(&binormal).normalize();
139 crate::vtx2xyz::to_vec3_mut(&mut vtx2nrm, ivtx1).copy_from_slice(&norm);
140 }
141 (vtx2nrm, vtx2bin)
142}
143
144pub fn smooth_gradient_of_distance(vtx2xyz: &[f64], q: &[f64; 3]) -> [f64; 3] {
145 use del_geo_core::vec3::Vec3;
146 let n = vtx2xyz.len() / 3;
147 let mut dd = [0f64; 3];
148 for i_seg in 0..n {
149 let ip0 = i_seg;
150 let ip1 = (i_seg + 1) % n;
151 let (_, dd0) = del_geo_core::edge3::wdw_integral_of_inverse_distance_cubic(
152 q,
153 crate::vtx2xyz::to_vec3(vtx2xyz, ip0),
154 crate::vtx2xyz::to_vec3(vtx2xyz, ip1),
155 );
156 dd.add_in_place(&dd0);
157 }
158 dd
159}
160
161pub fn extend_avoid_intersection(
162 p0: &[f64; 3],
163 v0: &[f64; 3],
164 vtx2xyz: &[f64],
165 eps: f64,
166 n: usize,
167) -> [f64; 3] {
168 use del_geo_core::vec3::Vec3;
169 let mut p1 = p0.add(&v0.scale(eps));
170 for _i in 0..n {
171 let v1 = smooth_gradient_of_distance(vtx2xyz, &p1)
172 .normalize()
173 .scale(-1f64);
174 p1.add_in_place(&v1.scale(eps));
175 }
176 p1
177}
178
179pub fn tube_mesh_avoid_intersection(
180 vtx2xyz: &[f64],
181 vtx2bin: &[f64],
182 eps: f64,
183 niter: usize,
184) -> (Vec<usize>, Vec<f64>) {
185 use del_geo_core::vec3::Vec3;
186 let n = 8;
187 let dtheta = std::f64::consts::PI * 2. / n as f64;
188 let num_vtx = vtx2xyz.len() / 3;
189 let mut pnt2xyz = Vec::<f64>::new();
190 for ipnt in 0..num_vtx {
191 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, ipnt);
192 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, (ipnt + 1) % num_vtx);
193 let z0 = p1.sub(p0).normalize();
194 let x0 = crate::vtx2xyz::to_vec3(vtx2bin, ipnt);
195 let y0 = z0.cross(x0);
196 for i in 0..n {
197 let theta = dtheta * i as f64;
198 let x0 = x0.scale(theta.cos());
199 let y0 = y0.scale(theta.sin());
200 let v0 = x0.add(&y0);
201 let q0 = extend_avoid_intersection(p0, &v0, vtx2xyz, eps, niter);
202 q0.iter().for_each(|&v| pnt2xyz.push(v));
204 }
205 }
206
207 let mut tri2pnt = Vec::<usize>::new();
208 for iseg in 0..num_vtx {
209 let ipnt0 = iseg;
210 let ipnt1 = (ipnt0 + 1) % num_vtx;
211 for i in 0..n {
212 tri2pnt.push(ipnt0 * n + i);
213 tri2pnt.push(ipnt0 * n + (i + 1) % n);
214 tri2pnt.push(ipnt1 * n + i);
215 tri2pnt.push(ipnt1 * n + (i + 1) % n);
217 tri2pnt.push(ipnt1 * n + i);
218 tri2pnt.push(ipnt0 * n + (i + 1) % n);
219 }
220 }
221 (tri2pnt, pnt2xyz)
222}
223
224pub fn write_wavefrontobj<P: AsRef<std::path::Path>>(filepath: P, vtx2xyz: &[f32]) {
225 use std::io::Write;
226 let mut file = std::fs::File::create(filepath).expect("file not found.");
227 for vtx in vtx2xyz.chunks(3) {
228 writeln!(file, "v {} {} {}", vtx[0], vtx[1], vtx[2]).expect("fail");
229 }
230 write!(file, "l ").expect("fail");
231 for i in 1..vtx2xyz.len() / 3 + 1 {
232 write!(file, "{} ", i).expect("fail");
233 }
234 writeln!(file, "1").expect("fail");
235}
236
237pub fn nearest_to_edge3<T>(vtx2xyz: &[T], p0: &[T; 3], p1: &[T; 3]) -> (T, T, T)
238where
239 T: num_traits::Float + Copy + 'static,
240 usize: AsPrimitive<T>,
241{
242 let num_vtx = vtx2xyz.len() / 3;
243 assert_eq!(vtx2xyz.len(), num_vtx * 3);
244 let mut res = (T::max_value(), T::zero(), T::zero());
245 for i_edge in 0..num_vtx {
246 let iv0 = i_edge;
247 let iv1 = (i_edge + 1) % num_vtx;
248 let q0 = crate::vtx2xyz::to_vec3(vtx2xyz, iv0);
249 let q1 = crate::vtx2xyz::to_vec3(vtx2xyz, iv1);
250 let (dist, r0, r1) = del_geo_core::edge3::nearest_to_edge3(p0, p1, q0, q1);
251 if dist > res.0 {
252 continue;
253 }
254 res.0 = dist;
257 res.1 = <usize as AsPrimitive<T>>::as_(i_edge) + r1;
258 res.2 = r0;
259 }
260 res
261}
262
263pub fn nearest_to_point3<T>(vtx2xyz: &[T], p0: &[T; 3]) -> (T, T)
264where
265 T: num_traits::Float + Copy + 'static,
266 f64: AsPrimitive<T>,
267 usize: AsPrimitive<T>,
268{
269 assert_eq!(p0.len(), 3);
270 let num_vtx = vtx2xyz.len() / 3;
271 assert_eq!(vtx2xyz.len(), num_vtx * 3);
272 let mut res = (T::max_value(), T::zero());
273 for i_edge in 0..num_vtx {
274 let iv0 = i_edge;
275 let iv1 = (i_edge + 1) % num_vtx;
276 let q0 = crate::vtx2xyz::to_vec3(vtx2xyz, iv0);
277 let q1 = crate::vtx2xyz::to_vec3(vtx2xyz, iv1);
278 let (dist, rq) = del_geo_core::edge3::nearest_to_point3(q0, q1, p0);
279 if dist < res.0 {
280 res.0 = dist;
283 res.1 = <usize as AsPrimitive<T>>::as_(i_edge) + rq;
284 }
285 }
286 res
287}
288
289pub fn winding_number(vtx2xyz: &[f64], org: &[f64; 3], dir: &[f64; 3]) -> f64 {
290 use del_geo_core::vec3::Vec3;
291 use num_traits::FloatConst;
292 let num_vtx = vtx2xyz.len() / 3;
295 assert_eq!(vtx2xyz.len(), num_vtx * 3);
296 let mut sum = 0.;
297 for i_edge in 0..num_vtx {
298 let iv0 = i_edge;
299 let iv1 = (i_edge + 1) % num_vtx;
300 let q0 = crate::vtx2xyz::to_vec3(vtx2xyz, iv0).sub(org);
301 let q1 = crate::vtx2xyz::to_vec3(vtx2xyz, iv1).sub(org);
302 let q0 = q0.sub(&dir.scale(q0.dot(dir)));
303 let q1 = q1.sub(&dir.scale(q1.dot(dir)));
304 let q0 = q0.normalize();
305 let q1 = q1.normalize();
306 let s = q0.cross(&q1).dot(dir);
307 let c = q0.dot(&q1);
308 sum += s.atan2(c);
309 }
310 sum * f64::FRAC_1_PI() * 0.5
311}
312
313#[allow(clippy::identity_op)]
314pub fn position_from_barycentric_coordinate<T>(vtx2xyz: &[T], r: T) -> [T; 3]
315where
316 T: num_traits::Float + AsPrimitive<usize> + std::fmt::Display + std::fmt::Debug,
317 usize: AsPrimitive<T>,
318{
319 use del_geo_core::vec3::Vec3;
320 let ied: usize = r.as_();
321 let ned = vtx2xyz.len() / 3;
322 if r.as_() == ned {
323 assert_eq!(ied.as_(), r);
324 return *crate::vtx2xyz::to_vec3(vtx2xyz, 0);
325 }
326 assert!(ied < ned, "{}, {}, {}", r, ied, ned);
327 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, ied);
328 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, (ied + 1) % ned);
329 let r0 = r - ied.as_();
330 p0.add(&p1.sub(p0).scale(r0))
331}
332
333#[allow(clippy::identity_op)]
334pub fn smooth<T>(vtx2xyz: &[T], r: T, num_iter: usize) -> Vec<T>
335where
336 T: num_traits::Float + Copy + 'static,
337 f64: AsPrimitive<T>,
338{
339 use del_geo_core::vec3::Vec3;
340 let num_vtx = vtx2xyz.len() / 3;
341 let mut vtx2xyz1 = Vec::from(vtx2xyz);
342 for _iter in 0..num_iter {
343 for ip1 in 0..num_vtx {
344 let ip0 = (ip1 + num_vtx - 1) % num_vtx;
345 let ip2 = (ip1 + 1) % num_vtx;
346 let p0 = crate::vtx2xyz::to_vec3(&vtx2xyz1, ip0);
347 let p1 = crate::vtx2xyz::to_vec3(&vtx2xyz1, ip1);
348 let p2 = crate::vtx2xyz::to_vec3(&vtx2xyz1, ip2);
349 let pm = p0.add(p2).scale(0.5f64.as_());
350 let p1n = del_geo_core::edge3::position_from_ratio(p1, &pm, r);
351 vtx2xyz1[ip1 * 3 + 0] = p1n[0];
352 vtx2xyz1[ip1 * 3 + 1] = p1n[1];
353 vtx2xyz1[ip1 * 3 + 2] = p1n[2];
354 }
355 }
356 vtx2xyz1
357}
358
359pub fn to_trimesh3_torus(
361 vtx2xyz: &[f32],
362 vtx2bin: &[f32],
363 rad: f32,
364 ndiv_circum: usize,
365) -> (Vec<usize>, Vec<f32>) {
366 use del_geo_core::vec3::Vec3;
367 let n = ndiv_circum;
368 let dtheta = std::f32::consts::PI * 2. / n as f32;
369 let num_vtx = vtx2xyz.len() / 3;
370 let mut pnt2xyz = Vec::<f32>::new();
371 for ipnt in 0..num_vtx {
372 let p0 = crate::vtx2xyz::to_vec3(vtx2xyz, ipnt);
373 let p1 = crate::vtx2xyz::to_vec3(vtx2xyz, (ipnt + 1) % num_vtx);
374 let z0 = p1.sub(p0).normalize();
375 let x0 = crate::vtx2xyz::to_vec3(vtx2bin, ipnt);
376 let y0 = z0.cross(x0);
377 for i in 0..n {
378 let theta = dtheta * i as f32;
379 let v0 = x0.scale(theta.cos()).add(&y0.scale(theta.sin()));
380 let q0 = p0.add(&v0.scale(rad));
381 q0.iter().for_each(|&v| pnt2xyz.push(v));
382 }
383 }
384
385 let mut tri2pnt = Vec::<usize>::new();
386 for iseg in 0..num_vtx {
387 let ipnt0 = iseg;
388 let ipnt1 = (ipnt0 + 1) % num_vtx;
389 for i in 0..n {
390 tri2pnt.push(ipnt0 * n + i);
391 tri2pnt.push(ipnt0 * n + (i + 1) % n);
392 tri2pnt.push(ipnt1 * n + i);
393 tri2pnt.push(ipnt1 * n + (i + 1) % n);
395 tri2pnt.push(ipnt1 * n + i);
396 tri2pnt.push(ipnt0 * n + (i + 1) % n);
397 }
398 }
399 (tri2pnt, pnt2xyz)
400}