croot_gui/
graph.rs

1use num_complex::Complex64;
2use plotters::prelude::*;
3
4pub fn generate_graph<T: AsRef<std::path::Path> + ?Sized>(
5    roots: Vec<Complex64>,
6    filename: &T,
7    dimensions: (u32, u32),
8) -> Result<(), Box<dyn std::error::Error>> {
9    let draw_area = BitMapBackend::new(filename, dimensions).into_drawing_area();
10
11    let radius = roots.first().map(|c| c.norm()).expect("No roots provided");
12    let axes_range = (radius * -1.2)..(radius * 1.2);
13
14    draw_area.fill(&WHITE)?;
15
16    // Create chart
17    let mut chart = ChartBuilder::on(&draw_area)
18        .caption(
19            format!(
20                "{} roots of {}",
21                roots.len(),
22                roots
23                    .first()
24                    .copied()
25                    .unwrap_or_default()
26                    .powi(roots.len() as i32)
27            ),
28            ("sans-serif", 50).into_font(),
29        )
30        .margin(5)
31        .x_label_area_size(30)
32        .y_label_area_size(30)
33        .build_cartesian_2d(axes_range.clone(), axes_range.clone())?;
34
35    // Add grid to background
36    chart.configure_mesh().draw()?;
37
38    // Draw line on y-axis
39    chart.draw_series(LineSeries::new(
40        (((radius * -1.5) as i32)..=((radius * 1.5) as i32))
41            .map(|x| x as f64)
42            .map(|y| (0.0, y)),
43        BLACK,
44    ))?;
45
46    // Draw line on x-axis
47    chart.draw_series(LineSeries::new(
48        (((radius * -1.5) as i32)..=((radius * 1.5) as i32))
49            .map(|x| x as f64)
50            .map(|x| (x, 0.0)),
51        BLACK,
52    ))?;
53
54    // Draw line from origin to each root
55    for root in roots.iter() {
56        chart.draw_series(LineSeries::new(
57            (0..=100)
58                .map(|x| x as f64 / 100.0)
59                .map(|x| (x * root.re, x * root.im)),
60            BLACK.stroke_width(2),
61        ))?;
62    }
63
64    // Draw circles on each root
65    chart.draw_series(
66        roots
67            .iter()
68            .map(|c| Circle::new((c.re, c.im), 5, BLACK.filled())),
69    )?;
70
71    // Draw circle at origin
72    chart
73        .plotting_area()
74        .draw(&Circle::new((0.0, 0.0), 5, BLACK.stroke_width(5).filled()))?;
75
76    // Generate graph
77    draw_area.present()?;
78
79    Ok(())
80}
81
82#[cfg(feature = "gui")]
83pub fn show_graph(
84    roots: Vec<Complex64>,
85    dimensions: (u32, u32),
86) -> Result<(), Box<dyn std::error::Error>> {
87    use std::path::PathBuf;
88
89    use crate::app::show_image;
90
91    let path: PathBuf = [".", "temp.png"].iter().collect();
92
93    generate_graph(roots, "temp.png", dimensions)?;
94    show_image("Complex Root Graph", path, dimensions)?;
95    std::fs::remove_file("temp.png")?;
96
97    Ok(())
98}