index/objects/geometry/
triangle.rs

1use wasm_bindgen::prelude::*;
2
3use crate::{objects::vector_object::VectorObjectBuilder, utils::point2d::Point2D};
4
5/// A Triangle is a polygon with three edges and three vertices.
6#[wasm_bindgen]
7#[derive(Clone, Debug, PartialEq)]
8pub struct Triangle {
9    /// The first vertex of the triangle as Point2D.
10    a: Point2D,
11    /// The second vertex of the triangle as Point2D.
12    b: Point2D,
13    /// The third vertex of the triangle as Point2D.
14    c: Point2D,
15}
16
17#[wasm_bindgen]
18impl Triangle {
19    /// Creates a new Triangle object from three points.
20    #[wasm_bindgen(constructor, return_description = "A triangle with the given vertices.")]
21    pub fn new(
22        #[wasm_bindgen(param_description = "The first vertex of the triangle as Point2D.")]
23        a: Point2D,
24        #[wasm_bindgen(param_description = "The second vertex of the triangle as Point2D.")]
25        b: Point2D,
26        #[wasm_bindgen(param_description = "The third vertex of the triangle as Point2D.")]
27        c: Point2D,
28    ) -> Triangle {
29        Triangle { a, b, c }
30    }
31
32    /// Returns the area of the triangle.
33    #[wasm_bindgen(getter, return_description = "The area of the triangle.")]
34    pub fn area(&self) -> f32 {
35        0.5 * ((self.b.x - self.a.x) * (self.c.y - self.a.y) - (self.c.x - self.a.x) * (self.b.y - self.a.y)).abs()
36    }
37
38    /// Returns the perimeter of the triangle.
39    #[wasm_bindgen(getter, return_description = "The perimeter of the triangle.")]
40    pub fn perimeter(&self) -> f32 {
41        self.a.distance(&self.b) + self.b.distance(&self.c) + self.c.distance(&self.a)
42    }
43
44    /// Creates a VectorObjectBuilder with the triangle's points.
45    #[wasm_bindgen(return_description = "A VectorObjectBuilder with the triangle's points.")]
46    pub fn vector_object_builder(&self) -> VectorObjectBuilder {
47        VectorObjectBuilder::default().move_point(&self.a).line_to(&self.b).line_to(&self.c).close()
48    }
49
50    /// Returns the first vertex of the triangle as Point2D.
51    #[wasm_bindgen(getter, return_description = "The first vertex of the triangle.")]
52    pub fn a(&self) -> Point2D {
53        self.a
54    }
55
56    /// Returns the second vertex of the triangle as Point2D.
57    #[wasm_bindgen(getter, return_description = "The second vertex of the triangle.")]
58    pub fn b(&self) -> Point2D {
59        self.b
60    }
61
62    /// Returns the third vertex of the triangle as Point2D.
63    #[wasm_bindgen(getter, return_description = "The third vertex of the triangle.")]
64    pub fn c(&self) -> Point2D {
65        self.c
66    }
67}
68
69/// An EquilateralTriangle is a triangle in which all three sides are equal in length.
70#[wasm_bindgen]
71#[derive(Clone, Debug, PartialEq)]
72pub struct EquilateralTriangle {
73    /// The center Point2D of the equilateral triangle.
74    center: Point2D,
75    /// The side length of the equilateral triangle.
76    side_length: f32,
77    /// The rotation of the equilateral triangle, if any.
78    rotation: Option<f32>,
79}
80
81#[wasm_bindgen]
82impl EquilateralTriangle {
83    /// Creates a new EquilateralTriangle from a center point and side length.
84    #[wasm_bindgen(constructor, return_description = "An equilateral triangle.")]
85    pub fn new(
86        #[wasm_bindgen(param_description = "The center Point2D of the equilateral triangle.")]
87        center: Point2D,
88        #[wasm_bindgen(param_description = "The side length of the equilateral triangle.")]
89        side_length: f32,
90        #[wasm_bindgen(param_description = "The rotation of the equilateral triangle, if any.")]
91        rotation: Option<f32>,
92    ) -> EquilateralTriangle {
93        EquilateralTriangle { center, side_length, rotation }
94    }
95
96    /// Creates a Triangle from the equilateral triangle.
97    #[wasm_bindgen(getter, return_description = "A triangle with the equilateral triangle's vertices.")]
98    pub fn triangle(&self) -> Triangle {
99        let mut a = Point2D::new(self.center.x - self.side_length / 2.0, self.center.y - self.side_length / 2.0 / 3.0f32.sqrt());
100        let mut b = Point2D::new(self.center.x, self.center.y + 2.0 / 3.0f32.sqrt() * self.side_length / 2.0);
101        let mut c = Point2D::new(self.center.x + self.side_length / 2.0, self.center.y - self.side_length / 2.0 / 3.0f32.sqrt());
102        if let Some(rotation) = self.rotation {
103            a = a.rotate_around(self.center, rotation);
104            b = b.rotate_around(self.center, rotation);
105            c = c.rotate_around(self.center, rotation);
106        }
107        Triangle::new(a, b, c)
108    }
109
110    /// Creates a VectorObjectBuilder from the equilateral triangle.
111    #[wasm_bindgen(getter, return_description = "A vector object builder with the equilateral triangle's points.")]
112    pub fn vector_object_builder(&self) -> VectorObjectBuilder {
113        self.triangle().vector_object_builder()
114    }
115
116    /// Returns the center Point2D of the equilateral triangle.
117    #[wasm_bindgen(getter, return_description = "The center point of the equilateral triangle.")]
118    pub fn center(&self) -> Point2D {
119        self.center
120    }
121
122    /// Returns the side length of the equilateral triangle.
123    #[wasm_bindgen(getter, return_description = "The side length of the equilateral triangle.")]
124    pub fn side_length(&self) -> f32 {
125        self.side_length
126    }
127
128    /// Returns the area of the equilateral triangle.
129    #[wasm_bindgen(getter, return_description = "The area of the equilateral triangle.")]
130    pub fn area(&self) -> f32 {
131        0.25 * 3.0f32.sqrt() * self.side_length * self.side_length
132    }
133
134    /// Returns the perimeter of the equilateral triangle.
135    #[wasm_bindgen(getter, return_description = "The perimeter of the equilateral triangle.")]
136    pub fn perimeter(&self) -> f32 {
137        3.0 * self.side_length
138    }
139
140    /// Returns the height of the equilateral triangle.
141    #[wasm_bindgen(getter, return_description = "The height of the equilateral triangle.")]
142    pub fn height(&self) -> f32 {
143        3.0f32.sqrt() / 2.0 * self.side_length
144    }
145}
146
147/// A RightTriangle is a triangle in which one angle is a right angle.
148#[wasm_bindgen]
149#[derive(Clone, Debug, PartialEq)]
150pub struct RightTriangle {
151    /// The center Point2D of the right triangle.
152    center: Point2D,
153    /// The base length of the right triangle.
154    base_length: f32,
155    /// The height of the right triangle.
156    height: f32,
157    /// The rotation of the right triangle, if any.
158    rotation: Option<f32>,
159    /// Whether the right triangle must be flipped, by default false.
160    flip: Option<bool>,
161}
162
163#[wasm_bindgen]
164impl RightTriangle {
165    /// Creates a new RightTriangle from a center point, base length, height, rotation, and flip.
166    #[wasm_bindgen(constructor, return_description = "A right triangle.")]
167    pub fn new(
168        #[wasm_bindgen(param_description = "The center Point2D of the right triangle.")]
169        center: Point2D,
170        #[wasm_bindgen(param_description = "The base length of the right triangle.")]
171        base_length: f32,
172        #[wasm_bindgen(param_description = "The height of the right triangle.")]
173        height: f32,
174        #[wasm_bindgen(param_description = "The rotation of the right triangle, if any.")]
175        rotation: Option<f32>,
176        #[wasm_bindgen(param_description = "The flip of the right triangle, by default false.")]
177        flip: Option<bool>,
178    ) -> RightTriangle {
179        RightTriangle { center, base_length, height, rotation, flip }
180    }
181
182    /// Creates a Triangle from the right triangle.
183    #[wasm_bindgen(getter, return_description = "A triangle.")]
184    pub fn triangle(&self) -> Triangle {
185        let mut a = Point2D::new(self.center.x - self.base_length / 2.0, self.center.y + self.height / 2.0);
186        let mut b = Point2D::new(self.center.x + self.base_length / 2.0, self.center.y + self.height / 2.0);
187        let mut c = if self.flip.unwrap_or(false) {
188            Point2D::new(self.center.x - self.base_length / 2.0, self.center.y - self.height / 2.0)
189        } else {
190            Point2D::new(self.center.x + self.base_length / 2.0, self.center.y - self.height / 2.0)
191        };
192        if let Some(rotation) = self.rotation {
193            a = a.rotate_around(self.center, rotation);
194            b = b.rotate_around(self.center, rotation);
195            c = c.rotate_around(self.center, rotation);
196        }
197        Triangle::new(a, b, c)
198    }
199
200    /// Creates a VectorObjectBuilder from the right triangle.
201    #[wasm_bindgen(getter, return_description = "A vector object builder with the right triangle's points.")]
202    pub fn vector_object_builder(&self) -> VectorObjectBuilder {
203        self.triangle().vector_object_builder()
204    }
205
206    /// Returns the center Point2D of the right triangle.
207    #[wasm_bindgen(getter, return_description = "The center point of the right triangle.")]
208    pub fn center(&self) -> Point2D {
209        self.center
210    }
211
212    /// Returns the base length of the right triangle.
213    #[wasm_bindgen(getter, return_description = "The base length of the right triangle.")]
214    pub fn base_length(&self) -> f32 {
215        self.base_length
216    }
217
218    /// Returns the height of the right triangle.
219    #[wasm_bindgen(getter, return_description = "The height of the right triangle.")]
220    pub fn height(&self) -> f32 {
221        self.height
222    }
223
224    /// Returns the area of the right triangle.
225    #[wasm_bindgen(getter, return_description = "The area of the right triangle.")]
226    pub fn area(&self) -> f32 {
227        0.5 * self.base_length * self.height
228    }
229
230    /// Returns the perimeter of the RightTriangle.
231    #[wasm_bindgen(getter, return_description = "The perimeter of the right triangle.")]
232    pub fn perimeter(&self) -> f32 {
233        self.base_length + self.height + (self.base_length.powi(2) + self.height.powi(2)).sqrt()
234    }
235
236    /// Returns the hypotenuse of the RightTriangle.
237    #[wasm_bindgen(getter, return_description = "The hypotenuse of the right triangle.")]
238    pub fn hypotenuse(&self) -> f32 {
239        (self.base_length.powi(2) + self.height.powi(2)).sqrt()
240    }
241}