src/cube.rs

changeset 0
989e2fe08db2
child 3
ff4656da04af
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cube.rs	Fri Oct 18 13:47:28 2024 -0500
@@ -0,0 +1,217 @@
+
+use core::f64;
+
+use alg_tools::loc::Loc;
+use alg_tools::norms::{Norm, L2};
+use crate::manifold::ManifoldPoint;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Face {F1, F2, F3, F4, F5, F6}
+use Face::*;
+
+pub type Point = Loc<f64, 2>;
+
+pub type AdjacentFaces = [Face; 4];
+
+pub enum Path {
+    Direct { destination : Face },
+    Indirect { destination : Face, intermediate : Face },
+}
+
+/// An iterator over paths on a cube, from a source face to a destination face.
+#[derive(Clone, Debug)]
+pub enum PathIter {
+    Direct(Face),
+    Indirect{ destination : Face, intermediate : AdjacentFaces, current : usize},
+    Exhausted,
+}
+
+impl std::iter::Iterator for PathIter {
+    type Item = Path;
+    
+    fn next(&mut self) -> Option<Self::Item> {
+        use PathIter::*;
+        match self {
+            &mut Exhausted => None,
+            &mut Direct(destination) => {
+                *self = Exhausted;
+                Some(Path::Direct { destination })
+            },
+            &mut Indirect{destination, intermediate : ref i, ref mut current} => {
+                if *current < i.len() {
+                    let intermediate = i[*current];
+                    *current += 1;
+                    Some(Path::Indirect{ destination, intermediate })
+                } else {
+                    *self = Exhausted;
+                    None
+                }
+            }
+        }
+    }
+}
+
+
+impl Face {
+    /// Returns an array of the four faces adjacent to `self`.
+    pub fn adjacent_faces(&self) -> AdjacentFaces {
+        match *self {
+            F1 => [F2, F3, F4, F5],
+            F2 => [F1, F4, F5, F6],
+            F3 => [F1, F4, F5, F6],
+            F4 => [F1, F2, F3, F6],
+            F5 => [F1, F2, F3, F6],
+            F6 => [F2, F3, F4, F5],
+        }
+    }
+
+    /// Returns the face opposing `self`.
+    pub fn opposing_face(&self) -> Face {
+        match *self {
+            F1 => F6,
+            F2 => F3,
+            F3 => F2,
+            F4 => F6,
+            F5 => F4,
+            F6 => F1,
+        }
+    }
+
+    /// Converts a point on an adjacent face to the coordinate system of `self`.
+    pub fn convert_adjacent(&self, adjacent : Face, p: &Point) -> Option<Point> {
+        let Loc([x, y]) = *p;
+        let mk = |x, y| Some(Loc([x, y]));
+        match adjacent {
+            F1 =>  match *self {
+                F2 => mk(y, x - 1.0),
+                F3 => mk(1.0 - y, -x),
+                F4 => mk(x, -y),
+                F5 => mk(1.0 - x, y - 1.0),
+                F1 => mk(x, y),
+                F6 => None,
+            },
+            F2 => match *self {
+                F1 => mk(y + 1.0, x),
+                F4 => mk(x + 1.0, y),
+                F5 => mk(x - 1.0, y),
+                F6 => mk(2.0 - y, x),
+                F2 => mk(x, y),
+                F3 => None,
+            },
+            F3 => match *self {
+                F1 => mk(-y, 1.0 - x),
+                F4 => mk(x - 1.0, y),
+                F5 => mk(x + 1.0, y),
+                F6 => mk(y - 1.0, 1.0 - x),
+                F3 => mk(x, y),
+                F2 => None,
+            },
+            F4 => match *self {
+                F1 => mk(x, -y),
+                F2 => mk(x - 1.0, y),
+                F3 => mk(x + 1.0, y),
+                F6 => mk(x, y - 1.0),
+                F4 => mk(x, y),
+                F5 => None,
+            },
+            F5 => match *self {
+                F1 => mk(1.0 -x, y + 1.0),
+                F2 => mk(x + 1.0, y),
+                F3 => mk(x - 1.0, y),
+                F6 => mk(1.0 -x, 2.0 - y),
+                F5 => mk(x, y),
+                F4 => None,
+            },
+            F6 => match *self {
+                F2 => mk(y, 2.0 - x),
+                F3 => mk(1.0 - y, x + 1.0),
+                F4 => mk(x, y + 1.0),
+                F5 => mk(1.0 - x, 2.0 - y),
+                F6 => mk(x, y),
+                F1 => None,
+            }
+        }
+    }
+
+    /// Converts a point behind a path to the coordinate system of `self`.
+    pub fn convert(&self, path : &Path, p: &Point) -> Point {
+        use Path::*;
+        match path {
+            &Direct{ destination : d} => self.convert_adjacent(d, p),
+            &Indirect{ destination : d, intermediate : i }
+                => {dbg!((d,i)); dbg!(self.convert_adjacent(i, dbg!(&i.convert_adjacent(d, p).unwrap())))}
+        }.unwrap()
+    }
+
+
+    /// Returns an iterator over all the paths from `self` to `other`.
+    fn paths(&self, other : Face) -> PathIter {
+        if self.opposing_face() == other {
+            PathIter::Indirect {
+                intermediate : self.adjacent_faces(),
+                destination : other,
+                current : 0
+            }
+        } else {
+            PathIter::Direct(other)
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct OnCube {
+    face : Face,
+    point : Point,
+}
+
+impl ManifoldPoint for OnCube {
+    type Tangent = Point;
+
+    fn exp(&self, tangent : &Self::Tangent) -> Self {
+        unimplemented!();
+    }
+
+    fn log(&self, other : &Self) -> Self::Tangent {
+        let mut best_len = f64::INFINITY;
+        let mut best_tan = Loc([0.0, 0.0]);
+        for path in self.face.paths(other.face) {
+            let tan = self.face.convert(&path, &other.point) - &self.point;
+            let len = tan.norm(L2);
+            if len < best_len {
+                best_tan = tan;
+                best_len = len;
+            }
+        }
+        best_tan
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn log_test_adjacent() {
+        let p1 = OnCube{ face : F1, point : Loc([0.5, 0.5])};
+        let p2 = OnCube{ face : F2, point : Loc([0.5, 0.5])};
+
+        assert_eq!(p1.log(&p2).norm(L2), 1.0);
+    }
+
+    #[test]
+    fn log_test_opposing_equal() {
+        let p1 = OnCube{ face : F1, point : Loc([0.5, 0.5])};
+        let p2 = OnCube{ face : F6, point : Loc([0.5, 0.5])};
+
+        assert_eq!(p1.log(&p2).norm(L2), 2.0);
+    }
+
+    #[test]
+    fn log_test_opposing_unique_shortest() {
+        let p1 = OnCube{ face : F1, point : Loc([0.3, 0.25])};
+        let p2 = OnCube{ face : F6, point : Loc([0.3, 0.25])};
+
+        assert_eq!(p1.log(&p2).norm(L2), 1.5);
+    }
+}
+

mercurial