use num_traits::{AsPrimitive, Euclid, FromPrimitive, Signed};
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default)]
pub enum EdgeMode {
#[default]
Clamp = 0,
KernelClip = 1,
Wrap = 2,
Reflect = 3,
Reflect101 = 4,
}
impl From<usize> for EdgeMode {
fn from(value: usize) -> Self {
return match value {
0 => EdgeMode::Clamp,
1 => EdgeMode::KernelClip,
2 => EdgeMode::Wrap,
3 => EdgeMode::Reflect,
4 => EdgeMode::Reflect101,
_ => {
panic!("Unknown edge mode for value: {}", value);
}
};
}
}
#[inline(always)]
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();
return 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_();
}
return i.as_();
}
#[macro_export]
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
}
}};
}
#[macro_export]
macro_rules! clamp_edge {
($edge_mode:expr, $value:expr, $min:expr, $max:expr) => {{
match $edge_mode {
EdgeMode::Clamp | EdgeMode::KernelClip => {
(std::cmp::min(std::cmp::max($value, $min), $max) as u32) as usize
}
EdgeMode::Wrap => {
let cx = $value.rem_euclid($max);
cx as usize
}
EdgeMode::Reflect => {
let cx = reflect_index($value, $max);
cx as usize
}
EdgeMode::Reflect101 => {
let cx = reflect_101!($value, $max);
cx as usize
}
}
}};
}