Skip to main content

rusterize/rasterization/
pixel_functions.rs

1use crate::prelude::*;
2use ndarray::ArrayViewMut2;
3use num_traits::Num;
4use std::{ops::AddAssign, str::FromStr};
5
6/// Supported functions to apply to overlapping pixels.
7#[derive(Clone)]
8pub enum PixelFunction {
9    Sum,
10    First,
11    Last,
12    Min,
13    Max,
14    Count,
15    Any,
16}
17
18impl FromStr for PixelFunction {
19    type Err = RusterizeError;
20
21    fn from_str(s: &str) -> RusterizeResult<Self> {
22        match s {
23            "sum" => Ok(Self::Sum),
24            "first" => Ok(Self::First),
25            "last" => Ok(Self::Last),
26            "min" => Ok(Self::Min),
27            "max" => Ok(Self::Max),
28            "count" => Ok(Self::Count),
29            "any" => Ok(Self::Any),
30            _ => Err(RusterizeError::ValueError("Unknown pixel function")),
31        }
32    }
33}
34
35impl PixelFunction {
36    pub(crate) fn to_function<N>(&self) -> PixelFn<N>
37    where
38        N: Num + Copy + AddAssign + PartialOrd + NaNAware,
39    {
40        match self {
41            Self::Sum => sum_values,
42            Self::First => first_values,
43            Self::Last => last_values,
44            Self::Min => min_values,
45            Self::Max => max_values,
46            Self::Count => count_values,
47            Self::Any => any_values,
48        }
49    }
50}
51
52/// On-demand function for overlapping pixels.
53pub(crate) type PixelFn<N> = fn(&mut ArrayViewMut2<N>, usize, usize, N, N);
54
55/// Sum values or NaN/background.
56fn sum_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, value: N, bg: N)
57where
58    N: Num + AddAssign + NaNAware + Copy,
59{
60    if array[[y, x]] == bg || array[[y, x]].is_nan() || value.is_nan() {
61        array[[y, x]] = value;
62    } else {
63        array[[y, x]] += value;
64    }
65}
66
67/// Set first value only if currently NaN/background.
68fn first_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, value: N, bg: N)
69where
70    N: Num + NaNAware + Copy,
71{
72    if array[[y, x]] == bg || array[[y, x]].is_nan() {
73        array[[y, x]] = value;
74    }
75}
76
77/// Always set last value.
78fn last_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, value: N, _bg: N)
79where
80    N: Num + Copy,
81{
82    array[[y, x]] = value;
83}
84
85/// Set value if smaller than current.
86fn min_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, value: N, bg: N)
87where
88    N: Num + NaNAware + PartialOrd + Copy,
89{
90    if array[[y, x]] == bg || array[[y, x]].is_nan() || array[[y, x]] > value {
91        array[[y, x]] = value;
92    }
93}
94
95/// Set value if larger than current.
96fn max_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, value: N, bg: N)
97where
98    N: Num + NaNAware + PartialOrd + Copy,
99{
100    if array[[y, x]] == bg || array[[y, x]].is_nan() || array[[y, x]] < value {
101        array[[y, x]] = value;
102    }
103}
104
105/// Count values at position.
106fn count_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, _value: N, bg: N)
107where
108    N: Num + AddAssign + NaNAware + Copy,
109{
110    if array[[y, x]] == bg || array[[y, x]].is_nan() {
111        array[[y, x]] = N::one();
112    } else {
113        array[[y, x]] += N::one();
114    }
115}
116
117/// Mark presence.
118fn any_values<N>(array: &mut ArrayViewMut2<N>, y: usize, x: usize, _value: N, _bg: N)
119where
120    N: Num,
121{
122    array[[y, x]] = N::one();
123}