//! Geometric primitives. #[allow(unused)] use crate::F32Ext; use core::borrow::Borrow; use core::ops::{Add, Div, Mul, Sub}; /// Represents an angle in degrees or radians. #[derive(Copy, Clone, PartialEq, Default, Debug)] pub struct Angle(f32); impl Angle { /// Angle of zero degrees. pub const ZERO: Self = Self(0.); /// Creates a new angle from degrees. pub fn from_degrees(degrees: f32) -> Self { Self(degrees * core::f32::consts::PI / 180.) } /// Creates a new angle from radians. pub fn from_radians(radians: f32) -> Self { Self(radians) } /// Creates a new angle from gradians. pub fn from_gradians(gradians: f32) -> Self { Self::from_degrees(gradians / 400. * 360.) } /// Creates a new angle from turns. pub fn from_turns(turns: f32) -> Self { Self::from_degrees(turns * 360.) } /// Returns the angle in radians. pub fn to_radians(self) -> f32 { self.0 } /// Returns the angle in degrees. pub fn to_degrees(self) -> f32 { self.0 * 180. / core::f32::consts::PI } } /// Two dimensional vector. #[derive(Copy, Clone, PartialEq, Default, Debug)] pub struct Vector { pub x: f32, pub y: f32, } impl Vector { /// Vector with both components set to zero. pub const ZERO: Self = Self { x: 0., y: 0. }; /// Creates a new vector with the specified coordinates. #[inline] pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } /// Returns the length of the vector. #[inline] pub fn length(self) -> f32 { (self.x * self.x + self.y * self.y).sqrt() } /// Returns the squared length of the vector. #[inline] pub fn length_squared(self) -> f32 { self.x * self.x + self.y * self.y } /// Returns the distance between two points. #[inline] pub fn distance_to(self, other: Self) -> f32 { (self - other).length() } /// Computes the dot product of two vectors. #[inline] pub fn dot(self, other: Self) -> f32 { self.x * other.x + self.y * other.y } /// Computes the cross product of two vectors. #[inline] pub fn cross(self, other: Self) -> f32 { self.x * other.y - self.y * other.x } /// Returns a normalized copy of the vector. #[inline] pub fn normalize(self) -> Self { let length = self.length(); if length == 0. { return Self::new(0., 0.); } let inverse = 1. / length; Self::new(self.x * inverse, self.y * inverse) } /// Returns a new vector containing the smallest integer values greater than /// or equal to each component. pub fn ceil(self) -> Self { Self::new(self.x.ceil(), self.y.ceil()) } /// Returns a new vector containing the largest integer values less than /// or equal to each component. pub fn floor(self) -> Self { Self::new(self.x.floor(), self.y.floor()) } /// Returns the angle to the specified vector. pub fn angle_to(self, other: Self) -> Angle { Angle::from_radians(self.cross(other).atan2(self.dot(other))) } /// Returns true if this vector is approximately equal to other using a /// standard single precision epsilon value. #[inline] pub fn nearly_eq(self, other: Vector) -> bool { self.nearly_eq_by(other, f32::EPSILON) } /// Returns true if this vector is approximately equal to other using /// the specified epsilon value. #[inline] pub fn nearly_eq_by(self, other: Vector, epsilon: f32) -> bool { (self.x - other.x).abs() < epsilon && (self.y - other.y).abs() < epsilon } } impl Add for Vector { type Output = Self; #[inline] fn add(self, rhs: Self) -> Self { Self::new(self.x + rhs.x, self.y + rhs.y) } } impl Sub for Vector { type Output = Self; #[inline] fn sub(self, rhs: Self) -> Self { Self::new(self.x - rhs.x, self.y - rhs.y) } } impl Mul for Vector { type Output = Self; #[inline] fn mul(self, rhs: Self) -> Self { Self::new(self.x * rhs.x, self.y * rhs.y) } } impl Mul for Vector { type Output = Self; #[inline] fn mul(self, rhs: f32) -> Self { Self::new(self.x * rhs, self.y * rhs) } } impl Div for Vector { type Output = Self; #[inline] fn div(self, rhs: Self) -> Self { Self::new(self.x / rhs.x, self.y / rhs.y) } } impl Div for Vector { type Output = Self; #[inline] fn div(self, rhs: f32) -> Self { let s = 1. / rhs; Self::new(self.x * s, self.y * s) } } impl From<[f32; 2]> for Vector { fn from(v: [f32; 2]) -> Self { Self::new(v[0], v[1]) } } impl From<[i32; 2]> for Vector { fn from(v: [i32; 2]) -> Self { Self::new(v[0] as f32, v[1] as f32) } } impl From<(f32, f32)> for Vector { fn from(v: (f32, f32)) -> Self { Self::new(v.0, v.1) } } impl From<(i32, i32)> for Vector { fn from(v: (i32, i32)) -> Self { Self::new(v.0 as f32, v.1 as f32) } } impl From<(f32, i32)> for Vector { fn from(v: (f32, i32)) -> Self { Self::new(v.0, v.1 as f32) } } impl From<(i32, f32)> for Vector { fn from(v: (i32, f32)) -> Self { Self::new(v.0 as f32, v.1) } } impl From for Vector { fn from(x: f32) -> Self { Self::new(x, x) } } impl From for Vector { fn from(x: i32) -> Self { let x = x as f32; Self::new(x, x) } } impl From for [f32; 2] { fn from(v: Vector) -> Self { [v.x, v.y] } } impl From for (f32, f32) { fn from(v: Vector) -> Self { (v.x, v.y) } } /// Alias for vector to distinguish intended use. pub type Point = Vector; #[inline(always)] pub(super) fn normal(start: Vector, end: Vector) -> Vector { Vector::new(end.y - start.y, -(end.x - start.x)).normalize() } /// Two dimensional transformation matrix. #[derive(Copy, Clone, Default, Debug)] pub struct Transform { pub xx: f32, pub xy: f32, pub yx: f32, pub yy: f32, pub x: f32, pub y: f32, } impl Transform { /// Identity matrix. pub const IDENTITY: Self = Self { xx: 1., xy: 0., yy: 1., yx: 0., x: 0., y: 0., }; /// Creates a new transform. pub fn new(xx: f32, xy: f32, yx: f32, yy: f32, x: f32, y: f32) -> Self { Self { xx, xy, yx, yy, x, y, } } /// Creates a translation transform. pub fn translation(x: f32, y: f32) -> Self { Self::new(1., 0., 0., 1., x, y) } /// Creates a rotation transform. pub fn rotation(angle: Angle) -> Self { let (sin, cos) = angle.0.sin_cos(); Self { xx: cos, xy: sin, yx: -sin, yy: cos, x: 0., y: 0., } } /// Creates a rotation transform around a point. pub fn rotation_about(point: impl Into, angle: Angle) -> Self { let p = point.into(); Self::translation(p.x, p.y) .then_rotate(angle) .then_translate(-p.x, -p.y) } /// Creates a scale transform. pub fn scale(x: f32, y: f32) -> Self { Self::new(x, 0., 0., y, 0., 0.) } /// Creates a skew transform. pub fn skew(x: Angle, y: Angle) -> Self { Self { xx: 1., xy: y.0.tan(), yx: x.0.tan(), yy: 1., x: 0., y: 0., } } fn combine(a: &Transform, b: &Transform) -> Self { let xx = a.xx * b.xx + a.yx * b.xy; let yx = a.xx * b.yx + a.yx * b.yy; let xy = a.xy * b.xx + a.yy * b.xy; let yy = a.xy * b.yx + a.yy * b.yy; let x = a.x * b.xx + a.y * b.xy + b.x; let y = a.x * b.yx + a.y * b.yy + b.y; Self { xx, yx, xy, yy, x, y, } } /// Returns a new transform that represents the application of this transform /// followed by other. pub fn then(&self, other: &Transform) -> Self { Self::combine(self, other) } /// Returns a new transform that represents a translation followed by this /// transform. pub fn pre_translate(&self, x: f32, y: f32) -> Self { Self::combine(&Self::translation(x, y), self) } /// Returns a new transform that represents this transform followed by a /// translation. pub fn then_translate(&self, x: f32, y: f32) -> Self { let mut t = *self; t.x += x; t.y += y; t } /// Returns a new transform that represents a rotation followed by this /// transform. pub fn pre_rotate(&self, angle: Angle) -> Self { Self::combine(&Self::rotation(angle), self) } /// Returns a new transform that represents this transform followed by a /// rotation. pub fn then_rotate(&self, angle: Angle) -> Self { Self::combine(self, &Self::rotation(angle)) } /// Returns a new transform that represents a scale followed by this /// transform. pub fn pre_scale(&self, x: f32, y: f32) -> Self { Self::combine(&Self::scale(x, y), self) } /// Returns a new transform that represents this transform followed by a /// scale. pub fn then_scale(&self, x: f32, y: f32) -> Self { Self::combine(self, &Self::scale(x, y)) } /// Returns the determinant of the transform. pub fn determinant(&self) -> f32 { self.xx * self.yy - self.yx * self.xy } /// Returns the inverse of the transform, if any. pub fn invert(&self) -> Option { let det = self.determinant(); if !det.is_finite() || det == 0. { return None; } let s = 1. / det; let a = self.xx; let b = self.xy; let c = self.yx; let d = self.yy; let x = self.x; let y = self.y; Some(Transform { xx: d * s, xy: -b * s, yx: -c * s, yy: a * s, x: (b * y - d * x) * s, y: (c * x - a * y) * s, }) } /// Returns the result of applying this transform to a point. #[inline(always)] pub fn transform_point(&self, point: Point) -> Point { Vector { x: (point.x * self.xx + point.y * self.yx) + self.x, y: (point.x * self.xy + point.y * self.yy) + self.y, } } /// Returns the result of applying this transform to a vector. #[inline(always)] pub fn transform_vector(&self, vector: Vector) -> Vector { Vector { x: (vector.x * self.xx + vector.y * self.yx), y: (vector.x * self.xy + vector.y * self.yy), } } } /// The origin of the coordinate system for rendering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Origin { /// Origin (0, 0) at the top left of the image. TopLeft, /// Origin (0, 0) at the bottom left of the image. BottomLeft, } impl Default for Origin { fn default() -> Self { Self::TopLeft } } /// Describes the offset and dimensions of a rendered mask. #[derive(Copy, Clone, Debug, Default)] pub struct Placement { /// Horizontal offset with respect to the origin specified when computing /// the placement. pub left: i32, /// Vertical offset with respect to the origin specified when computing /// the placement. pub top: i32, /// Width in pixels. pub width: u32, /// Height in pixels. pub height: u32, } impl Placement { /// Given an origin, offset and bounding box, computes the resulting offset /// and placement for a tightly bounded mask. pub fn compute( origin: Origin, offset: impl Into, bounds: &Bounds, ) -> (Vector, Placement) { let offset = offset.into(); let mut bounds = *bounds; bounds.min = (bounds.min + offset).floor(); bounds.max = (bounds.max + offset).ceil(); let offset = Vector::new(-bounds.min.x, -bounds.min.y); let width = bounds.width() as u32; let height = bounds.height() as u32; let left = -offset.x as i32; let top = if origin == Origin::BottomLeft { (-offset.y).floor() + height as f32 } else { -offset.y } as i32; ( offset, Placement { left, top, width, height, }, ) } } /// Axis-aligned bounding box. #[derive(Copy, Clone, Default, Debug)] pub struct Bounds { pub min: Point, pub max: Point, } impl Bounds { /// Creates a new bounding box from minimum and maximum points. pub fn new(min: Point, max: Point) -> Self { Self { min, max } } /// Creates a new bounding box from a sequence of points. pub fn from_points(points: I) -> Self where I: IntoIterator, I::Item: Borrow, { let mut b = BoundsBuilder::new(); for p in points { b.add(*p.borrow()); } b.build() } /// Returns true if the bounding box is empty. pub fn is_empty(&self) -> bool { self.min.x >= self.max.x || self.min.y >= self.max.y } /// Returns the width of the bounding box. pub fn width(&self) -> f32 { self.max.x - self.min.x } /// Returns the height of the bounding box. pub fn height(&self) -> f32 { self.max.y - self.min.y } /// Returns true if the box contains the specified point. pub fn contains(&self, point: impl Into) -> bool { let p = point.into(); p.x > self.min.x && p.x < self.max.x && p.y > self.min.y && p.y < self.max.y } } pub(super) struct BoundsBuilder { pub count: usize, #[allow(dead_code)] pub start: Point, pub current: Point, pub min: Point, pub max: Point, } impl BoundsBuilder { pub fn new() -> Self { Self { count: 0, start: Point::ZERO, current: Point::ZERO, min: Point::new(f32::MAX, f32::MAX), max: Point::new(f32::MIN, f32::MIN), } } pub fn add(&mut self, p: Point) -> &mut Self { let x = p.x; let y = p.y; if x < self.min.x { self.min.x = x; } if x > self.max.x { self.max.x = x; } if y < self.min.y { self.min.y = y; } if y > self.max.y { self.max.y = y; } self.count += 1; self } pub fn build(&self) -> Bounds { if self.count != 0 { Bounds { min: self.min, max: self.max, } } else { Bounds::default() } } }