added another example sub-project

This commit is contained in:
2024-05-24 02:41:33 +02:00
parent 64cdb36292
commit 42fe73d0ae
4 changed files with 468 additions and 43 deletions
+33 -35
View File
@@ -6,19 +6,19 @@ use asd::gfa::{Entry, Orientation};
use asd::parser;
use crossbeam::channel::{unbounded, Receiver, Sender};
use eframe::{run_native, App, CreationContext};
use egui::{CollapsingHeader, Context, Pos2, ScrollArea, Slider, Ui};
use egui::{CollapsingHeader, Context, Pos2, ScrollArea, Ui};
use egui_graphs::events::Event;
use egui_graphs::{to_graph, DefaultEdgeShape, DefaultNodeShape, Graph, GraphView};
use egui_graphs::{DefaultEdgeShape, DefaultNodeShape, Graph, GraphView};
use fdg_sim::glam::Vec3;
use fdg_sim::{ForceGraph, ForceGraphHelper, Simulation, SimulationParameters};
use petgraph::stable_graph::{DefaultIx, EdgeIndex, NodeIndex, StableGraph};
use petgraph::stable_graph::{DefaultIx, NodeIndex, StableGraph};
use petgraph::Directed;
use rand::Rng;
use settings::{SettingsInteraction, SettingsNavigation, SettingsStyle};
mod settings;
const SIMULATION_DT: f32 = 0.035;
// const SIMULATION_DT: f32 = 0.035;
const SIMULATION_DT: f32 = 0.075;
const EVENTS_LIMIT: usize = 100;
pub struct ConfigurableApp {
@@ -314,10 +314,6 @@ impl ConfigurableApp {
ui.add_space(10.);
self.draw_counts_sliders(ui);
ui.add_space(10.);
ui.separator();
});
}
@@ -443,40 +439,42 @@ impl ConfigurableApp {
};
ui.label(format!("FPS: {:.1}", self.fps));
ui.label(format!("Nodes: {}", self.g.node_count()));
ui.label(format!("Edges: {}", self.g.edge_count()));
});
}
fn draw_counts_sliders(&mut self, ui: &mut Ui) {
// ui.horizontal(|ui| {
// let before = self.settings_graph.count_node as i32;
// fn draw_counts_sliders(&mut self, ui: &mut Ui) {
// // ui.horizontal(|ui| {
// // let before = self.settings_graph.count_node as i32;
// ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes"));
// // ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes"));
// let delta = self.settings_graph.count_node as i32 - before;
// (0..delta.abs()).for_each(|_| {
// if delta > 0 {
// self.add_random_node();
// return;
// };
// self.remove_random_node();
// });
// });
// // let delta = self.settings_graph.count_node as i32 - before;
// // (0..delta.abs()).for_each(|_| {
// // if delta > 0 {
// // self.add_random_node();
// // return;
// // };
// // self.remove_random_node();
// // });
// // });
// ui.horizontal(|ui| {
// let before = self.settings_graph.count_edge as i32;
// // ui.horizontal(|ui| {
// // let before = self.settings_graph.count_edge as i32;
// ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges"));
// // ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges"));
// let delta = self.settings_graph.count_edge as i32 - before;
// (0..delta.abs()).for_each(|_| {
// if delta > 0 {
// self.add_random_edge();
// return;
// };
// self.remove_random_edge();
// });
// });
}
// // let delta = self.settings_graph.count_edge as i32 - before;
// // (0..delta.abs()).for_each(|_| {
// // if delta > 0 {
// // self.add_random_edge();
// // return;
// // };
// // self.remove_random_edge();
// // });
// // });
// }
}
impl App for ConfigurableApp {
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "fdg-example"
version = "0.1.0"
edition = "2021"
[dependencies]
nalgebra = { version = "0.32.3", features = ["rand"] }
petgraph = { version = "0.6.4", features = [
"stable_graph",
], default-features = false }
num-traits = "0.2.17"
rand = "0.8.5"
rustc-hash = "1.1.0"
rayon = { version = "1.8.0", optional = true }
macroquad = "0.4.4"
petgraph-gen = "0.1.3"
fdg = { git = "https://github.com/grantshandy/fdg" }
asd = { path = "../../" }
+147
View File
@@ -0,0 +1,147 @@
use std::{collections::HashMap, env};
use asd::{
gfa::{Entry, Orientation},
parser,
};
use fdg::{
fruchterman_reingold::{FruchtermanReingold, FruchtermanReingoldConfiguration},
nalgebra::Rotation2,
petgraph::Graph,
simple::Center,
Force, ForceGraph,
};
use macroquad::prelude::*;
#[macroquad::main("fdg demo")]
async fn main() {
let mut graph = Graph::<(String, Orientation), ()>::new();
let file = std::fs::File::open(env::args().nth(1).expect("missing gfa file argument")).unwrap();
let entries = parser::parse_source(file).unwrap();
let mut index_map = HashMap::new();
for entry in entries {
println!("{:?}", entry);
if let Entry::Link {
from,
from_orient,
to,
to_orient,
} = entry
{
// add first node if not present
let a = index_map
.entry(from.clone())
.or_insert_with(|| graph.add_node((from.clone(), from_orient)))
.to_owned();
// add second node if not present
let b = index_map
.entry(to.clone())
.or_insert_with(|| graph.add_node((to.clone(), to_orient)))
.to_owned();
graph.add_edge(a, b, ());
}
}
let mut force_graph: ForceGraph<f32, 2, (String, Orientation), ()> =
fdg::init_force_graph_uniform(graph, 200.0);
// custom closure force which rotates each node
// let mut rotate = |graph: &mut ForceGraph<f32, 2, (String, Orientation), ()>| {
// graph
// .node_weights_mut()
// .for_each(|(_, p)| *p = Rotation2::new(0.005).transform_point(p))
// };
let mut force = FruchtermanReingold {
conf: FruchtermanReingoldConfiguration {
scale: 400.0,
..Default::default()
},
..Default::default()
};
loop {
println!("frame");
force.apply_many(&mut force_graph, 1);
Center::default().apply(&mut force_graph);
// rotate.apply(&mut force_graph);
let scale = calculate_scale(&force_graph);
clear_background(WHITE);
for idx in force_graph.edge_indices() {
let ((_, source), (_, target)) = force_graph
.edge_endpoints(idx)
.map(|(a, b)| {
(
force_graph.node_weight(a).unwrap(),
force_graph.node_weight(b).unwrap(),
)
})
.unwrap();
draw_line(
translate_x(source.coords.column(0)[0], scale),
translate_y(source.coords.column(0)[1], scale),
translate_x(target.coords.column(0)[0], scale),
translate_y(target.coords.column(0)[1], scale),
4.0,
BLACK,
);
}
for ((name, orient), pos) in force_graph.node_weights() {
let x = translate_x(pos.coords.column(0)[0], scale);
let y = translate_y(pos.coords.column(0)[1], scale);
draw_circle(x, y, 20.0 * scale, RED);
draw_text(
format!("{}{}", name, orient).as_str(),
x - 30.0 * scale,
y - 30.0 * scale,
40.0 * scale,
BLACK,
);
}
next_frame().await
}
}
fn translate_x(x: f32, scale: f32) -> f32 {
(screen_width() / 2.0) + (x * scale)
}
fn translate_y(y: f32, scale: f32) -> f32 {
(screen_height() / 2.0) + (y * scale)
}
fn calculate_scale(graph: &ForceGraph<f32, 2, (String, Orientation), ()>) -> f32 {
let (min_x, max_x, min_y, max_y) = graph.node_weights().fold(
(f32::MAX, f32::MIN, f32::MAX, f32::MIN),
|(min_x, max_x, min_y, max_y), (_, pos)| {
(
min_x.min(pos.coords.column(0)[0]),
max_x.max(pos.coords.column(0)[0]),
min_y.min(pos.coords.column(0)[1]),
max_y.max(pos.coords.column(0)[1]),
)
},
);
let graph_width = max_x - min_x;
let graph_height = max_y - min_y;
let scale_x = screen_width() / graph_width;
let scale_y = screen_height() / graph_height;
scale_x.min(scale_y) * 0.9 // add some padding
}