sticknodes_rs/structs/
node.rs

1use petgraph::graph::NodeIndex;
2use petgraph::Graph;
3use serde::Deserialize;
4use serde::Serialize;
5
6use crate::color::Color;
7
8use super::stickfigure::DrawOrderIndex;
9
10use core::cell::RefCell;
11extern crate alloc;
12use alloc::{rc::Rc, vec::Vec};
13
14#[derive(Debug, Clone)]
15pub struct Node {
16    pub node_type: NodeType,
17    pub(crate) draw_order_index: DrawOrderIndex,
18    pub is_static: bool,
19    pub is_stretchy: bool,
20    pub is_smart_stretch: bool,
21    pub do_not_apply_smart_stretch: bool,
22    pub use_segment_color: bool,
23    pub use_circle_outline: bool,
24    pub circle_is_hollow: bool,
25    pub use_gradient: bool,
26    pub reverse_gradient: bool,
27    pub gradient_mode: i16,
28    pub use_segment_scale: bool,
29    pub local_x: f32,
30    pub local_y: f32,
31    pub scale: f32,
32    pub default_length: f32,
33    pub length: f32,
34    pub default_thickness: i32,
35    pub thickness: i32,
36    pub segment_curve_radius_and_default_curve_radius: i32,
37    pub curve_circulization: bool,
38    pub segment_curve_polyfill_precision: i16,
39    pub half_arc: bool,
40    pub right_triangle_direction: i16,
41    pub triangle_upside_down: bool,
42    pub trapezoid_top_thickness_ratio: f32,
43    pub num_polygon_vertices: i16,
44    pub default_local_angle: f32,
45    pub local_angle: f32,
46    pub default_angle: f32,
47    pub color: Color,
48    pub gradient_color: Color,
49    pub circle_outline_color: Color,
50}
51
52impl Default for Node {
53    fn default() -> Self {
54        Self {
55            node_type: NodeType::default(),
56            draw_order_index: DrawOrderIndex(0),
57            is_static: false,
58            is_stretchy: false,
59            is_smart_stretch: false,
60            do_not_apply_smart_stretch: false,
61            use_segment_color: false,
62            use_circle_outline: false,
63            circle_is_hollow: false,
64            use_gradient: false,
65            reverse_gradient: false,
66            gradient_mode: 0,
67            use_segment_scale: false,
68            local_x: 0.0,
69            local_y: 0.0,
70            scale: 1.0,
71            default_length: 0.0,
72            length: 0.0,
73            default_thickness: 0,
74            thickness: 0,
75            segment_curve_radius_and_default_curve_radius: 0,
76            curve_circulization: false,
77            segment_curve_polyfill_precision: 0,
78            half_arc: false,
79            right_triangle_direction: 0,
80            triangle_upside_down: false,
81            trapezoid_top_thickness_ratio: 0.0,
82            num_polygon_vertices: 0,
83            default_local_angle: 0.0,
84            local_angle: 0.0,
85            default_angle: 0.0,
86            color: Color::default(),
87            gradient_color: Color::default(),
88            circle_outline_color: Color::default(),
89        }
90    }
91}
92
93#[derive(Serialize, Deserialize, Clone, Debug)]
94pub struct SerializableNode {
95    pub draw_order_index: DrawOrderIndex,
96    pub node_type: NodeType,
97    pub is_static: bool,
98    pub is_stretchy: bool,
99    pub is_smart_stretch: bool,
100    pub do_not_apply_smart_stretch: bool,
101    pub use_segment_color: bool,
102    pub use_circle_outline: bool,
103    pub circle_is_hollow: bool,
104    pub use_gradient: bool,
105    pub reverse_gradient: bool,
106    pub gradient_mode: i16,
107    pub use_segment_scale: bool,
108    pub local_x: f32,
109    pub local_y: f32,
110    pub scale: f32,
111    pub default_length: f32,
112    pub length: f32,
113    pub default_thickness: i32,
114    pub thickness: i32,
115    pub segment_curve_radius_and_default_curve_radius: i32,
116    pub curve_circulization: bool,
117    pub segment_curve_polyfill_precision: i16,
118    pub half_arc: bool,
119    pub right_triangle_direction: i16,
120    pub triangle_upside_down: bool,
121    pub trapezoid_top_thickness_ratio: f32,
122    pub num_polygon_vertices: i16,
123    pub default_local_angle: f32,
124    pub local_angle: f32,
125    pub default_angle: f32,
126    pub color: Color,
127    pub gradient_color: Color,
128    pub circle_outline_color: Color,
129    pub children: Vec<SerializableNode>,
130}
131
132#[derive(Debug, Serialize, Deserialize)]
133pub struct NodeOptions {
134    pub node_type: NodeType,
135    pub is_static: bool,
136    pub is_stretchy: bool,
137    pub is_smart_stretch: bool,
138    pub do_not_apply_smart_stretch: bool,
139    pub use_segment_color: bool,
140    pub use_circle_outline: bool,
141    pub circle_is_hollow: bool,
142    pub use_gradient: bool,
143    pub reverse_gradient: bool,
144    pub gradient_mode: i16,
145    pub use_segment_scale: bool,
146    pub local_x: f32,
147    pub local_y: f32,
148    pub scale: f32,
149    pub default_length: f32,
150    pub length: f32,
151    pub default_thickness: i32,
152    pub thickness: i32,
153    pub segment_curve_radius_and_default_curve_radius: i32,
154    pub curve_circulization: bool,
155    pub segment_curve_polyfill_precision: i16,
156    pub half_arc: bool,
157    pub right_triangle_direction: i16,
158    pub triangle_upside_down: bool,
159    pub trapezoid_top_thickness_ratio: f32,
160    pub num_polygon_vertices: i16,
161    pub default_local_angle: f32,
162    pub local_angle: f32,
163    pub default_angle: f32,
164    pub color: Color,
165    pub gradient_color: Color,
166    pub circle_outline_color: Color,
167}
168
169impl Default for NodeOptions {
170    fn default() -> Self {
171        Self {
172            node_type: NodeType::default(),
173            is_static: false,
174            is_stretchy: false,
175            is_smart_stretch: false,
176            do_not_apply_smart_stretch: false,
177            use_segment_color: false,
178            use_circle_outline: false,
179            circle_is_hollow: false,
180            use_gradient: false,
181            reverse_gradient: false,
182            gradient_mode: 0,
183            use_segment_scale: false,
184            local_x: 0.0,
185            local_y: 0.0,
186            scale: 1.0,
187            default_length: 0.0,
188            length: 0.0,
189            default_thickness: 0,
190            thickness: 0,
191            segment_curve_radius_and_default_curve_radius: 0,
192            curve_circulization: false,
193            segment_curve_polyfill_precision: 0,
194            half_arc: false,
195            right_triangle_direction: 0,
196            triangle_upside_down: false,
197            trapezoid_top_thickness_ratio: 0.0,
198            num_polygon_vertices: 0,
199            default_local_angle: 0.0,
200            local_angle: 0.0,
201            default_angle: 0.0,
202            color: Color::default(),
203            gradient_color: Color::default(),
204            circle_outline_color: Color::default(),
205        }
206    }
207}
208
209impl Node {
210    /// Creates a new, empty `Node`.
211    pub fn new() -> Self {
212        Node::default()
213    }
214
215    pub fn from_options(options: NodeOptions) -> Self {
216        let mut node_type = options.node_type.clone();
217        if options.node_type.to_integer() == NodeType::RootNode.to_integer() {
218            node_type = NodeType::RoundedSegment;
219        }
220        Self {
221            node_type: node_type,
222            is_static: options.is_static,
223            is_stretchy: options.is_stretchy,
224            is_smart_stretch: options.is_smart_stretch,
225            do_not_apply_smart_stretch: options.do_not_apply_smart_stretch,
226            use_segment_color: options.use_segment_color,
227            use_circle_outline: options.use_circle_outline,
228            circle_is_hollow: options.circle_is_hollow,
229            use_gradient: options.use_gradient,
230            reverse_gradient: options.reverse_gradient,
231            gradient_mode: options.gradient_mode,
232            use_segment_scale: options.use_segment_scale,
233            local_x: options.local_x,
234            local_y: options.local_y,
235            scale: options.scale,
236            default_length: options.default_length,
237            length: options.length,
238            default_thickness: options.default_thickness,
239            thickness: options.thickness,
240            segment_curve_radius_and_default_curve_radius: options
241                .segment_curve_radius_and_default_curve_radius,
242            curve_circulization: options.curve_circulization,
243            segment_curve_polyfill_precision: options.segment_curve_polyfill_precision,
244            half_arc: options.half_arc,
245            right_triangle_direction: options.right_triangle_direction,
246            triangle_upside_down: options.triangle_upside_down,
247            trapezoid_top_thickness_ratio: options.trapezoid_top_thickness_ratio,
248            num_polygon_vertices: options.num_polygon_vertices,
249            default_local_angle: options.default_local_angle,
250            local_angle: options.local_angle,
251            default_angle: options.default_angle,
252            color: options.color,
253            gradient_color: options.gradient_color,
254            circle_outline_color: options.circle_outline_color,
255            ..Default::default()
256        }
257    }
258
259    pub fn to_options(&self) -> NodeOptions {
260        NodeOptions {
261            node_type: self.node_type.clone(),
262            is_static: self.is_static,
263            is_stretchy: self.is_stretchy,
264            is_smart_stretch: self.is_smart_stretch,
265            do_not_apply_smart_stretch: self.do_not_apply_smart_stretch,
266            use_segment_color: self.use_segment_color,
267            use_circle_outline: self.use_circle_outline,
268            circle_is_hollow: self.circle_is_hollow,
269            use_gradient: self.use_gradient,
270            reverse_gradient: self.reverse_gradient,
271            gradient_mode: self.gradient_mode,
272            use_segment_scale: self.use_segment_scale,
273            local_x: self.local_x,
274            local_y: self.local_y,
275            scale: self.scale,
276            default_length: self.default_length,
277            length: self.length,
278            default_thickness: self.default_thickness,
279            thickness: self.thickness,
280            segment_curve_radius_and_default_curve_radius: self
281                .segment_curve_radius_and_default_curve_radius,
282            curve_circulization: self.curve_circulization,
283            segment_curve_polyfill_precision: self.segment_curve_polyfill_precision,
284            half_arc: self.half_arc,
285            right_triangle_direction: self.right_triangle_direction,
286            triangle_upside_down: self.triangle_upside_down,
287            trapezoid_top_thickness_ratio: self.trapezoid_top_thickness_ratio,
288            num_polygon_vertices: self.num_polygon_vertices,
289            default_local_angle: self.default_local_angle,
290            local_angle: self.local_angle,
291            default_angle: self.default_angle,
292            color: self.color,
293            gradient_color: self.gradient_color,
294            circle_outline_color: self.circle_outline_color,
295        }
296    }
297
298    pub fn build_serializable_tree(
299        &self,
300        graph: &Graph<Rc<RefCell<Node>>, ()>,
301        current: NodeIndex,
302    ) -> SerializableNode {
303        let node = graph.node_weight(current).expect("Bug with library. NodeIndex passed to build_serializable_tree in Node is not valid.").borrow().clone();
304        let mut children = Vec::new();
305
306        for neighbor in graph.neighbors_directed(current, petgraph::Direction::Outgoing) {
307            children.push(self.build_serializable_tree(graph, neighbor));
308        }
309
310        SerializableNode {
311            draw_order_index: node.get_draw_order_index(),
312            children,
313            node_type: node.node_type.clone(),
314            is_static: node.is_static,
315            is_stretchy: node.is_stretchy,
316            is_smart_stretch: node.is_smart_stretch,
317            do_not_apply_smart_stretch: node.do_not_apply_smart_stretch,
318            use_segment_color: node.use_segment_color,
319            use_circle_outline: node.use_circle_outline,
320            circle_is_hollow: node.circle_is_hollow,
321            use_gradient: node.use_gradient,
322            reverse_gradient: node.reverse_gradient,
323            gradient_mode: node.gradient_mode,
324            use_segment_scale: node.use_segment_scale,
325            local_x: node.local_x,
326            local_y: node.local_y,
327            scale: node.scale,
328            default_length: node.default_length,
329            length: node.length,
330            default_thickness: node.default_thickness,
331            thickness: node.thickness,
332            segment_curve_radius_and_default_curve_radius: node
333                .segment_curve_radius_and_default_curve_radius,
334            curve_circulization: node.curve_circulization,
335            segment_curve_polyfill_precision: node.segment_curve_polyfill_precision,
336            half_arc: node.half_arc,
337            right_triangle_direction: node.right_triangle_direction,
338            triangle_upside_down: node.triangle_upside_down,
339            trapezoid_top_thickness_ratio: node.trapezoid_top_thickness_ratio,
340            num_polygon_vertices: node.num_polygon_vertices,
341            default_local_angle: node.default_local_angle,
342            local_angle: node.local_angle,
343            default_angle: node.default_angle,
344            color: node.color,
345            gradient_color: node.gradient_color,
346            circle_outline_color: node.circle_outline_color,
347        }
348    }
349
350    pub fn get_draw_order_index(&self) -> DrawOrderIndex {
351        return self.draw_order_index;
352    }
353
354    pub fn update<F>(rc_node: &Rc<RefCell<Self>>, f: F)
355    where
356        F: FnOnce(&mut Self),
357    {
358        let mut inner = rc_node.borrow_mut();
359        f(&mut *inner);
360    }
361}
362
363#[derive(Clone, Debug, Default, Serialize, Deserialize)]
364pub enum NodeType {
365    /// Should only be one RootNode per `Stickfigure`, and it should be the first node.
366    RootNode = -1,
367    #[default]
368    RoundedSegment = 0,
369    Segment = 1,
370    Circle = 2,
371    Triangle = 3,
372    FilledCircle = 4,
373    Ellipse = 5,
374    Trapezoid = 6,
375    Polygon = 7,
376}
377
378impl NodeType {
379    pub fn from_integer(int: i8) -> Option<Self> {
380        match int {
381            -1 => Some(NodeType::RootNode),
382            0 => Some(NodeType::RoundedSegment),
383            1 => Some(NodeType::Segment),
384            2 => Some(NodeType::Circle),
385            3 => Some(NodeType::Triangle),
386            4 => Some(NodeType::FilledCircle),
387            5 => Some(NodeType::Ellipse),
388            6 => Some(NodeType::Trapezoid),
389            7 => Some(NodeType::Polygon),
390            _ => None,
391        }
392    }
393    pub fn to_integer(&self) -> i8 {
394        self.clone() as i8
395    }
396}