Update egui_graphs, make maxflow problem generator work

This commit is contained in:
2025-03-17 10:21:35 +01:00
parent 818bfd569e
commit dcefeaa8c0
4 changed files with 819 additions and 467 deletions

View File

@@ -1,56 +1,99 @@
use petgraph::stable_graph::{StableGraph, NodeIndex};
use petgraph::{Directed};
use egui_graphs::{to_graph, Graph};
use egui_graphs::{Graph};
use egui::Pos2;
use rand::thread_rng;
use rand::Rng;
use rand::seq::SliceRandom;
use itertools::Itertools;
use geo::{Line, coord, line_intersection::{line_intersection, LineIntersection}};
use egui::Color32;
pub struct MaxflowProblem {
pub g: Graph<(), u64, Directed, u32, egui_graphs::DefaultNodeShape, egui_graphs::DefaultEdgeShape>,
pub s: NodeIndex,
pub t: NodeIndex,
}
impl MaxflowProblem {
pub fn new(num_nodes: u64, max_capacity: u64) -> Self {
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();
// generate nodes
for _i in 0..num_nodes {
let x: f32 = rng.gen_range(0.0..=500.0);
let y: 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..=300.0);
let pos = Pos2::new(x,y);
let n = graph.add_node_with_label_and_location((), String::new(), pos);
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
for _i in 0..num_nodes {
let node1 = nodes.choose(&mut rng).unwrap();
let node2 = nodes.choose(&mut rng).unwrap();
let capacity: u64 = rng.gen_range(1..=max_capacity);
//graph.add_edge_with_label(*node1, *node2, capacity, capacity.to_string());
// iterate over all possible edges
let mut possible_edges: Vec<(NodeIndex, NodeIndex, f32)> = Vec::new();
for pair in nodes.clone().into_iter().combinations(2) {
// calculate distance & append tuple (node_a, node_b, distance) to possible_edges
let distance = Self::distance(graph.node(pair[0]).expect("node index not found").location(), graph.node(pair[1]).expect("node index not found").location());
possible_edges.push((pair[0], pair[1], distance));
}
//let widget_graph: Graph<_, _, _, _, egui_graphs::DefaultNodeShape, egui_graphs::DefaultEdgeShape> = to_graph(&graph);
Self { g: graph }
// sort mapping by distance
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 {
let delta_x = a.x - b.x;
let delta_y = a.y - b.y;
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
}
}
}