Update egui_graphs, make maxflow problem generator work
This commit is contained in:
1175
Cargo.lock
generated
1175
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,11 @@ authors = ["Sebastian Schnorbus <sebastian.schnorbus@stud.tu-darmstadt.de>"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = "0.29"
|
ecolor = "0.31.1"
|
||||||
egui = "0.29"
|
eframe = "0.30"
|
||||||
egui_graphs = "0.22.0"
|
egui = "0.30"
|
||||||
|
egui_graphs = "0.23.0"
|
||||||
|
geo = "0.29.3"
|
||||||
|
itertools = "0.14.0"
|
||||||
petgraph = "0.6"
|
petgraph = "0.6"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|||||||
15
src/main.rs
15
src/main.rs
@@ -1,27 +1,32 @@
|
|||||||
use eframe::{run_native, App, CreationContext, NativeOptions, Frame};
|
use eframe::{run_native, App, CreationContext, NativeOptions, Frame};
|
||||||
use egui::{CentralPanel, SidePanel, Context};
|
use egui::{CentralPanel, SidePanel, Context};
|
||||||
use egui_graphs::{GraphView, Graph, SettingsStyle};
|
use egui_graphs::{GraphView, Graph, SettingsStyle, LayoutRandom, LayoutStateRandom};
|
||||||
|
|
||||||
|
use random_generator::MaxflowProblem;
|
||||||
|
use algorithms::{ford_fulk
|
||||||
//use petgraph::stable_graph::StableGraph;
|
//use petgraph::stable_graph::StableGraph;
|
||||||
|
|
||||||
mod random_generator;
|
mod random_generator;
|
||||||
|
mod algorithms;
|
||||||
|
|
||||||
pub struct MaxflowApp {
|
pub struct MaxflowApp {
|
||||||
g: Graph<(), u64>,
|
g: Graph<(), u64>,
|
||||||
|
p: MaxflowProblem,
|
||||||
node_count: u64,
|
node_count: u64,
|
||||||
max_capacity: u64,
|
max_capacity: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaxflowApp {
|
impl MaxflowApp {
|
||||||
fn new(_: &CreationContext<'_>) -> Self {
|
fn new(_: &CreationContext<'_>) -> Self {
|
||||||
let problem = random_generator::MaxflowProblem::new(10, 10);
|
let problem = MaxflowProblem::new(10, 10);
|
||||||
Self { g: problem.g, node_count: 10, max_capacity: 5 }
|
Self { g: problem.g.clone(), p: problem, node_count: 10, max_capacity: 5 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App for MaxflowApp {
|
impl App for MaxflowApp {
|
||||||
fn update(&mut self, ctx: &Context, _: &mut Frame) {
|
fn update(&mut self, ctx: &Context, _: &mut Frame) {
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.add(&mut GraphView::new(&mut self.g).with_styles(&SettingsStyle::default().with_labels_always(true)));
|
ui.add(&mut GraphView::<_, _, _, _, _, _, LayoutStateRandom, LayoutRandom>::new(&mut self.g).with_styles(&SettingsStyle::default().with_labels_always(true)));
|
||||||
});
|
});
|
||||||
SidePanel::right("right_panel")
|
SidePanel::right("right_panel")
|
||||||
.min_width(200.)
|
.min_width(200.)
|
||||||
@@ -34,6 +39,8 @@ impl App for MaxflowApp {
|
|||||||
let problem = random_generator::MaxflowProblem::new(self.node_count, self.max_capacity);
|
let problem = random_generator::MaxflowProblem::new(self.node_count, self.max_capacity);
|
||||||
self.g = problem.g;
|
self.g = problem.g;
|
||||||
}
|
}
|
||||||
|
if ui.button("run algorithm").clicked() {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,99 @@
|
|||||||
use petgraph::stable_graph::{StableGraph, NodeIndex};
|
use petgraph::stable_graph::{StableGraph, NodeIndex};
|
||||||
use petgraph::{Directed};
|
use petgraph::{Directed};
|
||||||
use egui_graphs::{to_graph, Graph};
|
use egui_graphs::{Graph};
|
||||||
use egui::Pos2;
|
use egui::Pos2;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use geo::{Line, coord, line_intersection::{line_intersection, LineIntersection}};
|
||||||
|
use egui::Color32;
|
||||||
|
|
||||||
pub struct MaxflowProblem {
|
pub struct MaxflowProblem {
|
||||||
pub g: Graph<(), u64, Directed, u32, egui_graphs::DefaultNodeShape, egui_graphs::DefaultEdgeShape>,
|
pub g: Graph<(), u64, Directed, u32, egui_graphs::DefaultNodeShape, egui_graphs::DefaultEdgeShape>,
|
||||||
|
pub s: NodeIndex,
|
||||||
|
pub t: NodeIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaxflowProblem {
|
impl MaxflowProblem {
|
||||||
pub fn new(num_nodes: u64, max_capacity: u64) -> Self {
|
pub fn new(num_nodes: u64, max_capacity: u64) -> Self {
|
||||||
let mut graph: Graph<_, u64> = Graph::new(StableGraph::default());
|
let mut graph: Graph<_, u64> = Graph::new(StableGraph::default());
|
||||||
let mut nodes = Vec::<NodeIndex>::new();
|
let mut nodes: Vec<NodeIndex> = Vec::new();
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
// generate nodes
|
// generate nodes
|
||||||
for _i in 0..num_nodes {
|
for _i in 0..num_nodes {
|
||||||
let x: f32 = rng.gen_range(0.0..=500.0);
|
let x: f32 = rng.gen_range(0.0..=400.0);
|
||||||
let y: f32 = rng.gen_range(0.0..=500.0);
|
let y: f32 = rng.gen_range(0.0..=300.0);
|
||||||
let pos = Pos2::new(x,y);
|
let pos = Pos2::new(x,y);
|
||||||
let n = graph.add_node_with_label_and_location((), String::new(), pos);
|
let n = graph.add_node_with_label_and_location((), String::new(), pos);
|
||||||
nodes.push(n);
|
nodes.push(n);
|
||||||
|
|
||||||
// to achieve a strongly connected graph, every node
|
|
||||||
// should have at least one edge pointing from and to
|
|
||||||
// a node TODO
|
|
||||||
let node1 = nodes.choose(&mut rng).unwrap();
|
|
||||||
let capacity1: u64 = rng.gen_range(1..=max_capacity);
|
|
||||||
// if node1.position() overlaps do sth
|
|
||||||
graph.add_edge_with_label(n, *node1, capacity1, capacity1.to_string());
|
|
||||||
graph.add_edge_with_label(*node1, n, capacity1, capacity1.to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort node pairs by distance
|
// select source (s) and sink (t)
|
||||||
|
let s = *nodes.choose(&mut rng).expect("no nodes found");
|
||||||
|
let t = *nodes.choose(&mut rng).expect("no nodes found");
|
||||||
|
graph.node_mut(s).expect("node index not found").set_label(String::from("s"));
|
||||||
|
graph.node_mut(t).expect("node index not found").set_label(String::from("t"));
|
||||||
|
graph.node_mut(s).expect("node index not found").set_color(Color32::RED);
|
||||||
|
graph.node_mut(t).expect("node index not found").set_color(Color32::GREEN);
|
||||||
|
|
||||||
// randomly add edges
|
// iterate over all possible edges
|
||||||
for _i in 0..num_nodes {
|
let mut possible_edges: Vec<(NodeIndex, NodeIndex, f32)> = Vec::new();
|
||||||
let node1 = nodes.choose(&mut rng).unwrap();
|
for pair in nodes.clone().into_iter().combinations(2) {
|
||||||
let node2 = nodes.choose(&mut rng).unwrap();
|
// calculate distance & append tuple (node_a, node_b, distance) to possible_edges
|
||||||
let capacity: u64 = rng.gen_range(1..=max_capacity);
|
let distance = Self::distance(graph.node(pair[0]).expect("node index not found").location(), graph.node(pair[1]).expect("node index not found").location());
|
||||||
//graph.add_edge_with_label(*node1, *node2, capacity, capacity.to_string());
|
possible_edges.push((pair[0], pair[1], distance));
|
||||||
}
|
}
|
||||||
|
|
||||||
//let widget_graph: Graph<_, _, _, _, egui_graphs::DefaultNodeShape, egui_graphs::DefaultEdgeShape> = to_graph(&graph);
|
// sort mapping by distance
|
||||||
Self { g: graph }
|
possible_edges.sort_by(|a, b| a.2.partial_cmp(&b.2).unwrap());
|
||||||
|
println!("possible_edges len: {}", possible_edges.len());
|
||||||
|
|
||||||
|
// insert the edge if possible
|
||||||
|
let mut inserted_edges: Vec<(NodeIndex, NodeIndex)> = Vec::new();
|
||||||
|
for (node1, node2, distance) in possible_edges {
|
||||||
|
// check for collision with already inserted edges
|
||||||
|
let mut intersects = false;
|
||||||
|
for (node3, node4) in &inserted_edges {
|
||||||
|
if Self::intersects(
|
||||||
|
graph.node(node1).expect("node index not found").location(),
|
||||||
|
graph.node(node2).expect("node index not found").location(),
|
||||||
|
graph.node(*node3).expect("node index not found").location(),
|
||||||
|
graph.node(*node4).expect("node index not found").location(),
|
||||||
|
) {
|
||||||
|
intersects = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if intersects == false {
|
||||||
|
// otherwise insert the edge and its residual edge
|
||||||
|
inserted_edges.push((node1, node2));
|
||||||
|
inserted_edges.push((node2, node1));
|
||||||
|
let capacity: u64 = rng.gen_range(1..=max_capacity);
|
||||||
|
graph.add_edge_with_label(node1, node2, capacity, capacity.to_string());
|
||||||
|
graph.add_edge_with_label(node2, node1, capacity, capacity.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { g: graph, s: s, t: t }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns the eudclidean distance between two points
|
||||||
fn distance(a: Pos2, b: Pos2) -> f32 {
|
fn distance(a: Pos2, b: Pos2) -> f32 {
|
||||||
let delta_x = a.x - b.x;
|
let delta_x = a.x - b.x;
|
||||||
let delta_y = a.y - b.y;
|
let delta_y = a.y - b.y;
|
||||||
return f32::sqrt(delta_x.powf(2.) + delta_y.powf(2.));
|
return f32::sqrt(delta_x.powf(2.) + delta_y.powf(2.));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks if the lines between a-b and c-d intersect
|
||||||
|
fn intersects(a: Pos2, b: Pos2, c: Pos2, d: Pos2) -> bool {
|
||||||
|
let line1 = Line::new(coord! {x: a.x, y: a.y }, coord! {x: b.x, y: b.y } );
|
||||||
|
let line2 = Line::new(coord! {x: c.x, y: c.y }, coord! {x: d.x, y: d.y } );
|
||||||
|
match line_intersection(line1, line2) {
|
||||||
|
// only return true for 'proper' intersections which are not at the end of a line
|
||||||
|
Some(LineIntersection::SinglePoint { is_proper: true, .. }) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user