use super::point::{CanvasPoint, GraphPoint};
#[derive(Clone, Copy, Debug)]
pub struct GraphOptions {
pub canvas_size: CanvasPoint<u16>,
pub center: GraphPoint<f64>,
pub scale: GraphPoint<f64>,
pub square_scale: bool,
pub label_canvas_boundaries: bool,
pub major_grid_spacing: GraphPoint<f64>,
pub major_grid_divisions: (u8, u8),
pub major_grid_opacity: f64,
pub minor_grid_opacity: f64,
}
impl Default for GraphOptions {
fn default() -> GraphOptions {
GraphOptions {
canvas_size: CanvasPoint(1000, 1000),
center: GraphPoint(0.0, 0.0),
scale: GraphPoint(10.0, 10.0),
square_scale: false,
label_canvas_boundaries: false,
major_grid_spacing: GraphPoint(2.0, 2.0),
major_grid_divisions: (4, 4),
major_grid_opacity: 0.8,
minor_grid_opacity: 0.4,
}
}
}
impl GraphOptions {
pub fn canvas_size(mut self, width: u16, height: u16) -> Self {
self.canvas_size = CanvasPoint(width, height);
self
}
pub fn center(mut self, x: f64, y: f64) -> Self {
self.center = GraphPoint(x, y);
self
}
pub fn scale(mut self, x: f64, y: f64) -> Self {
self.scale = GraphPoint(x, y);
self
}
pub fn square_scale(mut self, square_scale: bool) -> Self {
self.square_scale = square_scale;
self
}
pub fn label_canvas_boundaries(mut self, label_canvas_boundaries: bool) -> Self {
self.label_canvas_boundaries = label_canvas_boundaries;
self
}
pub fn major_grid_spacing(mut self, x: f64, y: f64) -> Self {
self.major_grid_spacing = GraphPoint(x, y);
self
}
pub fn major_grid_divisions(mut self, x: u8, y: u8) -> Self {
self.major_grid_divisions = (x, y);
self
}
pub fn major_grid_opacity(mut self, major_grid_opacity: f64) -> Self {
self.major_grid_opacity = major_grid_opacity;
self
}
pub fn minor_grid_opacity(mut self, minor_grid_opacity: f64) -> Self {
self.minor_grid_opacity = minor_grid_opacity;
self
}
}
impl GraphOptions {
pub(crate) fn x_to_canvas(&self, x: f64) -> f64 {
let graph_space_range = self.scale.0 * 2.0;
let normalized = (x - self.center.0) / graph_space_range + 0.5;
normalized * self.canvas_size.0 as f64
}
pub(crate) fn y_to_canvas(&self, y: f64) -> f64 {
let graph_space_range = self.scale.1 * 2.0;
let normalized = 0.5 - (y - self.center.1) / graph_space_range;
normalized * self.canvas_size.1 as f64
}
pub fn to_canvas(&self, point: GraphPoint<f64>) -> CanvasPoint<f64> {
CanvasPoint(
self.x_to_canvas(point.0),
self.y_to_canvas(point.1),
)
}
pub(crate) fn x_to_graph(&self, x: f64) -> f64 {
let normalized = x / self.canvas_size.0 as f64;
let graph_space_range = self.scale.0 * 2.0;
let left_edge_graph_space = self.center.0 - self.scale.0;
normalized * graph_space_range + left_edge_graph_space
}
pub(crate) fn y_to_graph(&self, y: f64) -> f64 {
let normalized = 1.0 - y / self.canvas_size.1 as f64;
let graph_space_range = self.scale.1 * 2.0;
let bottom_edge_graph_space = self.center.1 - self.scale.1;
normalized * graph_space_range + bottom_edge_graph_space
}
pub fn to_graph(&self, point: CanvasPoint<f64>) -> GraphPoint<f64> {
GraphPoint(
self.x_to_graph(point.0),
self.y_to_graph(point.1),
)
}
}
#[cfg(test)]
mod tests {
use crate::graph::round_to;
use super::*;
#[test]
fn canvas_to_graph() {
let options = GraphOptions {
canvas_size: CanvasPoint(465, 917),
center: GraphPoint(-3.0, 2.41),
scale: GraphPoint(3.59, 5.69),
..Default::default()
};
assert_eq!(
options.x_to_graph(0.0),
options.center.0 - options.scale.0,
);
assert_eq!(
options.x_to_graph(options.canvas_size.0 as f64),
options.center.0 + options.scale.0,
);
assert_eq!(
options.y_to_graph(0.0),
options.center.1 + options.scale.1,
);
assert_eq!(
options.y_to_graph(options.canvas_size.1 as f64),
options.center.1 - options.scale.1,
);
}
#[test]
fn graph_to_canvas() {
let options = GraphOptions {
canvas_size: CanvasPoint(465, 917),
center: GraphPoint(-3.0, 2.41),
scale: GraphPoint(3.59, 5.69),
..Default::default()
};
assert_eq!(
options.x_to_canvas(options.center.0 - options.scale.0),
0.0,
);
assert_eq!(
options.x_to_canvas(options.center.0 + options.scale.0),
options.canvas_size.0 as f64,
);
assert_eq!(
round_to(options.y_to_canvas(options.center.1 + options.scale.1), 1e-6),
0.0,
);
assert_eq!(
options.y_to_canvas(options.center.1 - options.scale.1),
options.canvas_size.1 as f64,
);
}
}