1use crate::math::{Point, Vector};
4#[cfg(feature = "dim3")]
5use crate::utils::{DeterministicState, HashablePartialEq};
6#[cfg(feature = "dim3")]
7use na;
8use na::RealField;
9#[cfg(feature = "dim3")]
10use num::Zero;
11#[cfg(feature = "dim3")]
12use std::collections::hash_map::Entry;
13#[cfg(feature = "dim3")]
14use std::collections::HashMap;
15#[cfg(feature = "dim3")]
16use std::iter;
17
18#[cfg(feature = "dim3")]
21#[inline]
22pub fn push_circle<N: RealField + Copy>(
23 radius: N,
24 nsubdiv: u32,
25 dtheta: N,
26 y: N,
27 out: &mut Vec<Point<N>>,
28) {
29 let mut curr_theta = N::zero();
30
31 for _ in 0..nsubdiv {
32 out.push(Point::new(
33 curr_theta.cos() * radius,
34 y.clone(),
35 curr_theta.sin() * radius,
36 ));
37 curr_theta = curr_theta + dtheta;
38 }
39}
40
41#[inline]
44pub fn push_xy_arc<N: RealField + Copy>(
45 radius: N,
46 nsubdiv: u32,
47 dtheta: N,
48 out: &mut Vec<Point<N>>,
49) {
50 let mut curr_theta = N::zero();
51
52 for _ in 0..nsubdiv {
53 let mut pt_coords = Vector::zeros();
54
55 pt_coords[0] = curr_theta.cos() * radius;
56 pt_coords[1] = curr_theta.sin() * radius;
57 out.push(Point::from(pt_coords));
58
59 curr_theta = 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<Point<u32>>,
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<Point<u32>>,
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<Point<u32>>,
110) {
111 push_degenerate_open_top_ring_indices(base_circle, point, nsubdiv, out);
112
113 out.push(Point::new(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<Point<u32>>,
124) {
125 assert!(nsubdiv > 0);
126
127 for i in 0..nsubdiv - 1 {
128 out.push(Point::new(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<Point<u32>>) {
138 for i in base_circle + 1..base_circle + nsubdiv - 1 {
139 out.push(Point::new(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<Point<u32>>) {
153 out.push(Point::new(ul.clone(), dl, dr.clone()));
154 out.push(Point::new(dr, ur, ul));
155}
156
157#[cfg(feature = "dim3")]
159#[inline]
160pub fn reverse_clockwising(indices: &mut [Point<u32>]) {
161 for i in indices.iter_mut() {
162 i.coords.swap((0, 0), (1, 0));
163 }
164}
165
166#[cfg(feature = "dim3")]
170#[inline]
171pub fn split_index_buffer(indices: &[Point<u32>]) -> Vec<Point<Point<u32>>> {
172 let mut resi = Vec::new();
173
174 for vertex in indices.iter() {
175 resi.push(Point::new(
176 Point::new(vertex.x, vertex.x, vertex.x),
177 Point::new(vertex.y, vertex.y, vertex.y),
178 Point::new(vertex.z, vertex.z, vertex.z),
179 ));
180 }
181
182 resi
183}
184
185#[cfg(feature = "dim3")]
188#[inline]
189pub fn split_index_buffer_and_recover_topology<N: RealField + Copy>(
190 indices: &[Point<u32>],
191 coords: &[Point<N>],
192) -> (Vec<Point<Point<u32>>>, Vec<Point<N>>) {
193 let mut vtx_to_id = HashMap::with_hasher(DeterministicState::new());
194 let mut new_coords = Vec::with_capacity(coords.len());
195 let mut out = Vec::with_capacity(indices.len());
196
197 fn resolve_coord_id<N: RealField + Copy>(
198 coord: &Point<N>,
199 vtx_to_id: &mut HashMap<HashablePartialEq<Point<N>>, u32, DeterministicState>,
200 new_coords: &mut Vec<Point<N>>,
201 ) -> u32 {
202 let key = unsafe { HashablePartialEq::new(coord.clone()) };
203 let id = match vtx_to_id.entry(key) {
204 Entry::Occupied(entry) => entry.into_mut(),
205 Entry::Vacant(entry) => entry.insert(new_coords.len() as u32),
206 };
207
208 if *id == new_coords.len() as u32 {
209 new_coords.push(coord.clone());
210 }
211
212 *id
213 }
214
215 for t in indices.iter() {
216 let va = resolve_coord_id(&coords[t.x as usize], &mut vtx_to_id, &mut new_coords);
217 let oa = t.x;
218
219 let vb = resolve_coord_id(&coords[t.y as usize], &mut vtx_to_id, &mut new_coords);
220 let ob = t.y;
221
222 let vc = resolve_coord_id(&coords[t.z as usize], &mut vtx_to_id, &mut new_coords);
223 let oc = t.z;
224
225 out.push(Point::new(
226 Point::new(va, oa, oa),
227 Point::new(vb, ob, ob),
228 Point::new(vc, oc, oc),
229 ));
230 }
231
232 new_coords.shrink_to_fit();
233
234 (out, new_coords)
235}
236
237#[cfg(feature = "dim3")]
240#[inline]
241pub fn compute_normals<N: RealField + Copy>(
242 coordinates: &[Point<N>],
243 faces: &[Point<u32>],
244 normals: &mut Vec<Vector<N>>,
245) {
246 let mut divisor: Vec<N> = iter::repeat(na::zero()).take(coordinates.len()).collect();
247
248 if normals.len() > coordinates.len() {
250 normals.truncate(coordinates.len())
251 }
252
253 normals.clear();
255 normals.extend(iter::repeat(na::zero::<Vector<N>>()).take(coordinates.len()));
256
257 for f in faces.iter() {
259 let edge1 = coordinates[f.y as usize] - coordinates[f.x as usize];
260 let edge2 = coordinates[f.z as usize] - coordinates[f.x as usize];
261 let cross = edge1.cross(&edge2);
262 let normal;
263
264 if !cross.is_zero() {
265 normal = cross.normalize()
266 } else {
267 normal = cross
268 }
269
270 normals[f.x as usize] = normals[f.x as usize] + normal;
271 normals[f.y as usize] = normals[f.y as usize] + normal;
272 normals[f.z as usize] = normals[f.z as usize] + normal;
273
274 divisor[f.x as usize] = divisor[f.x as usize] + na::one();
275 divisor[f.y as usize] = divisor[f.y as usize] + na::one();
276 divisor[f.z as usize] = divisor[f.z as usize] + na::one();
277 }
278
279 for (n, divisor) in normals.iter_mut().zip(divisor.iter()) {
281 *n = *n / *divisor
282 }
283}