use super::{Bounds, Point2D};
use crate::error::Result;
pub trait Drawable {
fn draw(&self, canvas: &mut dyn Canvas) -> Result<()>;
}
pub trait Canvas {
fn dimensions(&self) -> (u32, u32);
fn bounds(&self) -> Bounds;
fn set_bounds(&mut self, bounds: Bounds);
fn transform(&self, point: &Point2D) -> (f32, f32);
fn draw_line(
&mut self,
from: &Point2D,
to: &Point2D,
color: &[u8; 4],
width: f32,
) -> Result<()>;
fn draw_circle(
&mut self,
center: &Point2D,
radius: f32,
color: &[u8; 4],
filled: bool,
) -> Result<()>;
fn draw_rectangle(
&mut self,
top_left: &Point2D,
width: f64,
height: f64,
color: &[u8; 4],
) -> Result<()>;
fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: &[u8; 4]) -> Result<()>;
fn fill_background(&mut self, color: &[u8; 4]) -> Result<()>;
fn draw_line_pixels(
&mut self,
x1: f32,
y1: f32,
x2: f32,
y2: f32,
color: &[u8; 4],
width: f32,
) -> Result<()>;
fn draw_text_pixels(
&mut self,
text: &str,
x: f32,
y: f32,
size: f32,
color: &[u8; 4],
) -> Result<()>;
fn calculate_corner_densities(
&self,
_legend_width: u32,
_legend_height: u32,
) -> (f64, f64, f64, f64) {
(0.0, 0.0, 0.0, 0.0) }
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct LinearScale {
data_min: f64,
data_max: f64,
pixel_min: f32,
pixel_max: f32,
}
impl LinearScale {
#[must_use]
#[allow(dead_code)]
pub const fn new(data_min: f64, data_max: f64, pixel_min: f32, pixel_max: f32) -> Self {
Self {
data_min,
data_max,
pixel_min,
pixel_max,
}
}
#[must_use]
#[allow(dead_code)]
#[allow(clippy::cast_possible_truncation)]
pub fn transform(&self, value: f64) -> f32 {
let data_range = self.data_max - self.data_min;
let pixel_range = self.pixel_max - self.pixel_min;
let normalized = (value - self.data_min) / data_range;
self.pixel_min + normalized as f32 * pixel_range
}
}