use crate::{components::Viewport, CanvasSpace, DrawingSpace};
use euclid::{Point2D, Size2D, Transform2D, Vector2D};
pub fn to_canvas_coordinates(
point: Point2D<f64, DrawingSpace>,
viewport: &Viewport,
window: Size2D<f64, CanvasSpace>,
) -> Point2D<f64, CanvasSpace> {
transform_to_canvas_space(viewport, window).transform_point(point)
}
pub fn transform_to_canvas_space(
viewport: &Viewport,
window: Size2D<f64, CanvasSpace>,
) -> Transform2D<f64, DrawingSpace, CanvasSpace> {
transform_to_drawing_space(viewport, window)
.inverse()
.expect("The transform matrix should always be invertible")
}
pub fn transform_to_drawing_space(
viewport: &Viewport,
window: Size2D<f64, CanvasSpace>,
) -> Transform2D<f64, CanvasSpace, DrawingSpace> {
let drawing_units_per_pixel = viewport.pixels_per_drawing_unit.inv();
let x_axis = Vector2D::new(1.0, 0.0);
let x_axis_basis = drawing_units_per_pixel.transform_vector(x_axis);
let y_axis = Vector2D::new(0.0, -1.0);
let y_axis_basis = drawing_units_per_pixel.transform_vector(y_axis);
let new_origin = Vector2D::new(viewport.centre.x, viewport.centre.y)
+ Vector2D::new(-window.width / 2.0, window.height / 2.0)
* drawing_units_per_pixel;
Transform2D::from_row_arrays([
x_axis_basis.to_array(),
y_axis_basis.to_array(),
new_origin.to_array(),
])
}
pub fn to_drawing_coordinates(
point: Point2D<f64, CanvasSpace>,
viewport: &Viewport,
window: Size2D<f64, CanvasSpace>,
) -> Point2D<f64, DrawingSpace> {
transform_to_drawing_space(viewport, window).transform_point(point)
}
#[cfg(test)]
mod tests {
use super::*;
use euclid::Scale;
fn known_example() -> (
Vec<(Point2D<f64, DrawingSpace>, Point2D<f64, CanvasSpace>)>,
Viewport,
Size2D<f64, CanvasSpace>,
) {
let vertices = vec![
(Point2D::new(300.0, 150.0), Point2D::new(400.0, 200.0)),
(Point2D::new(200.0, 200.0), Point2D::new(0.0, 0.0)),
(Point2D::new(200.0, 100.0), Point2D::new(0.0, 400.0)),
(Point2D::new(400.0, 100.0), Point2D::new(800.0, 400.0)),
(Point2D::new(400.0, 200.0), Point2D::new(800.0, 0.0)),
];
let viewport = Viewport {
centre: Point2D::new(300.0, 150.0),
pixels_per_drawing_unit: Scale::new(4.0),
};
let window = Size2D::new(800.0, 400.0);
(vertices, viewport, window)
}
#[test]
fn drawing_to_canvas_space() {
let (inputs, viewport, window) = known_example();
for (drawing_space, expected) in inputs {
let got = to_canvas_coordinates(drawing_space, &viewport, window);
assert_eq!(got, expected);
}
}
#[test]
fn canvas_to_drawing_space() {
let (inputs, viewport, window) = known_example();
for (expected, canvas_space) in inputs {
let got = to_drawing_coordinates(canvas_space, &viewport, window);
assert_eq!(got, expected);
}
}
#[test]
fn known_transform_matrix() {
let (_, viewport, window) = known_example();
assert_eq!(
transform_to_drawing_space(&viewport, window).to_row_major_array(),
[0.25, 0.0, 0.0, -0.25, 200.0, 200.0]
);
assert_eq!(
transform_to_canvas_space(&viewport, window).to_row_major_array(),
[4.0, 0.0, 0.0, -4.0, -800.0, 800.0]
);
}
}