use std::io;
use std::time::Instant;
use rust_ppm::{Axes, Image, LineStyle, MarkerStyle, Pixel, Plot};
const IMAGE_SIZE: usize = 612;
fn main() -> io::Result<()> {
rings_image().save("output.ppm")?;
let points = [
(-1.0, 1.0),
(-0.5, 0.25),
(0.0, 0.0),
(0.5, 0.25),
(1.0, 1.0),
(2.0, 4.0),
(2.5, 6.25),
(3.0, 9.0),
(3.5, 12.25),
(4.0, 16.0),
];
Plot::new()
.size(800, 600)
.margins(80, 60)
.axes(
Axes::new()
.x_limits((-1.0, 4.0))
.y_limits((-2.0, 16.0))
.labels("x", "x squared")
.title("Quadratic samples"),
)
.markers(
&points,
MarkerStyle::new().size(5).color(Pixel::rgb(210, 45, 45)),
)
.save("scatter_plot.ppm")?;
let curve_points: Vec<(f64, f64)> = (-20..=20)
.map(|x| x as f64 / 5.0)
.map(|x| (x, x * x - 2.0 * x - 1.0))
.collect();
Plot::new()
.axes(Axes::new().labels("x", "y").title("Automatic limits"))
.line(
&curve_points,
LineStyle::new().width(2).color(Pixel::rgb(25, 95, 170)),
)
.markers(
&curve_points,
MarkerStyle::new().size(3).color(Pixel::rgb(230, 145, 25)),
)
.scale(2)
.save("curve_plot.ppm")?;
let multi_curve_a: Vec<(f64, f64)> = (-100..=100)
.map(|i| {
let x = i as f64 / 20.0;
let y = x * x - 2.0 * x - 1.0;
(x, y)
})
.collect();
let multi_curve_b: Vec<(f64, f64)> = (-100..=100)
.map(|i| {
let x = i as f64 / 20.0;
let y = 0.5 * x * x + 3.0 * x - 4.0;
(x, y)
})
.collect();
let multi_curve_c: Vec<(f64, f64)> = (-100..=100)
.map(|i| {
let x = i as f64 / 20.0;
let y = -(x * x) + 6.0 * x + 2.0;
(x, y)
})
.collect();
Plot::new()
.size(800, 600)
.margins(90, 70)
.axes(
Axes::new()
.labels("x", "y")
.title("Multiple curves example"),
)
.line(
&multi_curve_a,
LineStyle::new().width(3).color(Pixel::rgb(220, 60, 60)),
)
.line(
&multi_curve_b,
LineStyle::new().width(3).color(Pixel::rgb(60, 120, 220)),
)
.line(
&multi_curve_c,
LineStyle::new().width(3).color(Pixel::rgb(40, 180, 110)),
)
.save("multi_curve_plot.ppm")?;
let huge_curve_points: Vec<(f64, f64)> = (0..200_000)
.map(|i| {
let x = i as f64 / 1000.0;
let y = (x * 0.9).sin() * 15.0 + (x * 0.25).cos() * 7.0 + (x * 0.07).sin() * 4.0;
(x, y)
})
.collect();
let start = Instant::now();
let huge_curve = Plot::new()
.size(800, 600)
.margins(90, 70)
.axes(
Axes::new()
.labels("x", "y")
.title("Large multi-point curve"),
)
.line(
&huge_curve_points,
LineStyle::new().width(2).color(Pixel::rgb(118, 120, 200)),
)
.render();
let render_elapsed = start.elapsed();
huge_curve.save("huge_curve_plot.ppm")?;
println!("huge curve render time: {:?}", render_elapsed);
let line_image = Plot::new()
.size(800, 600)
.margins(80, 60)
.axes(
Axes::from_limits((-1.0, 4.0), (-2.0, 16.0))
.x_ticks([-1.0, 0.0, 1.0, 2.0, 3.0, 4.0])
.y_ticks([-2.0, 0.0, 4.0, 8.0, 12.0, 16.0])
.labels("x", "x squared")
.title("Custom ticks and line style"),
)
.line(
&points,
LineStyle::new().width(4).color(Pixel::rgb(40, 135, 80)),
)
.render();
line_image.save("line_plot.ppm")
}
fn rings_image() -> Image {
let center = IMAGE_SIZE as f64 / 2.0;
Image::from_pixel_fn(IMAGE_SIZE, IMAGE_SIZE, |x, y| {
let dx = x as f64 - center;
let dy = y as f64 - center;
let radius = (dx * dx + dy * dy).sqrt();
let value = if ((radius / 8.0) as u32).is_multiple_of(2) {
255
} else {
0
};
Pixel::rgb(value, value, value)
})
}