petaplot_core/lod/
builder.rs1use crate::compute::simd::{reduce_min_max_chunk, reduce_min_max_pairs};
2use crate::lod::pyramid::{LodLevel, LodPyramid, DEFAULT_LOD_FACTOR};
3
4pub struct LodBuilder {
6 factor: usize,
7 min_top_samples: usize,
8}
9
10impl Default for LodBuilder {
11 fn default() -> Self {
12 Self {
13 factor: DEFAULT_LOD_FACTOR,
14 min_top_samples: 100,
15 }
16 }
17}
18
19impl LodBuilder {
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn with_factor(mut self, factor: usize) -> Self {
25 self.factor = factor.max(2);
26 self
27 }
28
29 pub fn with_min_top_samples(mut self, min_top_samples: usize) -> Self {
30 self.min_top_samples = min_top_samples.max(1);
31 self
32 }
33
34 pub fn build_from_slice(&self, raw_data: &[f32]) -> LodPyramid {
36 let total_samples = raw_data.len();
37 let mut pyramid = LodPyramid::new(total_samples, self.factor);
38
39 if raw_data.is_empty() {
40 return pyramid;
41 }
42
43 let level_0_pairs = reduce_min_max_chunk(raw_data, self.factor);
45 pyramid.levels.push(LodLevel {
46 level_index: 0,
47 step_factor: self.factor,
48 pairs: level_0_pairs,
49 });
50
51 let mut current_level_index = 1;
53 let mut current_step_factor = self.factor * self.factor;
54
55 while let Some(prev_level) = pyramid.levels.last() {
56 if prev_level.pairs.len() <= self.min_top_samples {
57 break;
58 }
59
60 let next_pairs = reduce_min_max_pairs(&prev_level.pairs, self.factor);
61 if next_pairs.is_empty() {
62 break;
63 }
64
65 pyramid.levels.push(LodLevel {
66 level_index: current_level_index,
67 step_factor: current_step_factor,
68 pairs: next_pairs,
69 });
70
71 current_level_index += 1;
72 current_step_factor *= self.factor;
73 }
74
75 pyramid
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_lod_builder_pyramid_generation() {
85 let raw_data: Vec<f32> = (0..100_000).map(|i| (i as f32).sin()).collect();
86
87 let builder = LodBuilder::new().with_factor(10).with_min_top_samples(20);
88 let pyramid = builder.build_from_slice(&raw_data);
89
90 assert!(pyramid.num_levels() >= 3);
91 assert_eq!(pyramid.levels[0].pairs.len(), 10_000);
92 assert_eq!(pyramid.levels[1].pairs.len(), 1_000);
93 assert_eq!(pyramid.levels[2].pairs.len(), 100);
94 }
95}