polymorpher 0.1.4

Library for creating and morphing potentially rounded polygons
Documentation
//! Contains wrappers over geometric types from `euclid`, an extension trait for
//! them, and the `PointTransformer` trait required for
//! `RoundedPolygon::transformed`.

use core::f32;

pub type Size = euclid::default::Size2D<f32>;
pub type Point = euclid::default::Point2D<f32>;
pub type Vector = euclid::default::Vector2D<f32>;
pub type Aabb = euclid::default::Box2D<f32>;
pub type Matrix2 = euclid::default::Transform2D<f32>;
pub type Matrix3 = euclid::default::Transform3D<f32>;
pub type Angle = euclid::Angle<f32>;

pub const DISTANCE_EPSILON: f32 = 1e-4;
pub const ANGLE_EPSILON: f32 = 1e-6;

pub trait GeometryExt {
    #[must_use]
    fn rotated(self, angle: f32, center: Self) -> Self;
    #[must_use]
    fn rotate90(&self) -> Self;
    #[must_use]
    fn get_direction(&self) -> Self;
    fn is_convex(&self, current: Self, next: Self) -> bool;
}

impl GeometryExt for Point {
    fn rotated(self, a: f32, center: Self) -> Self {
        let a = a / 360.0 * 2.0 * f32::consts::PI;
        let off = self - center;

        Self::new(off.x.mul_add(a.cos(), -(off.y * a.sin())), off.x.mul_add(a.sin(), off.y * a.cos())) + center.to_vector()
    }

    fn rotate90(&self) -> Self {
        Self::new(-self.y, self.x)
    }

    fn get_direction(&self) -> Self {
        let d = self.to_vector().length();

        assert!(d > 0.0, "Can't get the direction of a 0-length vector");

        *self / d
    }

    fn is_convex(&self, current: Self, next: Self) -> bool {
        let a = current - *self;
        let b = next - current;

        a.x.mul_add(b.y, -(a.y * b.x)) > 0.0
    }
}

impl GeometryExt for Vector {
    fn rotated(self, a: f32, center: Self) -> Self {
        let a = a / 360.0 * 2.0 * f32::consts::PI;
        let off = self - center;

        Self::new(off.x.mul_add(a.cos(), -(off.y * a.sin())), off.x.mul_add(a.sin(), off.y * a.cos())) + center
    }

    fn rotate90(&self) -> Self {
        Self::new(-self.y, self.x)
    }

    fn get_direction(&self) -> Self {
        let d = self.length();

        assert!(d > 0.0, "Can't get the direction of a 0-length vector ({d} {} {self:?})", self.square_length());

        *self / d
    }

    fn is_convex(&self, current: Self, next: Self) -> bool {
        let a = current - *self;
        let b = next - current;

        a.x.mul_add(b.y, -(a.y * b.x)) > 0.0
    }
}

pub trait PointTransformer {
    fn transform(&self, point: Point) -> Point;
}

impl<F: Fn(Point) -> Point> PointTransformer for F {
    fn transform(&self, point: Point) -> Point {
        self(point)
    }
}

impl PointTransformer for Matrix3 {
    fn transform(&self, point: Point) -> Point {
        self.transform_point2d(point).unwrap_or(point)
    }
}