docvortex_core/
columns.rs1#[derive(Clone)]
4pub struct Column {
5 pub mean: f64,
6 pub hi: f64,
7 pub lo: f64,
8 pub count: usize,
9 pub rows: usize,
10 last_row: usize,
11}
12
13pub struct Columns {
14 pub groups: [Vec<Column>; 3],
15 pub row_count: usize,
16 compensated: bool,
17 valid: bool,
18}
19
20impl Columns {
21 pub fn new(compensated: bool) -> Self {
23 Self {
24 groups: Default::default(),
25 row_count: 0,
26 compensated,
27 valid: true,
28 }
29 }
30
31 pub fn extend(&mut self, rows: &[Vec<(f64, f64)>], tolerance: f64) -> Option<(usize, f64)> {
33 self.extend_rows(rows, tolerance)
34 }
35
36 pub fn extend_refs(&mut self, rows: &[&[(f64, f64)]], tolerance: f64) -> Option<(usize, f64)> {
38 self.extend_rows(rows, tolerance)
39 }
40
41 fn extend_rows<T: AsRef<[(f64, f64)]>>(
43 &mut self,
44 rows: &[T],
45 tolerance: f64,
46 ) -> Option<(usize, f64)> {
47 if !self.valid || !tolerance.is_finite() || tolerance < 0.0 {
48 return None;
49 }
50 for alignment in 0..3 {
51 let clusters = &mut self.groups[alignment];
52 for (offset, fragments) in rows.iter().enumerate() {
53 let row = self.row_count + offset;
54 for &(left, right) in fragments.as_ref() {
55 let anchor = match alignment {
56 0 => left,
57 1 => (left + right) / 2.0,
58 _ => right,
59 };
60 if !left.is_finite() || !right.is_finite() || !anchor.is_finite() {
61 self.valid = false;
62 return None;
63 }
64 if let Some(cluster) = clusters
65 .iter_mut()
66 .find(|c| (anchor - c.mean).abs() <= tolerance)
67 {
68 let t = cluster.hi + anchor;
69 if self.compensated {
70 cluster.lo += if cluster.hi.abs() >= anchor.abs() {
71 (cluster.hi - t) + anchor
72 } else {
73 (anchor - t) + cluster.hi
74 };
75 }
76 cluster.hi = t;
77 cluster.count += 1;
78 let sum = if self.compensated && cluster.lo != 0.0 && cluster.lo.is_finite()
79 {
80 cluster.hi + cluster.lo
81 } else {
82 cluster.hi
83 };
84 cluster.mean = sum / cluster.count as f64;
85 if !cluster.mean.is_finite()
86 || !cluster.hi.is_finite()
87 || !cluster.lo.is_finite()
88 {
89 self.valid = false;
90 return None;
91 }
92 if cluster.last_row != row {
93 cluster.rows += 1;
94 cluster.last_row = row;
95 }
96 } else {
97 clusters.push(Column {
98 mean: anchor,
99 hi: 0.0 + anchor,
100 lo: 0.0,
101 count: 1,
102 rows: 1,
103 last_row: row,
104 });
105 }
106 }
107 }
108 }
109 self.row_count += rows.len();
110 let mut best = (0, 0.0);
111 if self.row_count == 0 {
112 return Some(best);
113 }
114 for clusters in &self.groups {
115 let mut count = 0;
116 let mut minimum: f64 = 1.0;
117 for cluster in clusters {
118 let coverage = cluster.rows as f64 / self.row_count as f64;
119 if coverage >= 0.5 {
120 count += 1;
121 minimum = minimum.min(coverage);
122 }
123 }
124 let result = (count, if count == 0 { 0.0 } else { minimum });
125 if result > best {
126 best = result;
127 }
128 }
129 Some(best)
130 }
131}