use derive_more::{
Add, AddAssign, Constructor, Div, DivAssign, From, Into, Mul, MulAssign, Sub, SubAssign,
};
use num_traits::Bounded;
use serde::{Deserialize, Serialize};
use crate::Rect3;
#[derive(
Add,
AddAssign,
Clone,
Constructor,
Copy,
Debug,
Deserialize,
Div,
DivAssign,
Eq,
From,
Into,
Mul,
MulAssign,
Ord,
PartialEq,
PartialOrd,
Serialize,
Sub,
SubAssign,
)]
pub struct Vector2<T> {
pub x: T,
pub y: T,
}
impl<T: Copy> From<[T; 2]> for Vector2<T> {
fn from(from: [T; 2]) -> Self {
Self {
x: from[0],
y: from[1],
}
}
}
impl<T: Copy> From<Vector2<T>> for [T; 2] {
fn from(from: Vector2<T>) -> Self {
[from.x, from.y]
}
}
impl<T: Copy + Ord> Vector2<T> {
pub fn z_extruded(self, from: T, to: T) -> Rect3<T> {
Rect3 {
min: Vector3::new(self.x, self.y, std::cmp::min(from, to)),
max: Vector3::new(self.x, self.y, std::cmp::max(from, to)),
}
}
}
impl<T: Bounded + Copy> Vector2<T> {
pub fn z_extruded_infinitely(self) -> Rect3<T> {
Rect3 {
min: Vector3::new(self.x, self.y, Bounded::min_value()),
max: Vector3::new(self.x, self.y, Bounded::max_value()),
}
}
}
macro_rules! impl_vector2_inside_polygon {
($type:ty) => {
impl Vector2<$type> {
pub fn inside_polygon(&self, poly: &[Vector2<$type>]) -> bool {
let mut inside = false;
let n = poly.len();
let mut v1 = &poly[n - 1];
for v2 in poly.iter() {
let dx12 = v2.x - v1.x;
let dy12 = v2.y - v1.y;
if dy12 != (0 as $type) && (self.y > v1.y) != (self.y > v2.y) {
let dx01 = self.x - v1.x;
let dy01 = self.y - v1.y;
let crosses = if dy12 > (0 as $type) {
dx01 * dy12 < dx12 * dy01
} else {
dx01 * dy12 > dx12 * dy01
};
if crosses {
inside = !inside;
}
}
v1 = v2;
}
inside
}
}
};
}
impl_vector2_inside_polygon!(i8);
impl_vector2_inside_polygon!(i16);
impl_vector2_inside_polygon!(i32);
impl_vector2_inside_polygon!(i64);
impl_vector2_inside_polygon!(i128);
impl_vector2_inside_polygon!(u8);
impl_vector2_inside_polygon!(u16);
impl_vector2_inside_polygon!(u32);
impl_vector2_inside_polygon!(u64);
impl_vector2_inside_polygon!(u128);
impl_vector2_inside_polygon!(f32);
impl_vector2_inside_polygon!(f64);
macro_rules! impl_vector2_closest_point_on_boundary {
($type:ty) => {
impl Vector2<$type> {
pub fn closest_point_on_seg(
self,
seg_start: Vector2<$type>,
seg_end: Vector2<$type>,
) -> Vector2<$type> {
let abx = seg_end.x - seg_start.x;
let aby = seg_end.y - seg_start.y;
let apx = self.x - seg_start.x;
let apy = self.y - seg_start.y;
let ab_len_sq = abx * abx + aby * aby;
if ab_len_sq == 0 as $type {
return seg_start;
}
let t = (apx * abx + apy * aby).clamp(0 as $type, ab_len_sq);
Vector2::new(
seg_start.x + abx * t / ab_len_sq,
seg_start.y + aby * t / ab_len_sq,
)
}
pub fn closest_point_on_poly_boundary(self, poly: &[Vector2<$type>]) -> Vector2<$type> {
let mut closest_point = poly[0];
let mut best_distance_sq = <$type as Bounded>::max_value();
for i in 0..poly.len() {
let seg_start = poly[i];
let seg_end = poly[(i + 1) % poly.len()];
let candidate = self.closest_point_on_seg(seg_start, seg_end);
let dx = self.x - candidate.x;
let dy = self.y - candidate.y;
let distance_sq = dx * dx + dy * dy;
if distance_sq < best_distance_sq {
best_distance_sq = distance_sq;
closest_point = candidate;
}
}
closest_point
}
}
};
}
impl_vector2_closest_point_on_boundary!(i8);
impl_vector2_closest_point_on_boundary!(i16);
impl_vector2_closest_point_on_boundary!(i32);
impl_vector2_closest_point_on_boundary!(i64);
impl_vector2_closest_point_on_boundary!(i128);
impl_vector2_closest_point_on_boundary!(u8);
impl_vector2_closest_point_on_boundary!(u16);
impl_vector2_closest_point_on_boundary!(u32);
impl_vector2_closest_point_on_boundary!(u64);
impl_vector2_closest_point_on_boundary!(u128);
impl_vector2_closest_point_on_boundary!(f32);
impl_vector2_closest_point_on_boundary!(f64);
macro_rules! impl_vector2_rotate_around_point {
($type:ty) => {
impl Vector2<$type> {
pub fn rotate_around_point(&mut self, angle: $type, origin: Vector2<$type>) -> Self {
let sin = angle.sin();
let cos = angle.cos();
let tx = self.x - origin.x;
let ty = self.y - origin.y;
let rx = tx * cos - ty * sin;
let ry = tx * sin + ty * cos;
self.x = rx + origin.x;
self.y = ry + origin.y;
*self
}
pub fn rotate_around_point_degrees(
&mut self,
angle: $type,
origin: Vector2<$type>,
) -> Self {
self.rotate_around_point(angle.to_radians(), origin)
}
}
};
}
impl_vector2_rotate_around_point!(f32);
impl_vector2_rotate_around_point!(f64);
#[derive(
Add,
AddAssign,
Clone,
Constructor,
Copy,
Debug,
Deserialize,
Div,
DivAssign,
Eq,
From,
Into,
Mul,
MulAssign,
Ord,
PartialEq,
PartialOrd,
Serialize,
Sub,
SubAssign,
)]
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T: Copy> Vector3<T> {
pub fn xy(self) -> Vector2<T> {
Vector2::new(self.x, self.y)
}
}