use std::usize;
use crate::{
lla_node::{CartesianPosition, NodeOrData, Opts},
utils::{self, convert_max_distance},
};
struct TempPointer<T: Clone> {
pub node: NodeOrData<T>,
pub distance_along_axis: f64,
}
struct DataContainerWithDistance<T: Clone> {
pub data: T,
pub distance: f64,
}
pub fn get_nearest_neighbors<T: Clone>(
position: CartesianPosition,
tree: NodeOrData<T>,
opts: Opts,
) -> Vec<T> {
let max = convert_max_distance(opts.max_distance_threshold_meters);
let num_results: usize = opts.number_results.unwrap_or(usize::MAX);
let mut result: Vec<DataContainerWithDistance<T>> = vec![];
let entry = TempPointer {
distance_along_axis: 0.0,
node: tree,
};
let mut stack: Vec<TempPointer<T>> = vec![entry];
let mut distance_calc: f64;
let mut node: NodeOrData<T>;
while stack.len() > 0 {
if let Some(ptr) = stack.pop() {
distance_calc = ptr.distance_along_axis;
node = ptr.node;
} else {
continue;
}
if distance_calc > max {
continue;
}
if result.len() == num_results
&& result
.last()
.is_some_and(|x| x.distance < (distance_calc * distance_calc))
{
continue;
}
while let NodeOrData::Node(x) = node {
let lefty = *x.left;
let righty = *x.right;
if position[x.axis as usize] < x.split {
stack.push(TempPointer {
node: righty,
distance_along_axis: (x.split - position[x.axis as usize]),
});
node = lefty;
} else {
stack.push(TempPointer {
node: lefty,
distance_along_axis: position[x.axis as usize] - x.split,
});
node = righty;
}
}
match node {
NodeOrData::Node(_) => continue,
NodeOrData::Data(entry) => {
distance_calc = utils::make_distance_calculation(position, entry.position);
if distance_calc > (max * max) {
continue;
}
if result.len() == 0 {
result.insert(
0,
DataContainerWithDistance {
distance: distance_calc,
data: entry.data,
},
)
} else {
let insertion_result =
result.binary_search_by(|item| item.distance.total_cmp(&distance_calc));
let idx = match insertion_result {
Ok(ordered) => ordered,
Err(not_found_which_is_good) => not_found_which_is_good,
};
result.insert(
idx,
DataContainerWithDistance {
distance: distance_calc,
data: entry.data,
},
)
}
if result.len() > num_results {
result.pop();
}
}
}
}
return result.iter().map(|x| x.data.clone()).collect::<Vec<_>>();
}