1use crate::math::{Isometry, Point, Real, Vector};
4use crate::na::ComplexField;
5use alloc::vec::Vec;
6#[cfg(feature = "dim3")]
7use {crate::math::DIM, num::Zero};
8
9pub fn transform(points: &mut [Point<Real>], m: Isometry<Real>) {
11 points.iter_mut().for_each(|p| *p = m * *p);
12}
13
14pub fn transformed(mut points: Vec<Point<Real>>, m: Isometry<Real>) -> Vec<Point<Real>> {
16 transform(&mut points, m);
17 points
18}
19
20pub fn scaled(mut points: Vec<Point<Real>>, scale: Vector<Real>) -> Vec<Point<Real>> {
22 points
23 .iter_mut()
24 .for_each(|p| p.coords.component_mul_assign(&scale));
25 points
26}
27
28#[cfg(feature = "dim3")]
31#[inline]
32pub fn push_circle(radius: Real, nsubdiv: u32, dtheta: Real, y: Real, out: &mut Vec<Point<Real>>) {
33 let mut curr_theta = Real::zero();
34
35 for _ in 0..nsubdiv {
36 out.push(Point::new(
37 ComplexField::cos(curr_theta) * radius,
38 y,
39 ComplexField::sin(curr_theta) * radius,
40 ));
41 curr_theta += dtheta;
42 }
43}
44
45#[inline]
48#[cfg(feature = "dim2")]
49pub fn push_xy_arc(radius: Real, nsubdiv: u32, dtheta: Real, out: &mut Vec<Point<Real>>) {
50 let mut curr_theta: Real = 0.0;
51
52 for _ in 0..nsubdiv {
53 let mut pt_coords = Vector::zeros();
54
55 pt_coords[0] = ComplexField::cos(curr_theta) * radius;
56 pt_coords[1] = ComplexField::sin(curr_theta) * radius;
57 out.push(Point::from(pt_coords));
58
59 curr_theta += dtheta;
60 }
61}
62
63#[cfg(feature = "dim3")]
65#[inline]
66pub fn push_ring_indices(
67 base_lower_circle: u32,
68 base_upper_circle: u32,
69 nsubdiv: u32,
70 out: &mut Vec<[u32; DIM]>,
71) {
72 push_open_ring_indices(base_lower_circle, base_upper_circle, nsubdiv, out);
73
74 push_rectangle_indices(
76 base_upper_circle,
77 base_upper_circle + nsubdiv - 1,
78 base_lower_circle,
79 base_lower_circle + nsubdiv - 1,
80 out,
81 );
82}
83
84#[cfg(feature = "dim3")]
86#[inline]
87pub fn push_open_ring_indices(
88 base_lower_circle: u32,
89 base_upper_circle: u32,
90 nsubdiv: u32,
91 out: &mut Vec<[u32; DIM]>,
92) {
93 assert!(nsubdiv > 0);
94
95 for i in 0..nsubdiv - 1 {
96 let bli = base_lower_circle + i;
97 let bui = base_upper_circle + i;
98 push_rectangle_indices(bui + 1, bui, bli + 1, bli, out);
99 }
100}
101
102#[cfg(feature = "dim3")]
104#[inline]
105pub fn push_degenerate_top_ring_indices(
106 base_circle: u32,
107 point: u32,
108 nsubdiv: u32,
109 out: &mut Vec<[u32; DIM]>,
110) {
111 push_degenerate_open_top_ring_indices(base_circle, point, nsubdiv, out);
112
113 out.push([base_circle + nsubdiv - 1, point, base_circle]);
114}
115
116#[cfg(feature = "dim3")]
118#[inline]
119pub fn push_degenerate_open_top_ring_indices(
120 base_circle: u32,
121 point: u32,
122 nsubdiv: u32,
123 out: &mut Vec<[u32; DIM]>,
124) {
125 assert!(nsubdiv > 0);
126
127 for i in 0..nsubdiv - 1 {
128 out.push([base_circle + i, point, base_circle + i + 1]);
129 }
130}
131
132#[cfg(feature = "dim3")]
136#[inline]
137pub fn push_filled_circle_indices(base_circle: u32, nsubdiv: u32, out: &mut Vec<[u32; DIM]>) {
138 for i in base_circle + 1..base_circle + nsubdiv - 1 {
139 out.push([base_circle, i, i + 1]);
140 }
141}
142
143#[cfg(feature = "dim3")]
151#[inline]
152pub fn push_rectangle_indices(ul: u32, ur: u32, dl: u32, dr: u32, out: &mut Vec<[u32; DIM]>) {
153 out.push([ul, dl, dr]);
154 out.push([dr, ur, ul]);
155}
156
157#[cfg(feature = "dim3")]
159#[inline]
160pub fn reverse_clockwising(indices: &mut [[u32; DIM]]) {
161 indices.iter_mut().for_each(|idx| idx.swap(0, 1));
162}
163
164#[cfg(feature = "dim3")]
166#[inline]
167pub fn push_circle_outline_indices(indices: &mut Vec<[u32; 2]>, range: core::ops::Range<u32>) {
168 indices.extend((range.start..range.end - 1).map(|i| [i, i + 1]));
169 indices.push([range.end - 1, range.start]);
170}
171
172#[cfg(feature = "dim3")]
174#[inline]
175pub fn push_open_circle_outline_indices(indices: &mut Vec<[u32; 2]>, range: core::ops::Range<u32>) {
176 indices.extend((range.start..range.end - 1).map(|i| [i, i + 1]));
177}
178
179#[cfg(feature = "dim3")]
186pub fn push_arc_and_idx(
187 center: Point<Real>,
188 start: u32,
189 end: u32,
190 nsubdivs: u32,
191 out_vtx: &mut Vec<Point<Real>>,
192 out_idx: &mut Vec<[u32; 2]>,
193) {
194 let base = out_vtx.len() as u32;
195 push_arc(
196 center,
197 out_vtx[start as usize],
198 out_vtx[end as usize],
199 nsubdivs,
200 out_vtx,
201 );
202 push_arc_idx(start, base..base + nsubdivs - 1, end, out_idx);
203}
204
205pub fn push_arc(
209 center: Point<Real>,
210 start: Point<Real>,
211 end: Point<Real>,
212 nsubdivs: u32,
213 out: &mut Vec<Point<Real>>,
214) {
215 assert!(nsubdivs > 0);
216 if let (Some((start_dir, start_len)), Some((end_dir, end_len))) = (
217 na::Unit::try_new_and_get(start - center, 0.0),
218 na::Unit::try_new_and_get(end - center, 0.0),
219 ) {
220 let len_inc = (end_len - start_len) / nsubdivs as Real;
221
222 #[cfg(feature = "dim2")]
223 let rot = Some(na::UnitComplex::scaled_rotation_between_axis(
224 &start_dir,
225 &end_dir,
226 1.0 / nsubdivs as Real,
227 ));
228
229 #[cfg(feature = "dim3")]
230 let rot = na::UnitQuaternion::scaled_rotation_between_axis(
231 &start_dir,
232 &end_dir,
233 1.0 / nsubdivs as Real,
234 );
235
236 if let Some(rot) = rot {
237 let mut curr_dir = start_dir;
238 let mut curr_len = start_len;
239
240 for _ in 0..nsubdivs - 1 {
241 curr_dir = rot * curr_dir;
242 curr_len += len_inc;
243
244 out.push(center + *curr_dir * curr_len);
245 }
246 }
247 }
248}
249
250#[cfg(feature = "dim3")]
253pub fn push_arc_idx(start: u32, arc: core::ops::Range<u32>, end: u32, out: &mut Vec<[u32; 2]>) {
254 if arc.is_empty() {
255 out.push([start, end]);
256 } else {
257 out.push([start, arc.start]);
258 for i in arc.start..arc.end - 1 {
259 out.push([i, i + 1])
260 }
261 out.push([arc.end - 1, end])
262 }
263}
264
265#[cfg(feature = "dim3")]
267pub fn apply_revolution(
268 collapse_bottom: bool,
269 collapse_top: bool,
270 circle_ranges: &[core::ops::Range<u32>],
271 nsubdivs: u32,
272 out_vtx: &mut Vec<Point<Real>>, out_idx: &mut Vec<[u32; 2]>,
274) {
275 use na::RealField;
276 let ang_increment = Real::two_pi() / (nsubdivs as Real);
277 let angles = [
278 ang_increment * (nsubdivs / 4) as Real,
279 ang_increment * (nsubdivs / 2) as Real,
280 ang_increment * ((3 * nsubdivs) / 4) as Real,
281 ];
282
283 let half_profile_len = out_vtx.len();
284
285 for k in 0..half_profile_len as u32 - 1 {
286 out_idx.push([k, k + 1]);
287 }
288
289 let mut range = 0..half_profile_len;
290
291 if collapse_bottom {
292 range.start += 1;
293 }
294 if collapse_top {
295 range.end -= 1;
296 }
297
298 for angle in angles {
300 let base = out_vtx.len() as u32;
301 let rot = na::UnitQuaternion::new(Vector::y() * angle);
302
303 if collapse_bottom {
304 out_idx.push([0, base]);
305 }
306
307 for k in range.clone() {
308 out_vtx.push(rot * out_vtx[k]);
309 }
310
311 for k in 0..range.len() as u32 - 1 {
312 out_idx.push([base + k, base + k + 1]);
313 }
314
315 if collapse_top {
316 out_idx.push([base + range.len() as u32 - 1, half_profile_len as u32 - 1]);
317 }
318 }
319
320 for circle_range in circle_ranges {
324 for i in circle_range.clone() {
325 let pt = out_vtx[i as usize];
326 let base = out_vtx.len() as u32;
327 push_circle(
328 pt.coords.xz().norm(),
329 nsubdivs,
330 ang_increment,
331 pt.y,
332 out_vtx,
333 );
334 push_circle_outline_indices(out_idx, base..base + nsubdivs)
335 }
336 }
337}