• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.52
/operators/src/processing/temporal_raster_aggregation/aggregators.rs
1
use crate::util::Result;
2
use geoengine_datatypes::raster::{GridOrEmpty2D, MapIndexedElements, Pixel};
3
use std::marker::PhantomData;
4

5
/// An aggregator that uses input values to produce an inner state that can be used to produce an output aggregate value.
6
pub trait TemporalRasterPixelAggregator<P: Pixel>: Send + Clone {
7
    type PixelState: Send + Sync + Copy + Clone + Default;
8

9
    /// Tell whether the aggregator ignores incoming no data values
10
    const IGNORE_NO_DATA: bool;
11

12
    /// Initialize the state from the first value
13
    fn initialize(value: Option<P>) -> Option<Self::PixelState>;
14

15
    /// Produce a new state from the current state and new value
16
    fn aggregate(state: Option<Self::PixelState>, value: Option<P>) -> Option<Self::PixelState>;
17

18
    /// Produce a tile from the state container
19
    fn into_grid(state: GridOrEmpty2D<Self::PixelState>) -> Result<GridOrEmpty2D<P>>;
20
}
21

22
/// A method to process to pixel values inside the aggregator.
23
trait BinaryOperation<P: Pixel>: Send + Clone {
24
    fn unit(value: P) -> P {
182✔
25
        value
182✔
26
    }
182✔
27

28
    fn op(state: P, value: P) -> P;
29
}
30

31
#[derive(Clone)]
×
32
pub struct OpPixelAggregator<Op> {
33
    op: PhantomData<Op>,
34
}
35

36
impl<P: Pixel, Op: BinaryOperation<P>> TemporalRasterPixelAggregator<P> for OpPixelAggregator<Op> {
37
    type PixelState = P;
38

39
    const IGNORE_NO_DATA: bool = false;
40

41
    fn initialize(value: Option<P>) -> Option<Self::PixelState> {
156✔
42
        value.map(Op::unit)
156✔
43
    }
156✔
44

45
    fn aggregate(state: Option<Self::PixelState>, value: Option<P>) -> Option<Self::PixelState> {
46
        match (state, value) {
144✔
47
            (Some(state), Some(value)) => Some(Op::op(state, value)),
144✔
48
            _ => None,
×
49
        }
50
    }
144✔
51

52
    fn into_grid(state: GridOrEmpty2D<Self::PixelState>) -> Result<GridOrEmpty2D<P>> {
29✔
53
        Ok(state)
29✔
54
    }
29✔
55
}
56

57
#[derive(Clone)]
×
58
pub struct OpPixelAggregatorIngoringNoData<Op> {
59
    op: PhantomData<Op>,
60
}
61

62
impl<P: Pixel, Op: BinaryOperation<P>> TemporalRasterPixelAggregator<P>
63
    for OpPixelAggregatorIngoringNoData<Op>
64
{
65
    type PixelState = P;
66

67
    const IGNORE_NO_DATA: bool = true;
68

69
    fn initialize(value: Option<P>) -> Option<Self::PixelState> {
72✔
70
        value.map(Op::unit)
72✔
71
    }
72✔
72

73
    fn aggregate(state: Option<Self::PixelState>, value: Option<P>) -> Option<Self::PixelState> {
74
        match (state, value) {
48✔
75
            (Some(state), Some(value)) => Some(Op::op(state, value)),
40✔
76
            (Some(state), None) => Some(state),
4✔
77
            (None, Some(value)) => Some(Op::unit(value)),
4✔
78
            _ => None,
×
79
        }
80
    }
48✔
81

82
    fn into_grid(state: GridOrEmpty2D<Self::PixelState>) -> Result<GridOrEmpty2D<P>> {
12✔
83
        Ok(state)
12✔
84
    }
12✔
85
}
86

87
#[derive(Clone)]
×
88
pub struct Sum;
89

90
impl<P: Pixel> BinaryOperation<P> for Sum {
91
    fn op(state: P, value: P) -> P {
52✔
92
        state.saturating_add(value)
52✔
93
    }
52✔
94
}
95

96
pub type SumPixelAggregator = OpPixelAggregator<Sum>;
97
pub type SumPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<Sum>;
98

99
#[derive(Clone)]
×
100
pub struct Count;
101

102
impl<P: Pixel> BinaryOperation<P> for Count {
103
    fn unit(_value: P) -> P {
40✔
104
        P::one()
40✔
105
    }
40✔
106

107
    fn op(state: P, _value: P) -> P {
28✔
108
        state.saturating_add(P::one())
28✔
109
    }
28✔
110
}
111

112
pub type CountPixelAggregator = OpPixelAggregator<Count>;
113
pub type CountPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<Count>;
114

115
#[derive(Clone)]
×
116
pub struct Min;
117

118
impl<P: Pixel> BinaryOperation<P> for Min {
119
    fn op(state: P, value: P) -> P {
24✔
120
        if state < value {
24✔
121
            state
12✔
122
        } else {
123
            value
12✔
124
        }
125
    }
24✔
126
}
127

128
pub type MinPixelAggregator = OpPixelAggregator<Min>;
129
pub type MinPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<Min>;
130

131
#[derive(Clone)]
×
132
pub struct Max;
133

134
impl<P: Pixel> BinaryOperation<P> for Max {
135
    fn op(state: P, value: P) -> P {
72✔
136
        if state > value {
72✔
137
            state
36✔
138
        } else {
139
            value
36✔
140
        }
141
    }
72✔
142
}
143

144
pub type MaxPixelAggregator = OpPixelAggregator<Max>;
145
pub type MaxPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<Max>;
146

147
#[derive(Clone)]
×
148
pub struct First;
149

150
impl<P: Pixel> BinaryOperation<P> for First {
151
    fn op(state: P, _value: P) -> P {
4✔
152
        state
4✔
153
    }
4✔
154
}
155

156
pub type FirstPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<First>;
157

158
#[derive(Clone)]
×
159
pub struct Last;
160

161
impl<P: Pixel> BinaryOperation<P> for Last {
162
    fn op(_state: P, value: P) -> P {
4✔
163
        value
4✔
164
    }
4✔
165
}
166

167
pub type LastPixelAggregatorIngoringNoData = OpPixelAggregatorIngoringNoData<Last>;
168

169
#[derive(Clone)]
×
170
pub struct MeanPixelAggregator;
171

172
impl<P: Pixel> TemporalRasterPixelAggregator<P> for MeanPixelAggregator {
173
    type PixelState = (f64, usize);
174

175
    const IGNORE_NO_DATA: bool = false;
176

177
    fn initialize(value: Option<P>) -> Option<Self::PixelState> {
6✔
178
        value.map(|v| (v.as_(), 1))
6✔
179
    }
6✔
180

181
    fn aggregate(state: Option<Self::PixelState>, value: Option<P>) -> Option<Self::PixelState> {
182
        match (state, value) {
×
183
            (Some(state), Some(value)) => Some(mean_of_state_and_value(state, value)),
×
184
            _ => None,
×
185
        }
186
    }
×
187

188
    fn into_grid(state: GridOrEmpty2D<Self::PixelState>) -> Result<GridOrEmpty2D<P>> {
2✔
189
        Ok(state.map_indexed_elements(|_index: usize, (mean, _count)| P::from_(mean)))
6✔
190
    }
2✔
191
}
192

193
#[derive(Clone)]
×
194
pub struct MeanPixelAggregatorIngoringNoData;
195

196
impl<P: Pixel> TemporalRasterPixelAggregator<P> for MeanPixelAggregatorIngoringNoData {
197
    type PixelState = (f64, usize);
198

199
    const IGNORE_NO_DATA: bool = true;
200

201
    fn initialize(value: Option<P>) -> Option<Self::PixelState> {
13✔
202
        value.map(|v| (v.as_(), 1))
13✔
203
    }
13✔
204

205
    fn aggregate(state: Option<Self::PixelState>, value: Option<P>) -> Option<Self::PixelState> {
206
        match (state, value) {
6✔
207
            (Some(state), Some(value)) => Some(mean_of_state_and_value(state, value)),
4✔
208
            (Some(state), None) => Some(state),
1✔
209
            (None, Some(value)) => Self::initialize(Some(value)),
1✔
210
            _ => None,
×
211
        }
212
    }
6✔
213

214
    fn into_grid(state: GridOrEmpty2D<Self::PixelState>) -> Result<GridOrEmpty2D<P>> {
2✔
215
        Ok(state.map_indexed_elements(|_index: usize, (mean, _count)| P::from_(mean)))
12✔
216
    }
2✔
217
}
218

219
fn mean_of_state_and_value<P: Pixel>(
4✔
220
    (mean_value, count): (f64, usize),
4✔
221
    new_value: P,
4✔
222
) -> (f64, usize) {
4✔
223
    let new_value: f64 = new_value.as_();
4✔
224
    let new_count = count + 1;
4✔
225
    let delta: f64 = new_value - mean_value;
4✔
226
    let new_state_value = mean_value + delta / (new_count as f64);
4✔
227
    (new_state_value, new_count)
4✔
228
}
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc