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}