geo_aid_script/unroll/library/
segment.rs

1//! The `Segment` type and function
2
3use std::fmt::Display;
4
5use crate::{
6    figure::SegmentItem,
7    math::Build,
8    parser::PropertyValue,
9    span,
10    token::StrLit,
11    unroll::{
12        figure::{MaybeUnset, Node},
13        Dummy,
14    },
15};
16
17use super::prelude::*;
18use crate::token::Span;
19use geo_aid_figure::math_string::MathString;
20
21/// A segment with two delimiting points.
22#[derive(Debug)]
23pub struct Segment {
24    pub a: Expr<Point>,
25    pub b: Expr<Point>,
26}
27
28impl DerivedType for Segment {
29    fn as_any(&self) -> &dyn std::any::Any {
30        self
31    }
32}
33
34impl Display for Segment {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        write!(f, "Semgent({}, {})", self.a, self.b)
37    }
38}
39
40impl_derived! {Segment}
41
42#[derive(Debug)]
43struct SegmentNode {
44    /// Whether the node should be displayed
45    display: MaybeUnset<bool>,
46    /// Whether tge segment itself should be displayed
47    display_segment: MaybeUnset<bool>,
48    /// How the segment should be drawn.
49    style: MaybeUnset<Style>,
50    /// Expression of one endpoint
51    a: Expr<Point>,
52    /// Expression of the other endpoint
53    b: Expr<Point>,
54}
55
56impl Dummy for SegmentNode {
57    fn dummy() -> Self {
58        Self {
59            display: MaybeUnset::new(true),
60            display_segment: MaybeUnset::new(true),
61            style: MaybeUnset::new(Style::Solid),
62            a: Expr::dummy(),
63            b: Expr::dummy(),
64        }
65    }
66
67    fn is_dummy(&self) -> bool {
68        self.a.is_dummy() || self.b.is_dummy()
69    }
70}
71
72impl Node for SegmentNode {
73    fn set_display(&mut self, display: bool) {
74        self.display.set(display);
75    }
76
77    fn get_display(&self) -> bool {
78        self.display.get_copied()
79    }
80
81    fn build(self: Box<Self>, build: &mut Build) {
82        if self.display.unwrap() && !self.is_dummy() && self.display_segment.unwrap() {
83            let p_id = build.load(&self.a);
84            let q_id = build.load(&self.b);
85
86            build.add(SegmentItem {
87                p_id,
88                q_id,
89                label: MathString::new(),
90                style: self.style.get_copied(),
91            });
92        }
93    }
94}
95
96/// `Segment(point, point)` - a segment connecting two points.
97fn segment_function_point_point(
98    mut a: Expr<Point>,
99    mut b: Expr<Point>,
100    context: &CompileContext,
101    mut display: Properties,
102) -> SegmentExpr {
103    let node = SegmentNode {
104        display: display.get("display").maybe_unset(true),
105        display_segment: display.get("display_segment").maybe_unset(true),
106        style: display.get("style").maybe_unset(Style::default()),
107        a: a.clone_without_node(),
108        b: b.clone_without_node(),
109    };
110
111    display.ignore("default-label");
112    display.finish(context);
113
114    let mut node = HierarchyNode::new_dyn(node);
115    node.extend_children(a.take_node());
116    node.extend_children(b.take_node());
117
118    SegmentExpr::new(Segment { a, b }, node)
119}
120
121/// ```
122/// # use geo_aid_figure::Style;
123/// struct Associated {
124///     display_segment: bool,
125///     style: Style
126/// }
127/// ```
128#[derive(Debug)]
129pub struct Associated;
130
131/// The length of a segment.
132fn len(segment: SegmentExpr, context: &mut CompileContext, mut display: Properties) -> Distance {
133    display.add_if_not_present(
134        "display_segment",
135        (
136            Span::empty(),
137            PropertyValue::String(StrLit {
138                span: span!(0, 0, 0, 0),
139                content: String::from("false"),
140            }),
141        ),
142    );
143
144    let segment = segment.get();
145
146    if let Some(segment) = segment {
147        super::dst::distance_function_pp(
148            segment.a.clone_without_node(),
149            segment.b.clone_without_node(),
150            context,
151            display,
152        )
153    } else {
154        Distance::dummy()
155    }
156}
157
158/// Register the type and the function
159pub fn register(library: &mut Library) {
160    library
161        .add(
162            Function::new("segment")
163                .overload(|mut col: Pc<2>, context: &CompileContext, display| {
164                    segment_function_point_point(
165                        index!(node col,0),
166                        index!(node col,1),
167                        context,
168                        display,
169                    )
170                })
171                .overload(segment_function_point_point),
172        )
173        .add(
174            Function::new("len")
175                .alias_method(ty::derived("Segment"), "len")
176                .overload(len),
177        );
178}