use num_traits::{AsPrimitive, Euclid, FromPrimitive, Signed};
use std::ops::Index;
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default)]
pub enum EdgeMode {
#[default]
Clamp = 0,
Wrap = 1,
Reflect = 2,
Reflect101 = 3,
Constant = 4,
}
impl From<usize> for EdgeMode {
fn from(value: usize) -> Self {
match value {
0 => EdgeMode::Clamp,
1 => EdgeMode::Wrap,
2 => EdgeMode::Reflect,
3 => EdgeMode::Reflect101,
4 => EdgeMode::Constant,
_ => {
panic!("Unknown edge mode for value: {}", value);
}
}
}
}
#[inline]
pub(crate) fn reflect_index<
T: Copy
+ 'static
+ PartialOrd
+ PartialEq
+ std::ops::Sub<Output = T>
+ std::ops::Mul<Output = T>
+ Euclid
+ FromPrimitive
+ Signed
+ AsPrimitive<usize>,
>(
i: T,
n: T,
) -> usize
where
i64: AsPrimitive<T>,
{
let i = (i - n).rem_euclid(&(2i64.as_() * n));
let i = (i - n).abs();
i.as_()
}
#[inline(always)]
#[allow(dead_code)]
pub(crate) fn reflect_index_101<
T: Copy
+ 'static
+ PartialOrd
+ PartialEq
+ std::ops::Sub<Output = T>
+ std::ops::Mul<Output = T>
+ Euclid
+ FromPrimitive
+ Signed
+ AsPrimitive<usize>
+ Ord,
>(
i: T,
n: T,
) -> usize
where
i64: AsPrimitive<T>,
{
if i < T::from_i32(0i32).unwrap() {
let i = (i - n).rem_euclid(&(2i64.as_() * n));
let i = (i - n).abs();
return (i + T::from_i32(1).unwrap()).min(n).as_();
}
if i > n {
let i = (i - n).rem_euclid(&(2i64.as_() * n));
let i = (i - n).abs();
return (i - T::from_i32(1i32).unwrap())
.max(T::from_i32(0i32).unwrap())
.as_();
}
i.as_()
}
macro_rules! reflect_101 {
($i:expr, $n:expr) => {{
if $i < 0 {
let i = ($i - $n).rem_euclid(2i64 * $n as i64);
let i = (i - $n).abs();
(i + 1).min($n) as usize
} else if $i > $n {
let i = ($i - $n).rem_euclid(2i64 * $n as i64);
let i = (i - $n).abs();
(i - 1).max(0) as usize
} else {
$i as usize
}
}};
}
pub(crate) use reflect_101;
macro_rules! clamp_edge {
($edge_mode:expr, $value:expr, $min:expr, $max:expr) => {{
match $edge_mode {
EdgeMode::Clamp | EdgeMode::Constant => {
(std::cmp::min(std::cmp::max($value, $min), $max) as u32) as usize
}
EdgeMode::Wrap => {
if $value < $min || $value > $max {
$value.rem_euclid($max + 1) as usize
} else {
$value as usize
}
}
EdgeMode::Reflect => {
let cx = reflect_index($value, $max);
cx as usize
}
EdgeMode::Reflect101 => {
let cx = reflect_101!($value, $max);
cx as usize
}
}
}};
}
pub(crate) use clamp_edge;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
pub struct Scalar {
pub v0: f64,
pub v1: f64,
pub v2: f64,
pub v3: f64,
}
impl Scalar {
pub fn new(v0: f64, v1: f64, v2: f64, v3: f64) -> Self {
Self { v0, v1, v2, v3 }
}
pub fn dup(v: f64) -> Self {
Scalar::new(v, v, v, v)
}
}
impl Default for Scalar {
fn default() -> Self {
Self::new(0.0, 0.0, 0.0, 0.0)
}
}
impl Index<usize> for Scalar {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.v0,
1 => &self.v1,
2 => &self.v2,
3 => &self.v3,
_ => {
unimplemented!("Index out of bounds: {}", index);
}
}
}
}