use crate::cast::*;
use crate::dir::Directional;
use crate::geom::{Coord, Offset, Rect, Size};
use std::cmp::{Ordering, PartialOrd};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Quad {
pub a: Vec2,
pub b: Vec2,
}
impl Quad {
pub const ZERO: Quad = Quad::from_coords(Vec2::ZERO, Vec2::ZERO);
pub const INFINITY: Quad = Quad::from_coords(Vec2::NEG_INFINITY, Vec2::INFINITY);
pub const NAN: Quad = Quad::from_coords(Vec2::NAN, Vec2::NAN);
#[inline]
pub const fn from_coords(a: Vec2, b: Vec2) -> Self {
Quad { a, b }
}
#[inline]
pub fn from_pos_and_size(pos: Vec2, size: Vec2) -> Self {
Quad {
a: pos,
b: pos + size,
}
}
#[inline]
pub fn from_center(pos: Vec2, r: f32) -> Self {
let v = Vec2::splat(r);
Quad {
a: pos - v,
b: pos + v,
}
}
#[inline]
pub fn size(&self) -> Vec2 {
self.b - self.a
}
#[inline]
pub fn center(&self) -> Vec2 {
(self.a + self.b) * 0.5
}
#[inline]
pub fn ab(&self) -> Vec2 {
Vec2(self.a.0, self.b.1)
}
#[inline]
pub fn ba(&self) -> Vec2 {
Vec2(self.b.0, self.a.1)
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn shrink(&self, value: f32) -> Quad {
let a = self.a + value;
let b = self.b - value;
Quad { a, b }
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn grow(&self, value: f32) -> Quad {
let a = self.a - value;
let b = self.b + value;
Quad { a, b }
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn shrink_vec(&self, value: Vec2) -> Quad {
let a = self.a + value;
let b = self.b - value;
Quad { a, b }
}
pub fn intersection(&self, rhs: &Quad) -> Option<Quad> {
let a = Vec2(self.a.0.max(rhs.a.0), self.a.1.max(rhs.a.1));
let b = Vec2(self.b.0.min(rhs.b.0), self.b.1.min(rhs.b.1));
if a <= b { Some(Quad::from_coords(a, b)) } else { None }
}
}
impl AddAssign<Vec2> for Quad {
#[inline]
fn add_assign(&mut self, rhs: Vec2) {
self.a += rhs;
self.b += rhs;
}
}
impl SubAssign<Vec2> for Quad {
#[inline]
fn sub_assign(&mut self, rhs: Vec2) {
self.a -= rhs;
self.b -= rhs;
}
}
impl Add<Vec2> for Quad {
type Output = Quad;
#[inline]
fn add(mut self, rhs: Vec2) -> Self::Output {
self += rhs;
self
}
}
impl Sub<Vec2> for Quad {
type Output = Quad;
#[inline]
fn sub(mut self, rhs: Vec2) -> Self::Output {
self -= rhs;
self
}
}
impl Conv<Rect> for Quad {
#[inline]
fn try_conv(rect: Rect) -> Result<Self> {
let a = Vec2::try_conv(rect.pos)?;
let b = a + Vec2::try_conv(rect.size)?;
Ok(Quad { a, b })
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vec2(pub f32, pub f32);
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DVec2(pub f64, pub f64);
macro_rules! impl_vec2 {
($T:ident, $f:ty) => {
impl $T {
pub const ZERO: $T = $T::splat(0.0);
pub const ONE: $T = $T::splat(1.0);
pub const NEG_INFINITY: $T = $T::splat(<$f>::NEG_INFINITY);
pub const INFINITY: $T = $T::splat(<$f>::INFINITY);
pub const NAN: $T = $T::splat(<$f>::NAN);
#[inline]
pub const fn splat(value: $f) -> Self {
$T(value, value)
}
#[inline]
pub fn min_comp(self) -> $f {
self.0.min(self.1)
}
#[inline]
pub fn max_comp(self) -> $f {
self.0.max(self.1)
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn min(self, other: Self) -> Self {
$T(self.0.min(other.0), self.1.min(other.1))
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn max(self, other: Self) -> Self {
$T(self.0.max(other.0), self.1.max(other.1))
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn clamp(mut self, min: Self, max: Self) -> Self {
assert!(min <= max);
if self < min {
self = min;
}
if self > max {
self = max;
}
self
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn abs(self) -> Self {
$T(self.0.abs(), self.1.abs())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn floor(self) -> Self {
$T(self.0.floor(), self.1.floor())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn ceil(self) -> Self {
$T(self.0.ceil(), self.1.ceil())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn round(self) -> Self {
$T(self.0.round(), self.1.round())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn trunc(self) -> Self {
$T(self.0.trunc(), self.1.trunc())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn fract(self) -> Self {
$T(self.0.fract(), self.1.fract())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn sign(self) -> Self {
let one: $f = 1.0;
$T(one.copysign(self.0), one.copysign(self.1))
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn complex_mul(self, rhs: Self) -> Self {
$T(
self.0 * rhs.0 - self.1 * rhs.1,
self.0 * rhs.1 + self.1 * rhs.0,
)
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn complex_div(self, rhs: Self) -> Self {
self.complex_mul(rhs.complex_inv())
}
#[inline]
#[must_use = "method does not modify self but returns a new value"]
pub fn complex_inv(self) -> Self {
let ssi = 1.0 / self.sum_square();
$T(self.0 * ssi, -self.1 * ssi)
}
#[inline]
pub fn sum(self) -> $f {
self.0 + self.1
}
#[inline]
pub fn sum_square(self) -> $f {
self.0 * self.0 + self.1 * self.1
}
#[inline]
pub fn distance_l1(self) -> $f {
self.0.abs() + self.1.abs()
}
#[inline]
pub fn distance_l2(self) -> $f {
self.sum_square().sqrt()
}
#[inline]
pub fn distance_l_inf(self) -> $f {
self.0.abs().max(self.1.abs())
}
#[inline]
pub fn extract<D: Directional>(self, dir: D) -> $f {
match dir.is_vertical() {
false => self.0,
true => self.1,
}
}
#[inline]
pub fn is_finite(self) -> bool {
self.0.is_finite() && self.1.is_finite()
}
#[inline]
pub fn is_normal(self) -> bool {
self.0.is_normal() && self.1.is_normal()
}
}
impl Neg for $T {
type Output = $T;
#[inline]
fn neg(self) -> Self::Output {
$T(-self.0, -self.1)
}
}
impl Add<$T> for $T {
type Output = $T;
#[inline]
fn add(self, rhs: $T) -> Self::Output {
$T(self.0 + rhs.0, self.1 + rhs.1)
}
}
impl Add<$f> for $T {
type Output = $T;
#[inline]
fn add(self, rhs: $f) -> Self::Output {
$T(self.0 + rhs, self.1 + rhs)
}
}
impl AddAssign<$T> for $T {
#[inline]
fn add_assign(&mut self, rhs: $T) {
self.0 += rhs.0;
self.1 += rhs.1;
}
}
impl AddAssign<$f> for $T {
#[inline]
fn add_assign(&mut self, rhs: $f) {
self.0 += rhs;
self.1 += rhs;
}
}
impl Sub<$T> for $T {
type Output = $T;
#[inline]
fn sub(self, rhs: $T) -> Self::Output {
$T(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl Sub<$f> for $T {
type Output = $T;
#[inline]
fn sub(self, rhs: $f) -> Self::Output {
$T(self.0 - rhs, self.1 - rhs)
}
}
impl SubAssign<$T> for $T {
#[inline]
fn sub_assign(&mut self, rhs: $T) {
self.0 -= rhs.0;
self.1 -= rhs.1;
}
}
impl SubAssign<$f> for $T {
#[inline]
fn sub_assign(&mut self, rhs: $f) {
self.0 -= rhs;
self.1 -= rhs;
}
}
impl Mul<$T> for $T {
type Output = $T;
#[inline]
fn mul(self, rhs: $T) -> Self::Output {
$T(self.0 * rhs.0, self.1 * rhs.1)
}
}
impl MulAssign<$T> for $T {
#[inline]
fn mul_assign(&mut self, rhs: $T) {
self.0 *= rhs.0;
self.1 *= rhs.1;
}
}
impl Mul<$f> for $T {
type Output = $T;
#[inline]
fn mul(self, rhs: $f) -> Self::Output {
$T(self.0 * rhs, self.1 * rhs)
}
}
impl MulAssign<$f> for $T {
#[inline]
fn mul_assign(&mut self, rhs: $f) {
self.0 *= rhs;
self.1 *= rhs;
}
}
impl Div<$T> for $T {
type Output = $T;
#[inline]
fn div(self, rhs: $T) -> Self::Output {
$T(self.0 / rhs.0, self.1 / rhs.1)
}
}
impl Div<$f> for $T {
type Output = $T;
#[inline]
fn div(self, rhs: $f) -> Self::Output {
$T(self.0 / rhs, self.1 / rhs)
}
}
impl DivAssign<$f> for $T {
#[inline]
fn div_assign(&mut self, rhs: $f) {
self.0 /= rhs;
self.1 /= rhs;
}
}
impl PartialOrd for $T {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
if self == rhs {
Some(Ordering::Equal)
} else if self.0 < rhs.0 && self.1 < rhs.1 {
Some(Ordering::Less)
} else if self.0 > rhs.0 && self.1 > rhs.1 {
Some(Ordering::Greater)
} else {
None
}
}
#[inline]
fn lt(&self, rhs: &Self) -> bool {
self.0 < rhs.0 && self.1 < rhs.1
}
#[inline]
fn le(&self, rhs: &Self) -> bool {
self.0 <= rhs.0 && self.1 <= rhs.1
}
#[inline]
fn ge(&self, rhs: &Self) -> bool {
self.0 >= rhs.0 && self.1 >= rhs.1
}
#[inline]
fn gt(&self, rhs: &Self) -> bool {
self.0 > rhs.0 && self.1 > rhs.1
}
}
impl PartialEq<Coord> for $T {
fn eq(&self, rhs: &Coord) -> bool {
DVec2::from(*self) == DVec2::conv(*rhs)
}
}
impl PartialOrd<Coord> for $T {
fn partial_cmp(&self, rhs: &Coord) -> Option<Ordering> {
DVec2::from(*self).partial_cmp(&DVec2::conv(*rhs))
}
#[inline]
fn lt(&self, rhs: &Coord) -> bool {
DVec2::from(*self) < DVec2::conv(*rhs)
}
#[inline]
fn le(&self, rhs: &Coord) -> bool {
DVec2::from(*self) <= DVec2::conv(*rhs)
}
#[inline]
fn ge(&self, rhs: &Coord) -> bool {
DVec2::from(*self) >= DVec2::conv(*rhs)
}
#[inline]
fn gt(&self, rhs: &Coord) -> bool {
DVec2::from(*self) > DVec2::conv(*rhs)
}
}
impl From<($f, $f)> for $T {
#[inline]
fn from(arg: ($f, $f)) -> Self {
$T(arg.0, arg.1)
}
}
impl Conv<($f, $f)> for $T {
#[inline]
fn conv(arg: ($f, $f)) -> Self {
$T(arg.0, arg.1)
}
#[inline]
fn try_conv(v: ($f, $f)) -> Result<Self> {
Ok(Self::conv(v))
}
}
impl From<$T> for ($f, $f) {
#[inline]
fn from(v: $T) -> Self {
(v.0, v.1)
}
}
impl Conv<$T> for ($f, $f) {
#[inline]
fn conv(v: $T) -> Self {
(v.0, v.1)
}
#[inline]
fn try_conv(v: $T) -> Result<Self> {
Ok(Self::conv(v))
}
}
impl From<winit::dpi::PhysicalPosition<$f>> for $T {
#[inline]
fn from(pos: winit::dpi::PhysicalPosition<$f>) -> Self {
$T(pos.x, pos.y)
}
}
impl From<winit::dpi::PhysicalSize<$f>> for $T {
#[inline]
fn from(size: winit::dpi::PhysicalSize<$f>) -> Self {
$T(size.width, size.height)
}
}
};
}
impl From<kas_text::Vec2> for Vec2 {
#[inline]
fn from(size: kas_text::Vec2) -> Self {
Vec2(size.0, size.1)
}
}
impl Conv<kas_text::Vec2> for Vec2 {
#[inline]
fn conv(size: kas_text::Vec2) -> Self {
Vec2(size.0, size.1)
}
#[inline]
fn try_conv(v: kas_text::Vec2) -> Result<Self> {
Ok(Self::conv(v))
}
}
impl From<Vec2> for kas_text::Vec2 {
#[inline]
fn from(size: Vec2) -> kas_text::Vec2 {
kas_text::Vec2(size.0, size.1)
}
}
impl Conv<Vec2> for kas_text::Vec2 {
#[inline]
fn conv(size: Vec2) -> kas_text::Vec2 {
kas_text::Vec2(size.0, size.1)
}
#[inline]
fn try_conv(v: Vec2) -> Result<Self> {
Ok(Self::conv(v))
}
}
impl From<Vec2> for DVec2 {
#[inline]
fn from(v: Vec2) -> DVec2 {
DVec2(v.0.into(), v.1.into())
}
}
impl Conv<Vec2> for DVec2 {
#[inline]
fn try_conv(v: Vec2) -> Result<DVec2> {
Ok(DVec2(v.0.into(), v.1.into()))
}
}
impl ConvApprox<DVec2> for Vec2 {
fn try_conv_approx(size: DVec2) -> Result<Vec2> {
Ok(Vec2(size.0.try_cast_approx()?, size.1.try_cast_approx()?))
}
}
impl_vec2!(Vec2, f32);
impl_vec2!(DVec2, f64);
macro_rules! impl_conv_vec2 {
($S:ty, $T:ty) => {
impl Conv<$S> for $T {
#[inline]
fn try_conv(arg: $S) -> Result<Self> {
Ok(Self(arg.0.try_cast()?, arg.1.try_cast()?))
}
}
impl ConvApprox<$T> for $S {
#[inline]
fn try_conv_approx(arg: $T) -> Result<Self> {
Ok(Self(arg.0.try_cast_approx()?, arg.1.try_cast_approx()?))
}
}
impl ConvFloat<$T> for $S {
#[inline]
fn try_conv_trunc(x: $T) -> Result<Self> {
Ok(Self(i32::try_conv_trunc(x.0)?, i32::try_conv_trunc(x.1)?))
}
#[inline]
fn try_conv_nearest(x: $T) -> Result<Self> {
Ok(Self(
i32::try_conv_nearest(x.0)?,
i32::try_conv_nearest(x.1)?,
))
}
#[inline]
fn try_conv_floor(x: $T) -> Result<Self> {
Ok(Self(i32::try_conv_floor(x.0)?, i32::try_conv_floor(x.1)?))
}
#[inline]
fn try_conv_ceil(x: $T) -> Result<Self> {
Ok(Self(i32::try_conv_ceil(x.0)?, i32::try_conv_ceil(x.1)?))
}
}
};
}
impl_conv_vec2!(Coord, Vec2);
impl_conv_vec2!(Size, Vec2);
impl_conv_vec2!(Offset, Vec2);
impl_conv_vec2!(Coord, DVec2);
impl_conv_vec2!(Size, DVec2);
impl_conv_vec2!(Offset, DVec2);
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vec3(pub f32, pub f32, pub f32);
impl Vec3 {
#[inline]
pub fn from2(v: Vec2, z: f32) -> Self {
Vec3(v.0, v.1, z)
}
}