path based retrieval and setting
This commit is contained in:
parent
4e9ca044fb
commit
8567b102a8
173
src/oct_tree.rs
173
src/oct_tree.rs
|
@ -26,6 +26,18 @@ struct Path {
|
|||
length: usize,
|
||||
}
|
||||
|
||||
fn to_vec3(path: &Path, center: Vec3, size: usize) -> Vec3 {
|
||||
let mut iter = (center, size);
|
||||
for i in 0..path.length {
|
||||
iter = sub_region(
|
||||
iter.0,
|
||||
iter.1,
|
||||
get_pindex(&path, i.try_into().unwrap()).try_into().unwrap(),
|
||||
);
|
||||
}
|
||||
return iter.0;
|
||||
}
|
||||
|
||||
fn get_pindex(path: &Path, index: usize) -> usize {
|
||||
if path.length < index {
|
||||
panic!("in too deep!");
|
||||
|
@ -39,7 +51,7 @@ fn set_pindex(path: &mut Path, index: usize, value: usize) {
|
|||
if value > 7 {
|
||||
panic!("cannot set to more than 7!");
|
||||
}
|
||||
if index > path.length {
|
||||
if index + 1 > path.length {
|
||||
path.length = index + 1;
|
||||
}
|
||||
let shift_amount = index as u64 * 3;
|
||||
|
@ -59,17 +71,55 @@ impl<T: Clone> OctTree<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_voxel(&mut self, location: Vec3, value: T) {
|
||||
pub fn set_voxel_at_path(&mut self, path: &Path, value: T) -> bool {
|
||||
// return value is whether it was successful
|
||||
let mut iter = &mut self.root;
|
||||
if path.length == 0 {
|
||||
match &mut self.root {
|
||||
TreeNode::Leaf(nvalue) => {
|
||||
*nvalue = value;
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in 0..path.length {
|
||||
let region = get_pindex(path, i) as usize;
|
||||
match iter {
|
||||
TreeNode::Branch(branch) => {
|
||||
let arr = branch.as_mut();
|
||||
iter = &mut arr[region];
|
||||
}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
match &mut iter {
|
||||
TreeNode::Leaf(nvalue) => {
|
||||
*nvalue = value;
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_voxel_at_location(&mut self, location: Vec3, value: T) -> Path {
|
||||
// if the tree is empty, we want to fall out immediately - no looping needed.
|
||||
match self.root {
|
||||
TreeNode::None => {
|
||||
self.center = location;
|
||||
self.size = 1;
|
||||
self.root = TreeNode::Leaf(value);
|
||||
return;
|
||||
return Default::default();
|
||||
}
|
||||
_ => {} // continue to modify the tree structure - no easy answer yet
|
||||
}
|
||||
let mut path: Path = Default::default();
|
||||
// if we don't already have a big enough non-empty tree, we need to branch upward till our tree contains our subject matter
|
||||
if !bounds_contains(self.center, self.size, location) {
|
||||
println!("building up to contain addition {location}");
|
||||
|
@ -105,7 +155,7 @@ impl<T: Clone> OctTree<T> {
|
|||
}
|
||||
TreeNode::None => {
|
||||
println!("something went wrong with early fall-out. shouldn't be plausible unless you're using unsafe rust.");
|
||||
return;
|
||||
return Default::default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +174,10 @@ impl<T: Clone> OctTree<T> {
|
|||
|
||||
println!("searching down to set {location}");
|
||||
while rc_size > 0 {
|
||||
if search_direction != -1 {
|
||||
let pindex = path.length;
|
||||
set_pindex(&mut path, pindex, search_direction as usize);
|
||||
}
|
||||
println!("{rc_center}, size {rc_size}, region {search_direction}");
|
||||
match rc_loc {
|
||||
TreeNode::Branch(region) => {
|
||||
|
@ -138,19 +192,20 @@ impl<T: Clone> OctTree<T> {
|
|||
);
|
||||
let end = TreeNode::Leaf(value.clone());
|
||||
*next_rc_loc = end;
|
||||
return;
|
||||
return path;
|
||||
}
|
||||
match next_rc_loc {
|
||||
TreeNode::Branch(_) => {}
|
||||
TreeNode::Leaf(lvalue) => {
|
||||
if rc_size != 1 {
|
||||
println!("tree edited to contain non-unit node size. returning instead of losing data");
|
||||
return;
|
||||
return Default::default();
|
||||
} else {
|
||||
println!(
|
||||
"value set {location} within {rc_center}, {rc_size}, index {search_direction}"
|
||||
);
|
||||
*lvalue = value.clone();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
TreeNode::None => {
|
||||
|
@ -167,32 +222,73 @@ impl<T: Clone> OctTree<T> {
|
|||
"value set {location} within {rc_center}, {rc_size}, index {search_direction}"
|
||||
);
|
||||
*lvalue = value;
|
||||
return;
|
||||
return path;
|
||||
} else {
|
||||
println!("tree edited to contain non-unit node size. returning instead of losing data");
|
||||
return;
|
||||
return Default::default();
|
||||
}
|
||||
}
|
||||
TreeNode::None => {
|
||||
println!(
|
||||
"should be handled automatically before arrival at target node. returning"
|
||||
);
|
||||
return;
|
||||
return Default::default();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
pub fn voxel_at_path(&self, path: &Path) -> Option<T> {
|
||||
// return value is whether it was successful
|
||||
let mut iter = &self.root;
|
||||
if path.length == 0 {
|
||||
match &self.root {
|
||||
TreeNode::Leaf(nvalue) => {
|
||||
return Some(nvalue.clone());
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in 0..path.length {
|
||||
let region = get_pindex(path, i) as usize;
|
||||
match iter {
|
||||
TreeNode::Branch(branch) => {
|
||||
let arr = branch.as_ref();
|
||||
iter = &arr[region];
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
match &mut iter {
|
||||
TreeNode::Leaf(nvalue) => {
|
||||
return Some(nvalue.clone());
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn voxel_at(&self, location: Vec3) -> Option<(T, Path)> {
|
||||
pub fn voxel_at_location(&self, location: Vec3) -> Option<(T, Path)> {
|
||||
if bounds_contains(self.center, self.size, location) {
|
||||
let mut rc_center = self.center;
|
||||
let mut rc_size = self.size;
|
||||
let mut path_result: Path = Default::default();
|
||||
|
||||
let mut search_direction = constants::to_region_id(rc_center, location);
|
||||
|
||||
println!("searching for {location}");
|
||||
let mut rc_loc = &self.root;
|
||||
while rc_size > 1 {
|
||||
if search_direction != -1 {
|
||||
let pindex = path_result.length;
|
||||
set_pindex(&mut path_result, pindex, search_direction as usize);
|
||||
}
|
||||
println!("{rc_center}, size {rc_size}, region {search_direction}");
|
||||
match rc_loc {
|
||||
TreeNode::Branch(branch) => {
|
||||
|
@ -215,7 +311,7 @@ impl<T: Clone> OctTree<T> {
|
|||
match rc_loc {
|
||||
TreeNode::Leaf(value) => {
|
||||
println!("found at {rc_center}, {rc_size}");
|
||||
return Some((value.clone(), Default::default()));
|
||||
return Some((value.clone(), path_result));
|
||||
}
|
||||
_ => {
|
||||
println!("Couldn't find it..");
|
||||
|
@ -340,14 +436,14 @@ pub fn test_octtree() {
|
|||
let origin = Vec3::ZERO;
|
||||
let neighbor = Vec3::new(1., 1., 1.);
|
||||
let mut test_oct = OctTree::<i32>::new(origin, 1);
|
||||
test_oct.set_voxel(neighbor, 2);
|
||||
test_oct.set_voxel_at_location(neighbor, 2);
|
||||
|
||||
let far_off_bullshit = Vec3::new(26., 26., 26.);
|
||||
test_oct.set_voxel(far_off_bullshit, 5);
|
||||
test_oct.set_voxel_at_location(far_off_bullshit, 5);
|
||||
dbg!(&test_oct);
|
||||
assert_eq!(test_oct.voxel_at(neighbor).unwrap().0, 2);
|
||||
assert_eq!(test_oct.voxel_at(origin).unwrap().0, 1);
|
||||
assert_eq!(test_oct.voxel_at(far_off_bullshit).unwrap().0, 5);
|
||||
assert_eq!(test_oct.voxel_at_location(neighbor).unwrap().0, 2);
|
||||
assert_eq!(test_oct.voxel_at_location(origin).unwrap().0, 1);
|
||||
assert_eq!(test_oct.voxel_at_location(far_off_bullshit).unwrap().0, 5);
|
||||
}
|
||||
#[test]
|
||||
pub fn test_path() {
|
||||
|
@ -359,6 +455,51 @@ pub fn test_path() {
|
|||
assert_eq!(get_pindex(&path_test, 0), 6);
|
||||
println!("{:#?}", dbg!(path_test.clone()));
|
||||
}
|
||||
#[test]
|
||||
pub fn test_path_return() {
|
||||
let mut octtwee = OctTree::<String>::new(Vec3::ZERO, "a".to_string());
|
||||
octtwee.set_voxel_at_location(Vec3::splat(1.), "test".to_string());
|
||||
octtwee.set_voxel_at_location(Vec3::splat(19.), "test".to_string());
|
||||
let res0 = octtwee.set_voxel_at_location(Vec3::new(190., 15., -100.), "test".to_string());
|
||||
|
||||
println!("{:#?}", dbg!(res0.clone()));
|
||||
println!("{:064b}", res0.packed.clone());
|
||||
for i in 0..res0.length {
|
||||
println!("{}", get_pindex(&res0, i));
|
||||
}
|
||||
let res1 = octtwee.voxel_at_location(Vec3::new(190., 15., -100.));
|
||||
match res1.clone() {
|
||||
Some((b, c)) => {
|
||||
assert_eq!(res0.packed, res1.clone().unwrap().1.packed); //internal path consistency with both functions
|
||||
assert_eq!(
|
||||
Vec3::new(190., 15., -100.),
|
||||
to_vec3(&c, octtwee.center, octtwee.size)
|
||||
);
|
||||
assert_eq!(res1.clone().unwrap().0, "test".to_string());
|
||||
}
|
||||
_ => {
|
||||
panic!("should be something there!");
|
||||
}
|
||||
}
|
||||
assert!(octtwee.set_voxel_at_path(&res1.clone().unwrap().1, "test_change".to_string())); //if we cant modify it we get false, a failed test
|
||||
|
||||
assert_eq!(
|
||||
octtwee
|
||||
.voxel_at_location(Vec3::new(190., 15., -100.))
|
||||
.unwrap()
|
||||
.0,
|
||||
octtwee.voxel_at_path(&res1.clone().unwrap().1).unwrap()
|
||||
);
|
||||
let res1 = octtwee.voxel_at_location(Vec3::new(190., 15., -100.));
|
||||
match &res1 {
|
||||
Some((a, _)) => {
|
||||
assert_eq!(*a, "test_change".to_string());
|
||||
}
|
||||
None => {
|
||||
panic!("something should be here");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
use rand::Rng;
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue