diff --git a/lab3/src/gui/data.rs b/lab3/src/gui/data.rs new file mode 100644 index 0000000..058c915 --- /dev/null +++ b/lab3/src/gui/data.rs @@ -0,0 +1,37 @@ +use bgtu_ai_utility::graph::CompleteGraph; +use bgtu_ai_utility::UpdatePending; +use crate::algo::{AntsSimulationConfig, AntsSimulationState}; + +pub(crate)enum GlobalState { + Edit, + Running, +} +pub(crate) struct MyApp { + pub simulation: AntsSimulationState, + pub config: AntsSimulationConfig, + pub vertex_update: UpdatePending, + pub state: GlobalState, + pub vertex_locations: Vec<(f32, f32)>, + pub ants_per_vertex: usize, +} + +impl MyApp { + pub(crate) fn new() -> Self { + return Self { + simulation: AntsSimulationState { + graph: CompleteGraph::new(), + ants: Vec::new(), + }, + vertex_update: UpdatePending::NoChange, + config: AntsSimulationConfig { + ferment_weight: 0.5, + heuristic_coefficient: 0.5, + q: 1.0, + r: 0.5, + }, + state: GlobalState::Edit {}, + vertex_locations: Vec::new(), + ants_per_vertex: 1, + }; + } +} \ No newline at end of file diff --git a/lab3/src/gui/graph.rs b/lab3/src/gui/graph.rs new file mode 100644 index 0000000..bbc346a --- /dev/null +++ b/lab3/src/gui/graph.rs @@ -0,0 +1,47 @@ +use super::{GlobalState, MyApp}; +use crate::algo::updateState; +use bgtu_ai_utility::gui::render_graph; +use eframe::egui::Ui; + +pub(crate) fn graph_with_controls(ui: &mut Ui, data: &mut MyApp) { + ui.vertical(|ui| { + ui.horizontal(|ui| { + if ui.button("Exit").clicked() { + data.state = GlobalState::Edit + } + + if ui.button("Step").clicked() { + updateState(&mut data.simulation, &mut data.config, &mut rand::rng()); + } + ui.label(""); + }); + draw_ants(ui, data); + if ui.input(|i| i.viewport().close_requested()) { + data.state = GlobalState::Edit + } + }); +} + +fn draw_ants(ui: &mut Ui, data: &mut MyApp) { + let mut cap: f64 = 0.000000000001; + + for w in data + .simulation + .graph + .edges + .iter() + .map(|e| e.extra.ferment_intensity) + { + if w > cap { + cap = w + } + } + + render_graph( + ui, + &data.simulation.graph.vertices, + data.vertex_locations.as_mut_slice(), + &data.simulation.graph.edges, + |e| e.extra.ferment_intensity / cap, + ) +} diff --git a/lab3/src/gui/input.rs b/lab3/src/gui/input.rs new file mode 100644 index 0000000..175766a --- /dev/null +++ b/lab3/src/gui/input.rs @@ -0,0 +1,83 @@ +use std::collections::HashSet; +use eframe::egui::Ui; +use bgtu_ai_utility::gui::labeled_slider; +use bgtu_ai_utility::gui::lengths_table::draw_lengths_table; +use bgtu_ai_utility::UpdatePending; +use crate::algo::Ant; +use super::{GlobalState, MyApp}; + +pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { + let mut run: bool = false; + + labeled_slider( + ui, + "Ferment weight", + &mut data.config.ferment_weight, + 0.0..=1.0, + 0.001, + ); + ui.label(""); + labeled_slider( + ui, + "Heuristic coefficient", + &mut data.config.heuristic_coefficient, + 0.0..=1.0, + 0.001, + ); + ui.label(""); + labeled_slider(ui, "Q", &mut data.config.q, 0.0..=1.0, 0.001); + ui.label(""); + labeled_slider(ui, "r", &mut data.config.r, 0.0..=1.0, 0.001); + ui.label(""); + labeled_slider( + ui, + "Ants per vertex", + &mut data.ants_per_vertex, + 1..=100, + 1.0, + ); + ui.label(""); + ui.horizontal(|ui| { + if ui.button("Add vertex").clicked() { + data.vertex_update = UpdatePending::Add; + } + ui.separator(); + run = ui.button("Run").clicked(); + }); + + draw_lengths_table( + ui, + &mut data.simulation.graph.vertices, + &mut data.simulation.graph.edges, + &mut data.vertex_update, + ); + + if run { + let mut coords = vec![(0.0, 0.0); data.simulation.graph.vertices.capacity()]; + + for (i, _) in data.simulation.graph.vertices.iter_indexed() { + coords[i] = ( + rand::random::() * 0.8 + 0.1, + rand::random::() * 0.8 + 0.1, + ) + } + + data.state = GlobalState::Running; + data.vertex_locations = coords; + + let allowed_locations = data + .simulation + .graph.vertices + .iter_indexed() + .map(|(i, _)| i) + .collect::>(); + + let mut ants = Vec::new(); + for (i, _) in data.simulation.graph.vertices.iter_indexed() { + for _ in 0..data.ants_per_vertex { + ants.push(Ant::new(i, allowed_locations.clone())) + } + } + data.simulation.ants = ants; + } +} \ No newline at end of file diff --git a/lab3/src/gui/mod.rs b/lab3/src/gui/mod.rs new file mode 100644 index 0000000..8b49ee2 --- /dev/null +++ b/lab3/src/gui/mod.rs @@ -0,0 +1,7 @@ +mod data; +mod input; +mod graph; + +pub(crate) use data::{MyApp, GlobalState}; +pub(crate) use input::input; +pub(crate) use graph::graph_with_controls; \ No newline at end of file diff --git a/lab3/src/main.rs b/lab3/src/main.rs index 996717a..4a46683 100644 --- a/lab3/src/main.rs +++ b/lab3/src/main.rs @@ -1,66 +1,22 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release mod algo; +mod gui; -use crate::algo::{ - Ant, AntsSimulationConfig, AntsSimulationState, EdgeExtraData, EdgesVec, VerticesVec, - updateState, -}; +use crate::algo::EdgeExtraData; +use bgtu_ai_utility::gui::boot_eframe; +use bgtu_ai_utility::gui::subwindow; use bgtu_ai_utility::UpdatePending; -use bgtu_ai_utility::gui::lengths_table::draw_lengths_table; -use bgtu_ai_utility::gui::render_graph; -use bgtu_ai_utility::gui::{boot_eframe, labeled_slider}; use eframe::egui; -use eframe::egui::{Frame, Ui}; -use std::collections::HashSet; -use bgtu_ai_utility::graph::CompleteGraph; fn main() -> eframe::Result { - return boot_eframe( - "Ants simulation", - || MyApp::new() - ); + return boot_eframe("Ants simulation", || gui::MyApp::new()); } -enum GlobalState { - Edit, - Running, -} - -struct MyApp { - simulation: AntsSimulationState, - config: AntsSimulationConfig, - vertex_update: UpdatePending, - state: GlobalState, - vertex_locations: Vec<(f32, f32)>, - ants_per_vertex: usize, -} - -impl MyApp { - fn new() -> Self { - return Self { - simulation: AntsSimulationState { - graph: CompleteGraph::new(), - ants: Vec::new(), - }, - vertex_update: UpdatePending::NoChange, - config: AntsSimulationConfig { - ferment_weight: 0.5, - heuristic_coefficient: 0.5, - q: 1.0, - r: 0.5, - }, - state: GlobalState::Edit {}, - vertex_locations: Vec::new(), - ants_per_vertex: 1, - }; - } -} - -impl eframe::App for MyApp { +impl eframe::App for gui::MyApp { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ui, |ui| match self.state { - GlobalState::Edit {} => { + gui::GlobalState::Edit {} => { match self.vertex_update { UpdatePending::NoChange => {} UpdatePending::Add => { @@ -74,141 +30,16 @@ impl eframe::App for MyApp { self.vertex_update = UpdatePending::NoChange; } } - edit_panel(self, ui) + gui::input(ui, self) } - GlobalState::Running { .. } => { - ui.add_enabled_ui(false, |ui| edit_panel(self, ui)); - ui.ctx().show_viewport_immediate( - egui::ViewportId::from_hash_of("Visualisation"), - egui::ViewportBuilder::default() - .with_title("Visualisation") - .with_inner_size([640.0, 480.0]) - .with_resizable(false), - |ui, _| { - egui::CentralPanel::default() - .frame(Frame::default().inner_margin(0.0)) - .show(ui, |ui| visualization_panel(self, ui)); - }, - ); + gui::GlobalState::Running { .. } => { + ui.add_enabled_ui(false, |ui| gui::input(ui, self)); + subwindow( + ui, "visualisation", "Visualisation", + |vb| vb.with_inner_size([640.0, 480.0]), + |ui| gui::graph_with_controls(ui, self), + ).on_close(|| self.state = gui::GlobalState::Edit); } }); } } - -fn edit_panel(data: &mut MyApp, ui: &mut Ui) { - let mut run: bool = false; - - labeled_slider( - ui, - "Ferment weight", - &mut data.config.ferment_weight, - 0.0..=1.0, - 0.001, - ); - ui.label(""); - labeled_slider( - ui, - "Heuristic coefficient", - &mut data.config.heuristic_coefficient, - 0.0..=1.0, - 0.001, - ); - ui.label(""); - labeled_slider(ui, "Q", &mut data.config.q, 0.0..=1.0, 0.001); - ui.label(""); - labeled_slider(ui, "r", &mut data.config.r, 0.0..=1.0, 0.001); - ui.label(""); - labeled_slider( - ui, - "Ants per vertex", - &mut data.ants_per_vertex, - 1..=100, - 1.0, - ); - ui.label(""); - ui.horizontal(|ui| { - if ui.button("Add vertex").clicked() { - data.vertex_update = UpdatePending::Add; - } - ui.separator(); - run = ui.button("Run").clicked(); - }); - - draw_lengths_table( - ui, - &mut data.simulation.graph.vertices, - &mut data.simulation.graph.edges, - &mut data.vertex_update, - ); - - if run { - let mut coords = vec![(0.0, 0.0); data.simulation.graph.vertices.capacity()]; - - for (i, _) in data.simulation.graph.vertices.iter_indexed() { - coords[i] = ( - rand::random::() * 0.8 + 0.1, - rand::random::() * 0.8 + 0.1, - ) - } - - data.state = GlobalState::Running; - data.vertex_locations = coords; - - let allowed_locations = data - .simulation - .graph.vertices - .iter_indexed() - .map(|(i, _)| i) - .collect::>(); - - let mut ants = Vec::new(); - for (i, _) in data.simulation.graph.vertices.iter_indexed() { - for _ in 0..data.ants_per_vertex { - ants.push(Ant::new(i, allowed_locations.clone())) - } - } - data.simulation.ants = ants; - } -} - -fn visualization_panel(data: &mut MyApp, ui: &mut Ui) { - ui.vertical(|ui| { - ui.horizontal(|ui| { - if ui.button("Exit").clicked() { - data.state = GlobalState::Edit - } - - if ui.button("Step").clicked() { - updateState(&mut data.simulation, &mut data.config, &mut rand::rng()); - } - ui.label(""); - }); - draw_ants(data, ui); - if ui.input(|i| i.viewport().close_requested()) { - data.state = GlobalState::Edit - } - }); -} - -fn draw_ants(data: &mut MyApp, ui: &mut Ui) { - let mut cap: f64 = 0.000000000001; - - for w in data - .simulation - .graph.edges - .iter() - .map(|e| e.extra.ferment_intensity) - { - if w > cap { - cap = w - } - } - - render_graph( - ui, - &data.simulation.graph.vertices, - data.vertex_locations.as_mut_slice(), - &data.simulation.graph.edges, - |e| e.extra.ferment_intensity / cap, - ) -}