| |
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 |