1use num_traits::AsPrimitive;
4
5pub fn arclength_from_vtx2vecn<T, const N: usize>(vtxs: &[[T; N]]) -> T
7where
8 T: num_traits::Float + Copy + 'static + std::iter::Sum,
9 f64: AsPrimitive<T>,
10{
11 use del_geo_core::vecn::VecN;
12 if vtxs.len() < 2 {
13 return T::zero();
14 }
15 let np = vtxs.len();
16 let mut len: T = T::zero();
17 for ip0 in 0..np {
18 let ip1 = (ip0 + 1) % np;
19 len = len + vtxs[ip0].sub(&vtxs[ip1]).norm();
20 }
21 len
22}
23
24pub fn arclength<T, const N: usize>(vtx2xyz: &[T]) -> T
26where
27 T: num_traits::Float,
28{
29 let np = vtx2xyz.len() / N;
30 let mut len: T = T::zero();
31 for ip0 in 0..np {
32 let ip1 = (ip0 + 1) % np;
33 let p0: &[T; N] = &vtx2xyz[ip0 * N..ip0 * N + N].try_into().unwrap();
34 let p1: &[T; N] = &vtx2xyz[ip1 * N..ip1 * N + N].try_into().unwrap();
35 len = len + del_geo_core::edge::length::<T, N>(p0, p1);
36 }
37 len
38}
39
40pub fn edge2length<T, const N: usize>(vtx2xyz: &[T]) -> Vec<T>
41where
42 T: num_traits::Float + std::ops::AddAssign,
43{
44 let np = vtx2xyz.len() / N;
45 let mut edge2length = Vec::<T>::with_capacity(np);
46 for ip0 in 0..np {
47 let ip1 = (ip0 + 1) % np;
48 let p0: &[T; N] = &vtx2xyz[ip0 * N..ip0 * N + N].try_into().unwrap();
49 let p1: &[T; N] = &vtx2xyz[ip1 * N..ip1 * N + N].try_into().unwrap();
50 edge2length.push(del_geo_core::edge::length::<T, N>(p0, p1));
51 }
52 edge2length
53}
54
55pub fn cog_as_edges<T, const N: usize>(vtx2xyz: &[T]) -> [T; N]
58where
59 T: num_traits::Float + Copy + 'static + std::iter::Sum,
60 f64: AsPrimitive<T>,
61{
62 let num_vtx = vtx2xyz.len() / N;
63 assert_eq!(vtx2xyz.len(), num_vtx * N);
64 let mut cog = [T::zero(); N];
65 let mut len = T::zero();
66 use del_geo_core::vecn::VecN;
67 for i_edge in 0..num_vtx {
68 let iv0 = i_edge;
69 let iv1 = (i_edge + 1) % num_vtx;
70 let q0: &[T; N] = vtx2xyz[iv0 * N..iv0 * N + N].try_into().unwrap();
71 let q1: &[T; N] = vtx2xyz[iv1 * N..iv1 * N + N].try_into().unwrap();
72 let l = q0.sub(q1).norm();
73 let d = q0.add(q1).scale(0.5_f64.as_() * l);
74 cog = cog.add(&d);
75 len = len + l;
76 }
77 cog.scale(T::one() / len)
78}
79
80#[test]
81fn test_cog() {
82 let mut vtx2xy = crate::polyloop2::from_circle(1f32, 32);
83 let (x0, y0) = (1.3, 0.5);
84 vtx2xy.chunks_mut(2).for_each(|v| {
85 v[0] += x0;
86 v[1] += y0
87 });
88 let cog = cog_as_edges::<f32, 2>(vtx2xy.as_slice());
89 assert!(
90 del_geo_core::edge::length::<f32, 2>(&[x0, y0], cog.as_slice().try_into().unwrap())
91 < 1.0e-5
92 );
93}
94
95pub fn cov<T, const N: usize>(vtx2xyz: &[T]) -> [[T; N]; N]
125where
126 T: num_traits::Float + Copy + 'static + std::iter::Sum,
127 f64: AsPrimitive<T>,
128{
129 use del_geo_core::vecn::VecN;
130 let one = T::one();
131 let three = one + one + one;
132 let six = three + three;
133 let num_vtx = vtx2xyz.len() / N;
134 assert_eq!(vtx2xyz.len(), num_vtx * N);
135 let cog = cog_as_edges::<T, N>(vtx2xyz);
136 let mut cov = [[T::zero(); N]; N];
137 for i_edge in 0..num_vtx {
138 let iv0 = i_edge;
139 let iv1 = (i_edge + 1) % num_vtx;
140 let q0 = crate::vtx2xn::to_xn(vtx2xyz, iv0).sub(&cog);
141 let q1 = crate::vtx2xn::to_xn(vtx2xyz, iv1).sub(&cog);
142 let l = q0.sub(&q1).norm();
143 for i in 0..N {
144 for j in 0..N {
145 cov[i][j] = cov[i][j]
146 + (q0[i] * q0[j] + q1[i] * q1[j]) * (l / three)
147 + (q0[i] * q1[j] + q1[i] * q0[j]) * (l / six);
148 }
149 }
150 }
153 cov
154}
155
156pub fn resample<T, const N: usize>(vtx2xyz_in: &[T], num_edge_out: usize) -> Vec<T>
157where
158 T: num_traits::Float + Copy + std::iter::Sum + 'static,
159 usize: AsPrimitive<T>,
160{
161 use del_geo_core::vecn::VecN;
162 let mut v2x_out = Vec::<T>::new();
163 let num_edge_in = vtx2xyz_in.len() / N;
164 let len_edge_out = arclength::<T, N>(vtx2xyz_in) / num_edge_out.as_();
165 v2x_out.extend_from_slice(&vtx2xyz_in[0..N]);
166 let mut i_edge_in = 0;
167 let mut traveled_ratio0 = T::zero();
168 let mut remaining_length = len_edge_out;
169 loop {
170 if i_edge_in >= num_edge_in {
171 break;
172 }
173 if v2x_out.len() >= num_edge_out * N {
174 break;
175 }
176 let i0 = i_edge_in;
177 let i1 = (i_edge_in + 1) % num_edge_in;
178 let p0: &[T; N] = vtx2xyz_in[i0 * N..i0 * N + N].try_into().unwrap();
179 let p1: &[T; N] = vtx2xyz_in[i1 * N..i1 * N + N].try_into().unwrap();
180 let len_edge0 = p1.sub(p0).norm();
181 let len_togo0 = len_edge0 * (T::one() - traveled_ratio0);
182 if len_togo0 > remaining_length {
183 traveled_ratio0 = traveled_ratio0 + remaining_length / len_edge0;
185 let pn = p0
186 .scale(T::one() - traveled_ratio0)
187 .add(&p1.scale(traveled_ratio0));
188 v2x_out.extend(pn.iter());
189 remaining_length = len_edge_out;
190 } else {
191 remaining_length = remaining_length - len_togo0;
193 traveled_ratio0 = T::zero();
194 i_edge_in += 1;
195 }
196 }
197 v2x_out
198}
199
200pub fn resample_multiple_loops_remain_original_vtxs<T>(
201 loop2idx_inout: &mut Vec<usize>,
202 idx2vtx_inout: &mut Vec<usize>,
203 vtx2vec_inout: &mut Vec<[T; 2]>,
204 max_edge_length: T,
205) where
206 T: num_traits::Float + Copy + AsPrimitive<usize>,
207 usize: AsPrimitive<T>,
208{
209 use del_geo_core::vec2::Vec2;
210 let one = T::one();
211 assert_eq!(vtx2vec_inout.len(), idx2vtx_inout.len());
212 let loop2idx_in = loop2idx_inout.clone();
213 let idx2vtx_in = idx2vtx_inout.clone();
214 assert!(idx2vtx_in.len() >= 2);
215 let num_loop = loop2idx_in.len() - 1;
216 let mut edge2point: Vec<Vec<usize>> = vec![vec!(); idx2vtx_in.len()];
217 {
218 for i_loop in 0..num_loop {
219 assert!(loop2idx_in[i_loop + 1] > loop2idx_in[i_loop]);
220 let np = loop2idx_in[i_loop + 1] - loop2idx_in[i_loop];
221 for ip in 0..np {
222 let iipo0 = loop2idx_in[i_loop] + ip;
223 let iipo1 = loop2idx_in[i_loop] + (ip + 1) % np;
224 assert!(iipo0 < idx2vtx_in.len());
225 assert!(iipo1 < idx2vtx_in.len());
226 let ipo0 = idx2vtx_in[iipo0];
227 let ipo1 = idx2vtx_in[iipo1];
228 assert!(ipo0 < vtx2vec_inout.len());
229 assert!(ipo1 < vtx2vec_inout.len());
230 let po0 = vtx2vec_inout[ipo0]; let po1 = vtx2vec_inout[ipo1]; let nadd: usize = (po0.sub(&po1).norm() / max_edge_length).as_();
233 if nadd == 0 {
234 continue;
235 }
236 for iadd in 0..nadd {
237 let r2: T = (iadd + 1).as_() / (nadd + 1).as_();
238 let v2 = po0.scale(one - r2).add(&po1.scale(r2));
239 let ipo2 = vtx2vec_inout.len();
240 vtx2vec_inout.push(v2);
241 assert!(iipo0 < edge2point.len());
242 edge2point[iipo0].push(ipo2);
243 }
244 }
245 }
246 }
247 loop2idx_inout.resize(num_loop + 1, usize::MAX);
249 loop2idx_inout[0] = 0;
250 for iloop in 0..num_loop {
251 let nbar0 = loop2idx_in[iloop + 1] - loop2idx_in[iloop];
252 let mut nbar1 = nbar0;
253 for ibar in 0..nbar0 {
254 let iip_loop = loop2idx_in[iloop] + ibar;
255 nbar1 += edge2point[iip_loop].len();
256 }
257 loop2idx_inout[iloop + 1] = loop2idx_inout[iloop] + nbar1;
258 }
259 idx2vtx_inout.resize(loop2idx_inout[num_loop], usize::MAX);
261 let mut i_vtx0 = 0;
262 for i_loop in 0..num_loop {
263 for iip_loop in loop2idx_in[i_loop]..loop2idx_in[i_loop + 1] {
264 let ip_loop = idx2vtx_in[iip_loop];
265 idx2vtx_inout[i_vtx0] = ip_loop;
266 i_vtx0 += 1;
267 #[allow(clippy::needless_range_loop)]
268 for iadd in 0..edge2point[ip_loop].len() {
269 idx2vtx_inout[i_vtx0] = edge2point[iip_loop][iadd];
270 i_vtx0 += 1;
271 }
272 }
273 }
274 assert_eq!(idx2vtx_inout.len(), vtx2vec_inout.len());
275 assert_eq!(idx2vtx_inout.len(), i_vtx0);
276}
277
278pub fn to_cylinder_trimeshes<Real>(
279 vtx2xy: &[Real],
280 num_dim: usize,
281 radius: Real,
282) -> (Vec<usize>, Vec<Real>)
283where
284 Real: num_traits::Float + num_traits::FloatConst + 'static + Copy,
285 usize: AsPrimitive<Real>,
286{
287 let num_vtx = vtx2xy.len() / num_dim;
288 let mut out_tri2vtx: Vec<usize> = vec![];
289 let mut out_vtx2xyz: Vec<Real> = vec![];
290 for i_edge in 0..num_vtx {
291 let i0 = i_edge;
292 let i1 = (i_edge + 1) % num_vtx;
293 let p0 = &vtx2xy[i0 * num_dim..(i0 + 1) * num_dim];
294 let p1 = &vtx2xy[i1 * num_dim..(i1 + 1) * num_dim];
295 let p0 = if num_dim == 3 {
296 [p0[0], p0[1], p0[2]]
297 } else {
298 [p0[0], p0[1], Real::zero()]
299 };
300 let p1 = if num_dim == 3 {
301 [p1[0], p1[1], p1[2]]
302 } else {
303 [p1[0], p1[1], Real::zero()]
304 };
305 let (tri2vtx, vtx2xyz) =
306 crate::trimesh3_primitive::cylinder_open_connecting_two_points(32, radius, &p0, &p1);
307 crate::uniform_mesh::merge(
308 &mut out_tri2vtx,
309 &mut out_vtx2xyz,
310 tri2vtx.as_slice(),
311 vtx2xyz.as_slice(),
312 3,
313 );
314 }
315 (out_tri2vtx, out_vtx2xyz)
316}
317
318pub fn edge2vtx(num_vtx: usize) -> Vec<usize> {
319 let mut edge2vtx = Vec::<usize>::with_capacity(num_vtx * 2);
320 for i_vtx in 0..num_vtx {
321 edge2vtx.push(i_vtx);
322 edge2vtx.push((i_vtx + 1) % num_vtx);
323 }
324 edge2vtx
325}
326
327pub fn flip<Real>(vtx2xy: &[Real], num_dim: usize) -> Vec<Real>
328where
329 Real: num_traits::Float,
330{
331 let mut vtx2xy_out = Vec::<Real>::with_capacity(vtx2xy.len());
332 for xy in vtx2xy.chunks(num_dim).rev() {
333 vtx2xy_out.extend(xy);
334 }
340 vtx2xy_out
341}