1use crate::geometry::Box4;
4
5fn x_overlap(a: Box4, b: Box4) -> f64 {
7 let length = a[2].min(b[2]) - a[0].max(b[0]);
8 let smaller = (a[2] - a[0]).min(b[2] - b[0]);
9 if smaller > 0.0 {
10 (if length > 0.0 { length } else { 0.0 }) / smaller
11 } else {
12 0.0
13 }
14}
15
16pub fn title_gaps(
18 records: Vec<(usize, Option<usize>, Box4, f64, bool)>,
19) -> Option<Vec<(Option<f64>, Option<f64>)>> {
20 if records.iter().any(|r| {
21 r.2.iter().any(|v| !v.is_finite())
22 || !r.3.is_finite()
23 || !(r.2[2] - r.2[0]).is_finite()
24 || !(r.2[1] + r.2[3]).is_finite()
25 }) {
26 return None;
27 }
28 let centers: Vec<_> = records.iter().map(|r| (r.2[1] + r.2[3]) / 2.0).collect();
29 let mut output = Vec::with_capacity(records.len());
30 for (i, a) in records.iter().enumerate() {
31 let (mut above, mut below): (Option<f64>, Option<f64>) = (None, None);
32 for (j, b) in records.iter().enumerate() {
33 if a.0 == b.0 || x_overlap(a.2, b.2) < 0.1 || (a.1.is_some() && a.1 == b.1) {
34 continue;
35 }
36 let (first, second, target) = if centers[j] < centers[i] {
37 (b, a, &mut above)
38 } else if centers[j] > centers[i] {
39 (a, b, &mut below)
40 } else {
41 continue;
42 };
43 let gap = if first.4 {
44 (second.2[1] - first.2[3]).max(-0.25 * first.3)
45 } else {
46 second.2[1] - (first.2[1] + first.3)
47 };
48 if !gap.is_finite() {
49 return None;
50 }
51 let gap = if gap > 0.0 { gap } else { 0.0 };
52 if target.is_none_or(|previous| gap < previous) {
53 *target = Some(gap);
54 }
55 }
56 output.push((above, below));
57 }
58 Some(output)
59}
60
61pub fn line_neighbors(
63 records: Vec<(usize, Box4, f64, f64)>,
64) -> Option<Vec<(Option<usize>, Option<usize>)>> {
65 if records.iter().any(|r| {
66 r.1.iter().any(|v| !v.is_finite())
67 || !r.2.is_finite()
68 || !r.3.is_finite()
69 || !(r.1[2] - r.1[0]).is_finite()
70 }) {
71 return None;
72 }
73 let mut output = Vec::with_capacity(records.len());
74 for a in &records {
75 let (mut above, mut below): (Option<usize>, Option<usize>) = (None, None);
76 for (j, b) in records.iter().enumerate() {
77 if a.0 == b.0 {
78 continue;
79 }
80 let height = a.2.max(b.2);
81 let shift = (b.3 - a.3).abs();
82 if !shift.is_finite() || !(2.0 * height.max(1.0)).is_finite() {
83 return None;
84 }
85 if !(x_overlap(a.1, b.1) >= 0.35 || (a.1[0] - b.1[0]).abs() <= 2.0 * height.max(1.0))
86 || shift < 2.0_f64.max(0.6 * a.2)
87 {
88 continue;
89 }
90 if b.3 < a.3 && above.is_none_or(|k| b.3 > records[k].3) {
91 above = Some(j);
92 }
93 if b.3 > a.3 && below.is_none_or(|k| b.3 < records[k].3) {
94 below = Some(j);
95 }
96 }
97 output.push((above, below));
98 }
99 Some(output)
100}
101
102#[derive(Debug)]
103struct Group {
104 order: Vec<usize>,
105 lows: Vec<f64>,
106 maxima: Vec<f64>,
107 width: usize,
108}
109
110#[derive(Debug)]
111pub struct IntervalIndex {
112 bounds: Vec<(f64, f64)>,
113 group_ids: Vec<usize>,
114 groups: Vec<Group>,
115}
116
117impl IntervalIndex {
118 pub fn new(bounds: Vec<(f64, f64)>, group_ids: Vec<usize>) -> Option<Self> {
120 if bounds.len() != group_ids.len()
121 || bounds
122 .iter()
123 .any(|(a, b)| !a.is_finite() || !b.is_finite() || a > b)
124 || group_ids.iter().any(|g| *g >= bounds.len())
125 {
126 return None;
127 }
128 let count = group_ids.iter().max().map_or(0, |g| g + 1);
129 let mut members = vec![Vec::new(); count];
130 for (i, &group) in group_ids.iter().enumerate() {
131 members[group].push(i);
132 }
133 let mut groups = Vec::with_capacity(count);
134 for mut order in members {
135 order.sort_by(|a, b| {
136 bounds[*a]
137 .0
138 .partial_cmp(&bounds[*b].0)
139 .unwrap()
140 .then(a.cmp(b))
141 });
142 let width = order.len().max(1).next_power_of_two();
143 let mut maxima = vec![f64::NEG_INFINITY; 2 * width];
144 for (position, &index) in order.iter().enumerate() {
145 maxima[width + position] = bounds[index].1;
146 }
147 for node in (1..width).rev() {
148 maxima[node] = maxima[2 * node].max(maxima[2 * node + 1]);
149 }
150 let lows = order.iter().map(|i| bounds[*i].0).collect();
151 groups.push(Group {
152 order,
153 lows,
154 maxima,
155 width,
156 });
157 }
158 Some(Self {
159 bounds,
160 group_ids,
161 groups,
162 })
163 }
164
165 pub fn query(&self, index: usize) -> Vec<usize> {
167 let (low, high) = self.bounds[index];
168 let group = &self.groups[self.group_ids[index]];
169 let end = group.lows.partition_point(|value| *value <= high);
170 let mut stack = vec![(1, 0, group.width)];
171 let mut result = Vec::new();
172 while let Some((node, left, right)) = stack.pop() {
173 if left >= end || group.maxima[node] < low {
174 continue;
175 }
176 if right - left == 1 {
177 let other = group.order[left];
178 if other > index {
179 result.push(other);
180 }
181 } else {
182 let middle = (left + right) / 2;
183 stack.push((2 * node + 1, middle, right));
184 stack.push((2 * node, left, middle));
185 }
186 }
187 result.sort_unstable();
188 result
189 }
190
191 pub fn rows(&self, start: usize, count: usize, budget: usize) -> Vec<Vec<usize>> {
193 let mut result = Vec::new();
194 let mut total = 0;
195 for index in start..start.saturating_add(count).min(self.bounds.len()) {
196 let row = self.query(index);
197 total += row.len();
198 result.push(row);
199 if total >= budget {
200 break;
201 }
202 }
203 result
204 }
205}
206
207pub struct BaselineGeometry {
209 index: IntervalIndex,
210 boxes: Vec<Box4>,
211 heights: Vec<f64>,
212 sources: Vec<Option<Box4>>,
213}
214
215fn same_baseline(a: Box4, ah: f64, b: Box4, bh: f64) -> bool {
217 let h = ah.max(bh);
218 if ah.min(bh) <= 0.0 || h / ah.min(bh) > 1.35 {
219 return false;
220 }
221 let overlap = 0.0_f64.max(a[3].min(b[3]) - a[1].max(b[1]));
222 let shorter = 0.1_f64.max((a[3] - a[1]).min(b[3] - b[1]));
223 if overlap / shorter < 0.7 && (a[3] - b[3]).abs() > 0.25 * h {
224 return false;
225 }
226 let (left, right) = if a[0] <= b[0] { (a, b) } else { (b, a) };
227 let gap = right[0] - left[2];
228 gap >= -0.25 * h && gap <= 3.0_f64.max(0.75 * h)
229}
230
231fn safe_box(b: &Box4) -> bool {
233 b.iter().all(|v| v.is_finite() && v.abs() <= 1e100) && b[2] > b[0] && b[3] > b[1]
234}
235
236impl BaselineGeometry {
237 pub fn new(
239 bounds: Vec<(f64, f64)>,
240 groups: Vec<usize>,
241 boxes: Vec<Box4>,
242 heights: Vec<f64>,
243 sources: Vec<Option<Box4>>,
244 ) -> Option<Self> {
245 let n = bounds.len();
246 if boxes.len() != n
247 || heights.len() != n
248 || sources.len() != n
249 || boxes.iter().any(|b| !safe_box(b))
250 || heights.iter().any(|h| !h.is_finite() || h.abs() > 1e100)
251 || sources.iter().flatten().any(|b| !safe_box(b))
252 {
253 return None;
254 }
255 Some(Self {
256 index: IntervalIndex::new(bounds, groups)?,
257 boxes,
258 heights,
259 sources,
260 })
261 }
262
263 fn accepts(&self, i: usize, j: usize) -> bool {
265 let (a, b, ah, bh) = (
266 self.boxes[i],
267 self.boxes[j],
268 self.heights[i],
269 self.heights[j],
270 );
271 if same_baseline(a, ah, b, bh) {
272 return true;
273 }
274 if let (Some(sa), Some(sb)) = (self.sources[i], self.sources[j]) {
275 if same_baseline(sa, sa[3] - sa[1], sb, sb[3] - sb[1]) {
276 return true;
277 }
278 }
279 let h = ah.max(bh);
280 let overlap = 0.0_f64.max(a[3].min(b[3]) - a[1].max(b[1]));
281 let smaller = 0.1_f64.max((a[3] - a[1]).min(b[3] - b[1]));
282 if overlap / smaller < 0.7 || ((a[1] + a[3]) / 2.0 - (b[1] + b[3]) / 2.0).abs() > 0.5 * h {
283 return false;
284 }
285 let (left, right) = if a[0] <= b[0] { (a, b) } else { (b, a) };
286 let gap = right[0] - left[2];
287 gap >= -0.15 * h && gap <= 0.75
288 }
289
290 pub fn rows(&self, start: usize, count: usize, budget: usize) -> Vec<Vec<usize>> {
292 let mut output = Vec::new();
293 let mut total = 0;
294 for i in start..start.saturating_add(count).min(self.boxes.len()) {
295 let row: Vec<_> = self
296 .index
297 .query(i)
298 .into_iter()
299 .filter(|j| self.accepts(i, *j))
300 .collect();
301 total += row.len();
302 output.push(row);
303 if total >= budget {
304 break;
305 }
306 }
307 output
308 }
309}