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 let bussed = |u: usize, v: usize| band(u) != band(v) && col[u] != col[v];
310 let mut lanes_of: Vec<((usize, bool), Vec<usize>)> = Vec::new();
311 for &(_, _, k, _) in &dag {
312 let (u, v) = (edges[k].from, edges[k].to);
313 if !bussed(u, v) {
314 continue;
315 }
316 let key = (band(u), band(v) > band(u));
317 match lanes_of.iter_mut().find(|(c, _)| *c == key) {
318 Some((_, us)) if !us.contains(&u) => us.push(u),
319 Some(_) => {}
320 None => lanes_of.push((key, vec![u])),
321 }
322 }
323 const LANE: f64 = 8.0;
324 let route = |u: usize, v: usize| -> Vec<(f64, f64)> {
325 let (a, b) = (&pn[u], &pn[v]);
326 let down = band(v) > band(u);
327 let (top, bottom) = band_span[band(u)];
328 let channel = if down {
329 bottom + p.band_gap / 2.0
330 } else {
331 top - (if lanes { p.band_head } else { 0.0 }) - p.band_gap / 2.0
332 };
333 let us = lanes_of
334 .iter()
335 .find(|(c, _)| *c == (band(u), down))
336 .map_or(&[][..], |(_, us)| &us[..]);
337 let i = us.iter().position(|&x| x == u).unwrap_or(0) as f64;
338 let y = channel + (i - (us.len().max(1) - 1) as f64 / 2.0) * LANE;
339 let right = col[v] > col[u];
340 let side = |n: &PlacedNode, c: usize, r: bool| {
341 if r {
342 (
343 n.cx + n.w / 2.0,
344 col_x[c] + col_w[c] / 2.0 + p.col_gap / 2.0,
345 )
346 } else {
347 (
348 n.cx - n.w / 2.0,
349 col_x[c] - col_w[c] / 2.0 - p.col_gap / 2.0,
350 )
351 }
352 };
353 let (sx, sg) = side(a, col[u], right);
354 let sg = sg + (i - (us.len().max(1) - 1) as f64 / 2.0) * LANE;
356 let mut pts = vec![(sx, a.cy), (sg, a.cy), (sg, y)];
357 let next_band = band(v).abs_diff(band(u)) == 1;
358 let facing = if down {
359 track[v] == 0
360 } else {
361 track[v] + 1 == ntr[band(v)]
362 };
363 if next_band && facing {
364 let ey = if down {
365 b.cy - b.h / 2.0
366 } else {
367 b.cy + b.h / 2.0
368 };
369 pts.extend([(b.cx, y), (b.cx, ey)]);
370 } else {
371 let (ex, tg) = side(b, col[v], !right);
372 pts.extend([(tg, y), (tg, b.cy), (ex, b.cy)]);
373 }
374 pts
375 };
376 for &(_, _, k, rev) in &dag {
377 let (u, v) = (edges[k].from, edges[k].to);
378 edge_pts[k] = if bussed(u, v) {
379 route(u, v)
380 } else {
381 straight(&pn, u, v)
382 };
383 back[k] = rev;
384 }
385 for &k in &loops {
386 edge_pts[k] = self_loop(&pn[edges[k].from], true, 16.0);
387 }
388 let bands = if lanes {
389 let (x0, x1) = (-12.0, x - p.col_gap + 12.0);
390 (0..nb)
391 .filter(|&b| ntr[b] > 0)
392 .map(|b| {
393 let (top, bottom) = band_span[b];
394 (b, x0, top - p.band_head - 4.0, x1, bottom + 8.0)
395 })
396 .collect()
397 } else {
398 Vec::new()
399 };
400 finish(pn, edge_pts, back, ncol, bands, p.margin)
401}
402
403type DagEdge = (usize, usize, usize, bool);
405
406fn break_cycles(n: usize, edges: &[GraphEdge]) -> (Vec<DagEdge>, Vec<usize>) {
409 let mut out: Vec<Vec<(usize, usize)>> = vec![Vec::new(); n];
410 let mut loops = Vec::new();
411 for (k, e) in edges.iter().enumerate() {
412 if e.from == e.to {
413 loops.push(k);
414 } else {
415 out[e.from].push((e.to, k));
416 }
417 }
418 let mut state = vec![0u8; n]; let mut rev = vec![false; edges.len()];
420 for s in 0..n {
421 if state[s] != 0 {
422 continue;
423 }
424 state[s] = 1;
425 let mut stack = vec![(s, 0usize)];
426 while let Some(top) = stack.last_mut() {
427 let v = top.0;
428 if top.1 < out[v].len() {
429 let (w, k) = out[v][top.1];
430 top.1 += 1;
431 match state[w] {
432 0 => {
433 state[w] = 1;
434 stack.push((w, 0));
435 }
436 1 => rev[k] = true,
437 _ => {}
438 }
439 } else {
440 state[v] = 2;
441 stack.pop();
442 }
443 }
444 }
445 let dag = edges
446 .iter()
447 .enumerate()
448 .filter(|(_, e)| e.from != e.to)
449 .map(|(k, e)| {
450 if rev[k] {
451 (e.to, e.from, k, true)
452 } else {
453 (e.from, e.to, k, false)
454 }
455 })
456 .collect();
457 (dag, loops)
458}
459
460fn ordered(mut keys: Vec<(f64, f64, usize)>) -> Vec<usize> {
462 keys.sort_unstable_by(|a, b| {
463 a.0.total_cmp(&b.0)
464 .then(a.1.total_cmp(&b.1))
465 .then(a.2.cmp(&b.2))
466 });
467 keys.into_iter().map(|k| k.2).collect()
468}
469
470fn layer_crossings(upper: &[usize], succ: &[Vec<usize>], pos: &[usize], lower_len: usize) -> u64 {
473 let mut ends: Vec<(usize, usize)> = Vec::new();
474 for &u in upper {
475 for &v in &succ[u] {
476 ends.push((pos[u], pos[v]));
477 }
478 }
479 let lower: Vec<usize> = ordered(
480 ends.iter()
481 .enumerate()
482 .map(|(i, &(u, v))| (u as f64, v as f64, i))
483 .collect(),
484 )
485 .into_iter()
486 .map(|i| ends[i].1)
487 .collect();
488 let mut tree = vec![0u64; lower_len + 1];
489 let mut c = 0u64;
490 for (seen, &p) in lower.iter().enumerate() {
491 let mut i = p + 1;
492 let mut le = 0u64;
493 while i > 0 {
494 le += tree[i];
495 i -= 1 << i.trailing_zeros();
496 }
497 c += seen as u64 - le;
498 let mut i = p + 1;
499 while i <= lower_len {
500 tree[i] += 1;
501 i += 1 << i.trailing_zeros();
502 }
503 }
504 c
505}
506
507fn place(want: &[f64], weight: &[f64], gap: &[f64]) -> Vec<f64> {
511 let n = want.len();
512 let mut off = vec![0.0; n];
513 for i in 1..n {
514 off[i] = off[i - 1] + gap[i];
515 }
516 let mut blocks: Vec<(f64, f64, usize)> = Vec::new();
517 for i in 0..n {
518 blocks.push((weight[i] * (want[i] - off[i]), weight[i], 1));
519 while blocks.len() >= 2 {
520 let (b, a) = (blocks[blocks.len() - 1], blocks[blocks.len() - 2]);
521 if a.0 / a.1 > b.0 / b.1 {
522 blocks.pop();
523 let last = blocks.last_mut().expect("two blocks");
524 *last = (a.0 + b.0, a.1 + b.1, a.2 + b.2);
525 } else {
526 break;
527 }
528 }
529 }
530 let mut out = Vec::with_capacity(n);
531 for (s, w, c) in blocks {
532 for _ in 0..c {
533 let i = out.len();
534 out.push(s / w + off[i]);
535 }
536 }
537 out
538}
539
540fn exit(p: &PlacedNode, to: (f64, f64)) -> (f64, f64) {
542 let (dx, dy) = (to.0 - p.cx, to.1 - p.cy);
543 let sx = if dx != 0.0 {
544 p.w / 2.0 / dx.abs()
545 } else {
546 f64::INFINITY
547 };
548 let sy = if dy != 0.0 {
549 p.h / 2.0 / dy.abs()
550 } else {
551 f64::INFINITY
552 };
553 let k = sx.min(sy);
554 if k.is_finite() {
555 (p.cx + dx * k, p.cy + dy * k)
556 } else {
557 (p.cx, p.cy)
558 }
559}
560
561fn straight(pn: &[PlacedNode], u: usize, v: usize) -> Vec<(f64, f64)> {
562 let (a, b) = (&pn[u], &pn[v]);
563 vec![exit(a, (b.cx, b.cy)), exit(b, (a.cx, a.cy))]
564}
565
566fn self_loop(p: &PlacedNode, lr: bool, reach: f64) -> Vec<(f64, f64)> {
568 if lr {
569 let top = p.cy - p.h / 2.0;
570 vec![
571 (p.cx + p.w / 4.0, top),
572 (p.cx + p.w / 4.0, top - reach),
573 (p.cx - p.w / 4.0, top - reach),
574 (p.cx - p.w / 4.0, top),
575 ]
576 } else {
577 let right = p.cx + p.w / 2.0;
578 vec![
579 (right, p.cy - p.h / 4.0),
580 (right + reach, p.cy - p.h / 4.0),
581 (right + reach, p.cy + p.h / 4.0),
582 (right, p.cy + p.h / 4.0),
583 ]
584 }
585}
586
587fn layout_explicit(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
589 let sx = nodes.iter().map(|b| b.w).fold(0.0, f64::max) + 48.0;
590 let sy = nodes.iter().map(|b| b.h).fold(0.0, f64::max) + 24.0;
591 let pin = |v: usize| (nodes[v].pin.0.unwrap_or(0.0), nodes[v].pin.1.unwrap_or(0.0));
592 let mut xs: Vec<f64> = (0..nodes.len()).map(|v| pin(v).0).collect();
593 xs.sort_by(f64::total_cmp);
594 xs.dedup();
595 let reading = ordered((0..nodes.len()).map(|v| (pin(v).0, pin(v).1, v)).collect());
596 let mut pn: Vec<PlacedNode> = nodes
597 .iter()
598 .enumerate()
599 .map(|(v, b)| PlacedNode {
600 cx: pin(v).0 * sx,
601 cy: pin(v).1 * sy,
602 w: b.w,
603 h: b.h,
604 layer: xs.iter().position(|&x| x == pin(v).0).unwrap_or(0),
605 order: 0,
606 })
607 .collect();
608 for (i, &v) in reading.iter().enumerate() {
609 pn[v].order = i;
610 }
611 let lr = p.direction == Direction::LeftRight;
612 let pts = edges
613 .iter()
614 .map(|e| {
615 if e.from == e.to {
616 self_loop(&pn[e.from], lr, p.loop_size)
617 } else {
618 straight(&pn, e.from, e.to)
619 }
620 })
621 .collect();
622 finish(
623 pn,
624 pts,
625 vec![false; edges.len()],
626 xs.len().max(1),
627 Vec::new(),
628 p.margin,
629 )
630}
631
632fn layout(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
633 let n = nodes.len();
634 let (dag, loops) = break_cycles(n, edges);
635 let lr = p.direction == Direction::LeftRight;
636 let along = |b: &GraphNode| if lr { b.w } else { b.h };
637 let across = |b: &GraphNode| if lr { b.h } else { b.w };
638 let (rank_gap, node_gap) = if lr { (64.0, 20.0) } else { (48.0, 28.0) };
639 let (lane_gap, lane_head) = (p.lane_gap, p.lane_head);
640
641 let mut preds: Vec<Vec<usize>> = vec![Vec::new(); n];
644 let mut succs: Vec<Vec<usize>> = vec![Vec::new(); n];
645 for &(u, v, _, _) in &dag {
646 preds[v].push(u);
647 succs[u].push(v);
648 }
649 let mut indeg: Vec<usize> = preds.iter().map(Vec::len).collect();
650 let mut done = vec![false; n];
651 let mut topo = Vec::with_capacity(n);
652 while let Some(v) = (0..n).find(|&v| !done[v] && indeg[v] == 0) {
653 done[v] = true;
654 topo.push(v);
655 for &w in &succs[v] {
656 indeg[w] -= 1;
657 }
658 }
659 let pinned = |v: usize| {
661 nodes[v]
662 .pin
663 .0
664 .map(|x| x.round().clamp(0.0, 1000.0) as usize)
665 };
666 let any_pin = (0..n).any(|v| pinned(v).is_some());
667 let mut rank = vec![0usize; n];
668 for &v in &topo {
669 rank[v] =
670 pinned(v).unwrap_or_else(|| preds[v].iter().map(|&q| rank[q] + 1).max().unwrap_or(0));
671 }
672 for &v in topo.iter().rev() {
673 if preds[v].is_empty() && pinned(v).is_none() {
674 if let Some(m) = succs[v].iter().map(|&s| rank[s]).min() {
675 rank[v] = rank[v].max(m.saturating_sub(1));
676 }
677 }
678 }
679 let mut used = vec![false; rank.iter().max().map_or(1, |m| m + 1)];
681 for &r in &rank {
682 used[r] = true;
683 }
684 let mut renumber = vec![0usize; used.len()];
685 let mut nl = 0;
686 for (r, u) in used.iter().enumerate() {
687 renumber[r] = nl;
688 nl += usize::from(*u || any_pin);
689 }
690 for r in &mut rank {
691 *r = renumber[*r];
692 }
693 let nl = nl.max(1);
694 let (dag, free): (Vec<DagEdge>, Vec<DagEdge>) =
696 dag.into_iter().partition(|&(u, v, _, _)| rank[v] > rank[u]);
697
698 let mut vrank: Vec<usize> = rank.clone();
700 let mut vsucc: Vec<Vec<usize>> = vec![Vec::new(); n];
701 let mut vpred: Vec<Vec<usize>> = vec![Vec::new(); n];
702 let mut chains: Vec<Vec<usize>> = Vec::with_capacity(dag.len());
703 for &(u, v, _, _) in &dag {
704 let mut chain = vec![u];
705 let mut prev = u;
706 for r in rank[u] + 1..rank[v] {
707 let dmy = vrank.len();
708 vrank.push(r);
709 vsucc.push(Vec::new());
710 vpred.push(Vec::new());
711 vsucc[prev].push(dmy);
712 vpred[dmy].push(prev);
713 chain.push(dmy);
714 prev = dmy;
715 }
716 vsucc[prev].push(v);
717 vpred[v].push(prev);
718 chain.push(v);
719 chains.push(chain);
720 }
721 let nv = vrank.len();
722 let dummy = |v: usize| v >= n;
723 let mut vlane: Vec<usize> = (0..n).map(|v| nodes[v].lane.unwrap_or(p.lanes)).collect();
725 vlane.resize(nv, 0);
726 for ch in &chains {
727 for &dm in &ch[1..ch.len() - 1] {
728 vlane[dm] = vlane[ch[0]];
729 }
730 }
731 let laned = p.lanes > 0;
732
733 let mut layers: Vec<Vec<usize>> = vec![Vec::new(); nl];
735 let mut seen = vec![false; nv];
736 for s in ordered((0..nv).map(|v| (vrank[v] as f64, 0.0, v)).collect()) {
737 if seen[s] {
738 continue;
739 }
740 let mut stack = vec![s];
741 while let Some(v) = stack.pop() {
742 if seen[v] {
743 continue;
744 }
745 seen[v] = true;
746 layers[vrank[v]].push(v);
747 for &w in vsucc[v].iter().rev() {
748 if !seen[w] {
749 stack.push(w);
750 }
751 }
752 }
753 }
754 if laned {
755 for l in &mut layers {
756 *l = ordered(
757 l.iter()
758 .enumerate()
759 .map(|(i, &v)| (vlane[v] as f64, i as f64, v))
760 .collect(),
761 );
762 }
763 }
764 let mut pos = vec![0usize; nv];
765 let index = |layers: &[Vec<usize>], pos: &mut [usize]| {
766 for l in layers {
767 for (i, &v) in l.iter().enumerate() {
768 pos[v] = i;
769 }
770 }
771 };
772 index(&layers, &mut pos);
773 let crossings = |layers: &[Vec<usize>], pos: &[usize]| -> u64 {
774 (0..layers.len().saturating_sub(1))
775 .map(|r| layer_crossings(&layers[r], &vsucc, pos, layers[r + 1].len()))
776 .sum()
777 };
778
779 let mut best = layers.clone();
781 let mut best_c = crossings(&layers, &pos);
782 for it in 0..8 {
783 if best_c == 0 {
784 break;
785 }
786 let down = it % 2 == 0;
787 let rs: Vec<usize> = if down {
788 (1..nl).collect()
789 } else {
790 (0..nl.saturating_sub(1)).rev().collect()
791 };
792 for r in rs {
793 let nb = if down { &vpred } else { &vsucc };
794 let keyed: Vec<(f64, f64, usize)> = layers[r]
795 .iter()
796 .map(|&v| {
797 let k = if nb[v].is_empty() {
798 pos[v] as f64
799 } else {
800 nb[v].iter().map(|&w| pos[w] as f64).sum::<f64>() / nb[v].len() as f64
801 };
802 (vlane[v] as f64 * 1e6 + k, pos[v] as f64, v)
803 })
804 .collect();
805 layers[r] = ordered(keyed);
806 for (i, &v) in layers[r].iter().enumerate() {
807 pos[v] = i;
808 }
809 }
810 for _ in 0..4 {
811 let mut better = false;
812 for layer in layers.iter_mut() {
813 for i in 0..layer.len().saturating_sub(1) {
814 let (a, b) = (layer[i], layer[i + 1]);
815 if vlane[a] != vlane[b] {
816 continue;
817 }
818 let pair = |x: usize, y: usize| -> usize {
819 let c = |l: &[Vec<usize>]| {
820 l[x].iter()
821 .flat_map(|&q| l[y].iter().map(move |&r| (q, r)))
822 .filter(|&(q, r)| pos[q] > pos[r])
823 .count()
824 };
825 c(&vpred) + c(&vsucc)
826 };
827 if pair(b, a) < pair(a, b) {
828 layer.swap(i, i + 1);
829 pos[a] = i + 1;
830 pos[b] = i;
831 better = true;
832 }
833 }
834 }
835 if !better {
836 break;
837 }
838 }
839 let c = crossings(&layers, &pos);
840 if c < best_c {
841 best_c = c;
842 best = layers.clone();
843 }
844 }
845 let layers = best;
846 index(&layers, &mut pos);
847
848 let size = |v: usize| if dummy(v) { 0.0 } else { across(&nodes[v]) };
850 let gap_between = |a: usize, b: usize| -> f64 {
851 let g = match (dummy(a), dummy(b)) {
852 (true, true) => 8.0,
853 (false, false) => node_gap,
854 _ => 12.0,
855 };
856 let lane = if vlane[a] != vlane[b] {
857 lane_gap + lane_head
858 } else {
859 0.0
860 };
861 size(a) / 2.0 + g + lane + size(b) / 2.0
862 };
863 let mut y = vec![0.0f64; nv];
864 for l in &layers {
865 let mut at = 0.0;
866 for (i, &v) in l.iter().enumerate() {
867 if i > 0 {
868 at += gap_between(l[i - 1], v);
869 }
870 y[v] = at;
871 }
872 let mid = at / 2.0;
873 for &v in l {
874 y[v] -= mid;
875 }
876 }
877 let relax = |y: &mut Vec<f64>, r: usize, up: bool, down: bool| {
878 let l = &layers[r];
879 if l.is_empty() {
880 return;
881 }
882 let want: Vec<f64> = l
883 .iter()
884 .map(|&v| {
885 let mut nb: Vec<usize> = Vec::new();
886 if up {
887 nb.extend(&vpred[v]);
888 }
889 if down {
890 nb.extend(&vsucc[v]);
891 }
892 if nb.is_empty() {
893 y[v]
894 } else {
895 nb.iter().map(|&w| y[w]).sum::<f64>() / nb.len() as f64
896 }
897 })
898 .collect();
899 let weight: Vec<f64> = l
900 .iter()
901 .map(|&v| if dummy(v) { 2.0 } else { 1.0 })
902 .collect();
903 let gaps: Vec<f64> = (0..l.len())
904 .map(|i| {
905 if i == 0 {
906 0.0
907 } else {
908 gap_between(l[i - 1], l[i])
909 }
910 })
911 .collect();
912 for (&v, q) in l.iter().zip(place(&want, &weight, &gaps)) {
913 y[v] = q;
914 }
915 };
916 for _ in 0..6 {
917 for r in 1..nl {
918 relax(&mut y, r, true, false);
919 }
920 for r in (0..nl.saturating_sub(1)).rev() {
921 relax(&mut y, r, false, true);
922 }
923 }
924 for r in 0..nl {
925 relax(&mut y, r, true, true);
926 }
927 let mut lane_span: Vec<(f64, f64)> = Vec::new();
929 if laned {
930 let nlanes = p.lanes + 1;
931 let span = |y: &[f64], l: usize| {
932 (0..nv)
933 .filter(|&v| vlane[v] == l)
934 .map(|v| (y[v] - size(v) / 2.0, y[v] + size(v) / 2.0))
935 .fold(None, |acc: Option<(f64, f64)>, (a, b)| match acc {
936 None => Some((a, b)),
937 Some((x, z)) => Some((x.min(a), z.max(b))),
938 })
939 };
940 let mut floor: Option<f64> = None;
941 for l in 0..nlanes {
942 let Some((lo, _)) = span(&y, l) else {
943 lane_span.push((f64::NAN, f64::NAN));
944 continue;
945 };
946 if let Some(f) = floor {
947 let need = f + lane_gap + lane_head - lo;
948 if need > 0.0 {
949 for v in 0..nv {
950 if vlane[v] == l {
951 y[v] += need;
952 }
953 }
954 }
955 }
956 let (lo, hi) = span(&y, l).expect("lane has vertices");
957 lane_span.push((lo, hi));
958 floor = Some(hi);
959 }
960 }
961
962 let mut thick = vec![0.0f64; nl];
965 for v in 0..n {
966 thick[rank[v]] = thick[rank[v]].max(along(&nodes[v]));
967 }
968 let mut gap: Vec<f64> = vec![rank_gap; nl];
969 if lr {
970 for e in edges {
971 let (a, b) = (rank[e.from].min(rank[e.to]), rank[e.from].max(rank[e.to]));
972 if b != a + 1 {
973 continue;
974 }
975 if let Some(w) = e.label_w {
976 gap[a] = gap[a].max(w + 2.0 * p.arrow + 18.0);
977 }
978 }
979 }
980 let mut start_at = vec![0.0f64; nl];
981 for r in 1..nl {
982 start_at[r] = start_at[r - 1] + thick[r - 1] + gap[r - 1];
983 }
984 let centre = |r: usize| start_at[r] + thick[r] / 2.0;
985 let xy = |rk: f64, o: f64| if lr { (rk, o) } else { (o, rk) };
986
987 let mut pn: Vec<PlacedNode> = Vec::with_capacity(n);
988 for (v, b) in nodes.iter().enumerate() {
989 let (cx, cy) = xy(centre(rank[v]), y[v]);
990 pn.push(PlacedNode {
991 cx,
992 cy,
993 w: b.w,
994 h: b.h,
995 layer: rank[v],
996 order: 0,
997 });
998 }
999 let reading = ordered((0..n).map(|v| (rank[v] as f64, y[v], v)).collect());
1000 for (i, &v) in reading.iter().enumerate() {
1001 pn[v].order = i;
1002 }
1003
1004 let half_along = |v: usize| if lr { pn[v].w / 2.0 } else { pn[v].h / 2.0 };
1007 let side = |v: usize| if lr { pn[v].h } else { pn[v].w };
1008 let mut out_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
1009 let mut in_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
1010 for (c, ch) in chains.iter().enumerate() {
1011 out_ports[ch[0]].push(c);
1012 in_ports[ch[ch.len() - 1]].push(c);
1013 }
1014 for ports in &mut out_ports {
1015 *ports = ordered(ports.iter().map(|&c| (y[chains[c][1]], 0.0, c)).collect());
1016 }
1017 for ports in &mut in_ports {
1018 *ports = ordered(
1019 ports
1020 .iter()
1021 .map(|&c| (y[chains[c][chains[c].len() - 2]], 0.0, c))
1022 .collect(),
1023 );
1024 }
1025 let spread = |list: &[usize], c: usize, v: usize| -> f64 {
1026 let m = list.len();
1027 if m <= 1 {
1028 return 0.0;
1029 }
1030 let k = list.iter().position(|&x| x == c).unwrap_or(0);
1031 let span = (side(v) * 0.6).min(14.0 * (m - 1) as f64);
1032 -span / 2.0 + span * k as f64 / (m - 1) as f64
1033 };
1034 let mut edge_pts: Vec<Vec<(f64, f64)>> = vec![Vec::new(); edges.len()];
1035 let mut back = vec![false; edges.len()];
1036 for (c, ch) in chains.iter().enumerate() {
1037 let (u, v, k, rev) = dag[c];
1038 let mut pts = Vec::with_capacity(ch.len() * 2);
1039 pts.push(xy(
1040 centre(rank[u]) + half_along(u),
1041 y[u] + spread(&out_ports[u], c, u),
1042 ));
1043 for &dm in &ch[1..ch.len() - 1] {
1044 let r = vrank[dm];
1045 pts.push(xy(start_at[r], y[dm]));
1046 pts.push(xy(start_at[r] + thick[r], y[dm]));
1047 }
1048 pts.push(xy(
1049 centre(rank[v]) - half_along(v),
1050 y[v] + spread(&in_ports[v], c, v),
1051 ));
1052 if rev {
1053 pts.reverse();
1054 }
1055 edge_pts[k] = pts;
1056 back[k] = rev;
1057 }
1058 for k in loops {
1059 edge_pts[k] = self_loop(&pn[edges[k].from], lr, p.loop_size);
1060 }
1061 for &(u, v, k, rev) in &free {
1062 let mut pts = straight(&pn, u, v);
1063 if rev {
1064 pts.reverse();
1065 }
1066 edge_pts[k] = pts;
1067 back[k] = rev;
1068 }
1069 let total = start_at[nl - 1] + thick[nl - 1];
1071 let bands = lane_span
1072 .iter()
1073 .enumerate()
1074 .filter(|(l, (lo, _))| *l < p.lanes && lo.is_finite())
1075 .map(|(l, &(lo, hi))| {
1076 let (a, b) = if lr {
1077 xy(-12.0, lo - lane_head - 6.0)
1078 } else {
1079 xy(-lane_head - 10.0, lo - 8.0)
1080 };
1081 let (c, e) = xy(total + 12.0, hi + 8.0);
1082 (l, a, b, c, e)
1083 })
1084 .collect();
1085 finish(pn, edge_pts, back, nl, bands, p.margin)
1086}
1087
1088fn finish(
1090 mut pn: Vec<PlacedNode>,
1091 mut edge_pts: Vec<Vec<(f64, f64)>>,
1092 back: Vec<bool>,
1093 layers: usize,
1094 mut bands: Vec<(usize, f64, f64, f64, f64)>,
1095 margin: f64,
1096) -> GraphLayout {
1097 let (mut x0, mut y0, mut x1, mut y1) = (f64::MAX, f64::MAX, f64::MIN, f64::MIN);
1098 for q in &pn {
1099 x0 = x0.min(q.cx - q.w / 2.0);
1100 x1 = x1.max(q.cx + q.w / 2.0);
1101 y0 = y0.min(q.cy - q.h / 2.0);
1102 y1 = y1.max(q.cy + q.h / 2.0);
1103 }
1104 for &(px, py) in edge_pts.iter().flatten() {
1105 x0 = x0.min(px);
1106 x1 = x1.max(px);
1107 y0 = y0.min(py);
1108 y1 = y1.max(py);
1109 }
1110 for &(_, a, b, c, e) in &bands {
1111 x0 = x0.min(a.min(c));
1112 x1 = x1.max(a.max(c));
1113 y0 = y0.min(b.min(e));
1114 y1 = y1.max(b.max(e));
1115 }
1116 if pn.is_empty() {
1117 (x0, y0, x1, y1) = (0.0, 0.0, 0.0, 0.0);
1118 }
1119 let r = |v: f64| (v * 2.0).round() / 2.0;
1120 let (dx, dy) = (margin - x0, margin - y0);
1121 for q in &mut pn {
1122 q.cx = r(q.cx + dx);
1123 q.cy = r(q.cy + dy);
1124 }
1125 for pts in &mut edge_pts {
1126 for pt in pts.iter_mut() {
1127 *pt = (r(pt.0 + dx), r(pt.1 + dy));
1128 }
1129 }
1130 for b in &mut bands {
1131 *b = (b.0, r(b.1 + dx), r(b.2 + dy), r(b.3 + dx), r(b.4 + dy));
1132 }
1133 GraphLayout {
1134 w: r(x1 - x0 + 2.0 * margin),
1135 h: r(y1 - y0 + 2.0 * margin),
1136 nodes: pn,
1137 edges: edge_pts,
1138 back,
1139 layers,
1140 bands,
1141 }
1142}
1143
1144#[cfg(test)]
1145mod tests {
1146 use super::*;
1147
1148 fn node(w: f64, h: f64) -> GraphNode {
1149 GraphNode {
1150 w,
1151 h,
1152 ..Default::default()
1153 }
1154 }
1155 fn edge(from: usize, to: usize) -> GraphEdge {
1156 GraphEdge {
1157 from,
1158 to,
1159 label_w: None,
1160 }
1161 }
1162
1163 #[test]
1164 fn a_chain_runs_left_to_right_in_layers() {
1165 let l = layered(
1166 &[node(100.0, 40.0), node(100.0, 40.0), node(100.0, 40.0)],
1167 &[edge(0, 1), edge(1, 2)],
1168 &LayeredParams::default(),
1169 );
1170 assert_eq!(l.layers, 3);
1171 assert!(l.nodes[0].cx < l.nodes[1].cx && l.nodes[1].cx < l.nodes[2].cx);
1172 assert_eq!(l.nodes[0].cy, l.nodes[1].cy);
1173 assert_eq!(l.edges[0][0].0, l.nodes[0].cx + 50.0);
1175 assert_eq!(l.edges[0].last().unwrap().0, l.nodes[1].cx - 50.0);
1176 }
1177
1178 #[test]
1179 fn a_cycle_is_broken_and_marked_back() {
1180 let l = layered(
1181 &[node(80.0, 30.0), node(80.0, 30.0)],
1182 &[edge(0, 1), edge(1, 0)],
1183 &LayeredParams::default(),
1184 );
1185 assert_eq!(l.back, vec![false, true]);
1186 assert_eq!(l.layers, 2);
1187 }
1188
1189 #[test]
1190 fn crossings_are_removed_where_possible() {
1191 let ns = vec![node(60.0, 30.0); 4];
1193 let l = layered(&ns, &[edge(0, 3), edge(1, 2)], &LayeredParams::default());
1194 let (a, b, c, d) = (&l.nodes[0], &l.nodes[1], &l.nodes[2], &l.nodes[3]);
1195 assert_eq!(a.cy < b.cy, d.cy < c.cy, "{a:?} {b:?} {c:?} {d:?}");
1196 }
1197
1198 #[test]
1199 fn pins_and_the_explicit_grid() {
1200 let mut ns = vec![node(60.0, 30.0); 3];
1201 ns[2].pin.0 = Some(3.0);
1202 let l = layered(&ns, &[edge(0, 1)], &LayeredParams::default());
1203 assert_eq!(l.nodes[2].layer, 3, "a pinned layer keeps its number");
1204 let grid: Vec<GraphNode> = (0..4)
1205 .map(|i| GraphNode {
1206 w: 60.0,
1207 h: 30.0,
1208 pin: (Some((i % 2) as f64), Some((i / 2) as f64)),
1209 ..Default::default()
1210 })
1211 .collect();
1212 let g = layered(&grid, &[edge(0, 3)], &LayeredParams::default());
1213 assert_eq!(g.layers, 2);
1214 assert_eq!(g.nodes[0].cy, g.nodes[1].cy);
1215 assert_eq!(g.edges[0].len(), 2, "straight");
1216 }
1217
1218 #[test]
1219 fn lanes_become_bands_and_top_bottom_swaps_the_axes() {
1220 let mut ns = vec![node(60.0, 30.0); 2];
1221 ns[0].lane = Some(0);
1222 ns[1].lane = Some(1);
1223 let l = layered(
1224 &ns,
1225 &[edge(0, 1)],
1226 &LayeredParams {
1227 lanes: 2,
1228 ..Default::default()
1229 },
1230 );
1231 assert_eq!(l.bands.len(), 2);
1232 let tb = layered(
1233 &ns[..1],
1234 &[],
1235 &LayeredParams {
1236 direction: Direction::TopBottom,
1237 ..Default::default()
1238 },
1239 );
1240 assert_eq!(tb.nodes.len(), 1);
1241 let t = layered(
1242 &[node(60.0, 30.0), node(60.0, 30.0)],
1243 &[edge(0, 1)],
1244 &LayeredParams {
1245 direction: Direction::TopBottom,
1246 ..Default::default()
1247 },
1248 );
1249 assert!(t.nodes[0].cy < t.nodes[1].cy && t.nodes[0].cx == t.nodes[1].cx);
1250 }
1251
1252 #[test]
1253 fn edge_cases_loops_labels_ports_lanes_and_empty() {
1254 let p = LayeredParams::default();
1255 let empty = layered(&[], &[], &p);
1256 assert!(empty.nodes.is_empty() && empty.layers == 1);
1257 for dir in [Direction::LeftRight, Direction::TopBottom] {
1259 let q = LayeredParams {
1260 direction: dir,
1261 ..Default::default()
1262 };
1263 let l = layered(
1264 &[node(60.0, 30.0), node(60.0, 30.0)],
1265 &[edge(0, 0), edge(0, 1)],
1266 &q,
1267 );
1268 assert_eq!(l.edges[0].len(), 4, "a self-loop");
1269 let g: Vec<GraphNode> = (0..2)
1270 .map(|i| GraphNode {
1271 w: 60.0,
1272 h: 30.0,
1273 pin: (Some(i as f64), Some(0.0)),
1274 ..Default::default()
1275 })
1276 .collect();
1277 let gl = layered(&g, &[edge(1, 1), edge(0, 1)], &q);
1278 assert_eq!(gl.edges[0].len(), 4);
1279 }
1280 let ns = vec![node(60.0, 30.0); 4];
1282 let plain = layered(
1283 &ns,
1284 &[edge(0, 1), edge(1, 2), edge(0, 2), edge(0, 3), edge(2, 3)],
1285 &p,
1286 );
1287 let labelled = layered(
1288 &ns,
1289 &[
1290 GraphEdge {
1291 from: 0,
1292 to: 1,
1293 label_w: Some(300.0),
1294 },
1295 edge(1, 2),
1296 edge(0, 2),
1297 edge(0, 3),
1298 edge(2, 3),
1299 ],
1300 &p,
1301 );
1302 assert!(
1303 labelled.nodes[1].cx - labelled.nodes[0].cx > plain.nodes[1].cx - plain.nodes[0].cx
1304 );
1305 assert!(
1306 plain.edges[3].len() > 2,
1307 "a long edge bends through its dummies"
1308 );
1309 let starts: Vec<f64> = [0, 2, 3].iter().map(|&k| plain.edges[k][0].1).collect();
1311 assert!(starts.windows(2).any(|w| w[0] != w[1]), "{starts:?}");
1312 let mut pn = vec![node(60.0, 30.0); 3];
1314 pn[0].pin.0 = Some(2.0);
1315 pn[1].pin.0 = Some(0.0);
1316 let back = layered(&pn, &[edge(0, 1), edge(1, 2)], &p);
1317 assert_eq!(back.edges[0].len(), 2);
1318 let mut lanes = vec![node(60.0, 30.0); 5];
1320 for (i, n) in lanes.iter_mut().enumerate().take(4) {
1321 n.lane = Some(i % 2);
1322 }
1323 let q = LayeredParams {
1324 direction: Direction::TopBottom,
1325 lanes: 2,
1326 ..Default::default()
1327 };
1328 let tb = layered(
1329 &lanes,
1330 &[edge(0, 3), edge(1, 2), edge(2, 4), edge(3, 4)],
1331 &q,
1332 );
1333 assert_eq!(tb.bands.len(), 2);
1334 assert!(tb.bands.iter().all(|b| b.3 > b.1 && b.4 > b.2));
1335 }
1336
1337 #[test]
1340 fn banded_fans_out_drops_and_hangs_leaves_below() {
1341 let node = |lane| GraphNode {
1343 w: 40.0,
1344 h: 20.0,
1345 lane: Some(lane),
1346 ..Default::default()
1347 };
1348 let mut nodes = vec![node(0)];
1349 nodes.extend((0..3).map(|_| node(1)));
1350 nodes.extend((0..3).map(|_| node(1)));
1351 let edge = |from, to| GraphEdge {
1352 from,
1353 to,
1354 label_w: None,
1355 };
1356 let mut edges = Vec::new();
1357 for i in 0..3 {
1358 edges.push(edge(0, 1 + i));
1359 edges.push(edge(1 + i, 4 + i));
1360 }
1361 let l = banded(
1362 &nodes,
1363 &edges,
1364 &BandedParams {
1365 bands: 2,
1366 ..Default::default()
1367 },
1368 );
1369 let cx: Vec<f64> = (1..=3).map(|i| l.nodes[i].cx).collect();
1370 assert!(cx[0] < cx[1] && cx[1] < cx[2], "fanned out: {cx:?}");
1371 for i in 0..3 {
1372 let (f, y) = (&l.nodes[1 + i], &l.nodes[4 + i]);
1373 assert_eq!(f.cx, y.cx, "y{i} under its factor");
1374 assert!(y.cy > f.cy);
1375 }
1376 }
1377}