microcad_lang/model/
inner.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Model
5
6use crate::{model::*, render::*, src_ref::*, syntax::*};
7
8/// Render state of the model.
9pub enum ModelRenderState {
10    /// The model has not been rendered.
11    /// Model output is [`None`].
12    Pending,
13    /// The model has been pre-rendered via [`Model::pre-render`]
14    /// Model output is [`Some`], but there is no geometry.
15    Preparing,
16    /// Rendering is completed.
17    Complete,
18}
19
20/// The actual model contents
21#[derive(custom_debug::Debug, Default)]
22pub struct ModelInner {
23    /// Optional id.
24    ///
25    /// The id is set when the model was created by an assignment: `a = Cube(50mm)`.
26    pub id: Option<Identifier>,
27    /// Parent object.
28    #[debug(skip)]
29    pub parent: Option<Model>,
30    /// Children of the model.
31    pub children: Models,
32    /// Element of the model with [SrcRef].
33    pub element: Refer<Element>,
34    /// Attributes used for export.
35    pub attributes: Attributes,
36    /// The output type of the this model.
37    pub output: Option<RenderOutput>,
38}
39
40impl ModelInner {
41    /// Create a new [`ModelInner`] with a specific element.
42    pub fn new(element: Element, src_ref: SrcRef) -> Self {
43        Self {
44            element: Refer::new(element, src_ref),
45            ..Default::default()
46        }
47    }
48
49    /// Return render state of the model.
50    pub fn render_state(&self) -> ModelRenderState {
51        match &self.output {
52            Some(RenderOutput::Geometry2D { geometry, .. }) => match geometry {
53                Some(_) => ModelRenderState::Complete,
54                None => ModelRenderState::Preparing,
55            },
56            Some(RenderOutput::Geometry3D { geometry, .. }) => match geometry {
57                Some(_) => ModelRenderState::Complete,
58                None => ModelRenderState::Preparing,
59            },
60            None => ModelRenderState::Pending,
61        }
62    }
63
64    /// Clone only the content of this model without children and parent.
65    pub fn clone_content(&self) -> Self {
66        Self {
67            id: self.id.clone(),
68            parent: None,
69            element: self.element.clone(),
70            attributes: self.attributes.clone(),
71            output: self.output.clone(),
72            ..Default::default()
73        }
74    }
75
76    /// Return iterator of children.s
77    pub fn children(&self) -> std::slice::Iter<'_, Model> {
78        self.children.iter()
79    }
80
81    /// Return if ,model has no children.
82    pub fn is_empty(&self) -> bool {
83        self.children.is_empty()
84    }
85
86    /// Return element of this model.
87    pub fn element(&self) -> &Element {
88        &self.element
89    }
90
91    /// Returns the render output, panics if there is no render output.
92    pub fn output(&self) -> &RenderOutput {
93        self.output
94            .as_ref()
95            .expect("Render output. You have to pre-render() and render() the model first.")
96    }
97
98    /// Returns the mutable render output, panics if there is no render output.
99    pub fn output_mut(&mut self) -> &mut RenderOutput {
100        self.output
101            .as_mut()
102            .expect("Render output. You have to pre-render() and render() the model first.")
103    }
104}
105
106impl PropertiesAccess for ModelInner {
107    fn get_property(&self, id: &Identifier) -> Option<&Value> {
108        self.element.get_property(id)
109    }
110
111    fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
112        self.element.set_property(id, value)
113    }
114
115    fn get_properties(&self) -> Option<&Properties> {
116        self.element.get_properties()
117    }
118
119    fn add_properties(&mut self, props: Properties) {
120        self.element.add_properties(props);
121    }
122}
123
124impl SrcReferrer for ModelInner {
125    fn src_ref(&self) -> SrcRef {
126        self.element.src_ref.clone()
127    }
128}