use crate::{point, Coord, CoordFloat, CoordNum};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Eq, PartialEq, Clone, Copy, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point<T: CoordNum = f64>(pub Coord<T>);
impl<T: CoordNum> From<Coord<T>> for Point<T> {
fn from(x: Coord<T>) -> Self {
Point(x)
}
}
impl<T: CoordNum> From<(T, T)> for Point<T> {
fn from(coords: (T, T)) -> Self {
Point::new(coords.0, coords.1)
}
}
impl<T: CoordNum> From<[T; 2]> for Point<T> {
fn from(coords: [T; 2]) -> Self {
Point::new(coords[0], coords[1])
}
}
impl<T: CoordNum> From<Point<T>> for (T, T) {
fn from(point: Point<T>) -> Self {
point.0.into()
}
}
impl<T: CoordNum> From<Point<T>> for [T; 2] {
fn from(point: Point<T>) -> Self {
point.0.into()
}
}
impl<T: CoordNum> Point<T> {
pub fn new(x: T, y: T) -> Self {
point! { x: x, y: y }
}
pub fn x(self) -> T {
self.0.x
}
pub fn set_x(&mut self, x: T) -> &mut Self {
self.0.x = x;
self
}
pub fn x_mut(&mut self) -> &mut T {
&mut self.0.x
}
pub fn y(self) -> T {
self.0.y
}
pub fn set_y(&mut self, y: T) -> &mut Self {
self.0.y = y;
self
}
pub fn y_mut(&mut self) -> &mut T {
&mut self.0.y
}
pub fn x_y(self) -> (T, T) {
(self.0.x, self.0.y)
}
#[deprecated = "use `Point::x` instead, it's less ambiguous"]
pub fn lng(self) -> T {
self.x()
}
#[deprecated = "use `Point::set_x` instead, it's less ambiguous"]
pub fn set_lng(&mut self, lng: T) -> &mut Self {
self.set_x(lng)
}
#[deprecated = "use `Point::y` instead, it's less ambiguous"]
pub fn lat(self) -> T {
self.y()
}
#[deprecated = "use `Point::set_y` instead, it's less ambiguous"]
pub fn set_lat(&mut self, lat: T) -> &mut Self {
self.set_y(lat)
}
}
impl<T: CoordNum> Point<T> {
pub fn dot(self, other: Self) -> T {
self.x() * other.x() + self.y() * other.y()
}
pub fn cross_prod(self, point_b: Self, point_c: Self) -> T {
(point_b.x() - self.x()) * (point_c.y() - self.y())
- (point_b.y() - self.y()) * (point_c.x() - self.x())
}
}
impl<T: CoordFloat> Point<T> {
pub fn to_degrees(self) -> Self {
let (x, y) = self.x_y();
let x = x.to_degrees();
let y = y.to_degrees();
Point::new(x, y)
}
pub fn to_radians(self) -> Self {
let (x, y) = self.x_y();
let x = x.to_radians();
let y = y.to_radians();
Point::new(x, y)
}
}
impl<T> Neg for Point<T>
where
T: CoordNum + Neg<Output = T>,
{
type Output = Self;
fn neg(self) -> Self::Output {
Point::from(-self.0)
}
}
impl<T: CoordNum> Add for Point<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Point::from(self.0 + rhs.0)
}
}
impl<T: CoordNum> AddAssign for Point<T> {
fn add_assign(&mut self, rhs: Self) {
self.0 = self.0 + rhs.0;
}
}
impl<T: CoordNum> Sub for Point<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Point::from(self.0 - rhs.0)
}
}
impl<T: CoordNum> SubAssign for Point<T> {
fn sub_assign(&mut self, rhs: Self) {
self.0 = self.0 - rhs.0;
}
}
impl<T: CoordNum> Mul<T> for Point<T> {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
Point::from(self.0 * rhs)
}
}
impl<T: CoordNum> MulAssign<T> for Point<T> {
fn mul_assign(&mut self, rhs: T) {
self.0 = self.0 * rhs
}
}
impl<T: CoordNum> Div<T> for Point<T> {
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
Point::from(self.0 / rhs)
}
}
impl<T: CoordNum> DivAssign<T> for Point<T> {
fn div_assign(&mut self, rhs: T) {
self.0 = self.0 / rhs
}
}
#[cfg(any(feature = "approx", test))]
mod approx_integration {
use super::*;
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
impl<T> RelativeEq for Point<T>
where
T: CoordNum + RelativeEq<Epsilon = T>,
{
#[inline]
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.0.relative_eq(&other.0, epsilon, max_relative)
}
}
impl<T> AbsDiffEq for Point<T>
where
T: CoordNum + AbsDiffEq<Epsilon = T>,
{
type Epsilon = T::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.0.abs_diff_eq(&other.0, epsilon)
}
}
impl<T> UlpsEq for Point<T>
where
T: CoordNum + UlpsEq<Epsilon = T>,
{
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.0.ulps_eq(&other.0, epsilon, max_ulps)
}
}
}
#[cfg(feature = "rstar_0_8")]
impl<T> ::rstar_0_8::Point for Point<T>
where
T: ::num_traits::Float + ::rstar_0_8::RTreeNum,
{
type Scalar = T;
const DIMENSIONS: usize = 2;
fn generate(generator: impl Fn(usize) -> Self::Scalar) -> Self {
Point::new(generator(0), generator(1))
}
fn nth(&self, index: usize) -> Self::Scalar {
match index {
0 => self.0.x,
1 => self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
#[cfg(feature = "rstar_0_9")]
impl<T> ::rstar_0_9::Point for Point<T>
where
T: ::num_traits::Float + ::rstar_0_9::RTreeNum,
{
type Scalar = T;
const DIMENSIONS: usize = 2;
fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
Point::new(generator(0), generator(1))
}
fn nth(&self, index: usize) -> Self::Scalar {
match index {
0 => self.0.x,
1 => self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
#[cfg(feature = "rstar_0_10")]
impl<T> ::rstar_0_10::Point for Point<T>
where
T: ::num_traits::Float + ::rstar_0_10::RTreeNum,
{
type Scalar = T;
const DIMENSIONS: usize = 2;
fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
Point::new(generator(0), generator(1))
}
fn nth(&self, index: usize) -> Self::Scalar {
match index {
0 => self.0.x,
1 => self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
#[cfg(feature = "rstar_0_11")]
impl<T> ::rstar_0_11::Point for Point<T>
where
T: ::num_traits::Float + ::rstar_0_11::RTreeNum,
{
type Scalar = T;
const DIMENSIONS: usize = 2;
fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
Point::new(generator(0), generator(1))
}
fn nth(&self, index: usize) -> Self::Scalar {
match index {
0 => self.0.x,
1 => self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
#[cfg(feature = "rstar_0_12")]
impl<T> ::rstar_0_12::Point for Point<T>
where
T: ::num_traits::Float + ::rstar_0_12::RTreeNum,
{
type Scalar = T;
const DIMENSIONS: usize = 2;
fn generate(mut generator: impl FnMut(usize) -> Self::Scalar) -> Self {
Point::new(generator(0), generator(1))
}
fn nth(&self, index: usize) -> Self::Scalar {
match index {
0 => self.0.x,
1 => self.0.y,
_ => unreachable!(),
}
}
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
match index {
0 => &mut self.0.x,
1 => &mut self.0.y,
_ => unreachable!(),
}
}
}
impl<T: CoordNum> AsRef<Coord<T>> for Point<T> {
fn as_ref(&self) -> &Coord<T> {
&self.0
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::{AbsDiffEq, RelativeEq};
#[test]
fn test_abs_diff_eq() {
let delta = 1e-6;
let p = Point::new(1.0, 1.0);
let p_x = Point::new(1.0 - delta, 1.0);
assert!(p.abs_diff_eq(&p_x, 1e-2));
assert!(p.abs_diff_ne(&p_x, 1e-12));
let p_y = Point::new(1.0, 1.0 + delta);
assert!(p.abs_diff_eq(&p_y, 1e-2));
assert!(p.abs_diff_ne(&p_y, 1e-12));
let p_xy = Point::new(1.0 + delta, 1.0 - delta);
assert!(p.abs_diff_eq(&p_xy, 1e-2));
assert!(p.abs_diff_ne(&p_xy, 1e-12));
let p_inf = Point::new(f64::INFINITY, 1.);
assert!(p.abs_diff_ne(&p_inf, 1e-2));
}
#[test]
fn test_relative_eq() {
let delta = 1e-6;
let p = Point::new(1.0, 1.0);
let p_x = Point::new(1.0 - delta, 1.0);
assert!(p.relative_eq(&p_x, 1e-2, 1e-2));
assert!(p.relative_ne(&p_x, 1e-12, 1e-12));
let p_y = Point::new(1.0, 1.0 + delta);
assert!(p.relative_eq(&p_y, 1e-2, 1e-2));
assert!(p.relative_ne(&p_y, 1e-12, 1e-12));
let p_xy = Point::new(1.0 + delta, 1.0 - delta);
assert!(p.relative_eq(&p_xy, 1e-2, 1e-2));
assert!(p.relative_ne(&p_xy, 1e-12, 1e-12));
let p_inf = Point::new(f64::INFINITY, 1.);
assert!(p.relative_ne(&p_inf, 1e-2, 1e-2));
}
}