zeno/
geometry.rs

1//! Geometric primitives.
2
3#[allow(unused)]
4use crate::F32Ext;
5
6use core::borrow::Borrow;
7use core::ops::{Add, Div, Mul, Sub};
8
9/// Represents an angle in degrees or radians.
10#[derive(Copy, Clone, PartialEq, Default, Debug)]
11pub struct Angle(f32);
12
13impl Angle {
14    /// Angle of zero degrees.
15    pub const ZERO: Self = Self(0.);
16
17    /// Creates a new angle from degrees.
18    pub fn from_degrees(degrees: f32) -> Self {
19        Self(degrees * core::f32::consts::PI / 180.)
20    }
21
22    /// Creates a new angle from radians.
23    pub fn from_radians(radians: f32) -> Self {
24        Self(radians)
25    }
26
27    /// Creates a new angle from gradians.
28    pub fn from_gradians(gradians: f32) -> Self {
29        Self::from_degrees(gradians / 400. * 360.)
30    }
31
32    /// Creates a new angle from turns.
33    pub fn from_turns(turns: f32) -> Self {
34        Self::from_degrees(turns * 360.)
35    }
36
37    /// Returns the angle in radians.
38    pub fn to_radians(self) -> f32 {
39        self.0
40    }
41
42    /// Returns the angle in degrees.
43    pub fn to_degrees(self) -> f32 {
44        self.0 * 180. / core::f32::consts::PI
45    }
46}
47
48/// Two dimensional vector.
49#[derive(Copy, Clone, PartialEq, Default, Debug)]
50pub struct Vector {
51    pub x: f32,
52    pub y: f32,
53}
54
55impl Vector {
56    /// Vector with both components set to zero.
57    pub const ZERO: Self = Self { x: 0., y: 0. };
58
59    /// Creates a new vector with the specified coordinates.
60    #[inline]
61    pub const fn new(x: f32, y: f32) -> Self {
62        Self { x, y }
63    }
64
65    /// Returns the length of the vector.
66    #[inline]
67    pub fn length(self) -> f32 {
68        (self.x * self.x + self.y * self.y).sqrt()
69    }
70
71    /// Returns the squared length of the vector.
72    #[inline]
73    pub fn length_squared(self) -> f32 {
74        self.x * self.x + self.y * self.y
75    }
76
77    /// Returns the distance between two points.
78    #[inline]
79    pub fn distance_to(self, other: Self) -> f32 {
80        (self - other).length()
81    }
82
83    /// Computes the dot product of two vectors.
84    #[inline]
85    pub fn dot(self, other: Self) -> f32 {
86        self.x * other.x + self.y * other.y
87    }
88
89    /// Computes the cross product of two vectors.
90    #[inline]
91    pub fn cross(self, other: Self) -> f32 {
92        self.x * other.y - self.y * other.x
93    }
94
95    /// Returns a normalized copy of the vector.
96    #[inline]
97    pub fn normalize(self) -> Self {
98        let length = self.length();
99        if length == 0. {
100            return Self::new(0., 0.);
101        }
102        let inverse = 1. / length;
103        Self::new(self.x * inverse, self.y * inverse)
104    }
105
106    /// Returns a new vector containing the smallest integer values greater than
107    /// or equal to each component.
108    pub fn ceil(self) -> Self {
109        Self::new(self.x.ceil(), self.y.ceil())
110    }
111
112    /// Returns a new vector containing the largest integer values less than
113    /// or equal to each component.
114    pub fn floor(self) -> Self {
115        Self::new(self.x.floor(), self.y.floor())
116    }
117
118    /// Returns the angle to the specified vector.
119    pub fn angle_to(self, other: Self) -> Angle {
120        Angle::from_radians(self.cross(other).atan2(self.dot(other)))
121    }
122
123    /// Returns true if this vector is approximately equal to other using a
124    /// standard single precision epsilon value.
125    #[inline]
126    pub fn nearly_eq(self, other: Vector) -> bool {
127        self.nearly_eq_by(other, f32::EPSILON)
128    }
129
130    /// Returns true if this vector is approximately equal to other using
131    /// the specified epsilon value.
132    #[inline]
133    pub fn nearly_eq_by(self, other: Vector, epsilon: f32) -> bool {
134        (self.x - other.x).abs() < epsilon && (self.y - other.y).abs() < epsilon
135    }
136}
137
138impl Add for Vector {
139    type Output = Self;
140    #[inline]
141    fn add(self, rhs: Self) -> Self {
142        Self::new(self.x + rhs.x, self.y + rhs.y)
143    }
144}
145
146impl Sub for Vector {
147    type Output = Self;
148    #[inline]
149    fn sub(self, rhs: Self) -> Self {
150        Self::new(self.x - rhs.x, self.y - rhs.y)
151    }
152}
153
154impl Mul for Vector {
155    type Output = Self;
156    #[inline]
157    fn mul(self, rhs: Self) -> Self {
158        Self::new(self.x * rhs.x, self.y * rhs.y)
159    }
160}
161
162impl Mul<f32> for Vector {
163    type Output = Self;
164    #[inline]
165    fn mul(self, rhs: f32) -> Self {
166        Self::new(self.x * rhs, self.y * rhs)
167    }
168}
169
170impl Div for Vector {
171    type Output = Self;
172    #[inline]
173    fn div(self, rhs: Self) -> Self {
174        Self::new(self.x / rhs.x, self.y / rhs.y)
175    }
176}
177
178impl Div<f32> for Vector {
179    type Output = Self;
180    #[inline]
181    fn div(self, rhs: f32) -> Self {
182        let s = 1. / rhs;
183        Self::new(self.x * s, self.y * s)
184    }
185}
186
187impl From<[f32; 2]> for Vector {
188    fn from(v: [f32; 2]) -> Self {
189        Self::new(v[0], v[1])
190    }
191}
192
193impl From<[i32; 2]> for Vector {
194    fn from(v: [i32; 2]) -> Self {
195        Self::new(v[0] as f32, v[1] as f32)
196    }
197}
198
199impl From<(f32, f32)> for Vector {
200    fn from(v: (f32, f32)) -> Self {
201        Self::new(v.0, v.1)
202    }
203}
204
205impl From<(i32, i32)> for Vector {
206    fn from(v: (i32, i32)) -> Self {
207        Self::new(v.0 as f32, v.1 as f32)
208    }
209}
210
211impl From<(f32, i32)> for Vector {
212    fn from(v: (f32, i32)) -> Self {
213        Self::new(v.0, v.1 as f32)
214    }
215}
216
217impl From<(i32, f32)> for Vector {
218    fn from(v: (i32, f32)) -> Self {
219        Self::new(v.0 as f32, v.1)
220    }
221}
222
223impl From<f32> for Vector {
224    fn from(x: f32) -> Self {
225        Self::new(x, x)
226    }
227}
228
229impl From<i32> for Vector {
230    fn from(x: i32) -> Self {
231        let x = x as f32;
232        Self::new(x, x)
233    }
234}
235
236impl From<Vector> for [f32; 2] {
237    fn from(v: Vector) -> Self {
238        [v.x, v.y]
239    }
240}
241
242impl From<Vector> for (f32, f32) {
243    fn from(v: Vector) -> Self {
244        (v.x, v.y)
245    }
246}
247
248/// Alias for vector to distinguish intended use.
249pub type Point = Vector;
250
251#[inline(always)]
252pub(super) fn normal(start: Vector, end: Vector) -> Vector {
253    Vector::new(end.y - start.y, -(end.x - start.x)).normalize()
254}
255
256/// Two dimensional transformation matrix.
257#[derive(Copy, Clone, Default, Debug)]
258pub struct Transform {
259    pub xx: f32,
260    pub xy: f32,
261    pub yx: f32,
262    pub yy: f32,
263    pub x: f32,
264    pub y: f32,
265}
266
267impl Transform {
268    /// Identity matrix.
269    pub const IDENTITY: Self = Self {
270        xx: 1.,
271        xy: 0.,
272        yy: 1.,
273        yx: 0.,
274        x: 0.,
275        y: 0.,
276    };
277
278    /// Creates a new transform.
279    pub fn new(xx: f32, xy: f32, yx: f32, yy: f32, x: f32, y: f32) -> Self {
280        Self {
281            xx,
282            xy,
283            yx,
284            yy,
285            x,
286            y,
287        }
288    }
289
290    /// Creates a translation transform.
291    pub fn translation(x: f32, y: f32) -> Self {
292        Self::new(1., 0., 0., 1., x, y)
293    }
294
295    /// Creates a rotation transform.
296    pub fn rotation(angle: Angle) -> Self {
297        let (sin, cos) = angle.0.sin_cos();
298        Self {
299            xx: cos,
300            xy: sin,
301            yx: -sin,
302            yy: cos,
303            x: 0.,
304            y: 0.,
305        }
306    }
307
308    /// Creates a rotation transform around a point.
309    pub fn rotation_about(point: impl Into<Point>, angle: Angle) -> Self {
310        let p = point.into();
311        Self::translation(p.x, p.y)
312            .then_rotate(angle)
313            .then_translate(-p.x, -p.y)
314    }
315
316    /// Creates a scale transform.
317    pub fn scale(x: f32, y: f32) -> Self {
318        Self::new(x, 0., 0., y, 0., 0.)
319    }
320
321    /// Creates a skew transform.
322    pub fn skew(x: Angle, y: Angle) -> Self {
323        Self {
324            xx: 1.,
325            xy: y.0.tan(),
326            yx: x.0.tan(),
327            yy: 1.,
328            x: 0.,
329            y: 0.,
330        }
331    }
332
333    fn combine(a: &Transform, b: &Transform) -> Self {
334        let xx = a.xx * b.xx + a.yx * b.xy;
335        let yx = a.xx * b.yx + a.yx * b.yy;
336        let xy = a.xy * b.xx + a.yy * b.xy;
337        let yy = a.xy * b.yx + a.yy * b.yy;
338        let x = a.x * b.xx + a.y * b.xy + b.x;
339        let y = a.x * b.yx + a.y * b.yy + b.y;
340        Self {
341            xx,
342            yx,
343            xy,
344            yy,
345            x,
346            y,
347        }
348    }
349
350    /// Returns a new transform that represents the application of this transform
351    /// followed by other.
352    pub fn then(&self, other: &Transform) -> Self {
353        Self::combine(self, other)
354    }
355
356    /// Returns a new transform that represents a translation followed by this
357    /// transform.
358    pub fn pre_translate(&self, x: f32, y: f32) -> Self {
359        Self::combine(&Self::translation(x, y), self)
360    }
361
362    /// Returns a new transform that represents this transform followed by a
363    /// translation.
364    pub fn then_translate(&self, x: f32, y: f32) -> Self {
365        let mut t = *self;
366        t.x += x;
367        t.y += y;
368        t
369    }
370
371    /// Returns a new transform that represents a rotation followed by this
372    /// transform.
373    pub fn pre_rotate(&self, angle: Angle) -> Self {
374        Self::combine(&Self::rotation(angle), self)
375    }
376
377    /// Returns a new transform that represents this transform followed by a
378    /// rotation.
379    pub fn then_rotate(&self, angle: Angle) -> Self {
380        Self::combine(self, &Self::rotation(angle))
381    }
382
383    /// Returns a new transform that represents a scale followed by this
384    /// transform.
385    pub fn pre_scale(&self, x: f32, y: f32) -> Self {
386        Self::combine(&Self::scale(x, y), self)
387    }
388
389    /// Returns a new transform that represents this transform followed by a
390    /// scale.    
391    pub fn then_scale(&self, x: f32, y: f32) -> Self {
392        Self::combine(self, &Self::scale(x, y))
393    }
394
395    /// Returns the determinant of the transform.
396    pub fn determinant(&self) -> f32 {
397        self.xx * self.yy - self.yx * self.xy
398    }
399
400    /// Returns the inverse of the transform, if any.
401    pub fn invert(&self) -> Option<Transform> {
402        let det = self.determinant();
403        if !det.is_finite() || det == 0. {
404            return None;
405        }
406        let s = 1. / det;
407        let a = self.xx;
408        let b = self.xy;
409        let c = self.yx;
410        let d = self.yy;
411        let x = self.x;
412        let y = self.y;
413        Some(Transform {
414            xx: d * s,
415            xy: -b * s,
416            yx: -c * s,
417            yy: a * s,
418            x: (b * y - d * x) * s,
419            y: (c * x - a * y) * s,
420        })
421    }
422
423    /// Returns the result of applying this transform to a point.
424    #[inline(always)]
425    pub fn transform_point(&self, point: Point) -> Point {
426        Vector {
427            x: (point.x * self.xx + point.y * self.yx) + self.x,
428            y: (point.x * self.xy + point.y * self.yy) + self.y,
429        }
430    }
431
432    /// Returns the result of applying this transform to a vector.
433    #[inline(always)]
434    pub fn transform_vector(&self, vector: Vector) -> Vector {
435        Vector {
436            x: (vector.x * self.xx + vector.y * self.yx),
437            y: (vector.x * self.xy + vector.y * self.yy),
438        }
439    }
440}
441
442/// The origin of the coordinate system for rendering.
443#[derive(Copy, Clone, PartialEq, Eq, Debug)]
444pub enum Origin {
445    /// Origin (0, 0) at the top left of the image.
446    TopLeft,
447    /// Origin (0, 0) at the bottom left of the image.
448    BottomLeft,
449}
450
451impl Default for Origin {
452    fn default() -> Self {
453        Self::TopLeft
454    }
455}
456
457/// Describes the offset and dimensions of a rendered mask.
458#[derive(Copy, Clone, Debug, Default)]
459pub struct Placement {
460    /// Horizontal offset with respect to the origin specified when computing
461    /// the placement.
462    pub left: i32,
463    /// Vertical offset with respect to the origin specified when computing
464    /// the placement.
465    pub top: i32,
466    /// Width in pixels.
467    pub width: u32,
468    /// Height in pixels.
469    pub height: u32,
470}
471
472impl Placement {
473    /// Given an origin, offset and bounding box, computes the resulting offset
474    /// and placement for a tightly bounded mask.
475    pub fn compute(
476        origin: Origin,
477        offset: impl Into<Vector>,
478        bounds: &Bounds,
479    ) -> (Vector, Placement) {
480        let offset = offset.into();
481        let mut bounds = *bounds;
482        bounds.min = (bounds.min + offset).floor();
483        bounds.max = (bounds.max + offset).ceil();
484        let offset = Vector::new(-bounds.min.x, -bounds.min.y);
485        let width = bounds.width() as u32;
486        let height = bounds.height() as u32;
487        let left = -offset.x as i32;
488        let top = if origin == Origin::BottomLeft {
489            (-offset.y).floor() + height as f32
490        } else {
491            -offset.y
492        } as i32;
493        (
494            offset,
495            Placement {
496                left,
497                top,
498                width,
499                height,
500            },
501        )
502    }
503}
504
505/// Axis-aligned bounding box.
506#[derive(Copy, Clone, Default, Debug)]
507pub struct Bounds {
508    pub min: Point,
509    pub max: Point,
510}
511
512impl Bounds {
513    /// Creates a new bounding box from minimum and maximum points.
514    pub fn new(min: Point, max: Point) -> Self {
515        Self { min, max }
516    }
517
518    /// Creates a new bounding box from a sequence of points.
519    pub fn from_points<I>(points: I) -> Self
520    where
521        I: IntoIterator,
522        I::Item: Borrow<Point>,
523    {
524        let mut b = BoundsBuilder::new();
525        for p in points {
526            b.add(*p.borrow());
527        }
528        b.build()
529    }
530
531    /// Returns true if the bounding box is empty.
532    pub fn is_empty(&self) -> bool {
533        self.min.x >= self.max.x || self.min.y >= self.max.y
534    }
535
536    /// Returns the width of the bounding box.
537    pub fn width(&self) -> f32 {
538        self.max.x - self.min.x
539    }
540
541    /// Returns the height of the bounding box.
542    pub fn height(&self) -> f32 {
543        self.max.y - self.min.y
544    }
545
546    /// Returns true if the box contains the specified point.
547    pub fn contains(&self, point: impl Into<Point>) -> bool {
548        let p = point.into();
549        p.x > self.min.x && p.x < self.max.x && p.y > self.min.y && p.y < self.max.y
550    }
551}
552
553pub(super) struct BoundsBuilder {
554    pub count: usize,
555    #[allow(dead_code)]
556    pub start: Point,
557    pub current: Point,
558    pub min: Point,
559    pub max: Point,
560}
561
562impl BoundsBuilder {
563    pub fn new() -> Self {
564        Self {
565            count: 0,
566            start: Point::ZERO,
567            current: Point::ZERO,
568            min: Point::new(f32::MAX, f32::MAX),
569            max: Point::new(f32::MIN, f32::MIN),
570        }
571    }
572
573    pub fn add(&mut self, p: Point) -> &mut Self {
574        let x = p.x;
575        let y = p.y;
576        if x < self.min.x {
577            self.min.x = x;
578        }
579        if x > self.max.x {
580            self.max.x = x;
581        }
582        if y < self.min.y {
583            self.min.y = y;
584        }
585        if y > self.max.y {
586            self.max.y = y;
587        }
588        self.count += 1;
589        self
590    }
591
592    pub fn build(&self) -> Bounds {
593        if self.count != 0 {
594            Bounds {
595                min: self.min,
596                max: self.max,
597            }
598        } else {
599            Bounds::default()
600        }
601    }
602}