1use std::fmt;
2
3use crate::force::{self, Force};
4
5use super::ForceGraph;
6use glam::Vec3;
7use petgraph::{
8 graph::NodeIndex,
9 visit::{EdgeRef, IntoEdgeReferences},
10 EdgeType, Undirected,
11};
12use quad_rand::RandomRange;
13
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
16pub enum Dimensions {
17 Two,
18 Three,
19}
20
21impl fmt::Display for Dimensions {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 Dimensions::Two => write!(f, "2"),
25 Dimensions::Three => write!(f, "3"),
26 }
27 }
28}
29
30#[derive(Clone)]
32pub struct SimulationParameters<N, E, Ty = Undirected> {
33 pub node_start_size: f32,
35 pub dimensions: Dimensions,
37 force: Force<N, E, Ty>,
39}
40
41impl<N, E, Ty: EdgeType> SimulationParameters<N, E, Ty> {
42 pub fn new(node_start_size: f32, dimensions: Dimensions, force: Force<N, E, Ty>) -> Self {
44 Self {
45 node_start_size,
46 dimensions,
47 force,
48 }
49 }
50
51 pub fn force_mut(&mut self) -> &mut Force<N, E, Ty> {
53 &mut self.force
54 }
55
56 pub fn force(&self) -> &Force<N, E, Ty> {
58 &self.force
59 }
60
61 pub fn from_force(force: Force<N, E, Ty>) -> Self {
63 Self {
64 force,
65 ..Default::default()
66 }
67 }
68
69 pub fn set_force(&mut self, force: Force<N, E, Ty>) {
71 self.force = force;
72 }
73}
74
75impl<N, E, Ty: EdgeType> Default for SimulationParameters<N, E, Ty> {
76 fn default() -> Self {
77 Self {
78 node_start_size: 200.0,
79 dimensions: Dimensions::Two,
80 force: force::fruchterman_reingold(45.0, 0.975),
81 }
82 }
83}
84
85#[derive(Clone)]
87pub struct Simulation<N, E, Ty = Undirected> {
88 graph: ForceGraph<N, E, Ty>,
89 parameters: SimulationParameters<N, E, Ty>,
90}
91
92impl<N, E, Ty: EdgeType> Simulation<N, E, Ty> {
93 pub fn from_graph(
95 graph: ForceGraph<N, E, Ty>,
96 parameters: SimulationParameters<N, E, Ty>,
97 ) -> Self {
98 let mut myself = Self { graph, parameters };
99
100 myself.reset_node_placement();
101
102 myself
103 }
104
105 pub fn reset_node_placement(&mut self) {
108 let half_node_start_width = self.parameters.node_start_size / 2.0;
109
110 for node in self.graph.node_weights_mut() {
111 let random_location = Vec3::new(
112 RandomRange::gen_range(-half_node_start_width, half_node_start_width),
113 RandomRange::gen_range(-half_node_start_width, half_node_start_width),
114 match self.parameters.dimensions {
115 Dimensions::Three => RandomRange::gen_range(-half_node_start_width, half_node_start_width),
116 Dimensions::Two => 0.0,
117 }
118 );
119
120 node.velocity = Vec3::ZERO;
121 node.location = random_location;
122 node.old_location = random_location;
123 }
124 }
125
126 pub fn update(&mut self, dt: f32) {
128 self.parameters.force().update(&mut self.graph, dt);
129 }
130
131 pub fn update_custom(&mut self, force: &Force<N, E, Ty>, dt: f32) {
133 force.update(&mut self.graph, dt)
134 }
135
136 pub fn visit_nodes(&self, cb: &mut impl Fn(&Node<N>)) {
138 for n_idx in self.graph.node_indices() {
139 cb(&self.graph[n_idx]);
140 }
141 }
142
143 pub fn visit_edges(&self, cb: &mut impl Fn(&Node<N>, &Node<N>)) {
145 for edge_ref in self.graph.edge_references() {
146 cb(
147 &self.graph[edge_ref.source()],
148 &self.graph[edge_ref.target()],
149 );
150 }
151 }
152
153 pub fn get_graph(&self) -> &ForceGraph<N, E, Ty> {
155 &self.graph
156 }
157
158 pub fn get_graph_mut(&mut self) -> &mut ForceGraph<N, E, Ty> {
160 &mut self.graph
161 }
162
163 pub fn set_graph(&mut self, graph: ForceGraph<N, E, Ty>) {
165 self.graph = graph;
166 }
167
168 pub fn parameters(&self) -> &SimulationParameters<N, E, Ty> {
170 &self.parameters
171 }
172
173 pub fn parameters_mut(&mut self) -> &mut SimulationParameters<N, E, Ty> {
175 &mut self.parameters
176 }
177
178 pub fn find(&self, query: Vec3, radius: f32) -> Option<NodeIndex> {
180 let query_x = (query.x - radius)..=(query.x + radius);
181 let query_y = (query.y - radius)..=(query.y + radius);
182 let query_z = (query.z - radius)..=(query.z + radius);
183
184 for index in self.graph.node_indices() {
185 let node = &self.graph[index];
186
187 if query_x.contains(&node.location.x)
188 && query_y.contains(&node.location.y)
189 && query_z.contains(&node.location.z)
190 {
191 return Some(index);
192 }
193 }
194
195 None
196 }
197}
198
199impl<N, E, Ty: EdgeType> Default for Simulation<N, E, Ty> {
200 fn default() -> Self {
201 Self::from_graph(ForceGraph::default(), SimulationParameters::default())
202 }
203}
204
205#[derive(Clone, PartialEq)]
207#[cfg_attr(feature = "json", derive(serde::Serialize))]
208pub struct Node<N> {
209 pub name: String,
211 pub data: N,
213 pub location: Vec3,
214 pub old_location: Vec3,
215 pub velocity: Vec3,
216}
217
218impl<N> Node<N> {
219 pub fn new(name: impl AsRef<str>, data: N) -> Self {
221 Self {
222 name: name.as_ref().to_string(),
223 data,
224 location: Vec3::ZERO,
225 old_location: Vec3::ZERO,
226 velocity: Vec3::ZERO,
227 }
228 }
229
230 pub fn new_with_coords(name: impl AsRef<str>, data: N, location: Vec3) -> Self {
232 Self {
233 name: name.as_ref().to_string(),
234 data,
235 location,
236 old_location: Vec3::ZERO,
237 velocity: Vec3::ZERO,
238 }
239 }
240}
241
242impl<N: fmt::Debug> fmt::Debug for Node<N> {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f.debug_struct("Node")
245 .field("name", &self.name)
246 .field("data", &self.data)
247 .field("location", &self.location)
248 .finish()
249 }
250}