/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2026 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use async_trait::async_trait; use darkfi_serial::{SerialDecodable, SerialEncodable}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, Sub, SubAssign}; #[derive(Clone, Copy, Debug, SerialEncodable, SerialDecodable)] pub struct Dimension { pub w: f32, pub h: f32, } impl Dimension { pub fn contains(&self, other: &Dimension) -> bool { other.w <= self.w && other.h <= self.h } } impl From<[f32; 2]> for Dimension { fn from(dim: [f32; 2]) -> Self { Self { w: dim[0], h: dim[1] } } } impl Mul for Dimension { type Output = Dimension; fn mul(self, scale: f32) -> Self::Output { Self { w: self.w * scale, h: self.h * scale } } } impl Div for Dimension { type Output = Dimension; fn div(self, scale: f32) -> Self::Output { Self { w: self.w / scale, h: self.h / scale } } } #[derive(Clone, Copy, Default, SerialEncodable, SerialDecodable)] pub struct Point { pub x: f32, pub y: f32, } impl Point { pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } pub fn zero() -> Self { Self { x: 0., y: 0. } } pub fn unpack(&self) -> (f32, f32) { (self.x, self.y) } pub fn as_arr(&self) -> [f32; 2] { [self.x, self.y] } pub fn offset(&self, off_x: f32, off_y: f32) -> Self { Self { x: self.x + off_x, y: self.y + off_y } } pub fn to_rect(&self, w: f32, h: f32) -> Rectangle { Rectangle { x: self.x, y: self.y, w, h } } pub fn dist_sq(&self, other: Point) -> f32 { (self.x - other.x).powi(2) + (self.y - other.y).powi(2) } pub fn dist(&self, other: Point) -> f32 { self.dist_sq(other).sqrt() } pub fn normalize(&mut self) { let scale = self.dist(Point::zero()); self.x /= scale; self.y /= scale; assert!((self.dist(Point::zero()) - 1.) < f32::EPSILON); } /// Counterclockwise perp vector (with -y up) pub fn perp_left(&self) -> Point { Point::new(self.y, -self.x) } /// Clockwise perp vector (with +y down) pub fn perp_right(&self) -> Point { Point::new(-self.y, self.x) } } impl From<[f32; 2]> for Point { fn from(pos: [f32; 2]) -> Self { Self { x: pos[0], y: pos[1] } } } impl std::fmt::Debug for Point { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) } } impl Add for Point { type Output = Self; fn add(self, other: Self) -> Self::Output { Self { x: self.x + other.x, y: self.y + other.y } } } impl Sub for Point { type Output = Self; fn sub(self, other: Self) -> Self::Output { Self { x: self.x - other.x, y: self.y - other.y } } } impl AddAssign for Point { fn add_assign(&mut self, other: Self) { *self = Self { x: self.x + other.x, y: self.y + other.y }; } } impl SubAssign for Point { fn sub_assign(&mut self, other: Self) { *self = Self { x: self.x - other.x, y: self.y - other.y }; } } impl Mul for Point { type Output = Self; fn mul(self, scale: f32) -> Self { Point::new(scale * self.x, scale * self.y) } } #[derive(Clone, Copy, SerialEncodable, SerialDecodable)] pub struct Rectangle { pub x: f32, pub y: f32, pub w: f32, pub h: f32, } impl Rectangle { pub const fn new(x: f32, y: f32, w: f32, h: f32) -> Self { Self { x, y, w, h } } pub fn zero() -> Self { Self { x: 0., y: 0., w: 0., h: 0. } } /// Use from() instead #[deprecated] pub fn from_array(arr: [f32; 4]) -> Self { Self { x: arr[0], y: arr[1], w: arr[2], h: arr[3] } } pub fn clip(&self, other: &Self) -> Option { if other.x + other.w < self.x || other.x > self.x + self.w || other.y + other.h < self.y || other.y > self.y + self.h { return None } let mut clipped = other.clone(); if clipped.x < self.x { clipped.x = self.x; clipped.w = other.x + other.w - clipped.x; } if clipped.y < self.y { clipped.y = self.y; clipped.h = other.y + other.h - clipped.y; } if clipped.x + clipped.w > self.x + self.w { clipped.w = self.x + self.w - clipped.x; } if clipped.y + clipped.h > self.y + self.h { clipped.h = self.y + self.h - clipped.y; } Some(clipped) } pub fn with_zero_pos(&self) -> Self { Self::new(0., 0., self.w, self.h) } pub fn clip_point(&self, mut point: Point) -> Point { if point.x < self.x { point.x = self.x; } if point.y < self.y { point.y = self.y; } if point.x > self.x + self.w { point.x = self.x + self.w; } if point.y > self.y + self.h { point.y = self.y + self.h; } point } pub fn contains(&self, point: Point) -> bool { self.x <= point.x && point.x <= self.x + self.w && self.y <= point.y && point.y <= self.y + self.h } pub fn rhs(&self) -> f32 { self.x + self.w } pub fn bhs(&self) -> f32 { self.y + self.h } pub fn pos(&self) -> Point { Point { x: self.x, y: self.y } } pub fn corner(&self) -> Point { Point { x: self.x + self.w, y: self.y + self.h } } pub fn center(&self) -> Point { Point { x: self.x + self.w / 2., y: self.y + self.h / 2. } } pub fn top_right(&self) -> Point { Point { x: self.rhs(), y: self.y } } pub fn bot_left(&self) -> Point { Point { x: self.x, y: self.y + self.h } } pub fn dim(&self) -> Dimension { Dimension { w: self.w, h: self.h } } #[deprecated] pub fn top_left(&self) -> Point { Point { x: self.x, y: self.y } } #[deprecated] pub fn bottom_right(&self) -> Point { Point { x: self.x + self.w, y: self.y + self.h } } pub fn includes(&self, child: &Self) -> bool { self.contains(child.pos()) && self.contains(child.corner()) } } impl From<[f32; 4]> for Rectangle { fn from(rect: [f32; 4]) -> Self { Self { x: rect[0], y: rect[1], w: rect[2], h: rect[3] } } } impl Add for Rectangle { type Output = Rectangle; fn add(self, other: Point) -> Self::Output { Self { x: self.x + other.x, y: self.y + other.y, w: self.w, h: self.h } } } impl Sub for Rectangle { type Output = Rectangle; fn sub(self, other: Point) -> Self::Output { Self { x: self.x - other.x, y: self.y - other.y, w: self.w, h: self.h } } } impl Mul for Rectangle { type Output = Rectangle; fn mul(self, scale: f32) -> Self::Output { Self { x: self.x * scale, y: self.y * scale, w: self.w * scale, h: self.h * scale } } } impl Div for Rectangle { type Output = Rectangle; fn div(self, scale: f32) -> Self::Output { Self { x: self.x / scale, y: self.y / scale, w: self.w / scale, h: self.h / scale } } } impl DivAssign for Rectangle { fn div_assign(&mut self, scale: f32) { self.x /= scale; self.y /= scale; self.w /= scale; self.h /= scale; } } impl std::fmt::Debug for Rectangle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({}, {}, {}, {})", self.x, self.y, self.w, self.h) } } impl From for Rectangle { fn from(rect: parley::BoundingBox) -> Self { Self::new(rect.x0 as f32, rect.y0 as f32, rect.width() as f32, rect.height() as f32) } }