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