use std::cmp::Reverse;
pub(crate) struct Graph<'a> {
pub(crate) sizes: &'a [[f64; 2]],
pub(crate) links: &'a [[u32; 2]],
pub(crate) pinned: &'a [Option<[f64; 2]>],
pub(crate) groups: &'a [Option<u32>],
pub(crate) pads: &'a [[f64; 4]],
}
pub(crate) struct Level {
pub(crate) sizes: Vec<[f64; 2]>,
pub(crate) links: Vec<[u32; 2]>,
pub(crate) pinned: Vec<Option<[f64; 2]>>,
}
pub(crate) fn nested(graph: &Graph<'_>, mut place: impl FnMut(&Level) -> Vec<[f64; 2]>) -> Vec<[f64; 2]> {
let count = graph.sizes.len();
assert!(
graph.pinned.len() == count && graph.groups.len() == count && graph.pads.len() == count,
"a pin, a group, and pads for each vertex"
);
let parent = tree(graph.groups);
let depth = depths(&parent);
let mut holds = vec![false; count];
for &group in parent.iter().flatten() {
holds[group as usize] = true;
}
let mut groups: Vec<usize> = (0..count).filter(|&group| holds[group]).collect();
groups.sort_by_key(|&group| Reverse(depth[group]));
let mut level = vec![0; count];
for (k, &group) in groups.iter().enumerate() {
level[group] = k + 1;
}
let level_of = |vertex: usize| parent[vertex].map_or(0, |group| level[group as usize]);
let members = Runs::new(groups.len() + 1, (0..count).map(|vertex| (level_of(vertex), vertex as u32)));
let lifted: Vec<[u32; 2]> = graph.links.iter().filter_map(|&[from, to]| lift(from, to, &parent, &depth)).collect();
let links = Runs::new(groups.len() + 1, lifted.iter().map(|&link| (level_of(link[0] as usize), link)));
let mut sizes: Vec<[f64; 2]> =
graph.sizes.iter().map(|&[width, height]| [width.max(0.0), height.max(0.0)]).collect();
let mut pins: Vec<Option<[f64; 2]>> =
graph.pinned.iter().map(|pin| pin.filter(|at| at[0].is_finite() && at[1].is_finite())).collect();
let mut centers = vec![[0.0; 2]; count];
let mut middles = vec![[0.0; 2]; count];
let mut local = vec![0_u32; count];
let mut lay = |inside: &[u32], joins: &[[u32; 2]], sizes: &[[f64; 2]], pins: &[Option<[f64; 2]>]| {
for (i, &vertex) in inside.iter().enumerate() {
local[vertex as usize] = i as u32;
}
let level = Level {
sizes: inside.iter().map(|&vertex| sizes[vertex as usize]).collect(),
links: joins.iter().map(|&[from, to]| [local[from as usize], local[to as usize]]).collect(),
pinned: inside.iter().map(|&vertex| pins[vertex as usize]).collect(),
};
place(&level)
};
for (k, &group) in groups.iter().enumerate() {
let inside = members.get(k + 1);
for (&vertex, center) in inside.iter().zip(lay(inside, links.get(k + 1), &sizes, &pins)) {
centers[vertex as usize] = center;
}
let bounds = bounds(inside.iter().map(|&vertex| frame(centers[vertex as usize], sizes[vertex as usize])));
let [left, bottom, right, top] = graph.pads[group];
let grown = [bounds[0] - left, bounds[1] - bottom, bounds[2] + right, bounds[3] + top];
middles[group] = [grown[0].midpoint(grown[2]), grown[1].midpoint(grown[3])];
sizes[group] = [grown[2] - grown[0], grown[3] - grown[1]];
if inside.iter().any(|&vertex| pins[vertex as usize].is_some()) {
pins[group] = Some(middles[group]);
}
}
let top = members.get(0);
for (&vertex, center) in top.iter().zip(lay(top, links.get(0), &sizes, &pins)) {
centers[vertex as usize] = center;
}
let mut shifts = vec![[0.0; 2]; count];
for &group in groups.iter().rev() {
let outer = parent[group].map_or([0.0; 2], |up| shifts[up as usize]);
shifts[group] =
[centers[group][0] + outer[0] - middles[group][0], centers[group][1] + outer[1] - middles[group][1]];
}
centers
.iter()
.zip(&parent)
.map(|(center, group)| {
let shift = group.map_or([0.0; 2], |group| shifts[group as usize]);
[center[0] + shift[0], center[1] + shift[1]]
})
.collect()
}
fn tree(groups: &[Option<u32>]) -> Vec<Option<u32>> {
const NEW: u8 = 0;
const WALKING: u8 = 1;
const DONE: u8 = 2;
let count = groups.len();
let mut parent: Vec<Option<u32>> = groups
.iter()
.enumerate()
.map(|(vertex, group)| group.filter(|&group| (group as usize) < count && group as usize != vertex))
.collect();
let mut state = vec![NEW; count];
let mut walk: Vec<usize> = Vec::new();
for start in 0..count {
let mut at = start;
loop {
if state[at] != NEW {
if state[at] == WALKING {
parent[*walk.last().expect("a walk reaches itself only after a step")] = None;
}
break;
}
state[at] = WALKING;
walk.push(at);
match parent[at] {
Some(group) => at = group as usize,
None => break,
}
}
for vertex in walk.drain(..) {
state[vertex] = DONE;
}
}
parent
}
fn depths(parent: &[Option<u32>]) -> Vec<u32> {
let mut depth = vec![u32::MAX; parent.len()];
let mut walk: Vec<usize> = Vec::new();
for start in 0..parent.len() {
let mut at = start;
while depth[at] == u32::MAX {
walk.push(at);
match parent[at] {
Some(group) => at = group as usize,
None => break,
}
}
let mut next = if depth[at] == u32::MAX { 0 } else { depth[at] + 1 };
while let Some(vertex) = walk.pop() {
depth[vertex] = next;
next += 1;
}
}
depth
}
fn lift(from: u32, to: u32, parent: &[Option<u32>], depth: &[u32]) -> Option<[u32; 2]> {
if from as usize >= parent.len() || to as usize >= parent.len() {
return None;
}
let up = |vertex: usize| parent[vertex].expect("a held vertex has a group") as usize;
let (mut from, mut to) = (from as usize, to as usize);
while depth[from] > depth[to] {
from = up(from);
}
while depth[to] > depth[from] {
to = up(to);
}
while parent[from] != parent[to] {
(from, to) = (up(from), up(to));
}
(from != to).then_some([from as u32, to as u32])
}
pub(crate) fn frame(center: [f64; 2], size: [f64; 2]) -> [f64; 4] {
let half = [size[0] / 2.0, size[1] / 2.0];
[center[0] - half[0], center[1] - half[1], center[0] + half[0], center[1] + half[1]]
}
pub(crate) fn bounds(boxes: impl Iterator<Item = [f64; 4]>) -> [f64; 4] {
boxes.reduce(super::rect::union).unwrap_or([0.0; 4])
}
pub(crate) struct Runs<T> {
offsets: Vec<usize>,
pub(crate) items: Vec<T>,
}
impl<T: Copy + Default> Runs<T> {
pub(crate) fn new(buckets: usize, keyed: impl Iterator<Item = (usize, T)> + Clone) -> Runs<T> {
let mut offsets = vec![0; buckets + 1];
for (key, _) in keyed.clone() {
offsets[key] += 1;
}
let mut total = 0;
for offset in &mut offsets {
(*offset, total) = (total, total + *offset);
}
let mut items = vec![T::default(); total];
let mut fill = offsets.clone();
for (key, item) in keyed {
items[fill[key]] = item;
fill[key] += 1;
}
Runs { offsets, items }
}
}
impl<T> Runs<T> {
pub(crate) fn len(&self) -> usize {
self.offsets.len() - 1
}
pub(crate) fn get(&self, k: usize) -> &[T] {
&self.items[self.offsets[k]..self.offsets[k + 1]]
}
pub(crate) fn get_mut(&mut self, k: usize) -> &mut [T] {
&mut self.items[self.offsets[k]..self.offsets[k + 1]]
}
}
impl<T: Ord> Runs<T> {
pub(crate) fn sort_each(&mut self) {
for k in 0..self.len() {
self.get_mut(k).sort_unstable();
}
}
}