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
118type DagEdge = (usize, usize, usize, bool);
120
121fn break_cycles(n: usize, edges: &[GraphEdge]) -> (Vec<DagEdge>, Vec<usize>) {
124 let mut out: Vec<Vec<(usize, usize)>> = vec![Vec::new(); n];
125 let mut loops = Vec::new();
126 for (k, e) in edges.iter().enumerate() {
127 if e.from == e.to {
128 loops.push(k);
129 } else {
130 out[e.from].push((e.to, k));
131 }
132 }
133 let mut state = vec![0u8; n]; let mut rev = vec![false; edges.len()];
135 for s in 0..n {
136 if state[s] != 0 {
137 continue;
138 }
139 state[s] = 1;
140 let mut stack = vec![(s, 0usize)];
141 while let Some(top) = stack.last_mut() {
142 let v = top.0;
143 if top.1 < out[v].len() {
144 let (w, k) = out[v][top.1];
145 top.1 += 1;
146 match state[w] {
147 0 => {
148 state[w] = 1;
149 stack.push((w, 0));
150 }
151 1 => rev[k] = true,
152 _ => {}
153 }
154 } else {
155 state[v] = 2;
156 stack.pop();
157 }
158 }
159 }
160 let dag = edges
161 .iter()
162 .enumerate()
163 .filter(|(_, e)| e.from != e.to)
164 .map(|(k, e)| {
165 if rev[k] {
166 (e.to, e.from, k, true)
167 } else {
168 (e.from, e.to, k, false)
169 }
170 })
171 .collect();
172 (dag, loops)
173}
174
175fn ordered(mut keys: Vec<(f64, f64, usize)>) -> Vec<usize> {
177 keys.sort_unstable_by(|a, b| {
178 a.0.total_cmp(&b.0)
179 .then(a.1.total_cmp(&b.1))
180 .then(a.2.cmp(&b.2))
181 });
182 keys.into_iter().map(|k| k.2).collect()
183}
184
185fn layer_crossings(upper: &[usize], succ: &[Vec<usize>], pos: &[usize], lower_len: usize) -> u64 {
188 let mut ends: Vec<(usize, usize)> = Vec::new();
189 for &u in upper {
190 for &v in &succ[u] {
191 ends.push((pos[u], pos[v]));
192 }
193 }
194 let lower: Vec<usize> = ordered(
195 ends.iter()
196 .enumerate()
197 .map(|(i, &(u, v))| (u as f64, v as f64, i))
198 .collect(),
199 )
200 .into_iter()
201 .map(|i| ends[i].1)
202 .collect();
203 let mut tree = vec![0u64; lower_len + 1];
204 let mut c = 0u64;
205 for (seen, &p) in lower.iter().enumerate() {
206 let mut i = p + 1;
207 let mut le = 0u64;
208 while i > 0 {
209 le += tree[i];
210 i -= 1 << i.trailing_zeros();
211 }
212 c += seen as u64 - le;
213 let mut i = p + 1;
214 while i <= lower_len {
215 tree[i] += 1;
216 i += 1 << i.trailing_zeros();
217 }
218 }
219 c
220}
221
222fn place(want: &[f64], weight: &[f64], gap: &[f64]) -> Vec<f64> {
226 let n = want.len();
227 let mut off = vec![0.0; n];
228 for i in 1..n {
229 off[i] = off[i - 1] + gap[i];
230 }
231 let mut blocks: Vec<(f64, f64, usize)> = Vec::new();
232 for i in 0..n {
233 blocks.push((weight[i] * (want[i] - off[i]), weight[i], 1));
234 while blocks.len() >= 2 {
235 let (b, a) = (blocks[blocks.len() - 1], blocks[blocks.len() - 2]);
236 if a.0 / a.1 > b.0 / b.1 {
237 blocks.pop();
238 let last = blocks.last_mut().expect("two blocks");
239 *last = (a.0 + b.0, a.1 + b.1, a.2 + b.2);
240 } else {
241 break;
242 }
243 }
244 }
245 let mut out = Vec::with_capacity(n);
246 for (s, w, c) in blocks {
247 for _ in 0..c {
248 let i = out.len();
249 out.push(s / w + off[i]);
250 }
251 }
252 out
253}
254
255fn exit(p: &PlacedNode, to: (f64, f64)) -> (f64, f64) {
257 let (dx, dy) = (to.0 - p.cx, to.1 - p.cy);
258 let sx = if dx != 0.0 {
259 p.w / 2.0 / dx.abs()
260 } else {
261 f64::INFINITY
262 };
263 let sy = if dy != 0.0 {
264 p.h / 2.0 / dy.abs()
265 } else {
266 f64::INFINITY
267 };
268 let k = sx.min(sy);
269 if k.is_finite() {
270 (p.cx + dx * k, p.cy + dy * k)
271 } else {
272 (p.cx, p.cy)
273 }
274}
275
276fn straight(pn: &[PlacedNode], u: usize, v: usize) -> Vec<(f64, f64)> {
277 let (a, b) = (&pn[u], &pn[v]);
278 vec![exit(a, (b.cx, b.cy)), exit(b, (a.cx, a.cy))]
279}
280
281fn self_loop(p: &PlacedNode, lr: bool, reach: f64) -> Vec<(f64, f64)> {
283 if lr {
284 let top = p.cy - p.h / 2.0;
285 vec![
286 (p.cx + p.w / 4.0, top),
287 (p.cx + p.w / 4.0, top - reach),
288 (p.cx - p.w / 4.0, top - reach),
289 (p.cx - p.w / 4.0, top),
290 ]
291 } else {
292 let right = p.cx + p.w / 2.0;
293 vec![
294 (right, p.cy - p.h / 4.0),
295 (right + reach, p.cy - p.h / 4.0),
296 (right + reach, p.cy + p.h / 4.0),
297 (right, p.cy + p.h / 4.0),
298 ]
299 }
300}
301
302fn layout_explicit(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
304 let sx = nodes.iter().map(|b| b.w).fold(0.0, f64::max) + 48.0;
305 let sy = nodes.iter().map(|b| b.h).fold(0.0, f64::max) + 24.0;
306 let pin = |v: usize| (nodes[v].pin.0.unwrap_or(0.0), nodes[v].pin.1.unwrap_or(0.0));
307 let mut xs: Vec<f64> = (0..nodes.len()).map(|v| pin(v).0).collect();
308 xs.sort_by(f64::total_cmp);
309 xs.dedup();
310 let reading = ordered((0..nodes.len()).map(|v| (pin(v).0, pin(v).1, v)).collect());
311 let mut pn: Vec<PlacedNode> = nodes
312 .iter()
313 .enumerate()
314 .map(|(v, b)| PlacedNode {
315 cx: pin(v).0 * sx,
316 cy: pin(v).1 * sy,
317 w: b.w,
318 h: b.h,
319 layer: xs.iter().position(|&x| x == pin(v).0).unwrap_or(0),
320 order: 0,
321 })
322 .collect();
323 for (i, &v) in reading.iter().enumerate() {
324 pn[v].order = i;
325 }
326 let lr = p.direction == Direction::LeftRight;
327 let pts = edges
328 .iter()
329 .map(|e| {
330 if e.from == e.to {
331 self_loop(&pn[e.from], lr, p.loop_size)
332 } else {
333 straight(&pn, e.from, e.to)
334 }
335 })
336 .collect();
337 finish(
338 pn,
339 pts,
340 vec![false; edges.len()],
341 xs.len().max(1),
342 Vec::new(),
343 p.margin,
344 )
345}
346
347fn layout(nodes: &[GraphNode], edges: &[GraphEdge], p: &LayeredParams) -> GraphLayout {
348 let n = nodes.len();
349 let (dag, loops) = break_cycles(n, edges);
350 let lr = p.direction == Direction::LeftRight;
351 let along = |b: &GraphNode| if lr { b.w } else { b.h };
352 let across = |b: &GraphNode| if lr { b.h } else { b.w };
353 let (rank_gap, node_gap) = if lr { (64.0, 20.0) } else { (48.0, 28.0) };
354 let (lane_gap, lane_head) = (p.lane_gap, p.lane_head);
355
356 let mut preds: Vec<Vec<usize>> = vec![Vec::new(); n];
359 let mut succs: Vec<Vec<usize>> = vec![Vec::new(); n];
360 for &(u, v, _, _) in &dag {
361 preds[v].push(u);
362 succs[u].push(v);
363 }
364 let mut indeg: Vec<usize> = preds.iter().map(Vec::len).collect();
365 let mut done = vec![false; n];
366 let mut topo = Vec::with_capacity(n);
367 while let Some(v) = (0..n).find(|&v| !done[v] && indeg[v] == 0) {
368 done[v] = true;
369 topo.push(v);
370 for &w in &succs[v] {
371 indeg[w] -= 1;
372 }
373 }
374 let pinned = |v: usize| {
376 nodes[v]
377 .pin
378 .0
379 .map(|x| x.round().clamp(0.0, 1000.0) as usize)
380 };
381 let any_pin = (0..n).any(|v| pinned(v).is_some());
382 let mut rank = vec![0usize; n];
383 for &v in &topo {
384 rank[v] =
385 pinned(v).unwrap_or_else(|| preds[v].iter().map(|&q| rank[q] + 1).max().unwrap_or(0));
386 }
387 for &v in topo.iter().rev() {
388 if preds[v].is_empty() && pinned(v).is_none() {
389 if let Some(m) = succs[v].iter().map(|&s| rank[s]).min() {
390 rank[v] = rank[v].max(m.saturating_sub(1));
391 }
392 }
393 }
394 let mut used = vec![false; rank.iter().max().map_or(1, |m| m + 1)];
396 for &r in &rank {
397 used[r] = true;
398 }
399 let mut renumber = vec![0usize; used.len()];
400 let mut nl = 0;
401 for (r, u) in used.iter().enumerate() {
402 renumber[r] = nl;
403 nl += usize::from(*u || any_pin);
404 }
405 for r in &mut rank {
406 *r = renumber[*r];
407 }
408 let nl = nl.max(1);
409 let (dag, free): (Vec<DagEdge>, Vec<DagEdge>) =
411 dag.into_iter().partition(|&(u, v, _, _)| rank[v] > rank[u]);
412
413 let mut vrank: Vec<usize> = rank.clone();
415 let mut vsucc: Vec<Vec<usize>> = vec![Vec::new(); n];
416 let mut vpred: Vec<Vec<usize>> = vec![Vec::new(); n];
417 let mut chains: Vec<Vec<usize>> = Vec::with_capacity(dag.len());
418 for &(u, v, _, _) in &dag {
419 let mut chain = vec![u];
420 let mut prev = u;
421 for r in rank[u] + 1..rank[v] {
422 let dmy = vrank.len();
423 vrank.push(r);
424 vsucc.push(Vec::new());
425 vpred.push(Vec::new());
426 vsucc[prev].push(dmy);
427 vpred[dmy].push(prev);
428 chain.push(dmy);
429 prev = dmy;
430 }
431 vsucc[prev].push(v);
432 vpred[v].push(prev);
433 chain.push(v);
434 chains.push(chain);
435 }
436 let nv = vrank.len();
437 let dummy = |v: usize| v >= n;
438 let mut vlane: Vec<usize> = (0..n).map(|v| nodes[v].lane.unwrap_or(p.lanes)).collect();
440 vlane.resize(nv, 0);
441 for ch in &chains {
442 for &dm in &ch[1..ch.len() - 1] {
443 vlane[dm] = vlane[ch[0]];
444 }
445 }
446 let laned = p.lanes > 0;
447
448 let mut layers: Vec<Vec<usize>> = vec![Vec::new(); nl];
450 let mut seen = vec![false; nv];
451 for s in ordered((0..nv).map(|v| (vrank[v] as f64, 0.0, v)).collect()) {
452 if seen[s] {
453 continue;
454 }
455 let mut stack = vec![s];
456 while let Some(v) = stack.pop() {
457 if seen[v] {
458 continue;
459 }
460 seen[v] = true;
461 layers[vrank[v]].push(v);
462 for &w in vsucc[v].iter().rev() {
463 if !seen[w] {
464 stack.push(w);
465 }
466 }
467 }
468 }
469 if laned {
470 for l in &mut layers {
471 *l = ordered(
472 l.iter()
473 .enumerate()
474 .map(|(i, &v)| (vlane[v] as f64, i as f64, v))
475 .collect(),
476 );
477 }
478 }
479 let mut pos = vec![0usize; nv];
480 let index = |layers: &[Vec<usize>], pos: &mut [usize]| {
481 for l in layers {
482 for (i, &v) in l.iter().enumerate() {
483 pos[v] = i;
484 }
485 }
486 };
487 index(&layers, &mut pos);
488 let crossings = |layers: &[Vec<usize>], pos: &[usize]| -> u64 {
489 (0..layers.len().saturating_sub(1))
490 .map(|r| layer_crossings(&layers[r], &vsucc, pos, layers[r + 1].len()))
491 .sum()
492 };
493
494 let mut best = layers.clone();
496 let mut best_c = crossings(&layers, &pos);
497 for it in 0..8 {
498 if best_c == 0 {
499 break;
500 }
501 let down = it % 2 == 0;
502 let rs: Vec<usize> = if down {
503 (1..nl).collect()
504 } else {
505 (0..nl.saturating_sub(1)).rev().collect()
506 };
507 for r in rs {
508 let nb = if down { &vpred } else { &vsucc };
509 let keyed: Vec<(f64, f64, usize)> = layers[r]
510 .iter()
511 .map(|&v| {
512 let k = if nb[v].is_empty() {
513 pos[v] as f64
514 } else {
515 nb[v].iter().map(|&w| pos[w] as f64).sum::<f64>() / nb[v].len() as f64
516 };
517 (vlane[v] as f64 * 1e6 + k, pos[v] as f64, v)
518 })
519 .collect();
520 layers[r] = ordered(keyed);
521 for (i, &v) in layers[r].iter().enumerate() {
522 pos[v] = i;
523 }
524 }
525 for _ in 0..4 {
526 let mut better = false;
527 for layer in layers.iter_mut() {
528 for i in 0..layer.len().saturating_sub(1) {
529 let (a, b) = (layer[i], layer[i + 1]);
530 if vlane[a] != vlane[b] {
531 continue;
532 }
533 let pair = |x: usize, y: usize| -> usize {
534 let c = |l: &[Vec<usize>]| {
535 l[x].iter()
536 .flat_map(|&q| l[y].iter().map(move |&r| (q, r)))
537 .filter(|&(q, r)| pos[q] > pos[r])
538 .count()
539 };
540 c(&vpred) + c(&vsucc)
541 };
542 if pair(b, a) < pair(a, b) {
543 layer.swap(i, i + 1);
544 pos[a] = i + 1;
545 pos[b] = i;
546 better = true;
547 }
548 }
549 }
550 if !better {
551 break;
552 }
553 }
554 let c = crossings(&layers, &pos);
555 if c < best_c {
556 best_c = c;
557 best = layers.clone();
558 }
559 }
560 let layers = best;
561 index(&layers, &mut pos);
562
563 let size = |v: usize| if dummy(v) { 0.0 } else { across(&nodes[v]) };
565 let gap_between = |a: usize, b: usize| -> f64 {
566 let g = match (dummy(a), dummy(b)) {
567 (true, true) => 8.0,
568 (false, false) => node_gap,
569 _ => 12.0,
570 };
571 let lane = if vlane[a] != vlane[b] {
572 lane_gap + lane_head
573 } else {
574 0.0
575 };
576 size(a) / 2.0 + g + lane + size(b) / 2.0
577 };
578 let mut y = vec![0.0f64; nv];
579 for l in &layers {
580 let mut at = 0.0;
581 for (i, &v) in l.iter().enumerate() {
582 if i > 0 {
583 at += gap_between(l[i - 1], v);
584 }
585 y[v] = at;
586 }
587 let mid = at / 2.0;
588 for &v in l {
589 y[v] -= mid;
590 }
591 }
592 let relax = |y: &mut Vec<f64>, r: usize, up: bool, down: bool| {
593 let l = &layers[r];
594 if l.is_empty() {
595 return;
596 }
597 let want: Vec<f64> = l
598 .iter()
599 .map(|&v| {
600 let mut nb: Vec<usize> = Vec::new();
601 if up {
602 nb.extend(&vpred[v]);
603 }
604 if down {
605 nb.extend(&vsucc[v]);
606 }
607 if nb.is_empty() {
608 y[v]
609 } else {
610 nb.iter().map(|&w| y[w]).sum::<f64>() / nb.len() as f64
611 }
612 })
613 .collect();
614 let weight: Vec<f64> = l
615 .iter()
616 .map(|&v| if dummy(v) { 2.0 } else { 1.0 })
617 .collect();
618 let gaps: Vec<f64> = (0..l.len())
619 .map(|i| {
620 if i == 0 {
621 0.0
622 } else {
623 gap_between(l[i - 1], l[i])
624 }
625 })
626 .collect();
627 for (&v, q) in l.iter().zip(place(&want, &weight, &gaps)) {
628 y[v] = q;
629 }
630 };
631 for _ in 0..6 {
632 for r in 1..nl {
633 relax(&mut y, r, true, false);
634 }
635 for r in (0..nl.saturating_sub(1)).rev() {
636 relax(&mut y, r, false, true);
637 }
638 }
639 for r in 0..nl {
640 relax(&mut y, r, true, true);
641 }
642 let mut lane_span: Vec<(f64, f64)> = Vec::new();
644 if laned {
645 let nlanes = p.lanes + 1;
646 let span = |y: &[f64], l: usize| {
647 (0..nv)
648 .filter(|&v| vlane[v] == l)
649 .map(|v| (y[v] - size(v) / 2.0, y[v] + size(v) / 2.0))
650 .fold(None, |acc: Option<(f64, f64)>, (a, b)| match acc {
651 None => Some((a, b)),
652 Some((x, z)) => Some((x.min(a), z.max(b))),
653 })
654 };
655 let mut floor: Option<f64> = None;
656 for l in 0..nlanes {
657 let Some((lo, _)) = span(&y, l) else {
658 lane_span.push((f64::NAN, f64::NAN));
659 continue;
660 };
661 if let Some(f) = floor {
662 let need = f + lane_gap + lane_head - lo;
663 if need > 0.0 {
664 for v in 0..nv {
665 if vlane[v] == l {
666 y[v] += need;
667 }
668 }
669 }
670 }
671 let (lo, hi) = span(&y, l).expect("lane has vertices");
672 lane_span.push((lo, hi));
673 floor = Some(hi);
674 }
675 }
676
677 let mut thick = vec![0.0f64; nl];
680 for v in 0..n {
681 thick[rank[v]] = thick[rank[v]].max(along(&nodes[v]));
682 }
683 let mut gap: Vec<f64> = vec![rank_gap; nl];
684 if lr {
685 for e in edges {
686 let (a, b) = (rank[e.from].min(rank[e.to]), rank[e.from].max(rank[e.to]));
687 if b != a + 1 {
688 continue;
689 }
690 if let Some(w) = e.label_w {
691 gap[a] = gap[a].max(w + 2.0 * p.arrow + 18.0);
692 }
693 }
694 }
695 let mut start_at = vec![0.0f64; nl];
696 for r in 1..nl {
697 start_at[r] = start_at[r - 1] + thick[r - 1] + gap[r - 1];
698 }
699 let centre = |r: usize| start_at[r] + thick[r] / 2.0;
700 let xy = |rk: f64, o: f64| if lr { (rk, o) } else { (o, rk) };
701
702 let mut pn: Vec<PlacedNode> = Vec::with_capacity(n);
703 for (v, b) in nodes.iter().enumerate() {
704 let (cx, cy) = xy(centre(rank[v]), y[v]);
705 pn.push(PlacedNode {
706 cx,
707 cy,
708 w: b.w,
709 h: b.h,
710 layer: rank[v],
711 order: 0,
712 });
713 }
714 let reading = ordered((0..n).map(|v| (rank[v] as f64, y[v], v)).collect());
715 for (i, &v) in reading.iter().enumerate() {
716 pn[v].order = i;
717 }
718
719 let half_along = |v: usize| if lr { pn[v].w / 2.0 } else { pn[v].h / 2.0 };
722 let side = |v: usize| if lr { pn[v].h } else { pn[v].w };
723 let mut out_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
724 let mut in_ports: Vec<Vec<usize>> = vec![Vec::new(); n];
725 for (c, ch) in chains.iter().enumerate() {
726 out_ports[ch[0]].push(c);
727 in_ports[ch[ch.len() - 1]].push(c);
728 }
729 for ports in &mut out_ports {
730 *ports = ordered(ports.iter().map(|&c| (y[chains[c][1]], 0.0, c)).collect());
731 }
732 for ports in &mut in_ports {
733 *ports = ordered(
734 ports
735 .iter()
736 .map(|&c| (y[chains[c][chains[c].len() - 2]], 0.0, c))
737 .collect(),
738 );
739 }
740 let spread = |list: &[usize], c: usize, v: usize| -> f64 {
741 let m = list.len();
742 if m <= 1 {
743 return 0.0;
744 }
745 let k = list.iter().position(|&x| x == c).unwrap_or(0);
746 let span = (side(v) * 0.6).min(14.0 * (m - 1) as f64);
747 -span / 2.0 + span * k as f64 / (m - 1) as f64
748 };
749 let mut edge_pts: Vec<Vec<(f64, f64)>> = vec![Vec::new(); edges.len()];
750 let mut back = vec![false; edges.len()];
751 for (c, ch) in chains.iter().enumerate() {
752 let (u, v, k, rev) = dag[c];
753 let mut pts = Vec::with_capacity(ch.len() * 2);
754 pts.push(xy(
755 centre(rank[u]) + half_along(u),
756 y[u] + spread(&out_ports[u], c, u),
757 ));
758 for &dm in &ch[1..ch.len() - 1] {
759 let r = vrank[dm];
760 pts.push(xy(start_at[r], y[dm]));
761 pts.push(xy(start_at[r] + thick[r], y[dm]));
762 }
763 pts.push(xy(
764 centre(rank[v]) - half_along(v),
765 y[v] + spread(&in_ports[v], c, v),
766 ));
767 if rev {
768 pts.reverse();
769 }
770 edge_pts[k] = pts;
771 back[k] = rev;
772 }
773 for k in loops {
774 edge_pts[k] = self_loop(&pn[edges[k].from], lr, p.loop_size);
775 }
776 for &(u, v, k, rev) in &free {
777 let mut pts = straight(&pn, u, v);
778 if rev {
779 pts.reverse();
780 }
781 edge_pts[k] = pts;
782 back[k] = rev;
783 }
784 let total = start_at[nl - 1] + thick[nl - 1];
786 let bands = lane_span
787 .iter()
788 .enumerate()
789 .filter(|(l, (lo, _))| *l < p.lanes && lo.is_finite())
790 .map(|(l, &(lo, hi))| {
791 let (a, b) = if lr {
792 xy(-12.0, lo - lane_head - 6.0)
793 } else {
794 xy(-lane_head - 10.0, lo - 8.0)
795 };
796 let (c, e) = xy(total + 12.0, hi + 8.0);
797 (l, a, b, c, e)
798 })
799 .collect();
800 finish(pn, edge_pts, back, nl, bands, p.margin)
801}
802
803fn finish(
805 mut pn: Vec<PlacedNode>,
806 mut edge_pts: Vec<Vec<(f64, f64)>>,
807 back: Vec<bool>,
808 layers: usize,
809 mut bands: Vec<(usize, f64, f64, f64, f64)>,
810 margin: f64,
811) -> GraphLayout {
812 let (mut x0, mut y0, mut x1, mut y1) = (f64::MAX, f64::MAX, f64::MIN, f64::MIN);
813 for q in &pn {
814 x0 = x0.min(q.cx - q.w / 2.0);
815 x1 = x1.max(q.cx + q.w / 2.0);
816 y0 = y0.min(q.cy - q.h / 2.0);
817 y1 = y1.max(q.cy + q.h / 2.0);
818 }
819 for &(px, py) in edge_pts.iter().flatten() {
820 x0 = x0.min(px);
821 x1 = x1.max(px);
822 y0 = y0.min(py);
823 y1 = y1.max(py);
824 }
825 for &(_, a, b, c, e) in &bands {
826 x0 = x0.min(a.min(c));
827 x1 = x1.max(a.max(c));
828 y0 = y0.min(b.min(e));
829 y1 = y1.max(b.max(e));
830 }
831 if pn.is_empty() {
832 (x0, y0, x1, y1) = (0.0, 0.0, 0.0, 0.0);
833 }
834 let r = |v: f64| (v * 2.0).round() / 2.0;
835 let (dx, dy) = (margin - x0, margin - y0);
836 for q in &mut pn {
837 q.cx = r(q.cx + dx);
838 q.cy = r(q.cy + dy);
839 }
840 for pts in &mut edge_pts {
841 for pt in pts.iter_mut() {
842 *pt = (r(pt.0 + dx), r(pt.1 + dy));
843 }
844 }
845 for b in &mut bands {
846 *b = (b.0, r(b.1 + dx), r(b.2 + dy), r(b.3 + dx), r(b.4 + dy));
847 }
848 GraphLayout {
849 w: r(x1 - x0 + 2.0 * margin),
850 h: r(y1 - y0 + 2.0 * margin),
851 nodes: pn,
852 edges: edge_pts,
853 back,
854 layers,
855 bands,
856 }
857}
858
859#[cfg(test)]
860mod tests {
861 use super::*;
862
863 fn node(w: f64, h: f64) -> GraphNode {
864 GraphNode {
865 w,
866 h,
867 ..Default::default()
868 }
869 }
870 fn edge(from: usize, to: usize) -> GraphEdge {
871 GraphEdge {
872 from,
873 to,
874 label_w: None,
875 }
876 }
877
878 #[test]
879 fn a_chain_runs_left_to_right_in_layers() {
880 let l = layered(
881 &[node(100.0, 40.0), node(100.0, 40.0), node(100.0, 40.0)],
882 &[edge(0, 1), edge(1, 2)],
883 &LayeredParams::default(),
884 );
885 assert_eq!(l.layers, 3);
886 assert!(l.nodes[0].cx < l.nodes[1].cx && l.nodes[1].cx < l.nodes[2].cx);
887 assert_eq!(l.nodes[0].cy, l.nodes[1].cy);
888 assert_eq!(l.edges[0][0].0, l.nodes[0].cx + 50.0);
890 assert_eq!(l.edges[0].last().unwrap().0, l.nodes[1].cx - 50.0);
891 }
892
893 #[test]
894 fn a_cycle_is_broken_and_marked_back() {
895 let l = layered(
896 &[node(80.0, 30.0), node(80.0, 30.0)],
897 &[edge(0, 1), edge(1, 0)],
898 &LayeredParams::default(),
899 );
900 assert_eq!(l.back, vec![false, true]);
901 assert_eq!(l.layers, 2);
902 }
903
904 #[test]
905 fn crossings_are_removed_where_possible() {
906 let ns = vec![node(60.0, 30.0); 4];
908 let l = layered(&ns, &[edge(0, 3), edge(1, 2)], &LayeredParams::default());
909 let (a, b, c, d) = (&l.nodes[0], &l.nodes[1], &l.nodes[2], &l.nodes[3]);
910 assert_eq!(a.cy < b.cy, d.cy < c.cy, "{a:?} {b:?} {c:?} {d:?}");
911 }
912
913 #[test]
914 fn pins_and_the_explicit_grid() {
915 let mut ns = vec![node(60.0, 30.0); 3];
916 ns[2].pin.0 = Some(3.0);
917 let l = layered(&ns, &[edge(0, 1)], &LayeredParams::default());
918 assert_eq!(l.nodes[2].layer, 3, "a pinned layer keeps its number");
919 let grid: Vec<GraphNode> = (0..4)
920 .map(|i| GraphNode {
921 w: 60.0,
922 h: 30.0,
923 pin: (Some((i % 2) as f64), Some((i / 2) as f64)),
924 ..Default::default()
925 })
926 .collect();
927 let g = layered(&grid, &[edge(0, 3)], &LayeredParams::default());
928 assert_eq!(g.layers, 2);
929 assert_eq!(g.nodes[0].cy, g.nodes[1].cy);
930 assert_eq!(g.edges[0].len(), 2, "straight");
931 }
932
933 #[test]
934 fn lanes_become_bands_and_top_bottom_swaps_the_axes() {
935 let mut ns = vec![node(60.0, 30.0); 2];
936 ns[0].lane = Some(0);
937 ns[1].lane = Some(1);
938 let l = layered(
939 &ns,
940 &[edge(0, 1)],
941 &LayeredParams {
942 lanes: 2,
943 ..Default::default()
944 },
945 );
946 assert_eq!(l.bands.len(), 2);
947 let tb = layered(
948 &ns[..1],
949 &[],
950 &LayeredParams {
951 direction: Direction::TopBottom,
952 ..Default::default()
953 },
954 );
955 assert_eq!(tb.nodes.len(), 1);
956 let t = layered(
957 &[node(60.0, 30.0), node(60.0, 30.0)],
958 &[edge(0, 1)],
959 &LayeredParams {
960 direction: Direction::TopBottom,
961 ..Default::default()
962 },
963 );
964 assert!(t.nodes[0].cy < t.nodes[1].cy && t.nodes[0].cx == t.nodes[1].cx);
965 }
966
967 #[test]
968 fn edge_cases_loops_labels_ports_lanes_and_empty() {
969 let p = LayeredParams::default();
970 let empty = layered(&[], &[], &p);
971 assert!(empty.nodes.is_empty() && empty.layers == 1);
972 for dir in [Direction::LeftRight, Direction::TopBottom] {
974 let q = LayeredParams {
975 direction: dir,
976 ..Default::default()
977 };
978 let l = layered(
979 &[node(60.0, 30.0), node(60.0, 30.0)],
980 &[edge(0, 0), edge(0, 1)],
981 &q,
982 );
983 assert_eq!(l.edges[0].len(), 4, "a self-loop");
984 let g: Vec<GraphNode> = (0..2)
985 .map(|i| GraphNode {
986 w: 60.0,
987 h: 30.0,
988 pin: (Some(i as f64), Some(0.0)),
989 ..Default::default()
990 })
991 .collect();
992 let gl = layered(&g, &[edge(1, 1), edge(0, 1)], &q);
993 assert_eq!(gl.edges[0].len(), 4);
994 }
995 let ns = vec![node(60.0, 30.0); 4];
997 let plain = layered(
998 &ns,
999 &[edge(0, 1), edge(1, 2), edge(0, 2), edge(0, 3), edge(2, 3)],
1000 &p,
1001 );
1002 let labelled = layered(
1003 &ns,
1004 &[
1005 GraphEdge {
1006 from: 0,
1007 to: 1,
1008 label_w: Some(300.0),
1009 },
1010 edge(1, 2),
1011 edge(0, 2),
1012 edge(0, 3),
1013 edge(2, 3),
1014 ],
1015 &p,
1016 );
1017 assert!(
1018 labelled.nodes[1].cx - labelled.nodes[0].cx > plain.nodes[1].cx - plain.nodes[0].cx
1019 );
1020 assert!(
1021 plain.edges[3].len() > 2,
1022 "a long edge bends through its dummies"
1023 );
1024 let starts: Vec<f64> = [0, 2, 3].iter().map(|&k| plain.edges[k][0].1).collect();
1026 assert!(starts.windows(2).any(|w| w[0] != w[1]), "{starts:?}");
1027 let mut pn = vec![node(60.0, 30.0); 3];
1029 pn[0].pin.0 = Some(2.0);
1030 pn[1].pin.0 = Some(0.0);
1031 let back = layered(&pn, &[edge(0, 1), edge(1, 2)], &p);
1032 assert_eq!(back.edges[0].len(), 2);
1033 let mut lanes = vec![node(60.0, 30.0); 5];
1035 for (i, n) in lanes.iter_mut().enumerate().take(4) {
1036 n.lane = Some(i % 2);
1037 }
1038 let q = LayeredParams {
1039 direction: Direction::TopBottom,
1040 lanes: 2,
1041 ..Default::default()
1042 };
1043 let tb = layered(
1044 &lanes,
1045 &[edge(0, 3), edge(1, 2), edge(2, 4), edge(3, 4)],
1046 &q,
1047 );
1048 assert_eq!(tb.bands.len(), 2);
1049 assert!(tb.bands.iter().all(|b| b.3 > b.1 && b.4 > b.2));
1050 }
1051}