1use super::tensors::{ContravariantIndex, CovariantIndex, Matrix, Tensor};
4use crate::typenum::consts::U2;
5use crate::typenum::uint::Unsigned;
6use crate::typenum::Pow;
7use generic_array::{ArrayLength, GenericArray};
8use std::fmt;
9use std::ops::{Index, IndexMut};
10
11pub trait CoordinateSystem: Sized {
13    type Dimension: Unsigned + ArrayLength<f64> + ArrayLength<usize>;
15
16    fn small(_: &Point<Self>) -> f64 {
20        0.01
21    }
22
23    fn dimension() -> usize {
25        Self::Dimension::to_usize()
26    }
27}
28
29pub struct Point<T: CoordinateSystem> {
33    x: GenericArray<f64, T::Dimension>,
35}
36
37impl<T> Point<T>
38where
39    T: CoordinateSystem,
40{
41    pub fn new(coords: GenericArray<f64, T::Dimension>) -> Point<T> {
43        Point { x: coords }
44    }
45
46    pub fn from_slice(coords: &[f64]) -> Point<T> {
48        Point {
49            x: GenericArray::clone_from_slice(coords),
50        }
51    }
52
53    pub fn coords_array(&self) -> &GenericArray<f64, T::Dimension> {
55        &self.x
56    }
57}
58
59impl<T> Clone for Point<T>
60where
61    T: CoordinateSystem,
62{
63    fn clone(&self) -> Point<T> {
64        Point::new(self.x.clone())
65    }
66}
67
68impl<T> Copy for Point<T>
69where
70    T: CoordinateSystem,
71    <T::Dimension as ArrayLength<f64>>::ArrayType: Copy,
72{
73}
74
75impl<T> Index<usize> for Point<T>
76where
77    T: CoordinateSystem,
78{
79    type Output = f64;
80
81    fn index(&self, idx: usize) -> &f64 {
82        &self.x[idx]
83    }
84}
85
86impl<T> IndexMut<usize> for Point<T>
87where
88    T: CoordinateSystem,
89{
90    fn index_mut(&mut self, idx: usize) -> &mut f64 {
91        &mut self.x[idx]
92    }
93}
94
95impl<T> PartialEq<Point<T>> for Point<T>
96where
97    T: CoordinateSystem,
98{
99    fn eq(&self, rhs: &Point<T>) -> bool {
100        (0..T::dimension()).all(|i| self[i] == rhs[i])
101    }
102}
103
104impl<T> Eq for Point<T> where T: CoordinateSystem {}
105
106impl<T> fmt::Debug for Point<T>
107where
108    T: CoordinateSystem,
109{
110    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111        write!(f, "Point{:?}", &self.x)
112    }
113}
114
115pub trait ConversionTo<T: CoordinateSystem + 'static>: CoordinateSystem
119where
120    T::Dimension: Pow<U2>,
121    <T::Dimension as Pow<U2>>::Output: ArrayLength<f64>,
122{
123    fn convert_point(p: &Point<Self>) -> Point<T>;
125
126    fn jacobian(p: &Point<Self>) -> Matrix<T> {
131        let d = Self::dimension();
132        let mut result = Matrix::zero(Self::convert_point(p));
133        let h = Self::small(p);
134
135        for j in 0..d {
136            let mut x = p.clone();
137            x[j] = x[j] - h;
138            let y1 = Self::convert_point(&x);
139
140            x[j] = x[j] + h * 2.0;
141            let y2 = Self::convert_point(&x);
142
143            for i in 0..d {
144                let index = [i, j];
146                result[&index[..]] = (y2[i] - y1[i]) / (2.0 * h);
147            }
148        }
149
150        result
151    }
152
153    fn inv_jacobian(p: &Point<Self>) -> Tensor<T, (CovariantIndex, ContravariantIndex)> {
157        ConversionTo::<T>::jacobian(p).inverse().unwrap()
158    }
159}