pub trait HasParent {
type Node: Clone;
fn parent(&self) -> Option<Self::Node>;
}
pub trait NodeEquality {
fn is_same(&self, other: &Self) -> bool;
}
pub trait HasChildren {
type Node: Clone;
fn children(&self) -> Vec<Self::Node>;
}
pub trait Walking: HasParent<Node = Self> + NodeEquality + Clone {
fn depth(&self) -> usize {
let mut depth = 0;
let mut current = self.clone();
while let Some(parent) = current.parent() {
depth += 1;
current = parent;
}
depth
}
fn walk_up(&self, steps: usize) -> Option<Self> {
let mut current = self.clone();
for _ in 0..steps {
current = current.parent()?;
}
Some(current)
}
#[must_use]
fn root(&self) -> Self {
self.walk_up(self.depth()).unwrap_or_else(|| self.clone())
}
fn lca_with(&self, other: &Self) -> Option<Self> {
let mut own = self.clone();
let mut other = other.clone();
let own_depth = self.depth();
let other_depth = other.depth();
if own_depth > other_depth {
own = own.walk_up(own_depth - other_depth)?;
} else if other_depth > own_depth {
other = other.walk_up(other_depth - own_depth)?;
}
while !own.is_same(&other) {
own = own.parent()?;
other = other.parent()?;
}
Some(own)
}
}
impl<T> Walking for T where T: HasParent<Node = T> + NodeEquality + Clone {}
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::Frame;
use nalgebra::{UnitQuaternion, Vector3};
#[test]
fn test_depth() {
let root = Frame::new_origin("root");
assert_eq!(root.depth(), 0);
let child = root
.add_child("child", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
assert_eq!(child.depth(), 1);
let grandchild = child
.add_child("grandchild", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
assert_eq!(grandchild.depth(), 2);
}
#[test]
fn test_walk_up() {
let root = Frame::new_origin("root");
let child = root
.add_child("child", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
let grandchild = child
.add_child("grandchild", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
assert!(grandchild.walk_up(0).unwrap().is_same(&grandchild));
assert!(grandchild.walk_up(1).unwrap().is_same(&child));
assert!(grandchild.walk_up(2).unwrap().is_same(&root));
assert!(grandchild.walk_up(3).is_none());
}
#[test]
fn test_root() {
let root = Frame::new_origin("root");
let child = root
.add_child("child", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
let grandchild = child
.add_child("grandchild", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
assert!(root.root().is_same(&root));
assert!(child.root().is_same(&root));
assert!(grandchild.root().is_same(&root));
}
#[test]
fn test_lca_with() {
let root = Frame::new_origin("root");
let child1 = root
.add_child("child1", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
let child2 = root
.add_child("child2", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
let grandchild1 = child1
.add_child("grandchild1", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
let grandchild2 = child2
.add_child("grandchild2", Vector3::zeros(), UnitQuaternion::identity())
.unwrap();
assert!(child1.lca_with(&child1).unwrap().is_same(&child1));
assert!(child1.lca_with(&child2).unwrap().is_same(&root));
assert!(grandchild1.lca_with(&child1).unwrap().is_same(&child1));
assert!(grandchild1.lca_with(&grandchild2).unwrap().is_same(&root));
}
}