use super::*;
pub(in crate::layout::drawing) struct Rows {
extent: Bbox,
placed: Vec<(Side, f64, (f64, f64))>,
obstacles: Vec<Bbox>,
}
impl Rows {
pub(super) fn new(extent: Bbox) -> Rows {
Rows {
extent,
placed: Vec::new(),
obstacles: Vec::new(),
}
}
pub(super) fn obstruct_texts(&mut self, nodes: &[PlacedNode]) {
for n in nodes.iter().filter(|n| n.kind == NodeKind::Text) {
self.obstacles
.push(Bbox::extent_of(std::slice::from_ref(n), |_| true));
}
}
pub fn seat(&mut self, side: Side, interval: (f64, f64), pinned: Option<f64>) -> f64 {
let off = pinned.unwrap_or_else(|| {
(0..)
.map(|k| DIM_OFFSET + k as f64 * DIM_PITCH)
.find(|cand| {
let row_clash = self.placed.iter().any(|(s, o, iv)| {
*s == side
&& (o - cand).abs() < DIM_PITCH - 1e-6
&& iv.0 < interval.1 - 1e-6
&& iv.1 > interval.0 + 1e-6
});
!row_clash && !self.blocked(side, *cand, interval)
})
.expect("an offset frees up")
});
self.placed.push((side, off, interval));
self.line_at(side, off)
}
fn line_at(&self, side: Side, off: f64) -> f64 {
match side {
Side::Bottom => self.extent.max_y + off,
Side::Top => self.extent.min_y - off,
Side::Right => self.extent.max_x + off,
Side::Left => self.extent.min_x - off,
}
}
fn blocked(&self, side: Side, off: f64, interval: (f64, f64)) -> bool {
let line_c = self.line_at(side, off);
let (lo, hi) = (line_c - 14.0, line_c + EXT_OVERSHOOT + 1.0);
let band = match side {
Side::Top | Side::Bottom => Bbox {
min_x: interval.0,
max_x: interval.1,
min_y: lo,
max_y: hi,
},
Side::Left | Side::Right => Bbox {
min_x: lo,
max_x: hi,
min_y: interval.0,
max_y: interval.1,
},
};
self.obstacles.iter().any(|o| o.overlaps(band))
}
}