use alloc::borrow::ToOwned; use alloc::vec::Vec; use libm::sqrt; use crate::println; #[derive(Clone, Debug, PartialEq)] pub enum Line { Vertical(i64), Horizontal(i64), } #[derive(Clone, Debug, PartialEq)] pub struct Position { pub x: i64, pub y: i64, } /// a point represented with x and y coordinates. impl Position { /// checks if the point is on a given line pub fn touches_line(&self, line: &Line) -> bool { match line { Line::Vertical(y) => self.y as i64 == *y, Line::Horizontal(x) => self.x as i64 == *x, } } /// checks if two points are equal and returns the x and y equality result for each pub fn aligns(&self, other: &Position) -> (bool, bool) { (self.x == other.x, self.y == other.y) } /// calculates x + y distance between two points pub fn get_offset(&self, other: &Position) -> Position { Position { x: other.x - self.x, y: other.y - self.y } } pub fn diagonal_distance(&self, other: &Position) -> i64 { sqrt((self.x - other.x).pow(2) as f64 + (self.y - other.y).pow(2) as f64) as i64 } pub fn as_usize(&self) -> (usize, usize) { (self.x as usize, self.y as usize) } pub fn magnitude(&self) -> i64 { self.x.abs() + self.y.abs() } pub fn nearest(&self, points: &Vec) -> Position { let mut points = points.clone(); points.sort_by_key(|p| { let p = self.get_offset(p); p.x.abs() + p.y.abs() }); points.first().unwrap().to_owned() } pub fn rotated_aroundte(&self, angle: Direction, p: Position) -> Position { // rotates by an angle around a point // gets coords relative to point to rotate around let mut p_offset = self.get_offset(&p); p_offset = match angle { // default angle is posy = 0 degrees and negy = 180 Direction::Degrees0 => Position { x: p_offset.x, y: p_offset.y, }, Direction::Degrees90 => Position { x: -p_offset.y, y: p_offset.x, }, Direction::Degrees180 => Position { x: -p_offset.x, y: -p_offset.y, }, Direction::Degrees270 => Position { x: p_offset.y, y: -p_offset.x, }, Direction::None => panic!("direction should never be none in this application"), }; return p_offset + p; } pub fn rotate(&self, angle: Direction) -> Position { // rotates by an angle around origin match angle { // default angle is posy = 0 degrees and negy = 180 Direction::Degrees0 => Position { x: self.x, y: self.y, }, Direction::Degrees90 => Position { x: -self.y, y: self.x, }, Direction::Degrees180 => Position { x: -self.x, y: -self.y, }, Direction::Degrees270 => Position { x: self.y, y: -self.x, }, Direction::None => panic!("direction should never be none in this application"), } } pub fn real(self) -> PositionReal { PositionReal { x: self.x as f64, y: self.y as f64, } } } impl core::ops::Add for Position { type Output = Position; fn add(self, other: Position) -> Position { Position { x: self.x + other.x, y: self.y + other.y, } } } /// can be expressed as degrees relative to north (where north faces towards the top of the screen) /// none variant used for when the value is missing / no value is decided. #[derive(Clone, Debug, PartialEq)] pub enum Direction { Degrees0, Degrees180, Degrees90, Degrees270, None, } impl Direction { pub fn rev(&self) -> Direction { match self { Direction::Degrees0 => Direction::Degrees180, Direction::Degrees180 => Direction::Degrees0, Direction::Degrees90 => Direction::Degrees270, Direction::Degrees270 => Direction::Degrees90, Direction::None => Direction::None, } } } #[derive(Clone, Debug, PartialEq)] pub struct PositionReal { pub x: f64, pub y: f64, } /// a point represented with x and y coordinates. impl PositionReal { /// checks if the point is on a given line pub fn touches_line(&self, line: &Line) -> bool { match line { Line::Vertical(y) => self.y as i64 == *y, Line::Horizontal(x) => self.x as i64 == *x, } } /// checks if two points are equal and returns the x and y equality result for each pub fn aligns(&self, other: &PositionReal) -> (bool, bool) { (self.x == other.x, self.y == other.y) } /// calculates x + y distance between two points pub fn get_offset(&self, other: &PositionReal) -> PositionReal { PositionReal { x: other.x - self.x, y: other.y - self.y } } pub fn diagonal_distance(&self, other: &PositionReal) -> f64 { sqrt((self.x - other.x)*(self.x - other.x) + (self.y - other.y)* (self.y - other.y) as f64) } pub fn as_usize(&self) -> (usize, usize) { (self.x as usize, self.y as usize) } pub fn magnitude(&self) -> i64 { let absx = if self.x >= 0.0 { self.x } else { -self.x }; let absy = if self.y >= 0.0 { self.y } else { -self.y }; (absx + absy) as i64 } pub fn nearest(&self, points: &Vec) -> PositionReal { let mut points = points.clone(); points.sort_by_key(|p| { let p = self.get_offset(p); let absx = if p.x >= 0.0 { p.x } else { -p.x }; let absy = if p.y >= 0.0 { p.y } else { -p.y }; (absx + absy) as i64 }); points.first().unwrap().to_owned() } pub fn rotated_around(&self, angle: Direction, p: PositionReal) -> PositionReal { // rotates by an angle around a point // gets coords relative to point to rotate around let mut p_offset = self.get_offset(&p); p_offset = match angle { // default angle is posy = 0 degrees and negy = 180 Direction::Degrees0 => PositionReal { x: p_offset.x, y: p_offset.y, }, Direction::Degrees90 => PositionReal { x: -p_offset.y, y: p_offset.x, }, Direction::Degrees180 => PositionReal { x: -p_offset.x, y: -p_offset.y, }, Direction::Degrees270 => PositionReal { x: p_offset.y, y: -p_offset.x, }, Direction::None => panic!("direction should never be none in this application"), }; return p_offset + p; } pub fn rotate(&self, angle: Direction) -> PositionReal { // rotates by an angle around origin match angle { // default angle is posy = 0 degrees and negy = 180 Direction::Degrees0 => PositionReal { x: self.x, y: self.y, }, Direction::Degrees90 => PositionReal { x: -self.y, y: self.x, }, Direction::Degrees180 => PositionReal { x: -self.x, y: -self.y, }, Direction::Degrees270 => PositionReal { x: self.y, y: -self.x, }, Direction::None => panic!("direction should never be none in this application"), } } pub fn integer(self) -> Position { Position { x: self.x as i64, y: self.y as i64, } } } impl core::ops::Add for PositionReal { type Output = PositionReal; fn add(self, other: PositionReal) -> PositionReal { PositionReal { x: self.x + other.x, y: self.y + other.y, } } }