// -*- coding: utf-8 -*- // // Copyright 2021 Michael Büsch // // Licensed under the Apache License version 2.0 // or the MIT license, at your option. // SPDX-License-Identifier: Apache-2.0 OR MIT // use crate::base::{Axis, PhyType}; use crate::vector::Vector; use std::ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign}; #[derive(Clone, Copy, PartialEq, Debug)] pub struct Point { x: PhyType, y: PhyType, z: PhyType, } impl Point { pub fn new(x: PhyType, y: PhyType, z: PhyType) -> Point { Point { x, y, z } } pub fn new_zero() -> Point { Point::new(0.into(), 0.into(), 0.into()) } pub fn x(&self) -> PhyType { self.x } pub fn y(&self) -> PhyType { self.y } pub fn z(&self) -> PhyType { self.z } pub fn get(&self, axis: Axis) -> PhyType { match axis { Axis::X => self.x(), Axis::Y => self.y(), Axis::Z => self.z(), } } pub fn set_x(&mut self, x: PhyType) { self.x = x; } pub fn set_y(&mut self, y: PhyType) { self.y = y; } pub fn set_z(&mut self, z: PhyType) { self.z = z; } pub fn set_xyz(&mut self, x: PhyType, y: PhyType, z: PhyType) { self.set_x(x); self.set_y(y); self.set_z(z); } pub fn add_vector(&self, vect: Vector) -> Point { Point::new( self.x() + vect.x(), self.y() + vect.y(), self.z() + vect.z(), ) } } impl std::fmt::Display for Point { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Point(x={}, y={}, z={})", self.x(), self.y(), self.z()) } } impl Default for Point { fn default() -> Self { Point::new_zero() } } impl Add for Point { type Output = Self; fn add(self, other: Self) -> Self::Output { Point::new( self.x() + other.x(), self.y() + other.y(), self.z() + other.z(), ) } } impl AddAssign for Point { fn add_assign(&mut self, other: Self) { self.set_xyz( self.x() + other.x(), self.y() + other.y(), self.z() + other.z(), ); } } impl Sub for Point { type Output = Self; fn sub(self, other: Self) -> Self::Output { Point::new( self.x() - other.x(), self.y() - other.y(), self.z() - other.z(), ) } } impl SubAssign for Point { fn sub_assign(&mut self, other: Self) { self.set_xyz( self.x() - other.x(), self.y() - other.y(), self.z() - other.z(), ); } } #[derive(Clone, Debug)] pub struct PointLim { point: Point, x_lim: (PhyType, PhyType), y_lim: (PhyType, PhyType), z_lim: (PhyType, PhyType), } impl PointLim { pub fn new(point: Point) -> PointLim { PointLim { point, x_lim: (-PhyType::UNLIMITED, PhyType::UNLIMITED), y_lim: (-PhyType::UNLIMITED, PhyType::UNLIMITED), z_lim: (-PhyType::UNLIMITED, PhyType::UNLIMITED), } } pub fn get_limits(&self, axis: Axis) -> (PhyType, PhyType) { match axis { Axis::X => self.x_lim, Axis::Y => self.y_lim, Axis::Z => self.z_lim, } } pub fn set_limits(&mut self, axis: Axis, mut limits: (PhyType, PhyType)) { if limits.0 == PhyType::UNLIMITED { limits.0 = -PhyType::UNLIMITED; } if limits.1 == -PhyType::UNLIMITED { limits.1 = PhyType::UNLIMITED; } match axis { Axis::X => self.x_lim = limits, Axis::Y => self.y_lim = limits, Axis::Z => self.z_lim = limits, } } pub fn limited(&self) -> Point { let mut point = self.point; point.set_x(point.x().clamp(self.x_lim.0, self.x_lim.1)); point.set_y(point.y().clamp(self.y_lim.0, self.y_lim.1)); point.set_z(point.z().clamp(self.z_lim.0, self.z_lim.1)); point } pub fn apply_limits(&mut self) { self.point = self.limited(); } } impl std::fmt::Display for PointLim { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Lim({}, x_lim={}/{}, y_lim={}/{} z_lim={}/{})", self.point, self.x_lim.0, self.x_lim.1, self.y_lim.0, self.y_lim.1, self.z_lim.0, self.z_lim.1 ) } } impl Deref for PointLim { type Target = Point; fn deref(&self) -> &Self::Target { &self.point } } impl DerefMut for PointLim { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.point } } #[cfg(test)] mod tests { use super::*; #[test] fn test_base() { // Zero let a = Point::new_zero(); assert_eq!(a.x(), 0.into()); assert_eq!(a.y(), 0.into()); assert_eq!(a.z(), 0.into()); // Getter let a = Point::new(1.into(), 2.into(), 3.into()); assert_eq!(a.x(), 1.into()); assert_eq!(a.get(Axis::X), 1.into()); assert_eq!(a.y(), 2.into()); assert_eq!(a.get(Axis::Y), 2.into()); assert_eq!(a.z(), 3.into()); assert_eq!(a.get(Axis::Z), 3.into()); // Setter let mut a = Point::new(1.into(), 2.into(), 3.into()); a.set_x(10.into()); a.set_y(11.into()); a.set_z(12.into()); assert_eq!(a.x(), 10.into()); assert_eq!(a.y(), 11.into()); assert_eq!(a.z(), 12.into()); // Combined setter let mut a = Point::new(1.into(), 2.into(), 3.into()); a.set_xyz(10.into(), 11.into(), 12.into()); assert_eq!(a.x(), 10.into()); assert_eq!(a.y(), 11.into()); assert_eq!(a.z(), 12.into()); } #[test] fn test_arithmetic() { // Add let a = Point::new(1.into(), 2.into(), 3.into()); let b = Point::new(4.into(), 5.into(), 6.into()); let c = a + b; assert_eq!(c.x(), 5.into()); assert_eq!(c.y(), 7.into()); assert_eq!(c.z(), 9.into()); // AddAssign let mut a = Point::new(1.into(), 2.into(), 3.into()); let b = Point::new(4.into(), 5.into(), 6.into()); a += b; assert_eq!(a.x(), 5.into()); assert_eq!(a.y(), 7.into()); assert_eq!(a.z(), 9.into()); // Sub let a = Point::new(10.into(), 20.into(), 30.into()); let b = Point::new(4.into(), 5.into(), 6.into()); let c = a - b; assert_eq!(c.x(), 6.into()); assert_eq!(c.y(), 15.into()); assert_eq!(c.z(), 24.into()); // SubAssign let mut a = Point::new(10.into(), 20.into(), 30.into()); let b = Point::new(4.into(), 5.into(), 6.into()); a -= b; assert_eq!(a.x(), 6.into()); assert_eq!(a.y(), 15.into()); assert_eq!(a.z(), 24.into()); // Add vector let a = Point::new(1.into(), 2.into(), 3.into()); let b = Vector::new(4.into(), 5.into(), 6.into()); let c = a.add_vector(b); assert_eq!(c.x(), 5.into()); assert_eq!(c.y(), 7.into()); assert_eq!(c.z(), 9.into()); } #[test] fn test_limited() { // Set/get let mut a = PointLim::new(Point::new(1.into(), 2.into(), 3.into())); a.set_limits(Axis::X, ((-9).into(), 10.into())); a.set_limits(Axis::Y, ((-19).into(), 20.into())); a.set_limits(Axis::Z, ((-29).into(), 30.into())); assert_eq!(a.get_limits(Axis::X), ((-9).into(), 10.into())); assert_eq!(a.get_limits(Axis::Y), ((-19).into(), 20.into())); assert_eq!(a.get_limits(Axis::Z), ((-29).into(), 30.into())); a.set_limits(Axis::X, (PhyType::UNLIMITED, -PhyType::UNLIMITED)); assert_eq!( a.get_limits(Axis::X), (-PhyType::UNLIMITED, PhyType::UNLIMITED) ); // Pos let mut a = PointLim::new(Point::new(1.into(), 2.into(), 3.into())); a.set_limits(Axis::X, ((-9).into(), 10.into())); a.set_limits(Axis::Y, ((-19).into(), 20.into())); a.set_limits(Axis::Z, ((-29).into(), 30.into())); assert_eq!(a.x(), 1.into()); assert_eq!(a.y(), 2.into()); assert_eq!(a.z(), 3.into()); a.set_xyz(11.into(), 21.into(), 31.into()); assert_eq!(a.x(), 11.into()); assert_eq!(a.y(), 21.into()); assert_eq!(a.z(), 31.into()); assert_eq!(a.limited().x(), 10.into()); assert_eq!(a.limited().y(), 20.into()); assert_eq!(a.limited().z(), 30.into()); assert_eq!(a.x(), 11.into()); assert_eq!(a.y(), 21.into()); assert_eq!(a.z(), 31.into()); a.apply_limits(); assert_eq!(a.x(), 10.into()); assert_eq!(a.y(), 20.into()); assert_eq!(a.z(), 30.into()); // Neg let mut a = PointLim::new(Point::new((-1).into(), (-2).into(), (-3).into())); a.set_limits(Axis::X, ((-10).into(), 9.into())); a.set_limits(Axis::Y, ((-20).into(), 19.into())); a.set_limits(Axis::Z, ((-30).into(), 29.into())); assert_eq!(a.x(), (-1).into()); assert_eq!(a.y(), (-2).into()); assert_eq!(a.z(), (-3).into()); a.set_xyz((-11).into(), (-21).into(), (-31).into()); assert_eq!(a.x(), (-11).into()); assert_eq!(a.y(), (-21).into()); assert_eq!(a.z(), (-31).into()); assert_eq!(a.limited().x(), (-10).into()); assert_eq!(a.limited().y(), (-20).into()); assert_eq!(a.limited().z(), (-30).into()); assert_eq!(a.x(), (-11).into()); assert_eq!(a.y(), (-21).into()); assert_eq!(a.z(), (-31).into()); a.apply_limits(); assert_eq!(a.x(), (-10).into()); assert_eq!(a.y(), (-20).into()); assert_eq!(a.z(), (-30).into()); } } // vim: ts=4 sw=4 expandtab