1#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
20pub enum Direction {
21 #[default]
23 LeftRight,
24 TopBottom,
26}
27
28#[derive(Clone, Debug, Default)]
31pub struct GraphNode {
32 pub w: f64,
33 pub h: f64,
34 pub lane: Option<usize>,
36 pub pin: (Option<f64>, Option<f64>),
38}
39
40#[derive(Clone, Debug, Default)]
44pub struct GraphEdge {
45 pub from: usize,
46 pub to: usize,
47 pub label_w: Option<f64>,
48}
49
50#[derive(Clone, Debug)]
52pub struct LayeredParams {
53 pub direction: Direction,
54 pub lanes: usize,
56 pub margin: f64,
57 pub arrow: f64,
59 pub loop_size: f64,
61 pub lane_gap: f64,
63 pub lane_head: f64,
64}
65
66impl Default for LayeredParams {
67 fn default() -> Self {
68 LayeredParams {
69 direction: Direction::LeftRight,
70 lanes: 0,
71 margin: 10.0,
72 arrow: 7.0,
73 loop_size: 16.0,
74 lane_gap: 22.0,
75 lane_head: 16.0,
76 }
77 }
78}
79
80#[derive(Clone, Debug, PartialEq)]
83pub struct PlacedNode {
84 pub cx: f64,
85 pub cy: f64,
86 pub w: f64,
87 pub h: f64,
88 pub layer: usize,
89 pub order: usize,
90}
91
92#[derive(Clone, Debug, PartialEq)]
94pub struct GraphLayout {
95 pub w: f64,
96 pub h: f64,
97 pub nodes: Vec<PlacedNode>,
98 pub edges: Vec<Vec<(f64, f64)>>,
100 pub back: Vec<bool>,
102 pub layers: usize,
103 pub bands: Vec<(usize, f64, f64, f64, f64)>,
105}
106
107pub fn layered(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
109 let explicit =
110 !nodes.is_empty() && nodes.iter().all(|n| n.pin.0.is_some() && n.pin.1.is_some());
111 if explicit {
112 layout_explicit(nodes, edges, p)
113 } else {
114 layout(nodes, edges, p)
115 }
116}
117
118#[derive(Clone, Debug)]
120pub struct BandedParams {
121 pub bands: usize,
124 pub margin: f64,
125 pub col_gap: f64,
127 pub row_gap: f64,
128 pub band_gap: f64,
130 pub band_head: f64,
131}
132
133impl Default for BandedParams {
134 fn default() -> Self {
135 BandedParams {
136 bands: 0,
137 margin: 10.0,
138 col_gap: 36.0,
139 row_gap: 18.0,
140 band_gap: 22.0,
141 band_head: 16.0,
142 }
143 }
144}
145
146pub fn banded(nodes: &[GraphNode], edges: &[GraphEdge], p: &BandedParams) -> GraphLayout {
160 let n = nodes.len();
161 let band = |v: usize| nodes[v].lane.unwrap_or(0).min(p.bands.saturating_sub(1));
162 let (dag, loops) = break_cycles(n, edges);
163 let mut preds: Vec<Vec<usize>> = vec![Vec::new(); n];
164 let mut succs: Vec<Vec<usize>> = vec![Vec::new(); n];
165 for &(u, v, _, _) in &dag {
166 preds[v].push(u);
167 succs[u].push(v);
168 }
169 let mut indeg: Vec<usize> = preds.iter().map(Vec::len).collect();
171 let mut done = vec![false; n];
172 let mut topo = Vec::with_capacity(n);
173 while let Some(v) = (0..n).find(|&v| !done[v] && indeg[v] == 0) {
174 done[v] = true;
175 topo.push(v);
176 for &w in &succs[v] {
177 indeg[w] -= 1;
178 }
179 }
180 let step = |u: usize, v: usize| usize::from(band(u) == band(v));
181 let below =
184 |v: usize| succs[v].is_empty() && preds[v].len() == 1 && band(preds[v][0]) == band(v);
185 let drops = |v: usize| !preds[v].is_empty() && preds[v].iter().all(|&u| band(u) != band(v));
188 let mut col = vec![0usize; n];
189 let mut used: std::collections::HashSet<(usize, usize)> = Default::default();
190 for &v in &topo {
191 col[v] = if below(v) {
192 col[preds[v][0]]
193 } else {
194 preds[v]
195 .iter()
196 .map(|&u| col[u] + step(u, v))
197 .max()
198 .unwrap_or(0)
199 };
200 if drops(v) {
201 while used.contains(&(band(v), col[v])) {
202 col[v] += 1;
203 }
204 }
205 used.insert((band(v), col[v]));
206 }
207 for &v in topo.iter().rev() {
208 if preds[v].is_empty() {
209 if let Some(m) = succs[v]
210 .iter()
211 .map(|&w| col[w].saturating_sub(step(v, w)))
212 .min()
213 {
214 col[v] = col[v].max(m);
215 }
216 }
217 }
218 let mut track = vec![0usize; n];
220 let mut taken: std::collections::HashSet<(usize, usize, usize)> = Default::default();
221 for &v in &topo {
222 let want = if below(v) {
223 track[preds[v][0]] + 1
224 } else {
225 preds[v]
226 .iter()
227 .filter(|&&u| band(u) == band(v))
228 .map(|&u| track[u])
229 .min()
230 .unwrap_or(0)
231 };
232 let mut t = want;
233 while taken.contains(&(band(v), col[v], t)) {
234 t += 1;
235 }
236 taken.insert((band(v), col[v], t));
237 track[v] = t;
238 }
239 let ncol = col.iter().max().map_or(0, |m| m + 1);
241 let mut col_w = vec![0.0f64; ncol];
242 for v in 0..n {
243 col_w[col[v]] = col_w[col[v]].max(nodes[v].w);
244 }
245 let mut col_x = vec![0.0f64; ncol];
246 let mut x = 0.0;
247 for c in 0..ncol {
248 col_x[c] = x + col_w[c] / 2.0;
249 x += col_w[c] + p.col_gap;
250 }
251 let nb = p.bands.max(1);
252 let ntr: Vec<usize> = (0..nb)
253 .map(|b| {
254 (0..n)
255 .filter(|&v| band(v) == b)
256 .map(|v| track[v] + 1)
257 .max()
258 .unwrap_or(0)
259 })
260 .collect();
261 let mut track_h: Vec<Vec<f64>> = ntr.iter().map(|&k| vec![0.0; k]).collect();
262 for v in 0..n {
263 let h = &mut track_h[band(v)][track[v]];
264 *h = h.max(nodes[v].h);
265 }
266 let lanes = p.bands > 0;
267 let mut track_y: Vec<Vec<f64>> = Vec::with_capacity(nb);
268 let mut band_span: Vec<(f64, f64)> = Vec::with_capacity(nb);
269 let mut y = 0.0;
270 for heights in &track_h {
271 if lanes {
272 y += p.band_head;
273 }
274 let top = y;
275 let mut ys = Vec::new();
276 for &h in heights {
277 ys.push(y + h / 2.0);
278 y += h + p.row_gap;
279 }
280 let bottom = if heights.is_empty() { y } else { y - p.row_gap };
281 band_span.push((top, bottom));
282 track_y.push(ys);
283 y = bottom + if lanes { p.band_gap } else { p.row_gap };
284 }
285 let mut order: Vec<usize> = (0..n).collect();
286 order.sort_by_key(|&v| (col[v], band(v), track[v], v));
287 let mut rank = vec![0usize; n];
288 for (i, &v) in order.iter().enumerate() {
289 rank[v] = i;
290 }
291 let pn: Vec<PlacedNode> = (0..n)
292 .map(|v| PlacedNode {
293 cx: col_x[col[v]],
294 cy: track_y[band(v)][track[v]],
295 w: nodes[v].w,
296 h: nodes[v].h,
297 layer: col[v],
298 order: rank[v],
299 })
300 .collect();
301 let mut edge_pts = vec![Vec::new(); edges.len()];
302 let mut back = vec![false; edges.len()];
303 for &(_, _, k, rev) in &dag {
304 edge_pts[k] = straight(&pn, edges[k].from, edges[k].to);
305 back[k] = rev;
306 }
307 for &k in &loops {
308 edge_pts[k] = self_loop(&pn[edges[k].from], true, 16.0);
309 }
310 let bands = if lanes {
311 let (x0, x1) = (-12.0, x - p.col_gap + 12.0);
312 (0..nb)
313 .filter(|&b| ntr[b] > 0)
314 .map(|b| {
315 let (top, bottom) = band_span[b];
316 (b, x0, top - p.band_head - 4.0, x1, bottom + 8.0)
317 })
318 .collect()
319 } else {
320 Vec::new()
321 };
322 finish(pn, edge_pts, back, ncol, bands, p.margin)
323}
324
325type DagEdge = (usize, usize, usize, bool);
327
328fn break_cycles(n: usize, edges: &[GraphEdge]) -> (Vec<DagEdge>, Vec<usize>) {
331 let mut out: Vec<Vec<(usize, usize)>> = vec![Vec::new(); n];
332 let mut loops = Vec::new();
333 for (k, e) in edges.iter().enumerate() {
334 if e.from == e.to {
335 loops.push(k);
336 } else {
337 out[e.from].push((e.to, k));
338 }
339 }
340 let mut state = vec![0u8; n]; let mut rev = vec![false; edges.len()];
342 for s in 0..n {
343 if state[s] != 0 {
344 continue;
345 }
346 state[s] = 1;
347 let mut stack = vec![(s, 0usize)];
348 while let Some(top) = stack.last_mut() {
349 let v = top.0;
350 if top.1 < out[v].len() {
351 let (w, k) = out[v][top.1];
352 top.1 += 1;
353 match state[w] {
354 0 => {
355 state[w] = 1;
356 stack.push((w, 0));
357 }
358 1 => rev[k] = true,
359 _ => {}
360 }
361 } else {
362 state[v] = 2;
363 stack.pop();
364 }
365 }
366 }
367 let dag = edges
368 .iter()
369 .enumerate()
370 .filter(|(_, e)| e.from != e.to)
371 .map(|(k, e)| {
372 if rev[k] {
373 (e.to, e.from, k, true)
374 } else {
375 (e.from, e.to, k, false)
376 }
377 })
378 .collect();
379 (dag, loops)
380}
381
382fn ordered(mut keys: Vec<(f64, f64, usize)>) -> Vec<usize> {
384 keys.sort_unstable_by(|a, b| {
385 a.0.total_cmp(&b.0)
386 .then(a.1.total_cmp(&b.1))
387 .then(a.2.cmp(&b.2))
388 });
389 keys.into_iter().map(|k| k.2).collect()
390}
391
392fn layer_crossings(upper: &[usize], succ: &[Vec<usize>], pos: &[usize], lower_len: usize) -> u64 {
395 let mut ends: Vec<(usize, usize)> = Vec::new();
396 for &u in upper {
397 for &v in &succ[u] {
398 ends.push((pos[u], pos[v]));
399 }
400 }
401 let lower: Vec<usize> = ordered(
402 ends.iter()
403 .enumerate()
404 .map(|(i, &(u, v))| (u as f64, v as f64, i))
405 .collect(),
406 )
407 .into_iter()
408 .map(|i| ends[i].1)
409 .collect();
410 let mut tree = vec![0u64; lower_len + 1];
411 let mut c = 0u64;
412 for (seen, &p) in lower.iter().enumerate() {
413 let mut i = p + 1;
414 let mut le = 0u64;
415 while i > 0 {
416 le += tree[i];
417 i -= 1 << i.trailing_zeros();
418 }
419 c += seen as u64 - le;
420 let mut i = p + 1;
421 while i <= lower_len {
422 tree[i] += 1;
423 i += 1 << i.trailing_zeros();
424 }
425 }
426 c
427}
428
429fn place(want: &[f64], weight: &[f64], gap: &[f64]) -> Vec<f64> {
433 let n = want.len();
434 let mut off = vec![0.0; n];
435 for i in 1..n {
436 off[i] = off[i - 1] + gap[i];
437 }
438 let mut blocks: Vec<(f64, f64, usize)> = Vec::new();
439 for i in 0..n {
440 blocks.push((weight[i] * (want[i] - off[i]), weight[i], 1));
441 while blocks.len() >= 2 {
442 let (b, a) = (blocks[blocks.len() - 1], blocks[blocks.len() - 2]);
443 if a.0 / a.1 > b.0 / b.1 {
444 blocks.pop();
445 let last = blocks.last_mut().expect("two blocks");
446 *last = (a.0 + b.0, a.1 + b.1, a.2 + b.2);
447 } else {
448 break;
449 }
450 }
451 }
452 let mut out = Vec::with_capacity(n);
453 for (s, w, c) in blocks {
454 for _ in 0..c {
455 let i = out.len();
456 out.push(s / w + off[i]);
457 }
458 }
459 out
460}
461
462fn exit(p: &PlacedNode, to: (f64, f64)) -> (f64, f64) {
464 let (dx, dy) = (to.0 - p.cx, to.1 - p.cy);
465 let sx = if dx != 0.0 {
466 p.w / 2.0 / dx.abs()
467 } else {
468 f64::INFINITY
469 };
470 let sy = if dy != 0.0 {
471 p.h / 2.0 / dy.abs()
472 } else {
473 f64::INFINITY
474 };
475 let k = sx.min(sy);
476 if k.is_finite() {
477 (p.cx + dx * k, p.cy + dy * k)
478 } else {
479 (p.cx, p.cy)
480 }
481}
482
483fn straight(pn: &[PlacedNode], u: usize, v: usize) -> Vec<(f64, f64)> {
484 let (a, b) = (&pn[u], &pn[v]);
485 vec![exit(a, (b.cx, b.cy)), exit(b, (a.cx, a.cy))]
486}
487
488fn self_loop(p: &PlacedNode, lr: bool, reach: f64) -> Vec<(f64, f64)> {
490 if lr {
491 let top = p.cy - p.h / 2.0;
492 vec![
493 (p.cx + p.w / 4.0, top),
494 (p.cx + p.w / 4.0, top - reach),
495 (p.cx - p.w / 4.0, top - reach),
496 (p.cx - p.w / 4.0, top),
497 ]
498 } else {
499 let right = p.cx + p.w / 2.0;
500 vec![
501 (right, p.cy - p.h / 4.0),
502 (right + reach, p.cy - p.h / 4.0),
503 (right + reach, p.cy + p.h / 4.0),
504 (right, p.cy + p.h / 4.0),
505 ]
506 }
507}
508
509fn layout_explicit(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
511 let sx = nodes.iter().map(|b| b.w).fold(0.0, f64::max) + 48.0;
512 let sy = nodes.iter().map(|b| b.h).fold(0.0, f64::max) + 24.0;
513 let pin = |v: usize| (nodes[v].pin.0.unwrap_or(0.0), nodes[v].pin.1.unwrap_or(0.0));
514 let mut xs: Vec<f64> = (0..nodes.len()).map(|v| pin(v).0).collect();
515 xs.sort_by(f64::total_cmp);
516 xs.dedup();
517 let reading = ordered((0..nodes.len()).map(|v| (pin(v).0, pin(v).1, v)).collect());
518 let mut pn: Vec<PlacedNode> = nodes
519 .iter()
520 .enumerate()
521 .map(|(v, b)| PlacedNode {
522 cx: pin(v).0 * sx,
523 cy: pin(v).1 * sy,
524 w: b.w,
525 h: b.h,
526 layer: xs.iter().position(|&x| x == pin(v).0).unwrap_or(0),
527 order: 0,
528 })
529 .collect();
530 for (i, &v) in reading.iter().enumerate() {
531 pn[v].order = i;
532 }
533 let lr = p.direction == Direction::LeftRight;
534 let pts = edges
535 .iter()
536 .map(|e| {
537 if e.from == e.to {
538 self_loop(&pn[e.from], lr, p.loop_size)
539 } else {
540 straight(&pn, e.from, e.to)
541 }
542 })
543 .collect();
544 finish(
545 pn,
546 pts,
547 vec![false; edges.len()],
548 xs.len().max(1),
549 Vec::new(),
550 p.margin,
551 )
552}
553
554fn layout(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
555 let n = nodes.len();
556 let (dag, loops) = break_cycles(n, edges);
557 let lr = p.direction == Direction::LeftRight;
558 let along = |b: &GraphNode| if lr { b.w } else { b.h };
559 let across = |b: &GraphNode| if lr { b.h } else { b.w };
560 let (rank_gap, node_gap) = if lr { (64.0, 20.0) } else { (48.0, 28.0) };
561 let (lane_gap, lane_head) = (p.lane_gap, p.lane_head);
562
563 let mut preds: Vec<Vec<usize>> = vec![Vec::new(); n];
566 let mut succs: Vec<Vec<usize>> = vec![Vec::new(); n];
567 for &(u, v, _, _) in &dag {
568 preds[v].push(u);
569 succs[u].push(v);
570 }
571 let mut indeg: Vec<usize> = preds.iter().map(Vec::len).collect();
572 let mut done = vec![false; n];
573 let mut topo = Vec::with_capacity(n);
574 while let Some(v) = (0..n).find(|&v| !done[v] && indeg[v] == 0) {
575 done[v] = true;
576 topo.push(v);
577 for &w in &succs[v] {
578 indeg[w] -= 1;
579 }
580 }
581 let pinned = |v: usize| {
583 nodes[v]
584 .pin
585 .0
586 .map(|x| x.round().clamp(0.0, 1000.0) as usize)
587 };
588 let any_pin = (0..n).any(|v| pinned(v).is_some());
589 let mut rank = vec![0usize; n];
590 for &v in &topo {
591 rank[v] =
592 pinned(v).unwrap_or_else(|| preds[v].iter().map(|&q| rank[q] + 1).max().unwrap_or(0));
593 }
594 for &v in topo.iter().rev() {
595 if preds[v].is_empty() && pinned(v).is_none() {
596 if let Some(m) = succs[v].iter().map(|&s| rank[s]).min() {
597 rank[v] = rank[v].max(m.saturating_sub(1));
598 }
599 }
600 }
601 let mut used = vec![false; rank.iter().max().map_or(1, |m| m + 1)];
603 for &r in &rank {
604 used[r] = true;
605 }
606 let mut renumber = vec![0usize; used.len()];
607 let mut nl = 0;
608 for (r, u) in used.iter().enumerate() {
609 renumber[r] = nl;
610 nl += usize::from(*u || any_pin);
611 }
612 for r in &mut rank {
613 *r = renumber[*r];
614 }
615 let nl = nl.max(1);
616 let (dag, free): (Vec<DagEdge>, Vec<DagEdge>) =
618 dag.into_iter().partition(|&(u, v, _, _)| rank[v] > rank[u]);
619
620 let mut vrank: Vec<usize> = rank.clone();
622 let mut vsucc: Vec<Vec<usize>> = vec![Vec::new(); n];
623 let mut vpred: Vec<Vec<usize>> = vec![Vec::new(); n];
624 let mut chains: Vec<Vec<usize>> = Vec::with_capacity(dag.len());
625 for &(u, v, _, _) in &dag {
626 let mut chain = vec![u];
627 let mut prev = u;
628 for r in rank[u] + 1..rank[v] {
629 let dmy = vrank.len();
630 vrank.push(r);
631 vsucc.push(Vec::new());
632 vpred.push(Vec::new());
633 vsucc[prev].push(dmy);
634 vpred[dmy].push(prev);
635 chain.push(dmy);
636 prev = dmy;
637 }
638 vsucc[prev].push(v);
639 vpred[v].push(prev);
640 chain.push(v);
641 chains.push(chain);
642 }
643 let nv = vrank.len();
644 let dummy = |v: usize| v >= n;
645 let mut vlane: Vec<usize> = (0..n).map(|v| nodes[v].lane.unwrap_or(p.lanes)).collect();
647 vlane.resize(nv, 0);
648 for ch in &chains {
649 for &dm in &ch[1..ch.len() - 1] {
650 vlane[dm] = vlane[ch[0]];
651 }
652 }
653 let laned = p.lanes > 0;
654
655 let mut layers: Vec<Vec<usize>> = vec![Vec::new(); nl];
657 let mut seen = vec![false; nv];
658 for s in ordered((0..nv).map(|v| (vrank[v] as f64, 0.0, v)).collect()) {
659 if seen[s] {
660 continue;
661 }
662 let mut stack = vec![s];
663 while let Some(v) = stack.pop() {
664 if seen[v] {
665 continue;
666 }
667 seen[v] = true;
668 layers[vrank[v]].push(v);
669 for &w in vsucc[v].iter().rev() {
670 if !seen[w] {
671 stack.push(w);
672 }
673 }
674 }
675 }
676 if laned {
677 for l in &mut layers {
678 *l = ordered(
679 l.iter()
680 .enumerate()
681 .map(|(i, &v)| (vlane[v] as f64, i as f64, v))
682 .collect(),
683 );
684 }
685 }
686 let mut pos = vec![0usize; nv];
687 let index = |layers: &[Vec<usize>], pos: &mut [usize]| {
688 for l in layers {
689 for (i, &v) in l.iter().enumerate() {
690 pos[v] = i;
691 }
692 }
693 };
694 index(&layers, &mut pos);
695 let crossings = |layers: &[Vec<usize>], pos: &[usize]| -> u64 {
696 (0..layers.len().saturating_sub(1))
697 .map(|r| layer_crossings(&layers[r], &vsucc, pos, layers[r + 1].len()))
698 .sum()
699 };
700
701 let mut best = layers.clone();
703 let mut best_c = crossings(&layers, &pos);
704 for it in 0..8 {
705 if best_c == 0 {
706 break;
707 }
708 let down = it % 2 == 0;
709 let rs: Vec<usize> = if down {
710 (1..nl).collect()
711 } else {
712 (0..nl.saturating_sub(1)).rev().collect()
713 };
714 for r in rs {
715 let nb = if down { &vpred } else { &vsucc };
716 let keyed: Vec<(f64, f64, usize)> = layers[r]
717 .iter()
718 .map(|&v| {
719 let k = if nb[v].is_empty() {
720 pos[v] as f64
721 } else {
722 nb[v].iter().map(|&w| pos[w] as f64).sum::<f64>() / nb[v].len() as f64
723 };
724 (vlane[v] as f64 * 1e6 + k, pos[v] as f64, v)
725 })
726 .collect();
727 layers[r] = ordered(keyed);
728 for (i, &v) in layers[r].iter().enumerate() {
729 pos[v] = i;
730 }
731 }
732 for _ in 0..4 {
733 let mut better = false;
734 for layer in layers.iter_mut() {
735 for i in 0..layer.len().saturating_sub(1) {
736 let (a, b) = (layer[i], layer[i + 1]);
737 if vlane[a] != vlane[b] {
738 continue;
739 }
740 let pair = |x: usize, y: usize| -> usize {
741 let c = |l: &[Vec<usize>]| {
742 l[x].iter()
743 .flat_map(|&q| l[y].iter().map(move |&r| (q, r)))
744 .filter(|&(q, r)| pos[q] > pos[r])
745 .count()
746 };
747 c(&vpred) + c(&vsucc)
748 };
749 if pair(b, a) < pair(a, b) {
750 layer.swap(i, i + 1);
751 pos[a] = i + 1;
752 pos[b] = i;
753 better = true;
754 }
755 }
756 }
757 if !better {
758 break;
759 }
760 }
761 let c = crossings(&layers, &pos);
762 if c < best_c {
763 best_c = c;
764 best = layers.clone();
765 }
766 }
767 let layers = best;
768 index(&layers, &mut pos);
769
770 let size = |v: usize| if dummy(v) { 0.0 } else { across(&nodes[v]) };
772 let gap_between = |a: usize, b: usize| -> f64 {
773 let g = match (dummy(a), dummy(b)) {
774 (true, true) => 8.0,
775 (false, false) => node_gap,
776 _ => 12.0,
777 };
778 let lane = if vlane[a] != vlane[b] {
779 lane_gap + lane_head
780 } else {
781 0.0
782 };
783 size(a) / 2.0 + g + lane + size(b) / 2.0
784 };
785 let mut y = vec![0.0f64; nv];
786 for l in &layers {
787 let mut at = 0.0;
788 for (i, &v) in l.iter().enumerate() {
789 if i > 0 {
790 at += gap_between(l[i - 1], v);
791 }
792 y[v] = at;
793 }
794 let mid = at / 2.0;
795 for &v in l {
796 y[v] -= mid;
797 }
798 }
799 let relax = |y: &mut Vec<f64>, r: usize, up: bool, down: bool| {
800 let l = &layers[r];
801 if l.is_empty() {
802 return;
803 }
804 let want: Vec<f64> = l
805 .iter()
806 .map(|&v| {
807 let mut nb: Vec<usize> = Vec::new();
808 if up {
809 nb.extend(&vpred[v]);
810 }
811 if down {
812 nb.extend(&vsucc[v]);
813 }
814 if nb.is_empty() {
815 y[v]
816 } else {
817 nb.iter().map(|&w| y[w]).sum::<f64>() / nb.len() as f64
818 }
819 })
820 .collect();
821 let weight: Vec<f64> = l
822 .iter()
823 .map(|&v| if dummy(v) { 2.0 } else { 1.0 })
824 .collect();
825 let gaps: Vec<f64> = (0..l.len())
826 .map(|i| {
827 if i == 0 {
828 0.0
829 } else {
830 gap_between(l[i - 1], l[i])
831 }
832 })
833 .collect();
834 for (&v, q) in l.iter().zip(place(&want, &weight, &gaps)) {
835 y[v] = q;
836 }
837 };
838 for _ in 0..6 {
839 for r in 1..nl {
840 relax(&mut y, r, true, false);
841 }
842 for r in (0..nl.saturating_sub(1)).rev() {
843 relax(&mut y, r, false, true);
844 }
845 }
846 for r in 0..nl {
847 relax(&mut y, r, true, true);
848 }
849 let mut lane_span: Vec<(f64, f64)> = Vec::new();
851 if laned {
852 let nlanes = p.lanes + 1;
853 let span = |y: &[f64], l: usize| {
854 (0..nv)
855 .filter(|&v| vlane[v] == l)
856 .map(|v| (y[v] - size(v) / 2.0, y[v] + size(v) / 2.0))
857 .fold(None, |acc: Option<(f64, f64)>, (a, b)| match acc {
858 None => Some((a, b)),
859 Some((x, z)) => Some((x.min(a), z.max(b))),
860 })
861 };
862 let mut floor: Option<f64> = None;
863 for l in 0..nlanes {
864 let Some((lo, _)) = span(&y, l) else {
865 lane_span.push((f64::NAN, f64::NAN));
866 continue;
867 };
868 if let Some(f) = floor {
869 let need = f + lane_gap + lane_head - lo;
870 if need > 0.0 {
871 for v in 0..nv {
872 if vlane[v] == l {
873 y[v] += need;
874 }
875 }
876 }
877 }
878 let (lo, hi) = span(&y, l).expect("lane has vertices");
879 lane_span.push((lo, hi));
880 floor = Some(hi);
881 }
882 }
883
884 let mut thick = vec![0.0f64; nl];
887 for v in 0..n {
888 thick[rank[v]] = thick[rank[v]].max(along(&nodes[v]));
889 }
890 let mut gap: Vec<f64> = vec![rank_gap; nl];
891 if lr {
892 for e in edges {
893 let (a, b) = (rank[e.from].min(rank[e.to]), rank[e.from].max(rank[e.to]));
894 if b != a + 1 {
895 continue;
896 }
897 if let Some(w) = e.label_w {
898 gap[a] = gap[a].max(w + 2.0 * p.arrow + 18.0);
899 }
900 }
901 }
902 let mut start_at = vec![0.0f64; nl];
903 for r in 1..nl {
904 start_at[r] = start_at[r - 1] + thick[r - 1] + gap[r - 1];
905 }
906 let centre = |r: usize| start_at[r] + thick[r] / 2.0;
907 let xy = |rk: f64, o: f64| if lr { (rk, o) } else { (o, rk) };
908
909 let mut pn: Vec<PlacedNode> = Vec::with_capacity(n);
910 for (v, b) in nodes.iter().enumerate() {
911 let (cx, cy) = xy(centre(rank[v]), y[v]);
912 pn.push(PlacedNode {
913 cx,
914 cy,
915 w: b.w,
916 h: b.h,
917 layer: rank[v],
918 order: 0,
919 });
920 }
921 let reading = ordered((0..n).map(|v| (rank[v] as f64, y[v], v)).collect());
922 for (i, &v) in reading.iter().enumerate() {
923 pn[v].order = i;
924 }
925
926 let half_along = |v: usize| if lr { pn[v].w / 2.0 } else { pn[v].h / 2.0 };
929 let side = |v: usize| if lr { pn[v].h } else { pn[v].w };
930 let mut out_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
931 let mut in_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
932 for (c, ch) in chains.iter().enumerate() {
933 out_ports[ch[0]].push(c);
934 in_ports[ch[ch.len() - 1]].push(c);
935 }
936 for ports in &mut out_ports {
937 *ports = ordered(ports.iter().map(|&c| (y[chains[c][1]], 0.0, c)).collect());
938 }
939 for ports in &mut in_ports {
940 *ports = ordered(
941 ports
942 .iter()
943 .map(|&c| (y[chains[c][chains[c].len() - 2]], 0.0, c))
944 .collect(),
945 );
946 }
947 let spread = |list: &[usize], c: usize, v: usize| -> f64 {
948 let m = list.len();
949 if m <= 1 {
950 return 0.0;
951 }
952 let k = list.iter().position(|&x| x == c).unwrap_or(0);
953 let span = (side(v) * 0.6).min(14.0 * (m - 1) as f64);
954 -span / 2.0 + span * k as f64 / (m - 1) as f64
955 };
956 let mut edge_pts: Vec<Vec<(f64, f64)>> = vec![Vec::new(); edges.len()];
957 let mut back = vec![false; edges.len()];
958 for (c, ch) in chains.iter().enumerate() {
959 let (u, v, k, rev) = dag[c];
960 let mut pts = Vec::with_capacity(ch.len() * 2);
961 pts.push(xy(
962 centre(rank[u]) + half_along(u),
963 y[u] + spread(&out_ports[u], c, u),
964 ));
965 for &dm in &ch[1..ch.len() - 1] {
966 let r = vrank[dm];
967 pts.push(xy(start_at[r], y[dm]));
968 pts.push(xy(start_at[r] + thick[r], y[dm]));
969 }
970 pts.push(xy(
971 centre(rank[v]) - half_along(v),
972 y[v] + spread(&in_ports[v], c, v),
973 ));
974 if rev {
975 pts.reverse();
976 }
977 edge_pts[k] = pts;
978 back[k] = rev;
979 }
980 for k in loops {
981 edge_pts[k] = self_loop(&pn[edges[k].from], lr, p.loop_size);
982 }
983 for &(u, v, k, rev) in &free {
984 let mut pts = straight(&pn, u, v);
985 if rev {
986 pts.reverse();
987 }
988 edge_pts[k] = pts;
989 back[k] = rev;
990 }
991 let total = start_at[nl - 1] + thick[nl - 1];
993 let bands = lane_span
994 .iter()
995 .enumerate()
996 .filter(|(l, (lo, _))| *l < p.lanes && lo.is_finite())
997 .map(|(l, &(lo, hi))| {
998 let (a, b) = if lr {
999 xy(-12.0, lo - lane_head - 6.0)
1000 } else {
1001 xy(-lane_head - 10.0, lo - 8.0)
1002 };
1003 let (c, e) = xy(total + 12.0, hi + 8.0);
1004 (l, a, b, c, e)
1005 })
1006 .collect();
1007 finish(pn, edge_pts, back, nl, bands, p.margin)
1008}
1009
1010fn finish(
1012 mut pn: Vec<PlacedNode>,
1013 mut edge_pts: Vec<Vec<(f64, f64)>>,
1014 back: Vec<bool>,
1015 layers: usize,
1016 mut bands: Vec<(usize, f64, f64, f64, f64)>,
1017 margin: f64,
1018) -> GraphLayout {
1019 let (mut x0, mut y0, mut x1, mut y1) = (f64::MAX, f64::MAX, f64::MIN, f64::MIN);
1020 for q in &pn {
1021 x0 = x0.min(q.cx - q.w / 2.0);
1022 x1 = x1.max(q.cx + q.w / 2.0);
1023 y0 = y0.min(q.cy - q.h / 2.0);
1024 y1 = y1.max(q.cy + q.h / 2.0);
1025 }
1026 for &(px, py) in edge_pts.iter().flatten() {
1027 x0 = x0.min(px);
1028 x1 = x1.max(px);
1029 y0 = y0.min(py);
1030 y1 = y1.max(py);
1031 }
1032 for &(_, a, b, c, e) in &bands {
1033 x0 = x0.min(a.min(c));
1034 x1 = x1.max(a.max(c));
1035 y0 = y0.min(b.min(e));
1036 y1 = y1.max(b.max(e));
1037 }
1038 if pn.is_empty() {
1039 (x0, y0, x1, y1) = (0.0, 0.0, 0.0, 0.0);
1040 }
1041 let r = |v: f64| (v * 2.0).round() / 2.0;
1042 let (dx, dy) = (margin - x0, margin - y0);
1043 for q in &mut pn {
1044 q.cx = r(q.cx + dx);
1045 q.cy = r(q.cy + dy);
1046 }
1047 for pts in &mut edge_pts {
1048 for pt in pts.iter_mut() {
1049 *pt = (r(pt.0 + dx), r(pt.1 + dy));
1050 }
1051 }
1052 for b in &mut bands {
1053 *b = (b.0, r(b.1 + dx), r(b.2 + dy), r(b.3 + dx), r(b.4 + dy));
1054 }
1055 GraphLayout {
1056 w: r(x1 - x0 + 2.0 * margin),
1057 h: r(y1 - y0 + 2.0 * margin),
1058 nodes: pn,
1059 edges: edge_pts,
1060 back,
1061 layers,
1062 bands,
1063 }
1064}
1065
1066#[cfg(test)]
1067mod tests {
1068 use super::*;
1069
1070 fn node(w: f64, h: f64) -> GraphNode {
1071 GraphNode {
1072 w,
1073 h,
1074 ..Default::default()
1075 }
1076 }
1077 fn edge(from: usize, to: usize) -> GraphEdge {
1078 GraphEdge {
1079 from,
1080 to,
1081 label_w: None,
1082 }
1083 }
1084
1085 #[test]
1086 fn a_chain_runs_left_to_right_in_layers() {
1087 let l = layered(
1088 &[node(100.0, 40.0), node(100.0, 40.0), node(100.0, 40.0)],
1089 &[edge(0, 1), edge(1, 2)],
1090 &LayeredParams::default(),
1091 );
1092 assert_eq!(l.layers, 3);
1093 assert!(l.nodes[0].cx < l.nodes[1].cx && l.nodes[1].cx < l.nodes[2].cx);
1094 assert_eq!(l.nodes[0].cy, l.nodes[1].cy);
1095 assert_eq!(l.edges[0][0].0, l.nodes[0].cx + 50.0);
1097 assert_eq!(l.edges[0].last().unwrap().0, l.nodes[1].cx - 50.0);
1098 }
1099
1100 #[test]
1101 fn a_cycle_is_broken_and_marked_back() {
1102 let l = layered(
1103 &[node(80.0, 30.0), node(80.0, 30.0)],
1104 &[edge(0, 1), edge(1, 0)],
1105 &LayeredParams::default(),
1106 );
1107 assert_eq!(l.back, vec![false, true]);
1108 assert_eq!(l.layers, 2);
1109 }
1110
1111 #[test]
1112 fn crossings_are_removed_where_possible() {
1113 let ns = vec![node(60.0, 30.0); 4];
1115 let l = layered(&ns, &[edge(0, 3), edge(1, 2)], &LayeredParams::default());
1116 let (a, b, c, d) = (&l.nodes[0], &l.nodes[1], &l.nodes[2], &l.nodes[3]);
1117 assert_eq!(a.cy < b.cy, d.cy < c.cy, "{a:?} {b:?} {c:?} {d:?}");
1118 }
1119
1120 #[test]
1121 fn pins_and_the_explicit_grid() {
1122 let mut ns = vec![node(60.0, 30.0); 3];
1123 ns[2].pin.0 = Some(3.0);
1124 let l = layered(&ns, &[edge(0, 1)], &LayeredParams::default());
1125 assert_eq!(l.nodes[2].layer, 3, "a pinned layer keeps its number");
1126 let grid: Vec<GraphNode> = (0..4)
1127 .map(|i| GraphNode {
1128 w: 60.0,
1129 h: 30.0,
1130 pin: (Some((i % 2) as f64), Some((i / 2) as f64)),
1131 ..Default::default()
1132 })
1133 .collect();
1134 let g = layered(&grid, &[edge(0, 3)], &LayeredParams::default());
1135 assert_eq!(g.layers, 2);
1136 assert_eq!(g.nodes[0].cy, g.nodes[1].cy);
1137 assert_eq!(g.edges[0].len(), 2, "straight");
1138 }
1139
1140 #[test]
1141 fn lanes_become_bands_and_top_bottom_swaps_the_axes() {
1142 let mut ns = vec![node(60.0, 30.0); 2];
1143 ns[0].lane = Some(0);
1144 ns[1].lane = Some(1);
1145 let l = layered(
1146 &ns,
1147 &[edge(0, 1)],
1148 &LayeredParams {
1149 lanes: 2,
1150 ..Default::default()
1151 },
1152 );
1153 assert_eq!(l.bands.len(), 2);
1154 let tb = layered(
1155 &ns[..1],
1156 &[],
1157 &LayeredParams {
1158 direction: Direction::TopBottom,
1159 ..Default::default()
1160 },
1161 );
1162 assert_eq!(tb.nodes.len(), 1);
1163 let t = layered(
1164 &[node(60.0, 30.0), node(60.0, 30.0)],
1165 &[edge(0, 1)],
1166 &LayeredParams {
1167 direction: Direction::TopBottom,
1168 ..Default::default()
1169 },
1170 );
1171 assert!(t.nodes[0].cy < t.nodes[1].cy && t.nodes[0].cx == t.nodes[1].cx);
1172 }
1173
1174 #[test]
1175 fn edge_cases_loops_labels_ports_lanes_and_empty() {
1176 let p = LayeredParams::default();
1177 let empty = layered(&[], &[], &p);
1178 assert!(empty.nodes.is_empty() && empty.layers == 1);
1179 for dir in [Direction::LeftRight, Direction::TopBottom] {
1181 let q = LayeredParams {
1182 direction: dir,
1183 ..Default::default()
1184 };
1185 let l = layered(
1186 &[node(60.0, 30.0), node(60.0, 30.0)],
1187 &[edge(0, 0), edge(0, 1)],
1188 &q,
1189 );
1190 assert_eq!(l.edges[0].len(), 4, "a self-loop");
1191 let g: Vec<GraphNode> = (0..2)
1192 .map(|i| GraphNode {
1193 w: 60.0,
1194 h: 30.0,
1195 pin: (Some(i as f64), Some(0.0)),
1196 ..Default::default()
1197 })
1198 .collect();
1199 let gl = layered(&g, &[edge(1, 1), edge(0, 1)], &q);
1200 assert_eq!(gl.edges[0].len(), 4);
1201 }
1202 let ns = vec![node(60.0, 30.0); 4];
1204 let plain = layered(
1205 &ns,
1206 &[edge(0, 1), edge(1, 2), edge(0, 2), edge(0, 3), edge(2, 3)],
1207 &p,
1208 );
1209 let labelled = layered(
1210 &ns,
1211 &[
1212 GraphEdge {
1213 from: 0,
1214 to: 1,
1215 label_w: Some(300.0),
1216 },
1217 edge(1, 2),
1218 edge(0, 2),
1219 edge(0, 3),
1220 edge(2, 3),
1221 ],
1222 &p,
1223 );
1224 assert!(
1225 labelled.nodes[1].cx - labelled.nodes[0].cx > plain.nodes[1].cx - plain.nodes[0].cx
1226 );
1227 assert!(
1228 plain.edges[3].len() > 2,
1229 "a long edge bends through its dummies"
1230 );
1231 let starts: Vec<f64> = [0, 2, 3].iter().map(|&k| plain.edges[k][0].1).collect();
1233 assert!(starts.windows(2).any(|w| w[0] != w[1]), "{starts:?}");
1234 let mut pn = vec![node(60.0, 30.0); 3];
1236 pn[0].pin.0 = Some(2.0);
1237 pn[1].pin.0 = Some(0.0);
1238 let back = layered(&pn, &[edge(0, 1), edge(1, 2)], &p);
1239 assert_eq!(back.edges[0].len(), 2);
1240 let mut lanes = vec![node(60.0, 30.0); 5];
1242 for (i, n) in lanes.iter_mut().enumerate().take(4) {
1243 n.lane = Some(i % 2);
1244 }
1245 let q = LayeredParams {
1246 direction: Direction::TopBottom,
1247 lanes: 2,
1248 ..Default::default()
1249 };
1250 let tb = layered(
1251 &lanes,
1252 &[edge(0, 3), edge(1, 2), edge(2, 4), edge(3, 4)],
1253 &q,
1254 );
1255 assert_eq!(tb.bands.len(), 2);
1256 assert!(tb.bands.iter().all(|b| b.3 > b.1 && b.4 > b.2));
1257 }
1258
1259 #[test]
1262 fn banded_fans_out_drops_and_hangs_leaves_below() {
1263 let node = |lane| GraphNode {
1265 w: 40.0,
1266 h: 20.0,
1267 lane: Some(lane),
1268 ..Default::default()
1269 };
1270 let mut nodes = vec![node(0)];
1271 nodes.extend((0..3).map(|_| node(1)));
1272 nodes.extend((0..3).map(|_| node(1)));
1273 let edge = |from, to| GraphEdge {
1274 from,
1275 to,
1276 label_w: None,
1277 };
1278 let mut edges = Vec::new();
1279 for i in 0..3 {
1280 edges.push(edge(0, 1 + i));
1281 edges.push(edge(1 + i, 4 + i));
1282 }
1283 let l = banded(
1284 &nodes,
1285 &edges,
1286 &BandedParams {
1287 bands: 2,
1288 ..Default::default()
1289 },
1290 );
1291 let cx: Vec<f64> = (1..=3).map(|i| l.nodes[i].cx).collect();
1292 assert!(cx[0] < cx[1] && cx[1] < cx[2], "fanned out: {cx:?}");
1293 for i in 0..3 {
1294 let (f, y) = (&l.nodes[1 + i], &l.nodes[4 + i]);
1295 assert_eq!(f.cx, y.cx, "y{i} under its factor");
1296 assert!(y.cy > f.cy);
1297 }
1298 }
1299}