pub mod transform {
mod rotate;
mod scale;
mod shift;
pub use rotate::*;
pub use scale::*;
pub use shift::*;
}
pub use transform::*;
pub use crate::anchor::{Aabb, AabbPoint, Locate};
use std::ops::Range;
use color::{AlphaColor, ColorSpace, OpaqueColor, Srgb};
use glam::{
DAffine2, DAffine3, DMat4, DQuat, DVec2, DVec3, Mat4, USizeVec3, Vec3, Vec3Swizzles, dvec3,
};
use num::complex::Complex64;
use crate::{components::width::Width, utils::resize_preserving_order_with_repeated_indices};
pub trait With {
fn with(mut self, f: impl Fn(&mut Self)) -> Self
where
Self: Sized,
{
f(&mut self);
self
}
}
impl<T> With for T {}
pub trait Discard {
fn discard(&self) {}
}
impl<T> Discard for T {}
pub trait Interpolatable {
fn lerp(&self, target: &Self, t: f64) -> Self;
}
impl Interpolatable for usize {
fn lerp(&self, target: &Self, t: f64) -> Self {
(*self as f32).lerp(&(*target as f32), t) as usize
}
}
impl Interpolatable for f32 {
fn lerp(&self, target: &Self, t: f64) -> Self {
self + (target - self) * t as f32
}
}
impl Interpolatable for f64 {
fn lerp(&self, target: &Self, t: f64) -> Self {
self + (target - self) * t
}
}
impl Interpolatable for DVec3 {
fn lerp(&self, target: &Self, t: f64) -> Self {
self + (target - self) * t
}
}
impl Interpolatable for Vec3 {
fn lerp(&self, target: &Self, t: f64) -> Self {
self + (target - self) * t as f32
}
}
impl Interpolatable for DVec2 {
fn lerp(&self, target: &Self, t: f64) -> Self {
self + (target - self) * t
}
}
impl Interpolatable for DQuat {
fn lerp(&self, target: &Self, t: f64) -> Self {
self.slerp(*target, t)
}
}
impl<CS: ColorSpace> Interpolatable for AlphaColor<CS> {
fn lerp(&self, target: &Self, t: f64) -> Self {
AlphaColor::lerp_rect(*self, *target, t as f32)
}
}
impl<CS: ColorSpace> Interpolatable for OpaqueColor<CS> {
fn lerp(&self, target: &Self, t: f64) -> Self {
OpaqueColor::lerp_rect(*self, *target, t as f32)
}
}
impl Interpolatable for DMat4 {
fn lerp(&self, target: &Self, t: f64) -> Self {
let mut result = DMat4::ZERO;
for i in 0..4 {
for j in 0..4 {
result.col_mut(i)[j] = self.col(i)[j].lerp(&target.col(i)[j], t);
}
}
result
}
}
impl Interpolatable for Mat4 {
fn lerp(&self, other: &Self, t: f64) -> Self {
let t = t as f32;
let mut result = Mat4::ZERO;
for i in 0..4 {
for j in 0..4 {
result.col_mut(i)[j] = self.col(i)[j] + (other.col(i)[j] - self.col(i)[j]) * t;
}
}
result
}
}
impl<T: Interpolatable> Interpolatable for Vec<T> {
fn lerp(&self, target: &Self, t: f64) -> Self {
self.iter().zip(target).map(|(a, b)| a.lerp(b, t)).collect()
}
}
impl<T: Interpolatable, const N: usize> Interpolatable for [T; N] {
fn lerp(&self, target: &Self, t: f64) -> Self {
core::array::from_fn(|i| self[i].lerp(&target[i], t))
}
}
macro_rules! impl_interpolatable_tuple {
($(($T:ident, $s:ident)),*) => {
impl<$($T: Interpolatable),*> Interpolatable for ($($T,)*) {
#[allow(non_snake_case)]
fn lerp(&self, target: &Self, t: f64) -> Self {
let ($($s,)*) = self;
let ($($T,)*) = target;
($($s.lerp($T, t),)*)
}
}
}
}
variadics_please::all_tuples!(impl_interpolatable_tuple, 1, 12, T, S);
impl<T: Opacity + Alignable + Clone> Alignable for Vec<T> {
fn is_aligned(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.is_aligned(b))
}
fn align_with(&mut self, other: &mut Self) {
let len = self.len().max(other.len());
let transparent_repeated = |items: &mut Vec<T>, repeat_idxs: Vec<usize>| {
for idx in repeat_idxs {
items[idx].set_opacity(0.0);
}
};
if self.len() != len {
let (mut items, idxs) = resize_preserving_order_with_repeated_indices(self, len);
transparent_repeated(&mut items, idxs);
*self = items;
}
if other.len() != len {
let (mut items, idxs) = resize_preserving_order_with_repeated_indices(other, len);
transparent_repeated(&mut items, idxs);
*other = items;
}
self.iter_mut()
.zip(other)
.for_each(|(a, b)| a.align_with(b));
}
}
pub trait Alignable: Clone {
fn is_aligned(&self, other: &Self) -> bool;
fn align_with(&mut self, other: &mut Self);
}
impl Alignable for DVec3 {
fn align_with(&mut self, _other: &mut Self) {}
fn is_aligned(&self, _other: &Self) -> bool {
true
}
}
pub trait Opacity {
fn set_opacity(&mut self, opacity: f32) -> &mut Self;
}
impl<T: Opacity, I> Opacity for I
where
for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
{
fn set_opacity(&mut self, opacity: f32) -> &mut Self {
self.into_iter().for_each(|x: &mut T| {
x.set_opacity(opacity);
});
self
}
}
pub trait Partial {
fn get_partial(&self, range: Range<f64>) -> Self;
fn get_partial_closed(&self, range: Range<f64>) -> Self;
}
pub trait Empty {
fn empty() -> Self;
}
pub trait FillColor {
fn fill_color(&self) -> AlphaColor<Srgb>;
fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self;
fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
}
impl<T: FillColor> FillColor for [T] {
fn fill_color(&self) -> color::AlphaColor<color::Srgb> {
self[0].fill_color()
}
fn set_fill_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
self.iter_mut()
.for_each(|x| x.set_fill_color(color).discard());
self
}
fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
self.iter_mut()
.for_each(|x| x.set_fill_opacity(opacity).discard());
self
}
}
pub trait StrokeColor {
fn stroke_color(&self) -> AlphaColor<Srgb>;
fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self;
fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
}
impl<T: StrokeColor> StrokeColor for [T] {
fn stroke_color(&self) -> AlphaColor<Srgb> {
self[0].stroke_color()
}
fn set_stroke_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
self.iter_mut().for_each(|x| {
x.set_stroke_color(color);
});
self
}
fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
self.iter_mut().for_each(|x| {
x.set_stroke_opacity(opacity);
});
self
}
}
pub trait StrokeWidth {
fn stroke_width(&self) -> f32;
fn apply_stroke_func(&mut self, f: impl for<'a> Fn(&'a mut [Width])) -> &mut Self;
fn set_stroke_width(&mut self, width: f32) -> &mut Self {
self.apply_stroke_func(|widths| widths.fill(width.into()))
}
}
impl<T: StrokeWidth> StrokeWidth for [T] {
fn stroke_width(&self) -> f32 {
self[0].stroke_width()
}
fn apply_stroke_func(
&mut self,
f: impl for<'a> Fn(&'a mut [crate::components::width::Width]),
) -> &mut Self {
self.iter_mut().for_each(|x| {
x.apply_stroke_func(&f);
});
self
}
}
pub trait Color: FillColor + StrokeColor {
fn set_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
self.set_fill_color(color);
self.set_stroke_color(color);
self
}
}
impl<T: FillColor + StrokeColor + ?Sized> Color for T {}
pub trait PointsFunc {
fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self;
fn apply_affine2(&mut self, affine: DAffine2) -> &mut Self {
self.apply_point_func(|p| {
let transformed = affine.transform_point2(p.xy());
p.x = transformed.x;
p.y = transformed.y;
});
self
}
fn apply_affine3(&mut self, affine: DAffine3) -> &mut Self {
self.apply_point_func(|p| *p = affine.transform_point3(*p));
self
}
fn apply_point_func(&mut self, f: impl Fn(&mut DVec3)) -> &mut Self {
self.apply_points_func(|points| {
points.iter_mut().for_each(&f);
});
self
}
fn apply_point_map(&mut self, f: impl Fn(DVec3) -> DVec3) -> &mut Self {
self.apply_points_func(|points| {
points.iter_mut().for_each(|p| *p = f(*p));
});
self
}
fn apply_complex_func(&mut self, f: impl Fn(&mut Complex64)) -> &mut Self {
self.apply_point_func(|p| {
let mut c = Complex64::new(p.x, p.y);
f(&mut c);
p.x = c.re;
p.y = c.im;
});
self
}
fn apply_complex_map(&mut self, f: impl Fn(Complex64) -> Complex64) -> &mut Self {
self.apply_complex_func(|p| {
*p = f(*p);
});
self
}
}
impl PointsFunc for DVec3 {
fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self {
f(std::slice::from_mut(self));
self
}
}
impl<T: PointsFunc> PointsFunc for [T] {
fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self {
self.iter_mut()
.for_each(|x| x.apply_points_func(&f).discard());
self
}
}
pub trait AlignSlice<T: transform::ShiftTransformExt>: AsMut<[T]> {
fn align_anchor<A>(&mut self, axis: DVec3, anchor: A) -> &mut Self
where
A: Locate<T> + Clone,
{
let Some(dir) = axis.try_normalize() else {
return self;
};
let Some(point) = self.as_mut().first().map(|x| anchor.locate(x)) else {
return self;
};
self.as_mut().iter_mut().for_each(|x| {
let p = anchor.locate(x);
let v = p - point;
let proj = dir * v.dot(dir);
let closest = point + proj;
let displacement = closest - p;
x.shift(displacement);
});
self
}
fn align(&mut self, axis: DVec3) -> &mut Self
where
T: Aabb,
{
self.align_anchor(axis, AabbPoint::CENTER)
}
}
pub trait ArrangeSlice<T: transform::ShiftTransformExt>: AsMut<[T]> {
fn arrange_with(&mut self, pos_func: impl Fn(usize) -> DVec3)
where
AabbPoint: Locate<T>,
{
self.as_mut().iter_mut().enumerate().for_each(|(i, x)| {
x.move_to(pos_func(i));
});
}
fn arrange_in_y(&mut self, gap: f64)
where
T: Aabb,
AabbPoint: Locate<T>,
{
let Some(mut bbox) = self.as_mut().first().map(|x| x.aabb()) else {
return;
};
self.as_mut().iter_mut().for_each(|x| {
x.move_next_to_padded(bbox.as_slice(), AabbPoint(DVec3::Y), gap);
bbox = x.aabb();
});
}
fn arrange_in_grid(&mut self, cell_cnt: USizeVec3, cell_size: DVec3, gap: DVec3) -> &mut Self
where
AabbPoint: Locate<T>,
{
let pos_func = |idx: usize| {
let x = idx % cell_cnt.x;
let temp = idx / cell_cnt.x;
let y = temp % cell_cnt.y;
let z = temp / cell_cnt.y;
dvec3(x as f64, y as f64, z as f64) * cell_size
+ gap * dvec3(x as f64, y as f64, z as f64)
};
self.arrange_with(pos_func);
self
}
fn arrange_in_cols_with(&mut self, ncols: usize, pos_func: impl Fn(usize, usize) -> DVec3)
where
AabbPoint: Locate<T>,
{
let pos_func = |idx: usize| {
let row = idx / ncols;
let col = idx % ncols;
pos_func(row, col)
};
self.arrange_with(pos_func);
}
fn arrange_in_rows_with(&mut self, nrows: usize, pos_func: impl Fn(usize, usize) -> DVec3)
where
AabbPoint: Locate<T>,
{
let ncols = self.as_mut().len().div_ceil(nrows);
self.arrange_in_cols_with(ncols, pos_func);
}
}
impl<T: transform::ShiftTransformExt, E: AsMut<[T]>> ArrangeSlice<T> for E {}