flow_rs_core/layout/algorithms/
circular.rs1use crate::error::Result;
4use crate::graph::Graph;
5use crate::layout::LayoutAlgorithm;
6use crate::types::Position;
7
8#[derive(Debug, Clone)]
10pub struct CircularLayout {
11 pub radius: f64,
12 pub start_angle: f64,
13 pub clockwise: bool,
14}
15
16impl Default for CircularLayout {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22impl CircularLayout {
23 pub fn new() -> Self {
25 Self {
26 radius: 200.0,
27 start_angle: 0.0,
28 clockwise: true,
29 }
30 }
31
32 pub fn radius(mut self, radius: f64) -> Self {
34 self.radius = radius;
35 self
36 }
37
38 pub fn start_angle(mut self, angle: f64) -> Self {
40 self.start_angle = angle;
41 self
42 }
43
44 pub fn clockwise(mut self, clockwise: bool) -> Self {
46 self.clockwise = clockwise;
47 self
48 }
49}
50
51impl<N, E> LayoutAlgorithm<N, E> for CircularLayout {
52 fn name(&self) -> &str {
53 "Circular"
54 }
55
56 fn apply(&mut self, graph: &mut Graph<N, E>) -> Result<()> {
57 let nodes: Vec<_> = graph.nodes_mut().collect();
58 let node_count = nodes.len();
59
60 if node_count == 0 {
61 return Ok(());
62 }
63
64 let angle_step = 2.0 * std::f64::consts::PI / node_count as f64;
65
66 for (i, node) in nodes.into_iter().enumerate() {
67 let angle = if self.clockwise {
68 self.start_angle + i as f64 * angle_step
69 } else {
70 self.start_angle - i as f64 * angle_step
71 };
72
73 let x = self.radius * angle.cos();
74 let y = self.radius * angle.sin();
75
76 node.position = Position::new(x, y);
77 }
78
79 Ok(())
80 }
81}