use std::ops::{Add, Div, Mul, Sub};
use crate::types::{Angle, Point2D, Point3D, UnitAngle};
impl Copy for UnitAngle {}
impl Copy for Angle {}
impl Copy for Point2D {}
impl Copy for Point3D {}
impl Angle {
pub const ZERO: Self = Self {
unit: UnitAngle::Degrees,
value: 0.0,
};
pub fn from_degrees(size: f64) -> Self {
Self {
unit: UnitAngle::Degrees,
value: size,
}
}
pub fn from_radians(size: f64) -> Self {
Self {
unit: UnitAngle::Radians,
value: size,
}
}
pub fn radians(&self) -> f64 {
match self.unit {
UnitAngle::Radians => self.value,
UnitAngle::Degrees => self.value.to_radians(),
}
}
pub fn degrees(&self) -> f64 {
match self.unit {
UnitAngle::Degrees => self.value,
UnitAngle::Radians => self.value.to_degrees(),
}
}
}
impl std::ops::AddAssign for Angle {
fn add_assign(&mut self, rhs: Self) {
match self.unit {
UnitAngle::Degrees => self.value += rhs.degrees(),
UnitAngle::Radians => self.value += rhs.radians(),
}
}
}
impl std::ops::Add for Angle {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
unit: UnitAngle::Degrees,
value: self.degrees() + rhs.degrees(),
}
}
}
impl std::ops::SubAssign for Angle {
fn sub_assign(&mut self, rhs: Self) {
match self.unit {
UnitAngle::Degrees => self.value -= rhs.degrees(),
UnitAngle::Radians => self.value -= rhs.radians(),
}
}
}
impl std::ops::Sub for Angle {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
unit: UnitAngle::Degrees,
value: self.degrees() - rhs.degrees(),
}
}
}
impl From<[f64; 2]> for Point2D {
fn from([x, y]: [f64; 2]) -> Self {
Self { x, y }
}
}
impl From<&[f64; 2]> for Point2D {
fn from(p: &[f64; 2]) -> Self {
let [x, y] = *p;
Self { x, y }
}
}
impl From<Point2D> for [f64; 2] {
fn from(Point2D { x, y }: Point2D) -> Self {
[x, y]
}
}
impl Add<f64> for Point2D {
type Output = Self;
fn add(self, rhs: f64) -> Self::Output {
Self {
x: self.x + rhs,
y: self.y + rhs,
}
}
}
impl Sub<f64> for Point2D {
type Output = Self;
fn sub(self, rhs: f64) -> Self::Output {
Self {
x: self.x - rhs,
y: self.y - rhs,
}
}
}
impl Mul<f64> for Point2D {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl Div<f64> for Point2D {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl Add for Point2D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Sub for Point2D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl Mul for Point2D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self {
x: self.x * rhs.x,
y: self.y * rhs.y,
}
}
}
impl Div for Point2D {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self {
x: self.x / rhs.x,
y: self.y / rhs.y,
}
}
}
impl From<[f64; 3]> for Point3D {
fn from([x, y, z]: [f64; 3]) -> Self {
Self { x, y, z }
}
}
impl From<&[f64; 3]> for Point3D {
fn from(p: &[f64; 3]) -> Self {
let [x, y, z] = *p;
Self { x, y, z }
}
}
impl From<Point3D> for [f64; 3] {
fn from(Point3D { x, y, z }: Point3D) -> Self {
[x, y, z]
}
}
impl Add for Point3D {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl Sub for Point3D {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
impl Mul for Point3D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self {
x: self.x * rhs.x,
y: self.y * rhs.y,
z: self.z * rhs.z,
}
}
}
impl Div for Point3D {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self {
x: self.x / rhs.x,
y: self.y / rhs.y,
z: self.z / rhs.z,
}
}
}
impl Add<f64> for Point3D {
type Output = Self;
fn add(self, rhs: f64) -> Self::Output {
Self {
x: self.x + rhs,
y: self.y + rhs,
z: self.z + rhs,
}
}
}
impl Sub<f64> for Point3D {
type Output = Self;
fn sub(self, rhs: f64) -> Self::Output {
Self {
x: self.x - rhs,
y: self.y - rhs,
z: self.z - rhs,
}
}
}
impl Mul<f64> for Point3D {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
impl Div<f64> for Point3D {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
z: self.z / rhs,
}
}
}
impl Point3D {
pub fn with_z(Point2D { x, y }: Point2D, z: f64) -> Self {
Self { x, y, z }
}
pub const ZERO: Self = Self {
x: 0.0,
y: 0.0,
z: 0.0,
};
}
impl Point2D {
pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
}
impl From<Point3D> for Point2D {
fn from(Point3D { x, y, .. }: Point3D) -> Self {
Point2D { x, y }
}
}
#[cfg(test)]
mod tests {
use std::f64::consts::PI;
use super::*;
#[test]
fn scaling_points() {
assert_eq!(Point2D { x: 1.0, y: 1.0 } * 3.0, Point2D { x: 3.0, y: 3.0 });
}
#[test]
fn adding_points() {
for (mut start, plus, expected) in [
(
Angle::ZERO,
Angle::from_degrees(90.0),
Angle::from_degrees(90.0),
),
(
Angle::from_radians(PI),
Angle::from_degrees(180.0),
Angle::from_radians(2.0 * PI),
),
(
Angle::from_radians(PI / 4.0),
Angle::from_radians(PI / 4.0),
Angle::from_radians(PI / 2.0),
),
] {
assert_eq!((start + plus).degrees(), expected.degrees());
start += plus;
assert_eq!(start.degrees(), expected.degrees());
}
}
}