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}