|
1 |
|
2 use core::f64; |
|
3 |
|
4 use alg_tools::loc::Loc; |
|
5 use alg_tools::norms::{Norm, L2}; |
|
6 use crate::manifold::ManifoldPoint; |
|
7 |
|
8 #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
|
9 pub enum Face {F1, F2, F3, F4, F5, F6} |
|
10 use Face::*; |
|
11 |
|
12 pub type Point = Loc<f64, 2>; |
|
13 |
|
14 pub type AdjacentFaces = [Face; 4]; |
|
15 |
|
16 pub enum Path { |
|
17 Direct { destination : Face }, |
|
18 Indirect { destination : Face, intermediate : Face }, |
|
19 } |
|
20 |
|
21 /// An iterator over paths on a cube, from a source face to a destination face. |
|
22 #[derive(Clone, Debug)] |
|
23 pub enum PathIter { |
|
24 Direct(Face), |
|
25 Indirect{ destination : Face, intermediate : AdjacentFaces, current : usize}, |
|
26 Exhausted, |
|
27 } |
|
28 |
|
29 impl std::iter::Iterator for PathIter { |
|
30 type Item = Path; |
|
31 |
|
32 fn next(&mut self) -> Option<Self::Item> { |
|
33 use PathIter::*; |
|
34 match self { |
|
35 &mut Exhausted => None, |
|
36 &mut Direct(destination) => { |
|
37 *self = Exhausted; |
|
38 Some(Path::Direct { destination }) |
|
39 }, |
|
40 &mut Indirect{destination, intermediate : ref i, ref mut current} => { |
|
41 if *current < i.len() { |
|
42 let intermediate = i[*current]; |
|
43 *current += 1; |
|
44 Some(Path::Indirect{ destination, intermediate }) |
|
45 } else { |
|
46 *self = Exhausted; |
|
47 None |
|
48 } |
|
49 } |
|
50 } |
|
51 } |
|
52 } |
|
53 |
|
54 |
|
55 impl Face { |
|
56 /// Returns an array of the four faces adjacent to `self`. |
|
57 pub fn adjacent_faces(&self) -> AdjacentFaces { |
|
58 match *self { |
|
59 F1 => [F2, F3, F4, F5], |
|
60 F2 => [F1, F4, F5, F6], |
|
61 F3 => [F1, F4, F5, F6], |
|
62 F4 => [F1, F2, F3, F6], |
|
63 F5 => [F1, F2, F3, F6], |
|
64 F6 => [F2, F3, F4, F5], |
|
65 } |
|
66 } |
|
67 |
|
68 /// Returns the face opposing `self`. |
|
69 pub fn opposing_face(&self) -> Face { |
|
70 match *self { |
|
71 F1 => F6, |
|
72 F2 => F3, |
|
73 F3 => F2, |
|
74 F4 => F6, |
|
75 F5 => F4, |
|
76 F6 => F1, |
|
77 } |
|
78 } |
|
79 |
|
80 /// Converts a point on an adjacent face to the coordinate system of `self`. |
|
81 pub fn convert_adjacent(&self, adjacent : Face, p: &Point) -> Option<Point> { |
|
82 let Loc([x, y]) = *p; |
|
83 let mk = |x, y| Some(Loc([x, y])); |
|
84 match adjacent { |
|
85 F1 => match *self { |
|
86 F2 => mk(y, x - 1.0), |
|
87 F3 => mk(1.0 - y, -x), |
|
88 F4 => mk(x, -y), |
|
89 F5 => mk(1.0 - x, y - 1.0), |
|
90 F1 => mk(x, y), |
|
91 F6 => None, |
|
92 }, |
|
93 F2 => match *self { |
|
94 F1 => mk(y + 1.0, x), |
|
95 F4 => mk(x + 1.0, y), |
|
96 F5 => mk(x - 1.0, y), |
|
97 F6 => mk(2.0 - y, x), |
|
98 F2 => mk(x, y), |
|
99 F3 => None, |
|
100 }, |
|
101 F3 => match *self { |
|
102 F1 => mk(-y, 1.0 - x), |
|
103 F4 => mk(x - 1.0, y), |
|
104 F5 => mk(x + 1.0, y), |
|
105 F6 => mk(y - 1.0, 1.0 - x), |
|
106 F3 => mk(x, y), |
|
107 F2 => None, |
|
108 }, |
|
109 F4 => match *self { |
|
110 F1 => mk(x, -y), |
|
111 F2 => mk(x - 1.0, y), |
|
112 F3 => mk(x + 1.0, y), |
|
113 F6 => mk(x, y - 1.0), |
|
114 F4 => mk(x, y), |
|
115 F5 => None, |
|
116 }, |
|
117 F5 => match *self { |
|
118 F1 => mk(1.0 -x, y + 1.0), |
|
119 F2 => mk(x + 1.0, y), |
|
120 F3 => mk(x - 1.0, y), |
|
121 F6 => mk(1.0 -x, 2.0 - y), |
|
122 F5 => mk(x, y), |
|
123 F4 => None, |
|
124 }, |
|
125 F6 => match *self { |
|
126 F2 => mk(y, 2.0 - x), |
|
127 F3 => mk(1.0 - y, x + 1.0), |
|
128 F4 => mk(x, y + 1.0), |
|
129 F5 => mk(1.0 - x, 2.0 - y), |
|
130 F6 => mk(x, y), |
|
131 F1 => None, |
|
132 } |
|
133 } |
|
134 } |
|
135 |
|
136 /// Converts a point behind a path to the coordinate system of `self`. |
|
137 pub fn convert(&self, path : &Path, p: &Point) -> Point { |
|
138 use Path::*; |
|
139 match path { |
|
140 &Direct{ destination : d} => self.convert_adjacent(d, p), |
|
141 &Indirect{ destination : d, intermediate : i } |
|
142 => {dbg!((d,i)); dbg!(self.convert_adjacent(i, dbg!(&i.convert_adjacent(d, p).unwrap())))} |
|
143 }.unwrap() |
|
144 } |
|
145 |
|
146 |
|
147 /// Returns an iterator over all the paths from `self` to `other`. |
|
148 fn paths(&self, other : Face) -> PathIter { |
|
149 if self.opposing_face() == other { |
|
150 PathIter::Indirect { |
|
151 intermediate : self.adjacent_faces(), |
|
152 destination : other, |
|
153 current : 0 |
|
154 } |
|
155 } else { |
|
156 PathIter::Direct(other) |
|
157 } |
|
158 } |
|
159 } |
|
160 |
|
161 #[derive(Clone, Debug, PartialEq)] |
|
162 pub struct OnCube { |
|
163 face : Face, |
|
164 point : Point, |
|
165 } |
|
166 |
|
167 impl ManifoldPoint for OnCube { |
|
168 type Tangent = Point; |
|
169 |
|
170 fn exp(&self, tangent : &Self::Tangent) -> Self { |
|
171 unimplemented!(); |
|
172 } |
|
173 |
|
174 fn log(&self, other : &Self) -> Self::Tangent { |
|
175 let mut best_len = f64::INFINITY; |
|
176 let mut best_tan = Loc([0.0, 0.0]); |
|
177 for path in self.face.paths(other.face) { |
|
178 let tan = self.face.convert(&path, &other.point) - &self.point; |
|
179 let len = tan.norm(L2); |
|
180 if len < best_len { |
|
181 best_tan = tan; |
|
182 best_len = len; |
|
183 } |
|
184 } |
|
185 best_tan |
|
186 } |
|
187 } |
|
188 |
|
189 #[cfg(test)] |
|
190 mod tests { |
|
191 use super::*; |
|
192 |
|
193 #[test] |
|
194 fn log_test_adjacent() { |
|
195 let p1 = OnCube{ face : F1, point : Loc([0.5, 0.5])}; |
|
196 let p2 = OnCube{ face : F2, point : Loc([0.5, 0.5])}; |
|
197 |
|
198 assert_eq!(p1.log(&p2).norm(L2), 1.0); |
|
199 } |
|
200 |
|
201 #[test] |
|
202 fn log_test_opposing_equal() { |
|
203 let p1 = OnCube{ face : F1, point : Loc([0.5, 0.5])}; |
|
204 let p2 = OnCube{ face : F6, point : Loc([0.5, 0.5])}; |
|
205 |
|
206 assert_eq!(p1.log(&p2).norm(L2), 2.0); |
|
207 } |
|
208 |
|
209 #[test] |
|
210 fn log_test_opposing_unique_shortest() { |
|
211 let p1 = OnCube{ face : F1, point : Loc([0.3, 0.25])}; |
|
212 let p2 = OnCube{ face : F6, point : Loc([0.3, 0.25])}; |
|
213 |
|
214 assert_eq!(p1.log(&p2).norm(L2), 1.5); |
|
215 } |
|
216 } |
|
217 |