Skip to main content

rscad_csg_bsp/primitives/
cone.rs

1use crate::*;
2use nalgebra::{Point, Vector3};
3
4/// Create a cone with base at the origin, axis along Y.
5///
6/// - `radius`: base radius
7/// - `height`: total height (base at y=0, apex at y=height)
8/// - `segments`: number of sides around the base
9pub fn cone<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 two_pi = two * T::PI();
14    let seg_t = T::from(segments).expect("BUG: segment count is representable as T");
15
16    let apex = Point::from([T::zero(), half_h, T::zero()]);
17
18    let base: Vec<Point<T, 3>> = (0..segments)
19        .map(|j| {
20            let angle = two_pi * T::from(j).expect("BUG: loop index is representable as T") / seg_t;
21            Point::from([
22                radius * num_traits::real::Real::cos(angle),
23                -half_h,
24                radius * num_traits::real::Real::sin(angle),
25            ])
26        })
27        .collect();
28
29    let mut polygons = Vec::new();
30
31    // Base cap (-Y), reversed winding for outward normal
32    let mut base_cap = base.clone();
33    base_cap.reverse();
34    if let Ok(p) = Polygon::from_points_and_plane(base_cap, Plane::new(-Vector3::y(), half_h)) {
35        polygons.push(p);
36    }
37
38    // Side triangles from base edge to apex
39    for j in 0..segments {
40        let jn = (j + 1) % segments;
41        if let Ok(p) = Polygon::from_points(vec![apex, base[jn], base[j]]) {
42            polygons.push(p);
43        }
44    }
45
46    Csg::from_polygons(polygons).translate(Vector3::new(T::zero(), half_h, T::zero()))
47}