1#![no_std]
16#![warn(missing_docs)]
17#![warn(missing_copy_implementations)]
18#![warn(missing_debug_implementations)]
19#![allow(clippy::approx_constant)]
20#![allow(clippy::collapsible_if)]
21#![allow(clippy::eq_op)]
22#![allow(clippy::excessive_precision)]
23#![allow(clippy::identity_op)]
24#![allow(clippy::manual_range_contains)]
25#![allow(clippy::neg_cmp_op_on_partial_ord)]
26#![allow(clippy::too_many_arguments)]
27#![allow(clippy::upper_case_acronyms)]
28#![allow(clippy::wrong_self_convention)]
29
30#[cfg(not(any(feature = "std", feature = "no-std-float")))]
31compile_error!("You have to activate either the `std` or the `no-std-float` feature.");
32
33#[cfg(feature = "std")]
34extern crate std;
35
36extern crate alloc;
37
38mod dash;
39mod f32x2_t;
40mod f32x4_t;
41mod floating_point;
42mod path;
43mod path_builder;
44pub mod path_geometry;
45mod rect;
46mod scalar;
47mod size;
48mod stroker;
49mod transform;
50
51pub use dash::StrokeDash;
52pub use f32x2_t::f32x2;
53pub use floating_point::*;
54pub use path::*;
55pub use path_builder::*;
56pub use rect::*;
57pub use scalar::*;
58pub use size::*;
59pub use stroker::*;
60pub use transform::*;
61
62type LengthU32 = core::num::NonZeroU32;
64
65#[allow(missing_docs)]
69#[repr(C)]
70#[derive(Copy, Clone, PartialEq, Default, Debug)]
71pub struct Point {
72    pub x: f32,
73    pub y: f32,
74}
75
76impl From<(f32, f32)> for Point {
77    #[inline]
78    fn from(v: (f32, f32)) -> Self {
79        Point { x: v.0, y: v.1 }
80    }
81}
82
83impl Point {
84    pub fn from_xy(x: f32, y: f32) -> Self {
86        Point { x, y }
87    }
88
89    pub fn from_f32x2(r: f32x2) -> Self {
91        Point::from_xy(r.x(), r.y())
92    }
93
94    pub fn to_f32x2(&self) -> f32x2 {
96        f32x2::new(self.x, self.y)
97    }
98
99    pub fn zero() -> Self {
101        Point { x: 0.0, y: 0.0 }
102    }
103
104    pub fn is_zero(&self) -> bool {
106        self.x == 0.0 && self.y == 0.0
107    }
108
109    pub fn is_finite(&self) -> bool {
113        (self.x * self.y).is_finite()
114    }
115
116    pub(crate) fn almost_equal(&self, other: Point) -> bool {
118        !(*self - other).can_normalize()
119    }
120
121    pub(crate) fn equals_within_tolerance(&self, other: Point, tolerance: f32) -> bool {
123        (self.x - other.x).is_nearly_zero_within_tolerance(tolerance)
124            && (self.y - other.y).is_nearly_zero_within_tolerance(tolerance)
125    }
126
127    pub fn normalize(&mut self) -> bool {
133        self.set_length_from(self.x, self.y, 1.0)
134    }
135
136    pub fn set_normalize(&mut self, x: f32, y: f32) -> bool {
142        self.set_length_from(x, y, 1.0)
143    }
144
145    pub(crate) fn can_normalize(&self) -> bool {
146        self.x.is_finite() && self.y.is_finite() && (self.x != 0.0 || self.y != 0.0)
147    }
148
149    pub fn length(&self) -> f32 {
151        let mag2 = self.x * self.x + self.y * self.y;
152        if mag2.is_finite() {
153            mag2.sqrt()
154        } else {
155            let xx = f64::from(self.x);
156            let yy = f64::from(self.y);
157            (xx * xx + yy * yy).sqrt() as f32
158        }
159    }
160
161    pub fn set_length(&mut self, length: f32) -> bool {
166        self.set_length_from(self.x, self.y, length)
167    }
168
169    pub fn set_length_from(&mut self, x: f32, y: f32, length: f32) -> bool {
174        set_point_length(self, x, y, length, &mut None)
175    }
176
177    pub fn distance(&self, other: Point) -> f32 {
179        (*self - other).length()
180    }
181
182    pub fn dot(&self, other: Point) -> f32 {
184        self.x * other.x + self.y * other.y
185    }
186
187    pub fn cross(&self, other: Point) -> f32 {
193        self.x * other.y - self.y * other.x
194    }
195
196    pub(crate) fn distance_to_sqd(&self, pt: Point) -> f32 {
197        let dx = self.x - pt.x;
198        let dy = self.y - pt.y;
199        dx * dx + dy * dy
200    }
201
202    pub(crate) fn length_sqd(&self) -> f32 {
203        self.dot(*self)
204    }
205
206    pub fn scale(&mut self, scale: f32) {
208        self.x *= scale;
209        self.y *= scale;
210    }
211
212    pub(crate) fn scaled(&self, scale: f32) -> Self {
213        Point::from_xy(self.x * scale, self.y * scale)
214    }
215
216    pub(crate) fn swap_coords(&mut self) {
217        core::mem::swap(&mut self.x, &mut self.y);
218    }
219
220    pub(crate) fn rotate_cw(&mut self) {
221        self.swap_coords();
222        self.x = -self.x;
223    }
224
225    pub(crate) fn rotate_ccw(&mut self) {
226        self.swap_coords();
227        self.y = -self.y;
228    }
229}
230
231fn set_point_length(
238    pt: &mut Point,
239    mut x: f32,
240    mut y: f32,
241    length: f32,
242    orig_length: &mut Option<f32>,
243) -> bool {
244    let xx = x as f64;
248    let yy = y as f64;
249    let dmag = (xx * xx + yy * yy).sqrt();
250    let dscale = length as f64 / dmag;
251    x *= dscale as f32;
252    y *= dscale as f32;
253
254    if !x.is_finite() || !y.is_finite() || (x == 0.0 && y == 0.0) {
256        *pt = Point::zero();
257        return false;
258    }
259
260    let mut mag = 0.0;
261    if orig_length.is_some() {
262        mag = dmag as f32;
263    }
264
265    *pt = Point::from_xy(x, y);
266
267    if orig_length.is_some() {
268        *orig_length = Some(mag);
269    }
270
271    true
272}
273
274impl core::ops::Neg for Point {
275    type Output = Point;
276
277    fn neg(self) -> Self::Output {
278        Point {
279            x: -self.x,
280            y: -self.y,
281        }
282    }
283}
284
285impl core::ops::Add for Point {
286    type Output = Point;
287
288    fn add(self, other: Point) -> Self::Output {
289        Point::from_xy(self.x + other.x, self.y + other.y)
290    }
291}
292
293impl core::ops::AddAssign for Point {
294    fn add_assign(&mut self, other: Point) {
295        self.x += other.x;
296        self.y += other.y;
297    }
298}
299
300impl core::ops::Sub for Point {
301    type Output = Point;
302
303    fn sub(self, other: Point) -> Self::Output {
304        Point::from_xy(self.x - other.x, self.y - other.y)
305    }
306}
307
308impl core::ops::SubAssign for Point {
309    fn sub_assign(&mut self, other: Point) {
310        self.x -= other.x;
311        self.y -= other.y;
312    }
313}
314
315impl core::ops::Mul for Point {
316    type Output = Point;
317
318    fn mul(self, other: Point) -> Self::Output {
319        Point::from_xy(self.x * other.x, self.y * other.y)
320    }
321}
322
323impl core::ops::MulAssign for Point {
324    fn mul_assign(&mut self, other: Point) {
325        self.x *= other.x;
326        self.y *= other.y;
327    }
328}