Skip to content

Commit

Permalink
Merge pull request #107 from paxproject/zb/scoped-raycasting
Browse files Browse the repository at this point in the history
Support scoped raycasting
  • Loading branch information
samuelselleck authored Feb 13, 2024
2 parents f9617ca + e7134c3 commit bc6d709
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs
Submodule docs updated from cd88f2 to 37f467
16 changes: 16 additions & 0 deletions pax-runtime/src/engine/expanded_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,22 @@ impl ExpandedNode {
})
}

/// Returns whether this node is a descendant of the ExpandedNode described by `other_expanded_node_id` (id_chain)
/// Currently requires traversing linked list of ancestory, incurring a O(log(n)) cost for a tree of `n` elements.
/// This could be mitigated with caching/memoization, perhaps by storing a HashSet on each ExpandedNode describing its ancestory chain.
pub fn is_descendant_of(&self, other_expanded_node_id: &Vec<u32>) -> bool {
if let Some(parent) = self.parent_expanded_node.borrow().upgrade() {
// We have a parent — if it matches the ID, this node is indeed an ancestor of other_expanded_node_id. Otherwise, recurse upward.
if parent.id_chain.eq(other_expanded_node_id) {
true
} else {
parent.is_descendant_of(other_expanded_node_id)
}
} else {
false
}
}

pub fn create_children_detached(
self: &Rc<Self>,
templates: impl IntoIterator<Item = (Rc<dyn InstanceNode>, Rc<RuntimePropertiesStackFrame>)>,
Expand Down
48 changes: 39 additions & 9 deletions pax-runtime/src/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,37 @@ impl RuntimeContext {
}
}

/// Finds all ExpandedNodes with the CommonProperty#id matching the provided string
pub fn get_expanded_nodes_by_id(&self, id: &str) -> Vec<Rc<ExpandedNode>> {
//v0 limitation: currently an O(n) lookup cost (could be made O(1) with an id->expandednode cache)
self.node_cache
.values()
.filter(|val| {
if let Some(other_id) = &val.get_common_properties().borrow().id {
other_id.get() == id
} else {
false
}
})
.cloned()
.collect()
}

/// Simple 2D raycasting: the coordinates of the ray represent a
/// ray running orthogonally to the view plane, intersecting at
/// the specified point `ray`. Areas outside of clipping bounds will
/// not register a `hit`, nor will elements that suppress input events.
pub fn get_topmost_element_beneath_ray(&self, ray: (f64, f64)) -> Option<Rc<ExpandedNode>> {
pub fn get_elements_beneath_ray(
&self,
ray: (f64, f64),
limit_one: bool,
mut accum: Vec<Rc<ExpandedNode>>,
) -> Vec<Rc<ExpandedNode>> {
//Traverse all elements in render tree sorted by z-index (highest-to-lowest)
//First: check whether events are suppressed
//Next: check whether ancestral clipping bounds (hit_test) are satisfied
//Finally: check whether element itself satisfies hit_test(ray)

//Instead of storing a pointer to `last_rtc`, we should store a custom
//struct with exactly the fields we need for ray-casting

let mut ret: Option<Rc<ExpandedNode>> = None;
for node in self.z_index_node_cache.iter().rev().skip(1) {
if node.ray_cast_test(&ray) {
//We only care about the topmost node getting hit, and the element
Expand All @@ -66,7 +83,6 @@ impl RuntimeContext {
if let Some(unwrapped_parent) = parent {
if let Some(_) = unwrapped_parent.get_clipping_size() {
ancestral_clipping_bounds_are_satisfied =
//clew
(*unwrapped_parent).ray_cast_test(&ray);
break;
}
Expand All @@ -77,12 +93,26 @@ impl RuntimeContext {
}

if ancestral_clipping_bounds_are_satisfied {
ret = Some(Rc::clone(&node));
break;
accum.push(Rc::clone(&node));
if limit_one {
return accum;
}
}
}
}
ret
accum
}

/// Alias for `get_elements_beneath_ray` with `limit_one = true`
pub fn get_topmost_element_beneath_ray(&self, ray: (f64, f64)) -> Option<Rc<ExpandedNode>> {
let res = self.get_elements_beneath_ray(ray, true, vec![]);
if res.len() == 0 {
None
} else if res.len() == 1 {
Some(res.get(0).unwrap().clone())
} else {
unreachable!() //bug in limit_one logic
}
}

pub fn gen_uid(&mut self) -> Uid {
Expand Down
2 changes: 1 addition & 1 deletion www.pax.dev

0 comments on commit bc6d709

Please sign in to comment.