kyu_visualizer/graph/
layout.rs1use crate::state::{GraphData, Vec2};
7
8pub struct LayoutConfig {
10 pub area: f32,
12 pub cooling: f32,
14}
15
16impl Default for LayoutConfig {
17 fn default() -> Self {
18 Self {
19 area: 200_000.0, cooling: 0.95,
21 }
22 }
23}
24
25pub fn layout_step(graph: &mut GraphData, temperature: &mut f32, config: &LayoutConfig) -> bool {
29 let n = graph.nodes.len();
30 if n == 0 {
31 return false;
32 }
33
34 let k = (config.area / n as f32).sqrt();
35 let k_sq = k * k;
36
37 let mut disp: Vec<Vec2> = vec![Vec2::default(); n];
39
40 for i in 0..n {
42 for j in (i + 1)..n {
43 let delta = graph.nodes[i].pos - graph.nodes[j].pos;
44 let dist_sq = delta.x * delta.x + delta.y * delta.y;
45 let dist = dist_sq.sqrt().max(0.01);
46 let force = k_sq / dist;
48 let dir = delta * (force / dist);
49 disp[i] += dir;
50 disp[j] = disp[j] - dir;
51 }
52 }
53
54 for edge in &graph.edges {
56 let delta = graph.nodes[edge.src].pos - graph.nodes[edge.dst].pos;
57 let dist = delta.length().max(0.01);
58 let force = dist * dist / k;
60 let dir = delta * (force / dist);
61 disp[edge.src] = disp[edge.src] - dir;
62 disp[edge.dst] += dir;
63 }
64
65 for (i, d) in disp.iter().enumerate() {
67 if graph.nodes[i].pinned {
68 continue;
69 }
70 let mag = d.length().max(0.01);
71 let capped = mag.min(*temperature);
72 graph.nodes[i].pos += *d * (capped / mag);
73 }
74
75 *temperature *= config.cooling;
77
78 *temperature > 0.1
79}
80
81pub fn reset_temperature(node_count: usize) -> f32 {
83 (200_000.0_f32 / node_count.max(1) as f32).sqrt() * 0.5
85}
86
87pub fn layout_batch(graph: &mut GraphData, temperature: &mut f32, steps: usize) -> bool {
89 let config = LayoutConfig::default();
90 let mut running = true;
91 for _ in 0..steps {
92 running = layout_step(graph, temperature, &config);
93 if !running {
94 break;
95 }
96 }
97 running
98}
99
100pub fn center_graph(graph: &mut GraphData) {
102 if graph.nodes.is_empty() {
103 return;
104 }
105 let n = graph.nodes.len() as f32;
106 let cx: f32 = graph.nodes.iter().map(|n| n.pos.x).sum::<f32>() / n;
107 let cy: f32 = graph.nodes.iter().map(|n| n.pos.y).sum::<f32>() / n;
108 for node in &mut graph.nodes {
109 node.pos.x -= cx;
110 node.pos.y -= cy;
111 }
112}