use eframe::{run_native, App, CreationContext, NativeOptions, Frame}; use egui::{CentralPanel, CollapsingHeader, ComboBox, Context, ScrollArea, SidePanel}; use egui_graphs::{DefaultEdgeShape, DefaultNodeShape, Graph, GraphView, LayoutRandom, LayoutStateRandom, SettingsStyle}; use geo::algorithm; use petgraph::{stable_graph::{NodeIndex, StableGraph}, Directed}; use std::{fmt::Display, ptr::fn_addr_eq}; use random_generator::MaxflowProblem; use layout::CustomEdgeShape; use crate::algorithms::{ford_fulkerson, edmonds_karp}; mod random_generator; mod algorithms; mod layout; type MaxflowFn = fn(StableGraph<(f32, f32), (u64, u64)>, NodeIndex, NodeIndex) -> StableGraph<(f32, f32), (u64, u64)>; pub struct MaxflowApp { g: Graph<(f32, f32), (u64, u64), Directed, u32, DefaultNodeShape, CustomEdgeShape>, p: MaxflowProblem, node_count: u64, max_capacity: u64, algorithm: MaxflowFn, } impl MaxflowApp { fn new(_: &CreationContext<'_>) -> Self { let problem = MaxflowProblem::new(10, 10); Self { g: problem.to_gui_graph(), p: problem, node_count: 10, max_capacity: 5, algorithm: ford_fulkerson } } } impl App for MaxflowApp { fn update(&mut self, ctx: &Context, _: &mut Frame) { ctx.set_theme(egui::Theme::Light); CentralPanel::default().show(ctx, |ui| { ui.add(&mut GraphView::<_, _, _, _, _, CustomEdgeShape, LayoutStateRandom, LayoutRandom>::new(&mut self.g).with_styles(&SettingsStyle::default().with_labels_always(true))); }); SidePanel::right("right_panel") .min_width(200.) .show(ctx, |ui| { ScrollArea::vertical().show(ui, |ui| { CollapsingHeader::new("Graph generation") .default_open(true) .show(ui, |ui| { ui.label("node count"); ui.add(egui::DragValue::new(&mut self.node_count).range(2..=1000)); ui.label("maximum capacity"); ui.add(egui::DragValue::new(&mut self.max_capacity).range(1..=100)); // TODO: add generation strategy (random, pseudo-random) if ui.button("generate graph").clicked() { self.p = random_generator::MaxflowProblem::new(self.node_count, self.max_capacity); self.g = self.p.to_gui_graph(); } }); CollapsingHeader::new("Max-flow algorithms") .default_open(true) .show(ui, |ui| { ComboBox::from_label("algorithm") .selected_text(format!("{}", match self.algorithm { _ if fn_addr_eq(self.algorithm, ford_fulkerson as MaxflowFn) => "Ford-Fulkerson", _ if fn_addr_eq(self.algorithm, edmonds_karp as MaxflowFn) => "Edmonds-Karp", _ => "unknown" })) .show_ui(ui, |ui| { ui.selectable_value(&mut self.algorithm, ford_fulkerson, "Ford-Fulkerson"); ui.selectable_value(&mut self.algorithm, edmonds_karp, "Edmonds-Karp"); }); if ui.button("run algorithm").clicked() { let max_flow_graph = ford_fulkerson(self.p.g.clone(), self.p.s, self.p.t); self.p = MaxflowProblem::from(max_flow_graph, self.p.s, self.p.t); self.g = self.p.to_gui_graph(); } // reset button // step button (disable when finished) }); }); }); } } fn main() { run_native("Maxflow.rs", NativeOptions::default(), Box::new(|cc| Ok(Box::new(MaxflowApp::new(cc)))),).unwrap(); }