Skip to main content

geogebra_types/
lib.rs

1//! This is an attempt at creating a library for working with GeoGebra files.
2//! This is largely an educated guess and what works how as the documentation
3//! on the format is incredibly sparse. This is mostly incomplete and is mostly
4//! meant as a utility crate for Geo-AID.
5
6use std::{
7    io::{self, Seek, Write},
8    marker::PhantomData,
9    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
10    rc::Rc,
11};
12
13use num_traits::{Bounded, Num, One, Zero};
14use raw::{
15    Construction, ConstructionItem, Coords, Element, ElementType, LabelMode, ObjColorType, Show,
16};
17use zip::{write::FileOptions, ZipWriter};
18
19pub mod raw;
20pub use raw::{LineStyle, LineType};
21
22pub mod prelude {
23    pub use super::{
24        Conic, ConicAccess, Expr as _, Geogebra, Line, LineAccess, List, ListAccess, Numeric,
25        NumericAccess, Point, PointAccess, Ray, Segment,
26    };
27}
28
29/// High-level API for working with a Geogebra workspace.
30#[derive(Debug)]
31pub struct Geogebra {
32    data: raw::Geogebra,
33    /// Next element id to use for a label
34    next_id: usize,
35}
36
37impl Geogebra {
38    /// Create a new, empty workspace.
39    #[must_use]
40    pub fn new() -> Self {
41        Self {
42            data: raw::Geogebra {
43                format: String::from("5.0"),
44                construction: Construction::default(),
45                app: String::from("suite"),
46                sub_app: String::from("geometry"),
47            },
48            next_id: 0,
49        }
50    }
51
52    /// Write the ggb file to a stream.
53    pub fn write(&self, stream: impl Write + Seek) -> io::Result<()> {
54        let geogebra = quick_xml::se::to_string(&self.data).unwrap();
55
56        let mut file = ZipWriter::new(stream);
57
58        file.start_file("geogebra.xml", FileOptions::<()>::default())?;
59        file.write_all(b"<?xml version=\"1.0\" encoding=\"utf-8\" ?>")?;
60        file.write_all(geogebra.as_bytes())?;
61        file.finish()?;
62
63        Ok(())
64    }
65
66    fn next_label(&mut self) -> String {
67        let mut next_label = format!("elem{}", self.next_id);
68        self.next_id += 1;
69
70        while self.data.construction.items.iter().any(|item| match item {
71            ConstructionItem::Element(element) => element.label == next_label,
72            ConstructionItem::Command(_) => false,
73            ConstructionItem::Expression(expression) => expression.label == next_label,
74        }) {
75            next_label = format!("elem{}", self.next_id);
76            self.next_id += 1;
77        }
78
79        next_label
80    }
81}
82
83#[derive(Clone, Copy)]
84struct Style {
85    /// Whether to display the point's label
86    pub display_label: bool,
87    /// Settings for line display.
88    pub line_style: Option<LineStyle>,
89    /// Color of this object
90    pub color: Option<ObjColorType>,
91}
92
93impl Default for Style {
94    fn default() -> Self {
95        Self {
96            display_label: true,
97            line_style: None,
98            color: None,
99        }
100    }
101}
102
103impl Style {
104    #[must_use]
105    fn to_element(self) -> Element {
106        Element {
107            type_: ElementType::Point,
108            label: String::new(),
109            caption: None,
110            label_mode: LabelMode::Caption.into(),
111            show: Show {
112                object: true,
113                label: self.display_label,
114            },
115            coords: None,
116            line_style: self.line_style,
117            obj_color: self.color,
118        }
119    }
120}
121
122pub trait Object: Into<Expression> {}
123
124/// An immutable labeled expression. Passed by reference
125pub struct Var<T>(Rc<String>, PhantomData<T>);
126
127impl<T> Var<T> {
128    #[must_use]
129    fn new(expr: String) -> Self {
130        Self(Rc::new(expr), PhantomData)
131    }
132}
133
134impl<T: Object> Object for Var<T> {}
135
136impl<T: Object> Object for &Var<T> {}
137
138impl<T: Expr> Expr for Var<T> {
139    type Target = T::Target;
140
141    fn get_type() -> ElementType {
142        T::get_type()
143    }
144
145    fn var(expr: String) -> Var<Self::Target> {
146        T::var(expr)
147    }
148}
149
150impl<T: Expr> Expr for &Var<T> {
151    type Target = T::Target;
152
153    fn get_type() -> ElementType {
154        T::get_type()
155    }
156
157    fn var(expr: String) -> Var<Self::Target> {
158        T::var(expr)
159    }
160}
161
162/// A type-erased expression.
163#[derive(Clone)]
164pub struct Expression {
165    expr: Rc<String>,
166    style: Style,
167}
168
169impl Expression {
170    /// Expression from a string, default style.
171    pub fn expr(expr: impl ToString) -> Self {
172        Self {
173            expr: Rc::new(expr.to_string()),
174            style: Style::default(),
175        }
176    }
177}
178
179pub trait Expr: Into<Expression> {
180    /// Target primitive type.
181    type Target;
182
183    /// Get the element type of this expression
184    fn get_type() -> ElementType;
185
186    /// Create a variable of target type
187    #[must_use]
188    fn var(expr: String) -> Var<Self::Target>;
189}
190
191impl<X: Into<Numeric>, Y: Into<Numeric>> From<(X, Y)> for Expression {
192    fn from((x, y): (X, Y)) -> Self {
193        Self {
194            expr: Rc::new(format!(
195                "(real({}), real({}))",
196                x.into().0.expr,
197                y.into().0.expr
198            )),
199            style: Style::default(),
200        }
201    }
202}
203
204impl From<f64> for Expression {
205    fn from(value: f64) -> Self {
206        Self {
207            expr: Rc::new(format!("{value} + 0i")),
208            style: Style::default(),
209        }
210    }
211}
212
213impl<T> From<Var<T>> for Expression {
214    fn from(value: Var<T>) -> Self {
215        Self::from(&value)
216    }
217}
218
219impl<T> From<&Var<T>> for Expression {
220    fn from(value: &Var<T>) -> Self {
221        Self {
222            expr: Rc::clone(&value.0),
223            style: Style::default(),
224        }
225    }
226}
227
228impl From<Point> for Expression {
229    fn from(value: Point) -> Self {
230        value.0
231    }
232}
233
234/// A point element of the Geogebra construction
235#[derive(Clone)]
236pub struct Point(Expression);
237
238impl Point {
239    /// Set the line's color
240    pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
241        self.0.style.color = Some(ObjColorType { r, g, b });
242    }
243
244    /// Wether to display this line's label
245    pub fn set_display_label(&mut self, v: bool) {
246        self.0.style.display_label = v;
247    }
248
249    /// Style for a point bound to its expression
250    #[must_use]
251    fn bound() -> Style {
252        Style {
253            display_label: true,
254            line_style: None,
255            color: Some(ObjColorType {
256                r: 97,
257                g: 97,
258                b: 97,
259            }),
260        }
261    }
262
263    /// Style for a point bound to its expression
264    #[must_use]
265    fn free() -> Style {
266        Style {
267            display_label: true,
268            line_style: None,
269            color: Some(ObjColorType {
270                r: 21,
271                g: 101,
272                b: 192,
273            }),
274        }
275    }
276
277    /// Intersection of two lines
278    #[must_use]
279    pub fn intersect(k: impl Into<Line>, l: impl Into<Line>) -> Self {
280        Self(Expression {
281            expr: Rc::new(format!(
282                "Intersect({}, {})",
283                k.into().0.expr,
284                l.into().0.expr
285            )),
286            style: Self::bound(),
287        })
288    }
289
290    /// Point on another geometric object
291    #[must_use]
292    pub fn on(v: impl Object) -> Self {
293        Self(Expression {
294            expr: Rc::new(format!("Point({})", v.into().expr)),
295            style: Self::free(),
296        })
297    }
298
299    /// Get the x coordinate of this point
300    #[must_use]
301    pub fn x(self) -> Numeric {
302        Numeric(Expression {
303            expr: Rc::new(format!("x({})", self.0.expr)),
304            style: Style::default(),
305        })
306    }
307
308    /// Get the y coordinate of this point
309    #[must_use]
310    pub fn y(self) -> Numeric {
311        Numeric(Expression {
312            expr: Rc::new(format!("y({})", self.0.expr)),
313            style: Style::default(),
314        })
315    }
316
317    /// Convert this point to a complex number
318    #[must_use]
319    pub fn complex(self) -> Numeric {
320        Numeric(Expression::expr(format!("ToComplex({})", self.0.expr)))
321    }
322}
323
324impl<X: Into<Numeric>, Y: Into<Numeric>> From<(X, Y)> for Point {
325    fn from(value: (X, Y)) -> Self {
326        Self(Expression::from(value))
327    }
328}
329
330impl From<Var<Point>> for Point {
331    fn from(value: Var<Point>) -> Self {
332        Self(Expression::from(value))
333    }
334}
335
336impl From<&Var<Point>> for Point {
337    fn from(value: &Var<Point>) -> Self {
338        Self(Expression::from(value))
339    }
340}
341
342impl Expr for Point {
343    type Target = Self;
344
345    fn get_type() -> ElementType {
346        ElementType::Point
347    }
348
349    fn var(expr: String) -> Var<Self::Target> {
350        Var::new(expr)
351    }
352}
353
354impl Object for Point {}
355
356impl<X: Into<Numeric>, Y: Into<Numeric>> Expr for (X, Y) {
357    type Target = Point;
358
359    fn get_type() -> ElementType {
360        ElementType::Point
361    }
362
363    fn var(expr: String) -> Var<Self::Target> {
364        Var::new(expr)
365    }
366}
367
368/// Trait with point-related functions
369pub trait PointAccess: Sized
370where
371    Point: From<Self>,
372{
373    /// Get the x coordinate of this point
374    #[must_use]
375    fn x(self) -> Numeric {
376        Point::from(self).x()
377    }
378
379    /// Get the y coordinate of this point
380    #[must_use]
381    fn y(self) -> Numeric {
382        Point::from(self).x()
383    }
384
385    /// Convert to a complex number
386    #[must_use]
387    fn complex(self) -> Numeric {
388        Point::from(self).complex()
389    }
390}
391
392impl<T> PointAccess for T where Point: From<T> {}
393
394impl Expr for f64 {
395    type Target = Numeric;
396
397    fn get_type() -> ElementType {
398        ElementType::Numeric
399    }
400
401    fn var(expr: String) -> Var<Self::Target> {
402        Var::new(expr)
403    }
404}
405
406/// A line element of the Geogebra construction
407#[derive(Clone)]
408pub struct Line(Expression);
409
410impl Line {
411    /// Set the line's color
412    pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
413        self.0.style.color = Some(ObjColorType { r, g, b });
414    }
415
416    /// Set the line's style
417    pub fn set_style(&mut self, style: LineStyle) {
418        self.0.style.line_style = Some(style);
419    }
420
421    /// Wether to display this line's label
422    pub fn set_display_label(&mut self, v: bool) {
423        self.0.style.display_label = v;
424    }
425
426    /// Default line style.
427    #[must_use]
428    fn style() -> Style {
429        Style {
430            display_label: false,
431            line_style: Some(LineStyle::default()),
432            color: None,
433        }
434    }
435
436    /// Make a line through two points.
437    #[must_use]
438    pub fn new(a: impl Into<Point>, b: impl Into<Point>) -> Self {
439        Self(Expression {
440            expr: Rc::new(format!("Line({}, {})", a.into().0.expr, b.into().0.expr)),
441            style: Self::style(),
442        })
443    }
444
445    /// Make a line from a point and a direction vector
446    #[must_use]
447    pub fn point_vector(point: impl Into<Point>, vector: impl Into<Numeric>) -> Self {
448        Self(Expression {
449            expr: Rc::new(format!(
450                "Line({}, {})",
451                point.into().0.expr,
452                vector.into().0.expr
453            )),
454            style: Self::style(),
455        })
456    }
457
458    /// Bisector of an angle
459    #[must_use]
460    pub fn angle_bisector(a: impl Into<Point>, b: impl Into<Point>, c: impl Into<Point>) -> Self {
461        Self(Expression::expr(format!(
462            "AngleBisector({}, {}, {})",
463            a.into().0.expr,
464            b.into().0.expr,
465            c.into().0.expr
466        )))
467    }
468
469    /// A line perpendicular to another, going through a point
470    #[must_use]
471    pub fn perpendicular(to: impl Into<Line>, through: impl Into<Point>) -> Self {
472        Self(Expression::expr(format!(
473            "PerpendicularLine({}, {})",
474            through.into().0.expr,
475            to.into().0.expr
476        )))
477    }
478
479    /// A line parallel to another, going through a point
480    #[must_use]
481    pub fn parallel(to: impl Into<Line>, through: impl Into<Point>) -> Self {
482        Self(Expression::expr(format!(
483            "Line({}, {})",
484            through.into().0.expr,
485            to.into().0.expr
486        )))
487    }
488
489    /// Direction vector of this line
490    #[must_use]
491    pub fn direction(self) -> Numeric {
492        Numeric(Expression::expr(format!("Direction({})", self.0.expr)))
493    }
494}
495
496impl From<Var<Line>> for Line {
497    fn from(value: Var<Line>) -> Self {
498        Self(Expression::from(value))
499    }
500}
501
502impl From<&Var<Line>> for Line {
503    fn from(value: &Var<Line>) -> Self {
504        Self(Expression::from(value))
505    }
506}
507
508impl From<Line> for Expression {
509    fn from(value: Line) -> Self {
510        value.0
511    }
512}
513
514impl Expr for Line {
515    type Target = Self;
516
517    fn get_type() -> ElementType {
518        ElementType::Line
519    }
520
521    fn var(expr: String) -> Var<Self::Target> {
522        Var::new(expr)
523    }
524}
525
526impl Object for Line {}
527
528/// Trait with line-related functions
529pub trait LineAccess: Sized
530where
531    Line: From<Self>,
532{
533    /// Direction vector of this line
534    #[must_use]
535    fn direction(self) -> Numeric {
536        Line::from(self).direction()
537    }
538}
539
540impl<T> LineAccess for T where Line: From<T> {}
541
542/// A list expression
543#[derive(Clone)]
544pub struct List<T>(Expression, PhantomData<T>);
545
546impl<T: Expr, It: IntoIterator<Item = T>> From<It> for List<T::Target>
547where
548    Expression: From<T>,
549{
550    fn from(value: It) -> Self {
551        let mut args = String::new();
552
553        for arg in value {
554            args += Expression::from(arg).expr.as_ref();
555            args += ", "
556        }
557
558        args.pop();
559        args.pop();
560
561        Self(
562            Expression {
563                expr: Rc::new(format!("{{{args}}}")),
564                style: Style::default(),
565            },
566            PhantomData,
567        )
568    }
569}
570
571impl<T> From<List<T>> for Expression {
572    fn from(value: List<T>) -> Self {
573        value.0
574    }
575}
576
577impl<T> Expr for List<T> {
578    type Target = List<T>;
579
580    fn get_type() -> ElementType {
581        ElementType::List
582    }
583
584    fn var(expr: String) -> Var<Self::Target> {
585        Var::new(expr)
586    }
587}
588
589impl<T> From<&Var<List<T>>> for List<T> {
590    fn from(value: &Var<List<T>>) -> Self {
591        Self(value.into(), PhantomData)
592    }
593}
594
595impl List<Point> {
596    /// Mean value of X coordinates of points.
597    #[must_use]
598    pub fn mean_x(self) -> Numeric {
599        Numeric(Expression {
600            expr: Rc::new(format!("MeanX({})", self.0.expr)),
601            style: Style::default(),
602        })
603    }
604
605    /// Mean value of Y coordinates of points.
606    #[must_use]
607    pub fn mean_y(self) -> Numeric {
608        Numeric(Expression {
609            expr: Rc::new(format!("MeanX({})", self.0.expr)),
610            style: Style::default(),
611        })
612    }
613}
614
615impl List<Numeric> {
616    /// Sum of these numbers
617    #[must_use]
618    pub fn sum(self) -> Numeric {
619        Numeric(Expression {
620            expr: Rc::new(format!("Sum(Append({}, 0 + 0i))", self.0.expr)),
621            style: Style::default(),
622        })
623    }
624
625    /// Product of these numbers
626    #[must_use]
627    pub fn product(self) -> Numeric {
628        Numeric(Expression {
629            expr: Rc::new(format!("Product(Append({}, 1 + 0i))", self.0.expr)),
630            style: Style::default(),
631        })
632    }
633}
634
635/// A trait for accessing list functions through convertible types
636pub trait ListAccess<T>: Sized
637where
638    List<T>: From<Self>,
639{
640    /// Get the mean X coordinate
641    fn mean_x(self) -> Numeric
642    where
643        List<Point>: From<Self>,
644    {
645        List::from(self).mean_x()
646    }
647
648    /// Get the mean Y coordinate
649    fn mean_y(self) -> Numeric
650    where
651        List<Point>: From<Self>,
652    {
653        List::from(self).mean_y()
654    }
655
656    /// Get the sum of numbers
657    fn sum(self) -> Numeric
658    where
659        List<Numeric>: From<Self>,
660    {
661        List::from(self).sum()
662    }
663
664    /// Get the product of numbers
665    fn product(self) -> Numeric
666    where
667        List<Numeric>: From<Self>,
668    {
669        List::from(self).product()
670    }
671}
672
673impl<T, V> ListAccess<T> for V where List<T>: From<V> {}
674
675/// A number value
676#[derive(Clone)]
677pub struct Numeric(Expression);
678
679impl Numeric {
680    /// Check if this numeric is a constant
681    #[must_use]
682    pub fn is_const(&self) -> bool {
683        self.0.expr.parse::<f64>().is_ok()
684    }
685
686    /// Distance between a point and an object
687    #[must_use]
688    pub fn distance<T: Object>(point: impl Into<Point>, object: T) -> Self {
689        Self(Expression {
690            expr: Rc::new(format!(
691                "Distance({}, {})",
692                point.into().0.expr,
693                object.into().expr
694            )),
695            style: Style::default(),
696        })
697    }
698
699    /// A complex number
700    #[must_use]
701    pub fn complex(real: impl Into<Numeric>, imaginary: impl Into<Numeric>) -> Self {
702        Self(Expression {
703            expr: Rc::new(format!(
704                "({}) + ({})i",
705                real.into().0.expr,
706                imaginary.into().0.expr
707            )),
708            style: Style::default(),
709        })
710    }
711
712    /// An angle defined by three points
713    #[must_use]
714    pub fn angle(a: impl Into<Point>, b: impl Into<Point>, c: impl Into<Point>) -> Self {
715        Self(Expression::expr(format!(
716            "Angle({}, {}, {})",
717            a.into().0.expr,
718            b.into().0.expr,
719            c.into().0.expr
720        )))
721    }
722
723    /// Angle between two lines
724    #[must_use]
725    pub fn angle_lines(k: impl Into<Line>, l: impl Into<Line>) -> Self {
726        Self(Expression::expr(format!(
727            "Angle({}, {})",
728            k.into().0.expr,
729            l.into().0.expr
730        )))
731    }
732
733    /// atan2 function
734    #[must_use]
735    pub fn atan2(y: impl Into<Numeric>, x: impl Into<Numeric>) -> Self {
736        Self(Expression::expr(format!(
737            "atan2({}, {})",
738            y.into().0.expr,
739            x.into().0.expr
740        )))
741    }
742
743    /// Raise this number to a power.
744    #[must_use]
745    pub fn pow(self, exponent: impl Into<Numeric>) -> Self {
746        Self(Expression::expr(format!(
747            "({})^({})",
748            self.0.expr,
749            exponent.into().0.expr
750        )))
751    }
752
753    /// Get the real part of this number
754    #[must_use]
755    pub fn real(self) -> Self {
756        Self(Expression::expr(format!("real({})", self.0.expr)))
757    }
758
759    /// Get the imaginary part of this number
760    #[must_use]
761    pub fn imaginary(self) -> Self {
762        Self(Expression::expr(format!("imaginary({})", self.0.expr)))
763    }
764
765    /// Natural logarithm (base e)
766    #[must_use]
767    pub fn ln(self) -> Self {
768        Self(Expression::expr(format!("ln({})", self.0.expr)))
769    }
770
771    /// Exponential function (e^this)
772    #[must_use]
773    pub fn exp(self) -> Self {
774        Self(Expression::expr(format!("exp({})", self.0.expr)))
775    }
776
777    /// Get the argument of a complex number.
778    #[must_use]
779    pub fn arg(self) -> Self {
780        Self(Expression::expr(format!("arg({})", self.0.expr)))
781    }
782
783    /// Convert this to a point
784    #[must_use]
785    pub fn point(self) -> Point {
786        Point(Expression::expr(format!("ToPoint({})", self.0.expr)))
787    }
788
789    /// Get the sine of this angle.
790    #[must_use]
791    pub fn sin(self) -> Numeric {
792        Numeric(Expression::expr(format!("sin({})", self.0.expr)))
793    }
794
795    /// Get the cosine of this angle.
796    #[must_use]
797    pub fn cos(self) -> Numeric {
798        Numeric(Expression::expr(format!("cos({})", self.0.expr)))
799    }
800
801    /// Get the arcsine of this angle.
802    #[must_use]
803    pub fn asin(self) -> Numeric {
804        Numeric(Expression::expr(format!("asin({})", self.0.expr)))
805    }
806
807    /// Get the arccosine of this angle.
808    #[must_use]
809    pub fn acos(self) -> Numeric {
810        Numeric(Expression::expr(format!("acos({})", self.0.expr)))
811    }
812
813    /// Get the arctan of this angle.
814    #[must_use]
815    pub fn atan(self) -> Numeric {
816        Numeric(Expression::expr(format!("atan({})", self.0.expr)))
817    }
818
819    /// Normalize the value (abs of 1)
820    #[must_use]
821    pub fn normalize(self) -> Numeric {
822        Numeric(Expression::expr(format!("UnitVector({})", self.0.expr)))
823    }
824}
825
826impl From<f64> for Numeric {
827    fn from(value: f64) -> Self {
828        Self(Expression::from(value))
829    }
830}
831
832impl From<&Var<Numeric>> for Numeric {
833    fn from(value: &Var<Numeric>) -> Self {
834        Self(Expression::from(value))
835    }
836}
837
838impl From<Numeric> for Expression {
839    fn from(value: Numeric) -> Self {
840        value.0
841    }
842}
843
844impl Expr for Numeric {
845    type Target = Self;
846
847    fn get_type() -> ElementType {
848        ElementType::Numeric
849    }
850
851    fn var(expr: String) -> Var<Self::Target> {
852        Var::new(expr)
853    }
854}
855
856impl<T: Into<Numeric>> Add<T> for Numeric {
857    type Output = Self;
858
859    fn add(mut self, rhs: T) -> Self::Output {
860        self += rhs;
861        self
862    }
863}
864
865impl<T: Into<Numeric>> AddAssign<T> for Numeric {
866    fn add_assign(&mut self, rhs: T) {
867        let expr = Expression {
868            expr: Rc::new(format!("({}) + ({})", self.0.expr, rhs.into().0.expr)),
869            style: Style::default(),
870        };
871        self.0 = expr;
872    }
873}
874
875impl<T: Into<Numeric>> Sub<T> for Numeric {
876    type Output = Self;
877
878    fn sub(mut self, rhs: T) -> Self::Output {
879        self -= rhs;
880        self
881    }
882}
883
884impl<T: Into<Numeric>> SubAssign<T> for Numeric {
885    fn sub_assign(&mut self, rhs: T) {
886        let expr = Expression {
887            expr: Rc::new(format!("({}) - ({})", self.0.expr, rhs.into().0.expr)),
888            style: Style::default(),
889        };
890        self.0 = expr;
891    }
892}
893
894impl<T: Into<Numeric>> Mul<T> for Numeric {
895    type Output = Self;
896
897    fn mul(mut self, rhs: T) -> Self::Output {
898        self *= rhs;
899        self
900    }
901}
902
903impl<T: Into<Numeric>> MulAssign<T> for Numeric {
904    fn mul_assign(&mut self, rhs: T) {
905        let expr = Expression {
906            expr: Rc::new(format!("({}) * ({})", self.0.expr, rhs.into().0.expr)),
907            style: Style::default(),
908        };
909        self.0 = expr;
910    }
911}
912
913impl<T: Into<Numeric>> Div<T> for Numeric {
914    type Output = Self;
915
916    fn div(mut self, rhs: T) -> Self::Output {
917        self /= rhs;
918        self
919    }
920}
921
922impl<T: Into<Numeric>> DivAssign<T> for Numeric {
923    fn div_assign(&mut self, rhs: T) {
924        let expr = Expression {
925            expr: Rc::new(format!("({}) / ({})", self.0.expr, rhs.into().0.expr)),
926            style: Style::default(),
927        };
928        self.0 = expr;
929    }
930}
931
932impl Neg for Numeric {
933    type Output = Self;
934
935    fn neg(self) -> Self::Output {
936        Self(Expression {
937            expr: Rc::new(format!("-({})", self.0.expr)),
938            style: Style::default(),
939        })
940    }
941}
942
943impl<T: Into<Numeric>> Rem<T> for Numeric {
944    type Output = Numeric;
945
946    fn rem(mut self, rhs: T) -> Self::Output {
947        self %= rhs;
948        self
949    }
950}
951
952impl<T: Into<Numeric>> RemAssign<T> for Numeric {
953    fn rem_assign(&mut self, rhs: T) {
954        let expr = Expression::expr(format!("Mod({}, {})", self.0.expr, rhs.into().0.expr));
955        self.0 = expr;
956    }
957}
958
959impl From<&Self> for Numeric {
960    fn from(value: &Self) -> Self {
961        Self(value.0.clone())
962    }
963}
964
965impl<T: Copy + Into<Numeric>> From<&T> for Numeric {
966    fn from(value: &T) -> Self {
967        (*value).into()
968    }
969}
970
971impl<T> PartialEq<T> for Numeric
972where
973    Numeric: for<'a> From<&'a T>,
974{
975    fn eq(&self, other: &T) -> bool {
976        let other = Self::from(other);
977        if self.0.expr == other.0.expr {
978            return true;
979        }
980
981        if let Ok(v) = self.0.expr.parse::<f64>() {
982            if let Ok(u) = other.0.expr.parse::<f64>() {
983                return v.partial_cmp(&u).is_some_and(|v| v.is_eq());
984            }
985        }
986
987        false
988    }
989}
990
991impl Zero for Numeric {
992    fn zero() -> Self {
993        Self(Expression::expr("0"))
994    }
995
996    /// WARNING: This is not necessarily always precise
997    fn is_zero(&self) -> bool {
998        self.0.expr.as_str() == "0" || self.0.expr.as_str() == "0.0"
999    }
1000}
1001
1002impl One for Numeric {
1003    fn one() -> Self {
1004        Self(Expression::expr("1"))
1005    }
1006
1007    /// WARNING: This is not necessarily always precise
1008    fn is_one(&self) -> bool {
1009        self.0.expr.as_str() == "1" || self.0.expr.as_str() == "1.0"
1010    }
1011}
1012
1013impl Bounded for Numeric {
1014    fn min_value() -> Self {
1015        Self::zero()
1016    }
1017
1018    fn max_value() -> Self {
1019        Self(Expression::expr(format!("{} + {}i", f64::MAX, f64::MAX)))
1020    }
1021}
1022
1023impl Num for Numeric {
1024    type FromStrRadixErr = &'static str;
1025
1026    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
1027        if radix != 10 {
1028            return Err("Only radix of 10 is supported.");
1029        }
1030
1031        Ok(Self(Expression::expr(str)))
1032    }
1033}
1034
1035/// Trait for accessing numeric functions
1036pub trait NumericAccess: Sized
1037where
1038    Numeric: From<Self>,
1039{
1040    /// Raise the number to a power
1041    #[must_use]
1042    fn pow(self, exponent: impl Into<Numeric>) -> Numeric {
1043        Numeric::from(self).pow(exponent)
1044    }
1045
1046    /// Get the real part of this number
1047    #[must_use]
1048    fn real(self) -> Numeric {
1049        Numeric::from(self).real()
1050    }
1051
1052    /// Get the imaginary part of this number
1053    #[must_use]
1054    fn imaginary(self) -> Numeric {
1055        Numeric::from(self).imaginary()
1056    }
1057
1058    /// Get this complex number's argument
1059    #[must_use]
1060    fn arg(self) -> Numeric {
1061        Numeric::from(self).arg()
1062    }
1063
1064    /// Convert this number to a point
1065    #[must_use]
1066    fn point(self) -> Point {
1067        Numeric::from(self).point()
1068    }
1069
1070    /// Natural logarithm (base e)
1071    #[must_use]
1072    fn ln(self) -> Numeric {
1073        Numeric::from(self).ln()
1074    }
1075
1076    /// Exponential function (e^this)
1077    #[must_use]
1078    fn exp(self) -> Numeric {
1079        Numeric::from(self).exp()
1080    }
1081
1082    /// Get the sine of this angle.
1083    #[must_use]
1084    fn sin(self) -> Numeric {
1085        Numeric::from(self).sin()
1086    }
1087
1088    /// Get the cosine of this angle.
1089    #[must_use]
1090    fn cos(self) -> Numeric {
1091        Numeric::from(self).cos()
1092    }
1093
1094    /// Get the arcsine of this angle.
1095    #[must_use]
1096    fn asin(self) -> Numeric {
1097        Numeric::from(self).asin()
1098    }
1099
1100    /// Get the arccosine of this angle.
1101    #[must_use]
1102    fn acos(self) -> Numeric {
1103        Numeric::from(self).acos()
1104    }
1105
1106    /// Get the arctan of this angle.
1107    #[must_use]
1108    fn atan(self) -> Numeric {
1109        Numeric::from(self).atan()
1110    }
1111
1112    /// Normalize this value (abs of 1)
1113    #[must_use]
1114    fn normalize(self) -> Numeric {
1115        Numeric::from(self).normalize()
1116    }
1117}
1118
1119impl<T> NumericAccess for T where Numeric: From<Self> {}
1120
1121/// A circle in the construction
1122#[derive(Clone)]
1123pub struct Conic(Expression);
1124
1125impl Conic {
1126    /// Set the line's color
1127    pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
1128        self.0.style.color = Some(ObjColorType { r, g, b });
1129    }
1130
1131    /// Set the line's style
1132    pub fn set_style(&mut self, style: LineStyle) {
1133        self.0.style.line_style = Some(style);
1134    }
1135
1136    /// Wether to display this line's label
1137    pub fn set_display_label(&mut self, v: bool) {
1138        self.0.style.display_label = v;
1139    }
1140
1141    /// Default style for a conic
1142    #[must_use]
1143    fn style() -> Style {
1144        Style {
1145            display_label: false,
1146            line_style: None,
1147            color: None,
1148        }
1149    }
1150
1151    /// Create a new circle with a center and a radius
1152    #[must_use]
1153    pub fn circle(center: impl Into<Point>, radius: impl Into<Numeric>) -> Self {
1154        Self(Expression {
1155            expr: Rc::new(format!(
1156                "Circle({}, abs({}))",
1157                center.into().0.expr,
1158                radius.into().0.expr
1159            )),
1160            style: Self::style(),
1161        })
1162    }
1163
1164    /// Get the center of this conic
1165    #[must_use]
1166    pub fn center(self) -> Point {
1167        Point(Expression {
1168            expr: Rc::new(format!("Center({})", self.0.expr)),
1169            style: Point::bound(),
1170        })
1171    }
1172}
1173
1174impl Object for Conic {}
1175
1176impl From<Var<Conic>> for Conic {
1177    fn from(value: Var<Conic>) -> Self {
1178        Self(value.into())
1179    }
1180}
1181
1182impl From<&Var<Conic>> for Conic {
1183    fn from(value: &Var<Conic>) -> Self {
1184        Self(value.into())
1185    }
1186}
1187
1188impl From<Conic> for Expression {
1189    fn from(value: Conic) -> Self {
1190        value.0
1191    }
1192}
1193
1194impl Expr for Conic {
1195    type Target = Self;
1196
1197    fn get_type() -> ElementType {
1198        ElementType::Conic
1199    }
1200
1201    fn var(expr: String) -> Var<Self::Target> {
1202        Var::new(expr)
1203    }
1204}
1205
1206/// Access for conic functions
1207pub trait ConicAccess: Sized
1208where
1209    Conic: From<Self>,
1210{
1211    /// Get the conic's center
1212    #[must_use]
1213    fn center(self) -> Point {
1214        Conic::from(self).center()
1215    }
1216}
1217
1218impl<T> ConicAccess for T where Conic: From<T> {}
1219
1220/// A ray (half-line)
1221#[derive(Clone)]
1222pub struct Ray(Expression);
1223
1224impl Ray {
1225    /// Set the line's color
1226    pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
1227        self.0.style.color = Some(ObjColorType { r, g, b });
1228    }
1229
1230    /// Set the line's style
1231    pub fn set_style(&mut self, style: LineStyle) {
1232        self.0.style.line_style = Some(style);
1233    }
1234
1235    /// Wether to display this line's label
1236    pub fn set_display_label(&mut self, v: bool) {
1237        self.0.style.display_label = v;
1238    }
1239
1240    /// Create a ray with an origin, going through a point
1241    #[must_use]
1242    pub fn new(origin: impl Into<Point>, through: impl Into<Point>) -> Self {
1243        Self(Expression::expr(format!(
1244            "Ray({}, {})",
1245            origin.into().0.expr,
1246            through.into().0.expr
1247        )))
1248    }
1249}
1250
1251impl Object for Ray {}
1252
1253impl From<Var<Ray>> for Ray {
1254    fn from(value: Var<Ray>) -> Self {
1255        Self(value.into())
1256    }
1257}
1258
1259impl From<&Var<Ray>> for Ray {
1260    fn from(value: &Var<Ray>) -> Self {
1261        Self(value.into())
1262    }
1263}
1264
1265impl From<Ray> for Expression {
1266    fn from(value: Ray) -> Self {
1267        value.0
1268    }
1269}
1270
1271impl Expr for Ray {
1272    type Target = Self;
1273
1274    fn get_type() -> ElementType {
1275        ElementType::Ray
1276    }
1277
1278    fn var(expr: String) -> Var<Self::Target> {
1279        Var::new(expr)
1280    }
1281}
1282
1283impl Addable for Ray {}
1284
1285/// A segment
1286#[derive(Clone)]
1287pub struct Segment(Expression);
1288
1289impl Segment {
1290    /// Set the line's color
1291    pub fn set_color(&mut self, r: u8, g: u8, b: u8) {
1292        self.0.style.color = Some(ObjColorType { r, g, b });
1293    }
1294
1295    /// Set the line's style
1296    pub fn set_style(&mut self, style: LineStyle) {
1297        self.0.style.line_style = Some(style);
1298    }
1299
1300    /// Wether to display this line's label
1301    pub fn set_display_label(&mut self, v: bool) {
1302        self.0.style.display_label = v;
1303    }
1304
1305    /// Create a segment connecting two points
1306    #[must_use]
1307    pub fn new(a: impl Into<Point>, b: impl Into<Point>) -> Self {
1308        Self(Expression::expr(format!(
1309            "Segment({}, {})",
1310            a.into().0.expr,
1311            b.into().0.expr
1312        )))
1313    }
1314}
1315
1316impl Object for Segment {}
1317
1318impl From<Var<Segment>> for Segment {
1319    fn from(value: Var<Segment>) -> Self {
1320        Self(value.into())
1321    }
1322}
1323
1324impl From<&Var<Segment>> for Segment {
1325    fn from(value: &Var<Segment>) -> Self {
1326        Self(value.into())
1327    }
1328}
1329
1330impl From<Segment> for Expression {
1331    fn from(value: Segment) -> Self {
1332        value.0
1333    }
1334}
1335
1336impl Expr for Segment {
1337    type Target = Self;
1338
1339    fn get_type() -> ElementType {
1340        ElementType::Segment
1341    }
1342
1343    fn var(expr: String) -> Var<Self::Target> {
1344        Var::new(expr)
1345    }
1346}
1347
1348/// Marks this as addable
1349pub trait Addable {}
1350
1351impl Addable for Point {}
1352
1353impl Addable for Line {}
1354
1355impl Addable for Conic {}
1356
1357impl Addable for Segment {}
1358
1359impl Geogebra {
1360    /// Create an object defined by an expression.
1361    pub fn add<T: Expr>(&mut self, expr: T, caption: impl ToString) -> Var<T::Target>
1362    where
1363        T::Target: Addable,
1364    {
1365        let label = self.next_label();
1366        let expr = expr.into();
1367
1368        self.data
1369            .construction
1370            .items
1371            .push(ConstructionItem::Expression(raw::Expression {
1372                type_: T::get_type(),
1373                label: label.clone(),
1374                exp: expr.expr.as_ref().clone(),
1375            }));
1376
1377        self.data
1378            .construction
1379            .items
1380            .push(ConstructionItem::Element(Element {
1381                type_: T::get_type(),
1382                label: label.clone(),
1383                caption: Some(caption.to_string().into()),
1384                ..expr.style.to_element()
1385            }));
1386
1387        T::var(label)
1388    }
1389
1390    /// Add a point with a position hint.
1391    pub fn add_point(
1392        &mut self,
1393        point: impl Into<Point>,
1394        caption: impl ToString,
1395        (x, y): (f64, f64),
1396    ) -> Var<Point> {
1397        let label = self.next_label();
1398        let point = point.into();
1399
1400        self.data
1401            .construction
1402            .items
1403            .push(ConstructionItem::Expression(raw::Expression {
1404                type_: ElementType::Point,
1405                label: label.clone(),
1406                exp: point.0.expr.as_ref().clone(),
1407            }));
1408
1409        self.data
1410            .construction
1411            .items
1412            .push(ConstructionItem::Element(Element {
1413                type_: ElementType::Point,
1414                label: label.clone(),
1415                caption: Some(caption.to_string().into()),
1416                coords: Some(Coords::xy(x, y)),
1417                ..point.0.style.to_element()
1418            }));
1419
1420        Point::var(label)
1421    }
1422
1423    /// Make an expression into a variable without making it an element.
1424    pub fn var<T: Expr>(&mut self, expr: T) -> Var<T::Target> {
1425        let label = self.next_label();
1426        let expr = expr.into();
1427
1428        self.data
1429            .construction
1430            .items
1431            .push(ConstructionItem::Expression(raw::Expression {
1432                type_: T::get_type(),
1433                label: label.clone(),
1434                exp: expr.expr.as_ref().clone(),
1435            }));
1436
1437        self.data
1438            .construction
1439            .items
1440            .push(ConstructionItem::Element(Element {
1441                type_: T::get_type(),
1442                label: label.clone(),
1443                caption: None,
1444                show: Show::none(),
1445                ..expr.style.to_element()
1446            }));
1447
1448        T::var(label)
1449    }
1450}
1451
1452impl Default for Geogebra {
1453    fn default() -> Self {
1454        Self::new()
1455    }
1456}