pix_engine/shape/
triangle.rs

1//! A shape type representing triangles used for drawing.
2//!
3//! # Examples
4//!
5//! You can create a [Triangle][Tri] using [`Tri::new`]:
6//!
7//! ```
8//! use pix_engine::prelude::*;
9//!
10//! // 2D
11//! let tri = Tri::new([10, 20], [30, 10], [20, 25]);
12//!
13//! let p1 = point!(10, 20);
14//! let p2 = point!(30, 10);
15//! let p3 = point!(20, 25);
16//! let tri = Tri::new(p1, p2, p3);
17//! ```
18
19use crate::{error::Result, prelude::*};
20#[cfg(feature = "serde")]
21use serde::{de::DeserializeOwned, Deserialize, Serialize};
22
23/// A `Triangle` with three [Point]s.
24///
25/// Please see the [module-level documentation] for examples.
26///
27/// [module-level documentation]: crate::shape::triangle
28#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
29#[repr(transparent)]
30#[must_use]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + DeserializeOwned"))]
33pub struct Tri<T = i32, const N: usize = 2>(pub(crate) [Point<T, N>; 3]);
34
35/// Constructs a [Triangle][Tri] with three points.
36///
37/// ```
38/// # use pix_engine::prelude::*;
39///
40/// let t = tri!([10, 20], [30, 10], [20, 25]);
41/// assert_eq!(t.points(), [
42///   point!(10, 20),
43///   point!(30, 10),
44///   point!(20, 25),
45/// ]);
46///
47/// let t = tri!([10, 20, 10], [30, 10, 40], [20, 25, 20]);
48/// assert_eq!(t.points(), [
49///   point!(10, 20, 10),
50///   point!(30, 10, 40),
51///   point!(20, 25, 20),
52/// ]);
53/// ```
54#[macro_export]
55macro_rules! tri {
56    ($p1:expr, $p2:expr, $p3:expr$(,)?) => {
57        $crate::prelude::Tri::new($p1, $p2, $p3)
58    };
59    ($x1:expr, $y1:expr, $x2:expr, $y2:expr, $x3:expr, $y3:expr$(,)?) => {
60        $crate::prelude::Tri::from_xy($x1, $y1, $x2, $y2, $x3, $y3)
61    };
62    ($x1:expr, $y1:expr, $z1:expr, $x2:expr, $y2:expr, $z2:expr, $x3:expr, $y3:expr, $z3:expr$(,)?) => {
63        $crate::prelude::Tri::from_xyz($x1, $y1, $z2, $x2, $y2, $z2, $x3, $y3, $z3)
64    };
65}
66
67impl<T, const N: usize> Tri<T, N> {
68    /// Constructs a `Triangle` with the given [Point]s.
69    ///
70    /// # Example
71    ///
72    /// ```
73    /// # use pix_engine::prelude::*;
74    /// let tri = Tri::new([10, 20], [30, 10], [20, 25]);
75    /// assert_eq!(tri.p1().coords(), [10, 20]);
76    /// assert_eq!(tri.p2().coords(), [30, 10]);
77    /// assert_eq!(tri.p3().coords(), [20, 25]);
78    /// ```
79    pub fn new<P1, P2, P3>(p1: P1, p2: P2, p3: P3) -> Self
80    where
81        P1: Into<Point<T, N>>,
82        P2: Into<Point<T, N>>,
83        P3: Into<Point<T, N>>,
84    {
85        Self([p1.into(), p2.into(), p3.into()])
86    }
87}
88
89impl<T> Tri<T> {
90    /// Constructs a `Triangle` from individual x/y coordinates.
91    #[inline]
92    pub const fn from_xy(x1: T, y1: T, x2: T, y2: T, x3: T, y3: T) -> Self {
93        Self([point!(x1, y1), point!(x2, y2), point!(x3, y3)])
94    }
95}
96
97impl<T: Copy> Tri<T> {
98    /// Returns `Triangle` coordinates as `[x1, y1, x2, y2, x3, y3]`.
99    ///
100    /// # Example
101    ///
102    /// ```
103    /// # use pix_engine::prelude::*;
104    /// let tri = Tri::new([10, 20], [30, 10], [20, 25]);
105    /// assert_eq!(tri.coords(), [10, 20, 30, 10, 20, 25]);
106    /// ```
107    #[inline]
108    pub fn coords(&self) -> [T; 6] {
109        let [p1, p2, p3] = self.points();
110        let [x1, y1] = p1.coords();
111        let [x2, y2] = p2.coords();
112        let [x3, y3] = p3.coords();
113        [x1, y1, x2, y2, x3, y3]
114    }
115}
116
117impl<T> Tri<T, 3> {
118    /// Constructs a `Triangle` from individual x/y/z coordinates.
119    #[allow(clippy::too_many_arguments)]
120    #[inline]
121    pub const fn from_xyz(x1: T, y1: T, z1: T, x2: T, y2: T, z2: T, x3: T, y3: T, z3: T) -> Self {
122        Self([point!(x1, y1, z1), point!(x2, y2, z2), point!(x3, y3, z3)])
123    }
124}
125
126impl<T: Copy> Tri<T, 3> {
127    /// Returns `Triangle` coordinates as `[x1, y1, z1, x2, y2, z2, x3, y3, z3]`.
128    ///
129    /// # Example
130    ///
131    /// ```
132    /// # use pix_engine::prelude::*;
133    /// let tri = Tri::new([10, 20, 5], [30, 10, 5], [20, 25, 5]);
134    /// assert_eq!(tri.coords(), [10, 20, 5, 30, 10, 5, 20, 25, 5]);
135    /// ```
136    #[inline]
137    pub fn coords(&self) -> [T; 9] {
138        let [p1, p2, p3] = self.points();
139        let [x1, y1, z1] = p1.coords();
140        let [x2, y2, z2] = p2.coords();
141        let [x3, y3, z3] = p3.coords();
142        [x1, y1, z1, x2, y2, z2, x3, y3, z3]
143    }
144}
145
146impl<T: Copy, const N: usize> Tri<T, N> {
147    /// Returns the first point of the triangle.
148    #[inline]
149    pub fn p1(&self) -> Point<T, N> {
150        self.0[0]
151    }
152
153    /// Sets the first point of the triangle.
154    #[inline]
155    pub fn set_p1<P>(&mut self, p: P)
156    where
157        P: Into<Point<T, N>>,
158    {
159        self.0[0] = p.into();
160    }
161
162    /// Returns the second point of the triangle.
163    #[inline]
164    pub fn p2(&self) -> Point<T, N> {
165        self.0[1]
166    }
167
168    /// Sets the second point of the triangle.
169    #[inline]
170    pub fn set_p2<P>(&mut self, p: P)
171    where
172        P: Into<Point<T, N>>,
173    {
174        self.0[1] = p.into();
175    }
176
177    /// Returns the third point of the triangle.
178    #[inline]
179    pub fn p3(&self) -> Point<T, N> {
180        self.0[2]
181    }
182
183    /// Sets the third point of the triangle.
184    #[inline]
185    pub fn set_p3<P>(&mut self, p: P)
186    where
187        P: Into<Point<T, N>>,
188    {
189        self.0[2] = p.into();
190    }
191
192    /// Returns `Triangle` points as `[Point<T, N>; 3]`.
193    ///
194    /// # Example
195    ///
196    /// ```
197    /// # use pix_engine::prelude::*;
198    /// let tri = Tri::new([10, 20], [30, 10], [20, 25]);
199    /// assert_eq!(tri.points(), [
200    ///     point!(10, 20),
201    ///     point!(30, 10),
202    ///     point!(20, 25),
203    /// ]);
204    /// ```
205    #[inline]
206    pub fn points(&self) -> [Point<T, N>; 3] {
207        self.0
208    }
209
210    /// Returns `Triangle` points as a mutable slice `&mut [Point<T, N>; 3]`.
211    ///
212    /// # Example
213    ///
214    /// ```
215    /// # use pix_engine::prelude::*;
216    /// let mut tri = Tri::new([10, 20], [30, 10], [20, 25]);
217    /// for p in tri.points_mut() {
218    ///     *p += 5;
219    /// }
220    /// assert_eq!(tri.points(), [
221    ///     point!(15, 25),
222    ///     point!(35, 15),
223    ///     point!(25, 30),
224    /// ]);
225    /// ```
226    #[inline]
227    pub fn points_mut(&mut self) -> &mut [Point<T, N>; 3] {
228        &mut self.0
229    }
230
231    /// Returns `Triangle` as a [Vec].
232    ///
233    /// # Example
234    ///
235    /// ```
236    /// # use pix_engine::prelude::*;
237    /// let tri = Tri::new([10, 20], [30, 10], [20, 25]);
238    /// assert_eq!(
239    ///   tri.to_vec(),
240    ///   vec![
241    ///     point!(10, 20),
242    ///     point!(30, 10),
243    ///     point!(20, 25),
244    ///   ]
245    /// );
246    /// ```
247    pub fn to_vec(self) -> Vec<Point<T, N>> {
248        self.0.to_vec()
249    }
250}
251
252impl<T: Num> Contains<Point<T>> for Tri<T> {
253    /// Returns whether this rectangle contains a given [Point].
254    fn contains(&self, p: Point<T>) -> bool {
255        let [p1, p2, p3] = self.points();
256        let b1 = ((p.x() - p2.x()) * (p1.y() - p2.y()) - (p.y() - p2.y()) * (p1.x() - p2.x()))
257            < T::zero();
258        let b2 = ((p.x() - p3.x()) * (p2.y() - p3.y()) - (p.y() - p3.y()) * (p2.x() - p3.x()))
259            < T::zero();
260        let b3 = ((p.x() - p1.x()) * (p3.y() - p1.y()) - (p.y() - p1.y()) * (p3.x() - p1.x()))
261            < T::zero();
262        (b1 == b2) && (b2 == b3)
263    }
264}
265
266impl Draw for Tri<i32> {
267    /// Draw `Triangle` to the current [`PixState`] canvas.
268    fn draw(&self, s: &mut PixState) -> Result<()> {
269        s.triangle(*self)
270    }
271}
272
273impl<T: Copy> From<[T; 6]> for Tri<T> {
274    /// Converts `[T; 6]` into `Tri<T>`.
275    #[inline]
276    fn from([x1, y1, x2, y2, x3, y3]: [T; 6]) -> Self {
277        Self::from_xy(x1, y1, x2, y2, x3, y3)
278    }
279}
280
281impl<T: Copy> From<[T; 9]> for Tri<T, 3> {
282    /// Converts `[T; 9]` into `Tri<T, 3>`.
283    #[inline]
284    fn from([x1, y1, z1, x2, y2, z2, x3, y3, z3]: [T; 9]) -> Self {
285        Self::from_xyz(x1, y1, z1, x2, y2, z2, x3, y3, z3)
286    }
287}
288
289impl<T: Copy> From<[[T; 2]; 3]> for Tri<T> {
290    /// Converts `[[T; 2]; 3]` into `Tri<T>`.
291    #[inline]
292    fn from([[x1, y1], [x2, y2], [x3, y3]]: [[T; 2]; 3]) -> Self {
293        Self::from_xy(x1, y1, x2, y2, x3, y3)
294    }
295}
296
297impl<T: Copy> From<[[T; 3]; 3]> for Tri<T, 3> {
298    /// Converts `[[T; 3]; 3]` into `Tri<T, 3>`.
299    #[inline]
300    fn from([[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]]: [[T; 3]; 3]) -> Self {
301        Self::from_xyz(x1, y1, z1, x2, y2, z2, x3, y3, z3)
302    }
303}