rscad_csg_bsp/primitives/
cylinder.rs1use crate::*;
2use nalgebra::{Point, Vector3};
3
4pub fn cylinder<T: Number>(radius: T, height: T, segments: usize) -> Csg<T> {
10 let segments = segments.max(3);
11 let two = T::one() + T::one();
12 let half_h = height / two;
13 let pi = T::PI();
14 let two_pi = pi + pi;
15 let seg_t = T::from(segments).expect("BUG: segment count is representable as T");
16
17 let circle_point = |j: usize, y: T| -> Point<T, 3> {
18 let angle = two_pi * T::from(j).expect("BUG: loop index is representable as T") / seg_t;
19 Point::from([
20 radius * num_traits::real::Real::cos(angle),
21 y,
22 radius * num_traits::real::Real::sin(angle),
23 ])
24 };
25
26 let top: Vec<Point<T, 3>> = (0..segments).map(|j| circle_point(j, half_h)).collect();
27 let bot: Vec<Point<T, 3>> = (0..segments).map(|j| circle_point(j, -half_h)).collect();
28
29 let mut polygons = Vec::new();
30
31 if let Ok(p) = Polygon::from_points_and_plane(top.clone(), Plane::new(Vector3::y(), half_h)) {
33 polygons.push(p);
34 }
35
36 let mut bot_cap = bot.clone();
38 bot_cap.reverse();
39 if let Ok(p) = Polygon::from_points_and_plane(bot_cap, Plane::new(-Vector3::y(), half_h)) {
40 polygons.push(p);
41 }
42
43 for j in 0..segments {
45 let jn = (j + 1) % segments;
46
47 let mid_angle =
49 (two * T::from(j).expect("BUG: loop index is representable as T") + T::one()) * pi
50 / seg_t;
51 let normal = Vector3::new(
52 num_traits::real::Real::cos(mid_angle),
53 T::zero(),
54 num_traits::real::Real::sin(mid_angle),
55 );
56 let dist = radius * num_traits::real::Real::cos(pi / seg_t);
57
58 let verts = [top[j], top[jn], bot[jn], bot[j]];
59 if let Ok(p) = Polygon::from_points_and_plane(verts, Plane::new(normal, dist)) {
60 polygons.push(p);
61 }
62 }
63
64 Csg::from_polygons(polygons).translate(Vector3::new(T::zero(), half_h, T::zero()))
65}