microcad_core/geo3d/
primitives.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! 3D primitives
5
6use std::rc::Rc;
7
8use manifold_rs::Manifold;
9
10use crate::{geo3d::RenderToMesh, *};
11
12/// The builtin cube primitive, defined by its size in the x, y, and z dimensions.
13#[derive(Debug, Clone)]
14pub struct Cube {
15    /// Size of the cube in millimeters.
16    pub size: Vec3,
17}
18
19impl RenderToMesh for Cube {
20    fn render_to_manifold(&self, _: &RenderResolution) -> Rc<Manifold> {
21        Rc::new(geo3d::Manifold::cube(self.size.x, self.size.y, self.size.z))
22    }
23}
24
25impl FetchBounds3D for Cube {
26    fn fetch_bounds_3d(&self) -> Bounds3D {
27        Bounds3D::new(Vec3::new(0.0, 0.0, 0.0), self.size)
28    }
29}
30
31/// The builtin sphere primitive, defined by its radius.
32#[derive(Debug, Clone)]
33pub struct Sphere {
34    /// Radius of the sphere in millimeters.
35    pub radius: Scalar,
36}
37
38impl FetchBounds3D for Sphere {
39    fn fetch_bounds_3d(&self) -> Bounds3D {
40        let r = self.radius;
41        let r = Vec3::new(r, r, r);
42        Bounds3D::new(-r, r)
43    }
44}
45
46impl RenderToMesh for Sphere {
47    fn render_to_manifold(&self, resolution: &RenderResolution) -> Rc<Manifold> {
48        use std::f64::consts::PI;
49        let segments = (self.radius / resolution.linear * PI * 0.5).max(3.0) as u32;
50        Rc::new(geo3d::Manifold::sphere(self.radius, segments))
51    }
52}
53
54/// The built-in cylinder primitive, defined by an bottom radius, top radius and height.
55/// The cylinder is oriented along the z-axis.
56#[derive(Debug, Clone)]
57pub struct Cylinder {
58    /// Bottom radius of the cylinder in millimeters.
59    pub radius_bottom: Scalar,
60    /// Top radius of the cylinder in millimeters.
61    pub radius_top: Scalar,
62    /// Height of the cylinder in millimeters.
63    pub height: Scalar,
64}
65
66impl FetchBounds3D for Cylinder {
67    fn fetch_bounds_3d(&self) -> Bounds3D {
68        let r = self.radius_bottom.max(self.radius_top);
69        Bounds3D::new(Vec3::new(0.0, -r, -r), Vec3::new(self.height, r, r))
70    }
71}
72
73impl RenderToMesh for Cylinder {
74    fn render_to_manifold(&self, resolution: &RenderResolution) -> Rc<Manifold> {
75        use std::f64::consts::PI;
76        let n = (self.radius_bottom / resolution.linear * PI * 0.5).max(3.0) as u32;
77        Rc::new(geo3d::Manifold::cylinder(
78            self.radius_bottom,
79            self.radius_top,
80            self.height,
81            n,
82        ))
83    }
84}