use std::ops::{Add, AddAssign, Sub, SubAssign};
use egui::Vec2;
pub struct Viewport {
pub(crate) position: Vec2,
pub(crate) grid: Grid,
}
#[derive(Clone)]
pub(crate) struct Grid {
pub(crate) size: f32,
}
impl Viewport {
pub(crate) fn viewport_to_canvas(&self, pos: egui::Pos2) -> CanvasPos {
CanvasPos(pos - self.position)
}
pub(crate) fn canvas_to_viewport(&self, pos: CanvasPos) -> egui::Pos2 {
let CanvasPos(pos) = pos;
pos + self.position
}
#[must_use]
#[inline]
pub fn viewport_to_graph(&self, pos: egui::Pos2) -> Pos {
self.grid.canvas_to_graph(self.viewport_to_canvas(pos))
}
}
impl Grid {
pub(crate) fn graph_to_canvas(&self, pos: Pos) -> CanvasPos {
let Pos { x, y } = pos;
#[allow(clippy::cast_precision_loss)]
let x = x as f32 * self.size;
#[allow(clippy::cast_precision_loss)]
let y = -y as f32 * self.size;
CanvasPos(egui::pos2(x, y))
}
fn canvas_to_graph_unrounded(&self, pos: CanvasPos) -> (f32, f32) {
let CanvasPos(egui::Pos2 { x, y }) = pos;
let y = -y;
let x = x / self.size;
let y = y / self.size;
(x, y)
}
pub(crate) fn canvas_to_graph(&self, pos: CanvasPos) -> Pos {
let (x, y) = self.canvas_to_graph_unrounded(pos);
#[allow(clippy::cast_possible_truncation)]
let x = x.floor() as i32;
#[allow(clippy::cast_possible_truncation)]
let y = y.ceil() as i32;
Pos { x, y }
}
pub(crate) fn canvas_to_graph_nearest(&self, pos: CanvasPos) -> Pos {
let (x, y) = self.canvas_to_graph_unrounded(pos);
#[allow(clippy::cast_possible_truncation)]
let x = x.round() as i32;
#[allow(clippy::cast_possible_truncation)]
let y = y.round() as i32;
Pos { x, y }
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CanvasPos(egui::Pos2);
impl CanvasPos {
pub(crate) const ZERO: CanvasPos = CanvasPos(egui::Pos2::ZERO);
pub(crate) fn to_vec2(self) -> Vec2 {
self.0.to_vec2()
}
}
impl Add<Vec2> for CanvasPos {
type Output = CanvasPos;
fn add(self, rhs: Vec2) -> Self::Output {
let CanvasPos(pos) = self;
CanvasPos(pos + rhs)
}
}
impl AddAssign<Vec2> for CanvasPos {
fn add_assign(&mut self, rhs: Vec2) {
*self = *self + rhs;
}
}
impl Sub<Vec2> for CanvasPos {
type Output = CanvasPos;
fn sub(self, rhs: Vec2) -> Self::Output {
let CanvasPos(pos) = self;
CanvasPos(pos - rhs)
}
}
impl SubAssign<Vec2> for CanvasPos {
fn sub_assign(&mut self, rhs: Vec2) {
*self = *self - rhs;
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Pos {
#[allow(missing_docs)]
pub x: i32,
#[allow(missing_docs)]
pub y: i32,
}
impl Pos {
#[inline]
#[must_use]
pub fn new(x: i32, y: i32) -> Self {
Pos { x, y }
}
}