use super::*;
use std::ops::{Index, IndexMut};
macro_rules! coord_indexing {
($type:ty, $output:ty) => {
impl Index<usize> for $type {
type Output = $output;
fn index(&self, i: usize) -> &Self::Output {
&self.0[i]
}
}
impl IndexMut<usize> for $type {
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
&mut self.0[i]
}
}
};
}
coord_indexing!(Coor2D, f64);
coord_indexing!(Coor3D, f64);
coord_indexing!(Coor4D, f64);
coord_indexing!(Coor32, f32);
use std::ops::{Add, Div, Mul, Sub};
macro_rules! coor4d {
($symbol:tt, $self:ident, $other:ident) => {
Coor4D([
$self.0[0] $symbol ($other.0[0] as f64),
$self.0[1] $symbol ($other.0[1] as f64),
$self.0[2] $symbol ($other.0[2] as f64),
$self.0[3] $symbol ($other.0[3] as f64),
])
}
}
macro_rules! coor3d {
($symbol:tt, $self:ident, $other:ident) => {
Coor3D([
$self.0[0] $symbol ($other.0[0] as f64),
$self.0[1] $symbol ($other.0[1] as f64),
$self.0[2] $symbol ($other.0[2] as f64),
])
}
}
macro_rules! coor2d {
($symbol:tt, $self:ident, $other:ident) => {
Coor2D([
$self.0[0] $symbol ($other.0[0] as f64),
$self.0[1] $symbol ($other.0[1] as f64),
])
}
}
macro_rules! coor32 {
($symbol:tt, $self:ident, $other:ident) => {
Coor32([
$self.0[0] $symbol ($other.0[0] as f32),
$self.0[1] $symbol ($other.0[1] as f32),
])
}
}
macro_rules! coord_operator {
($type:ty, $othertype:ty, $typemacro:ident, $op:ident, $symbol:tt, $function:ident) => {
impl $op<$othertype> for $type {
type Output = Self;
fn $function(self, other: $othertype) -> Self {
$typemacro!($symbol, self, other)
}
}
};
}
macro_rules! all_coord_operators {
($type:ty, $othertype:ty, $typemacro:ident) => {
coord_operator!($type, $othertype, $typemacro, Add, +, add);
coord_operator!($type, $othertype, $typemacro, Sub, -, sub);
coord_operator!($type, $othertype, $typemacro, Mul, *, mul);
coord_operator!($type, $othertype, $typemacro, Div, /, div);
};
}
all_coord_operators!(Coor4D, &Coor4D, coor4d);
all_coord_operators!(Coor3D, &Coor3D, coor3d);
all_coord_operators!(Coor2D, &Coor2D, coor2d);
all_coord_operators!(Coor2D, &Coor32, coor2d);
all_coord_operators!(Coor32, &Coor32, coor32);
all_coord_operators!(Coor4D, Coor4D, coor4d);
all_coord_operators!(Coor3D, Coor3D, coor3d);
all_coord_operators!(Coor2D, Coor2D, coor2d);
all_coord_operators!(Coor2D, Coor32, coor2d);
all_coord_operators!(Coor32, Coor32, coor32);
pub trait CoordinateTuple {
fn new(fill: f64) -> Self;
fn nth_unchecked(&self, n: usize) -> f64;
fn set_nth_unchecked(&mut self, n: usize, value: f64);
fn dim(&self) -> usize;
fn nth(&self, n: usize) -> f64 {
if n < self.dim() {
self.nth_unchecked(n)
} else {
f64::NAN
}
}
fn x(&self) -> f64 {
self.nth_unchecked(0)
}
fn y(&self) -> f64 {
if self.dim() > 1 {
self.nth_unchecked(1)
} else {
f64::NAN
}
}
fn z(&self) -> f64 {
if self.dim() > 2 {
self.nth_unchecked(2)
} else {
f64::NAN
}
}
fn t(&self) -> f64 {
if self.dim() > 3 {
self.nth_unchecked(3)
} else {
f64::NAN
}
}
fn xy(&self) -> (f64, f64) {
(self.x(), self.y())
}
fn xyz(&self) -> (f64, f64, f64) {
(self.x(), self.y(), self.z())
}
fn xyzt(&self) -> (f64, f64, f64, f64) {
(self.x(), self.y(), self.z(), self.t())
}
fn xy_to_degrees(&self) -> (f64, f64) {
(self.x().to_degrees(), self.y().to_degrees())
}
fn xyz_to_degrees(&self) -> (f64, f64, f64) {
(self.x().to_degrees(), self.y().to_degrees(), self.z())
}
fn xyzt_to_degrees(&self) -> (f64, f64, f64, f64) {
(
self.x().to_degrees(),
self.y().to_degrees(),
self.z(),
self.t(),
)
}
fn xy_to_arcsec(&self) -> (f64, f64) {
(self.x().to_degrees() * 3600., self.y().to_degrees() * 3600.)
}
fn xyz_to_arcsec(&self) -> (f64, f64, f64) {
(
self.x().to_degrees() * 3600.,
self.y().to_degrees() * 3600.,
self.z(),
)
}
fn xyzt_to_arcsec(&self) -> (f64, f64, f64, f64) {
(
self.x().to_degrees() * 3600.,
self.y().to_degrees() * 3600.,
self.z(),
self.t(),
)
}
fn xy_to_radians(&self) -> (f64, f64) {
(self.x().to_radians(), self.y().to_radians())
}
fn xyz_to_radians(&self) -> (f64, f64, f64) {
(self.x().to_radians(), self.y().to_radians(), self.z())
}
fn xyzt_to_radians(&self) -> (f64, f64, f64, f64) {
(
self.x().to_radians(),
self.y().to_radians(),
self.z(),
self.t(),
)
}
fn fill(&mut self, value: f64) {
for n in 0..self.dim() {
self.set_nth_unchecked(n, value);
}
}
fn set_nth(&mut self, n: usize, value: f64) {
if n < self.dim() {
self.set_nth_unchecked(n, value)
} else {
self.fill(f64::NAN);
}
}
fn set_xy(&mut self, x: f64, y: f64) {
if self.dim() > 1 {
self.set_nth_unchecked(0, x);
self.set_nth_unchecked(1, y);
} else {
self.fill(f64::NAN);
}
}
fn set_xyz(&mut self, x: f64, y: f64, z: f64) {
if self.dim() > 2 {
self.set_nth_unchecked(0, x);
self.set_nth_unchecked(1, y);
self.set_nth_unchecked(2, z);
} else {
self.fill(f64::NAN);
}
}
fn set_xyzt(&mut self, x: f64, y: f64, z: f64, t: f64) {
if self.dim() > 3 {
self.set_nth_unchecked(0, x);
self.set_nth_unchecked(1, y);
self.set_nth_unchecked(2, z);
self.set_nth_unchecked(3, t);
} else {
self.fill(f64::NAN);
}
}
#[allow(clippy::needless_range_loop)]
fn update(&mut self, value: &[f64]) {
let n = value.len().min(self.dim());
for i in 0..n {
self.set_nth_unchecked(i, value[i])
}
}
#[must_use]
fn hypot2(&self, other: &Self) -> f64
where
Self: Sized,
{
let (u, v) = self.xy();
let (x, y) = other.xy();
(u - x).hypot(v - y)
}
#[must_use]
fn hypot3(&self, other: &Self) -> f64
where
Self: Sized,
{
if self.dim() < 3 {
return f64::NAN;
}
let (u, v, w) = self.xyz();
let (x, y, z) = other.xyz();
(u - x).hypot(v - y).hypot(w - z)
}
fn scale(&self, factor: f64) -> Self
where
Self: Sized + Copy,
{
let mut res = *self;
for i in 0..self.dim() {
res.set_nth(i, self.nth(i) * factor);
}
res
}
fn dot(&self, other: Self) -> f64
where
Self: Sized,
{
let mut res = 0.;
for i in 0..self.dim() {
res += self.nth(i) * other.nth(i);
}
res
}
}
#[rustfmt::skip]
impl CoordinateTuple for (f64, f64) {
fn new(fill: f64) -> Self {
(fill, fill)
}
fn dim(&self) -> usize { 2 }
fn nth_unchecked(&self, n: usize) -> f64 {
match n {
0 => self.0,
1 => self.1,
_ => panic!()
}
}
fn set_nth_unchecked(&mut self, n: usize, value: f64) {
match n {
0 => self.0 = value,
1 => self.1 = value,
_ => ()
}
}
}