244 lines
5.9 KiB
Rust
244 lines
5.9 KiB
Rust
use std::{
|
||
fmt::{Display, Formatter},
|
||
ops,
|
||
};
|
||
|
||
#[derive(Debug, Clone, Copy, Default, PartialEq)]
|
||
pub struct Point {
|
||
pub x: f64,
|
||
pub y: f64,
|
||
}
|
||
|
||
impl Point {
|
||
pub fn new(x: f64, y: f64) -> Point {
|
||
Point { x, y }
|
||
}
|
||
pub fn zero() -> Point {
|
||
Point { x: 0.0, y: 0.0 }
|
||
}
|
||
pub fn is_valid(&self) -> bool {
|
||
!self.x.is_nan() && !self.y.is_nan()
|
||
}
|
||
pub fn module(&self) -> f64 {
|
||
f64::sqrt(self.x * self.x + self.y * self.y)
|
||
}
|
||
pub fn phase(&self) -> f64 {
|
||
f64::atan2(self.y, self.x)
|
||
}
|
||
pub fn distance(a: &Point, b: &Point) -> f64 {
|
||
(a - b).module()
|
||
}
|
||
pub fn distance_to(&self, other: &Point) -> f64 {
|
||
(self - other).module()
|
||
}
|
||
pub fn as_versor(&self) -> Option<Point> {
|
||
if self.x == 0.0 && self.y == 0.0 {
|
||
None
|
||
} else {
|
||
Some(self / self.module())
|
||
}
|
||
}
|
||
pub fn rotate_by(&mut self, α: f64) {
|
||
let m = self.module();
|
||
let (sin, cos) = f64::sin_cos(self.phase() + α);
|
||
self.x = m * cos;
|
||
self.y = m * sin;
|
||
}
|
||
}
|
||
|
||
impl Display for Point {
|
||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||
write!(f, "({:.2},{:.2})", &self.x, &self.y)
|
||
}
|
||
}
|
||
|
||
impl ops::Add<Point> for Point {
|
||
type Output = Point;
|
||
fn add(self, rhs: Point) -> Point {
|
||
Point {
|
||
x: self.x + rhs.x,
|
||
y: self.y + rhs.y,
|
||
}
|
||
}
|
||
}
|
||
impl ops::Add<&Point> for &Point {
|
||
type Output = Point;
|
||
fn add(self, rhs: &Point) -> Point {
|
||
Point {
|
||
x: self.x + rhs.x,
|
||
y: self.y + rhs.y,
|
||
}
|
||
}
|
||
}
|
||
impl ops::AddAssign<&Point> for Point {
|
||
fn add_assign(&mut self, rhs: &Point) {
|
||
*self = Self {
|
||
x: self.x + rhs.x,
|
||
y: self.y + rhs.y,
|
||
};
|
||
}
|
||
}
|
||
impl ops::AddAssign<Point> for Point {
|
||
fn add_assign(&mut self, rhs: Point) {
|
||
*self = Self {
|
||
x: self.x + rhs.x,
|
||
y: self.y + rhs.y,
|
||
};
|
||
}
|
||
}
|
||
impl ops::SubAssign<&Point> for Point {
|
||
fn sub_assign(&mut self, rhs: &Point) {
|
||
*self = Self {
|
||
x: self.x - rhs.x,
|
||
y: self.y - rhs.y,
|
||
};
|
||
}
|
||
}
|
||
impl ops::SubAssign<Point> for Point {
|
||
fn sub_assign(&mut self, rhs: Point) {
|
||
*self = Self {
|
||
x: self.x - rhs.x,
|
||
y: self.y - rhs.y,
|
||
};
|
||
}
|
||
}
|
||
impl ops::Sub<Point> for Point {
|
||
type Output = Point;
|
||
fn sub(self, rhs: Point) -> Point {
|
||
Point {
|
||
x: self.x - rhs.x,
|
||
y: self.y - rhs.y,
|
||
}
|
||
}
|
||
}
|
||
impl ops::Sub<&Point> for &Point {
|
||
type Output = Point;
|
||
fn sub(self, rhs: &Point) -> Point {
|
||
Point {
|
||
x: self.x - rhs.x,
|
||
y: self.y - rhs.y,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl ops::Mul<f64> for Point {
|
||
type Output = Point;
|
||
fn mul(self, rhs: f64) -> Point {
|
||
Point {
|
||
x: self.x * rhs,
|
||
y: self.y * rhs,
|
||
}
|
||
}
|
||
}
|
||
impl ops::MulAssign<f64> for Point {
|
||
fn mul_assign(&mut self, rhs: f64) {
|
||
*self = Point {
|
||
x: self.x * rhs,
|
||
y: self.y * rhs,
|
||
}
|
||
}
|
||
}
|
||
impl ops::Mul<f64> for &Point {
|
||
type Output = Point;
|
||
fn mul(self, rhs: f64) -> Point {
|
||
Point {
|
||
x: self.x * rhs,
|
||
y: self.y * rhs,
|
||
}
|
||
}
|
||
}
|
||
impl ops::Div<f64> for Point {
|
||
type Output = Point;
|
||
fn div(self, rhs: f64) -> Point {
|
||
Point {
|
||
x: self.x / rhs,
|
||
y: self.y / rhs,
|
||
}
|
||
}
|
||
}
|
||
impl ops::DivAssign<f64> for Point {
|
||
fn div_assign(&mut self, rhs: f64) {
|
||
*self = Point {
|
||
x: self.x / rhs,
|
||
y: self.y / rhs,
|
||
}
|
||
}
|
||
}
|
||
impl ops::Div<f64> for &Point {
|
||
type Output = Point;
|
||
fn div(self, rhs: f64) -> Point {
|
||
Point {
|
||
x: self.x / rhs,
|
||
y: self.y / rhs,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test() {
|
||
use std::f64::consts::{FRAC_1_SQRT_2, FRAC_PI_2, FRAC_PI_4, SQRT_2};
|
||
// New
|
||
let p = Point::new(0.0, 0.0);
|
||
print!("Testing Point::new()");
|
||
assert_eq!(p, Point { x: 0.0, y: 0.0 });
|
||
assert_ne!(p, Point { x: -1.0, y: 1.0 });
|
||
println!(" ... ok");
|
||
|
||
// is_valid
|
||
let n = Point::new(std::f64::NAN, std::f64::NAN);
|
||
let nn = Point::new(std::f64::NAN, 0.0);
|
||
print!("Testing Point::is_valid()");
|
||
assert_eq!(p.is_valid(), true);
|
||
assert_eq!(n.is_valid(), false);
|
||
assert_eq!(nn.is_valid(), false);
|
||
println!(" ... ok");
|
||
|
||
// module
|
||
let p = Point::new(1.0, 1.0);
|
||
let r = Point::new(2.0, 0.0);
|
||
print!("Testing Point::module()");
|
||
assert!(f64::abs(p.module() - SQRT_2) < 1e-10);
|
||
assert!(f64::abs(r.module() - 2.0) < 1e-10);
|
||
println!(" ... ok");
|
||
|
||
// phase
|
||
let p = Point::new(1.0, 1.0);
|
||
let r = Point::new(2.0, 0.0);
|
||
let q = Point::new(2.0, -2.0);
|
||
print!("Testing Point::phase()");
|
||
assert!(f64::abs(p.phase() - FRAC_PI_4) < 1e-6);
|
||
assert!(f64::abs(r.phase() - 0.0) < 1e-6);
|
||
assert!(f64::abs(q.phase() + FRAC_PI_4) < 1e-6);
|
||
println!(" ... ok");
|
||
|
||
//distance
|
||
let z = Point::zero();
|
||
let p = Point::new(1.0, 0.0);
|
||
let q = Point::new(1.0, 1.0);
|
||
print!("Testing Point::distance() and distance_to()");
|
||
assert_eq!(z.distance_to(&p), 1.0);
|
||
assert_eq!(Point::distance(&z, &p), 1.0);
|
||
assert!(f64::abs(Point::distance(&z, &q) - SQRT_2) < 1e-10);
|
||
println!(" ... ok");
|
||
|
||
//versor
|
||
print!("Testing Point::as_versor()");
|
||
assert_eq!(z.as_versor(), None);
|
||
assert_eq!(p, p.as_versor().unwrap());
|
||
let q_ver = q.as_versor().unwrap();
|
||
assert!(f64::abs(q_ver.x - FRAC_1_SQRT_2) < 1e-10);
|
||
assert!(f64::abs(q_ver.y - FRAC_1_SQRT_2) < 1e-10);
|
||
println!(" ... ok");
|
||
|
||
//rotate_by
|
||
let mut p = Point::new(1.0, 0.0);
|
||
print!("Testing Point::rotate_by()");
|
||
p.rotate_by(FRAC_PI_2);
|
||
assert!(f64::abs(p.x - 0.0) < 1e-10);
|
||
assert!(f64::abs(p.y - 1.0) < 1e-10);
|
||
p.rotate_by(-FRAC_PI_4);
|
||
assert!(f64::abs(p.x - FRAC_1_SQRT_2) < 1e-10);
|
||
assert!(f64::abs(p.y - FRAC_1_SQRT_2) < 1e-10);
|
||
println!(" ... ok");
|
||
}
|