microcad_core/
render.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Render trait.
5
6use cgmath::InnerSpace;
7
8use crate::*;
9
10/// A trait renders something.
11pub trait Render<T> {
12    /// The render function.
13    fn render(&self, resolution: &RenderResolution) -> T;
14
15    /// A render hint to tell whether this geometry is independent from resolution.
16    ///
17    /// Example: a rectangle is resolution independent, but a circle is not.
18    fn is_resolution_independent(&self) -> bool {
19        false
20    }
21}
22
23/// Render resolution when rendering things to polygons or meshes.
24#[derive(Debug, Clone)]
25pub struct RenderResolution {
26    /// Linear resolution in millimeters (Default = 0.1mm)
27    pub linear: Scalar,
28}
29
30impl RenderResolution {
31    /// Create new render resolution.
32    pub fn new(linear: Scalar) -> Self {
33        Self { linear }
34    }
35
36    /// Coarse render resolution of 1.0mm.
37    pub fn coarse() -> Self {
38        Self { linear: 1.0 }
39    }
40
41    /// Medium render resolution of 0.25mm.
42    pub fn medium() -> Self {
43        Self { linear: 0.25 }
44    }
45
46    /// High render resolution of 0.1mm.
47    pub fn high() -> Self {
48        Self { linear: 0.1 }
49    }
50
51    /// Get the number segments for a circle as power of 2.
52    ///
53    /// The minimal number of segments is 4, the maximum number of segments is 1024.
54    pub fn circular_segments(&self, radius: Scalar) -> u32 {
55        let n = (radius / self.linear * std::f64::consts::PI * 0.5).max(3.0);
56        2_u32.pow(n.log2().ceil() as u32).clamp(8, 1024)
57    }
58}
59
60impl std::ops::Mul<Mat3> for RenderResolution {
61    type Output = RenderResolution;
62
63    fn mul(self, rhs: Mat3) -> Self::Output {
64        let scale = (rhs.x.magnitude() * rhs.y.magnitude()).sqrt();
65        Self {
66            linear: self.linear / scale,
67        }
68    }
69}
70
71impl std::ops::Mul<Mat4> for RenderResolution {
72    type Output = RenderResolution;
73
74    fn mul(self, rhs: Mat4) -> Self::Output {
75        let scale = (rhs.x.magnitude() * rhs.y.magnitude() * rhs.z.magnitude()).powf(1.0 / 3.0);
76        Self {
77            linear: self.linear / scale,
78        }
79    }
80}
81
82impl Default for RenderResolution {
83    fn default() -> Self {
84        RenderResolution::medium()
85    }
86}
87
88impl std::fmt::Display for RenderResolution {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        write!(f, "@{}mm", self.linear)
91    }
92}
93
94impl std::hash::Hash for RenderResolution {
95    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
96        bytemuck::bytes_of(&self.linear).hash(state);
97    }
98}