Make some changes to gtk beanconqueror GUI part, but prepare for switching to dioxus or flutter with the html5 canvas backend for plotters
This commit is contained in:
parent
6da6fd8326
commit
45ea316bef
19
config.toml
19
config.toml
|
@ -4,10 +4,6 @@ output_dir = "images"
|
|||
width = 1600
|
||||
height = 900
|
||||
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
|
||||
[shots]
|
||||
|
||||
|
@ -123,22 +119,37 @@ title = "Laura 19.07.2022 #1"
|
|||
[charts.0]
|
||||
title = "Elisabeth Shots"
|
||||
shots = [0, 1, 10, 14, 15]
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
[charts.1]
|
||||
title = "Laura Shots"
|
||||
shots = [2, 3, 4, 5, 6, 7, 8, 9, 12, 16, 17, 18, 19, 20, 21, 22, 23]
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
[charts.2]
|
||||
title = "Josephine Shots"
|
||||
shots = [11, 13]
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
[charts.3]
|
||||
title = "First Shots"
|
||||
shots = [0, 1, 2, 4, 5, 7, 9, 10, 12, 13, 14, 16, 18, 20, 23]
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
[charts.4]
|
||||
title = "Second Shots"
|
||||
shots = [3, 6, 8, 15, 17, 19, 21]
|
||||
max_time = 45
|
||||
max_weight = 35
|
||||
max_flow = 5
|
||||
|
||||
|
||||
|
||||
|
|
202
src/main.rs
202
src/main.rs
|
@ -24,10 +24,14 @@ struct Shot {
|
|||
disable: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Clone, Deserialize)]
|
||||
struct Chart {
|
||||
title: String,
|
||||
shots: Vec<u64>,
|
||||
|
||||
max_time: u64,
|
||||
max_weight: u64,
|
||||
max_flow: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -40,10 +44,6 @@ struct Config {
|
|||
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
max_time: u64,
|
||||
max_weight: u64,
|
||||
max_flow: u64,
|
||||
}
|
||||
|
||||
const WGHT_SHEET: usize = 0;
|
||||
|
@ -144,158 +144,43 @@ fn load_data(path: &str, cutoff: Option<f64>) -> Option<Data> {
|
|||
|
||||
#[derive(Clone, Copy)]
|
||||
struct PlottingState {
|
||||
mean_x: f64,
|
||||
mean_y: f64,
|
||||
std_x: f64,
|
||||
std_y: f64,
|
||||
pitch: f64,
|
||||
roll: f64,
|
||||
}
|
||||
|
||||
impl PlottingState {
|
||||
fn guassian_pdf(&self, x: f64, y: f64) -> f64 {
|
||||
let x_diff = (x - self.mean_x) / self.std_x;
|
||||
let y_diff = (y - self.mean_y) / self.std_y;
|
||||
let exponent = -(x_diff * x_diff + y_diff * y_diff) / 2.0;
|
||||
let denom = (2.0 * std::f64::consts::PI / self.std_x / self.std_y).sqrt();
|
||||
let gaussian_pdf = 1.0 / denom;
|
||||
gaussian_pdf * exponent.exp()
|
||||
}
|
||||
fn plot_pdf<'a, DB: DrawingBackend + 'a>(
|
||||
fn plot<'a, DB: DrawingBackend + 'a>(
|
||||
&self,
|
||||
backend: DB,
|
||||
chart: Rc<RefCell<Chart>>,
|
||||
config: Rc<RefCell<Config>>,
|
||||
) -> Result<(), Box<dyn Error + 'a>> {
|
||||
let root = backend.into_drawing_area();
|
||||
let root_area = backend.into_drawing_area();
|
||||
|
||||
root.fill(&WHITE)?;
|
||||
|
||||
let mut chart = ChartBuilder::on(&root).build_cartesian_3d(
|
||||
-10.0f64..10.0,
|
||||
0.0f64..1.2,
|
||||
-10.0f64..10.0,
|
||||
)?;
|
||||
|
||||
chart.with_projection(|mut p| {
|
||||
p.pitch = self.pitch;
|
||||
p.yaw = self.roll;
|
||||
p.scale = 0.7;
|
||||
p.into_matrix() // build the projection matrix
|
||||
});
|
||||
|
||||
chart
|
||||
.configure_axes()
|
||||
.light_grid_style(BLACK.mix(0.15))
|
||||
.max_light_lines(3)
|
||||
.draw()?;
|
||||
let self_cloned = self.clone();
|
||||
chart.draw_series(
|
||||
SurfaceSeries::xoz(
|
||||
(-50..=50).map(|x| x as f64 / 5.0),
|
||||
(-50..=50).map(|x| x as f64 / 5.0),
|
||||
move |x, y| self_cloned.guassian_pdf(x, y),
|
||||
)
|
||||
.style_func(&|&v| (&HSLColor(240.0 / 360.0 - 240.0 / 360.0 * v, 1.0, 0.7)).into()),
|
||||
)?;
|
||||
|
||||
root.present()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn build_ui(app: >k::Application) {
|
||||
let builder = gtk::Builder::from_string(UI_SOURCE);
|
||||
let window: gtk::Window = builder
|
||||
.object::<gtk::Window>("MainWindow")
|
||||
.unwrap();
|
||||
|
||||
window.set_title(Some("Beanconqueror GUI (gtk4)"));
|
||||
|
||||
let drawing_area: gtk::DrawingArea = builder.object("MainDrawingArea").unwrap();
|
||||
let pitch_scale = builder.object::<gtk::Scale>("PitchScale").unwrap();
|
||||
let yaw_scale = builder.object::<gtk::Scale>("YawScale").unwrap();
|
||||
let mean_x_scale = builder.object::<gtk::Scale>("MeanXScale").unwrap();
|
||||
let mean_y_scale = builder.object::<gtk::Scale>("MeanYScale").unwrap();
|
||||
let std_x_scale = builder.object::<gtk::Scale>("SDXScale").unwrap();
|
||||
let std_y_scale = builder.object::<gtk::Scale>("SDYScale").unwrap();
|
||||
|
||||
let app_state = Rc::new(RefCell::new(PlottingState {
|
||||
mean_x: mean_x_scale.value(),
|
||||
mean_y: mean_y_scale.value(),
|
||||
std_x: std_x_scale.value(),
|
||||
std_y: std_y_scale.value(),
|
||||
pitch: pitch_scale.value(),
|
||||
roll: yaw_scale.value(),
|
||||
}));
|
||||
|
||||
window.set_application(Some(app));
|
||||
|
||||
let state_cloned = app_state.clone();
|
||||
drawing_area.set_draw_func(move |widget, cr, _i, _j| {
|
||||
let state = state_cloned.borrow().clone();
|
||||
let w = widget.allocated_width();
|
||||
let h = widget.allocated_height();
|
||||
let backend = CairoBackend::new(cr, (w as u32, h as u32)).unwrap();
|
||||
state.plot_pdf(backend).unwrap();
|
||||
});
|
||||
|
||||
let handle_change =
|
||||
|what: >k::Scale, how: Box<dyn Fn(&mut PlottingState) -> &mut f64 + 'static>| {
|
||||
let app_state = app_state.clone();
|
||||
let drawing_area = drawing_area.clone();
|
||||
what.connect_value_changed(move |target| {
|
||||
let mut state = app_state.borrow_mut();
|
||||
*how(&mut *state) = target.value();
|
||||
drawing_area.queue_draw();
|
||||
});
|
||||
};
|
||||
|
||||
handle_change(&pitch_scale, Box::new(|s| &mut s.pitch));
|
||||
handle_change(&yaw_scale, Box::new(|s| &mut s.roll));
|
||||
handle_change(&mean_x_scale, Box::new(|s| &mut s.mean_x));
|
||||
handle_change(&mean_y_scale, Box::new(|s| &mut s.mean_y));
|
||||
handle_change(&std_x_scale, Box::new(|s| &mut s.std_x));
|
||||
handle_change(&std_y_scale, Box::new(|s| &mut s.std_y));
|
||||
|
||||
window.show();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let config_file = fs::read_to_string("config.toml").expect("Can't read config.toml");
|
||||
let config: Config = toml::from_str(&config_file).expect("Can't deserialize config.toml");
|
||||
|
||||
for chart in config.charts {
|
||||
// println!("Chart: {}\n", chart.1.title);
|
||||
|
||||
let title = format!("{}/{}.svg", config.output_dir, chart.1.title);
|
||||
let root_area = SVGBackend::new(&title, (config.width, config.height)).into_drawing_area();
|
||||
root_area.fill(&WHITE).unwrap();
|
||||
root_area.fill(&WHITE)?;
|
||||
|
||||
let mut ctx = ChartBuilder::on(&root_area)
|
||||
.set_label_area_size(LabelAreaPosition::Left, 40)
|
||||
.set_label_area_size(LabelAreaPosition::Bottom, 40)
|
||||
.caption(&chart.1.title, ("Fira Code", 24))
|
||||
.caption(&chart.borrow().title, ("Fira Code", 24))
|
||||
.build_cartesian_2d(
|
||||
0f64..(config.max_time as f64),
|
||||
0f64..(config.max_weight as f64),
|
||||
)
|
||||
.unwrap();
|
||||
0f64..(chart.borrow().max_time as f64),
|
||||
0f64..(chart.borrow().max_weight as f64),
|
||||
)?;
|
||||
|
||||
ctx.configure_mesh()
|
||||
.label_style(("Fira Code", 12))
|
||||
.draw()
|
||||
.unwrap();
|
||||
.draw()?;
|
||||
|
||||
let shot_count = chart.1.shots.len();
|
||||
let shot_count = chart.borrow().shots.len();
|
||||
|
||||
let palette = ColorPalette::new(shot_count as u32, PaletteType::Random, false);
|
||||
let mut palette_iter = palette.colors.iter();
|
||||
|
||||
for shot_nr in chart.1.shots {
|
||||
if let Some(shot) = config.shots.get(&shot_nr.to_string()) {
|
||||
for shot_nr in &chart.borrow().shots {
|
||||
if let Some(shot) = config.borrow().shots.get(&shot_nr.to_string()) {
|
||||
// println!("\tShot: {}n", shot.title);
|
||||
|
||||
if let Some(data) = load_data(
|
||||
&format!("{}/{}", config.shot_dir, shot.filename),
|
||||
&format!("{}/{}", config.borrow().shot_dir, shot.filename),
|
||||
shot.cutoff,
|
||||
) {
|
||||
if let Some(disable) = shot.disable {
|
||||
|
@ -346,13 +231,58 @@ fn main() {
|
|||
.label_font(("Fira Code", 12))
|
||||
.draw()
|
||||
.unwrap();
|
||||
|
||||
root_area.present()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn build_ui(app: >k::Application) {
|
||||
let builder = gtk::Builder::from_string(UI_SOURCE);
|
||||
|
||||
let config_file = fs::read_to_string("config.toml").expect("Can't read config.toml");
|
||||
let config: Rc<RefCell<Config>> = Rc::new(RefCell::new(toml::from_str(&config_file).expect("Can't deserialize config.toml")));
|
||||
|
||||
let chart_values = config.clone().borrow().charts;
|
||||
for value in chart_values {
|
||||
let config_cloned = config.clone();
|
||||
let chart = Rc::new(RefCell::new(value.1));
|
||||
|
||||
let window: gtk::Window = builder
|
||||
.object::<gtk::Window>("MainWindow")
|
||||
.unwrap();
|
||||
|
||||
window.set_title(Some(&chart.clone().borrow().title));
|
||||
|
||||
let drawing_area: gtk::DrawingArea = builder.object("MainDrawingArea").unwrap();
|
||||
|
||||
let app_state = Rc::new(RefCell::new(PlottingState {}));
|
||||
|
||||
window.set_application(Some(app));
|
||||
|
||||
{
|
||||
let state_cloned = app_state.clone();
|
||||
let config_cloned = Rc::clone(&config);
|
||||
let chart_cloned = Rc::clone(&chart);
|
||||
|
||||
drawing_area.set_draw_func(move |widget, cr, _i, _j| {
|
||||
let w = widget.allocated_width();
|
||||
let h = widget.allocated_height();
|
||||
let backend = CairoBackend::new(cr, (w as u32, h as u32)).unwrap();
|
||||
(*state_cloned).borrow_mut().plot(backend, chart_cloned, config_cloned).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
window.show();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let application =
|
||||
gtk::Application::new(Some("de.dustvoice.beanconqueror-gtk"), Default::default());
|
||||
|
||||
application.connect_activate(|app| {
|
||||
build_ui(app);
|
||||
application.connect_activate(move |app| {
|
||||
build_ui(&app)
|
||||
});
|
||||
|
||||
application.run();
|
||||
|
|
Loading…
Reference in New Issue