fix(input): O(n log n) instead of O(n^2)

This commit is contained in:
Nova
2022-12-02 11:09:23 -05:00
parent 6a3024657f
commit 03ccf9127d
4 changed files with 47 additions and 23 deletions

View File

@@ -11,7 +11,10 @@ pub struct Hand {
pub base: FlatHand, pub base: FlatHand,
} }
impl InputSpecialization for Hand { impl InputSpecialization for Hand {
fn distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 { fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
self.true_distance(space, field).abs()
}
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
let mut min_distance = f32::MAX; let mut min_distance = f32::MAX;
for tip in [ for tip in [

View File

@@ -29,7 +29,8 @@ static INPUT_METHOD_REGISTRY: Registry<InputMethod> = Registry::new();
static INPUT_HANDLER_REGISTRY: Registry<InputHandler> = Registry::new(); static INPUT_HANDLER_REGISTRY: Registry<InputHandler> = Registry::new();
pub trait InputSpecialization: Send + Sync { pub trait InputSpecialization: Send + Sync {
fn distance(&self, space: &Arc<Spatial>, field: &Field) -> f32; fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32;
fn serialize( fn serialize(
&self, &self,
distance_link: &DistanceLink, distance_link: &DistanceLink,
@@ -108,8 +109,13 @@ impl InputMethod {
Ok(()) Ok(())
} }
fn distance(&self, to: &Field) -> f32 { fn compare_distance(&self, to: &Field) -> f32 {
self.specialization.lock().distance(&self.spatial, to) self.specialization
.lock()
.compare_distance(&self.spatial, to)
}
fn true_distance(&self, to: &Field) -> f32 {
self.specialization.lock().true_distance(&self.spatial, to)
} }
} }
impl Drop for InputMethod { impl Drop for InputMethod {
@@ -128,7 +134,7 @@ impl DistanceLink {
fn from(method: Arc<InputMethod>, handler: Arc<InputHandler>) -> Option<Self> { fn from(method: Arc<InputMethod>, handler: Arc<InputHandler>) -> Option<Self> {
let handler_field = handler.field.upgrade()?; let handler_field = handler.field.upgrade()?;
Some(DistanceLink { Some(DistanceLink {
distance: method.distance(&handler_field), distance: method.compare_distance(&handler_field),
method, method,
handler, handler,
handler_field, handler_field,
@@ -147,7 +153,9 @@ impl DistanceLink {
let root = InputData { let root = InputData {
uid: self.method.uid.clone(), uid: self.method.uid.clone(),
input, input,
distance: self.distance, distance: self
.method
.true_distance(&self.handler.field.upgrade().unwrap()),
datamap, datamap,
}; };
root.serialize() root.serialize()
@@ -237,42 +245,47 @@ pub fn create_input_handler_flex(
InputHandler::add_to(&node, &field)?; InputHandler::add_to(&node, &field)?;
Ok(()) Ok(())
} }
pub fn process_input() { pub fn process_input() {
// Iterate over all valid input methods
for method in INPUT_METHOD_REGISTRY for method in INPUT_METHOD_REGISTRY
.get_valid_contents() .get_valid_contents()
.into_iter() .into_iter()
.filter(|method| *method.enabled.lock()) .filter(|method| *method.enabled.lock())
.filter(|method| method.datamap.lock().is_some()) .filter(|method| method.datamap.lock().is_some())
{ {
// Get all valid input handlers and convert them to DistanceLink objects
let mut distance_links: Vec<DistanceLink> = INPUT_HANDLER_REGISTRY let mut distance_links: Vec<DistanceLink> = INPUT_HANDLER_REGISTRY
.get_valid_contents() .get_valid_contents()
.into_iter() .into_iter()
.filter(|handler| handler.field.upgrade().is_some()) .filter(|handler| handler.field.upgrade().is_some())
.filter_map(|handler| DistanceLink::from(method.clone(), handler)) .filter_map(|handler| DistanceLink::from(method.clone(), handler))
.collect(); .collect();
distance_links.sort_unstable_by(|a, b| {
a.distance
.abs()
.partial_cmp(&b.distance.abs())
.unwrap()
.reverse()
});
let mut last_distance = 0.0; // Sort the distance links by their distance in ascending order
distance_links
.sort_unstable_by(|a, b| a.distance.abs().partial_cmp(&b.distance.abs()).unwrap());
// Get the current frame
let frame = FRAME.load(Ordering::Relaxed); let frame = FRAME.load(Ordering::Relaxed);
// Get the list of captured input handlers for this method
let captures = method.captures.get_valid_contents(); let captures = method.captures.get_valid_contents();
// Iterate over the distance links and send input to them
for distance_link in distance_links { for distance_link in distance_links {
distance_link.send_input(frame, method.datamap.lock().clone().unwrap()); distance_link.send_input(frame, method.datamap.lock().clone().unwrap());
if last_distance != distance_link.distance
&& captures // If the current distance link is in the list of captured input handlers,
.iter() // break out of the loop to avoid sending input to the remaining distance links
.any(|c| Arc::ptr_eq(c, &distance_link.handler)) if captures
.iter()
.any(|c| Arc::ptr_eq(c, &distance_link.handler))
{ {
break; break;
} }
last_distance = distance_link.distance;
} }
// Clear the list of captured input handlers for this method
method.captures.clear(); method.captures.clear();
} }
} }

View File

@@ -26,8 +26,13 @@ impl Pointer {
} }
impl InputSpecialization for Pointer { impl InputSpecialization for Pointer {
fn distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 { fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
self.ray_march(space, field).min_distance let ray_info = self.ray_march(space, field);
ray_info.deepest_point_distance.hypot(ray_info.min_distance)
}
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
let ray_info = self.ray_march(space, field);
ray_info.min_distance
} }
fn serialize( fn serialize(
&self, &self,

View File

@@ -25,7 +25,10 @@ impl Tip {
} }
} }
impl InputSpecialization for Tip { impl InputSpecialization for Tip {
fn distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 { fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
field.distance(space, vec3a(0.0, 0.0, 0.0)).abs()
}
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
field.distance(space, vec3a(0.0, 0.0, 0.0)) field.distance(space, vec3a(0.0, 0.0, 0.0))
} }
fn serialize( fn serialize(