Query pipeline: add methods to collect all intersections with a point or a shape.

This commit is contained in:
Crozet Sébastien
2020-12-31 18:23:14 +01:00
parent 7b098606c2
commit a1aa8855f7

View File

@@ -12,6 +12,9 @@ use cdl::query::details::{
RayCompositeShapeToiAndNormalBestFirstVisitor, RayCompositeShapeToiBestFirstVisitor, RayCompositeShapeToiAndNormalBestFirstVisitor, RayCompositeShapeToiBestFirstVisitor,
TOICompositeShapeShapeBestFirstVisitor, TOICompositeShapeShapeBestFirstVisitor,
}; };
use cdl::query::visitors::{
BoundingVolumeIntersectionsVisitor, PointIntersectionsVisitor, RayIntersectionsVisitor,
};
use cdl::query::{DefaultQueryDispatcher, QueryDispatcher, TOI}; use cdl::query::{DefaultQueryDispatcher, QueryDispatcher, TOI};
use cdl::shape::{FeatureId, Shape, TypedSimdCompositeShape}; use cdl::shape::{FeatureId, Shape, TypedSimdCompositeShape};
use std::sync::Arc; use std::sync::Arc;
@@ -183,35 +186,33 @@ impl QueryPipeline {
/// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `Real::MAX` for an unbounded ray. /// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `Real::MAX` for an unbounded ray.
/// - `callback`: function executed on each collider for which a ray intersection has been found. /// - `callback`: function executed on each collider for which a ray intersection has been found.
/// There is no guarantees on the order the results will be yielded. If this callback returns `false`, /// There is no guarantees on the order the results will be yielded. If this callback returns `false`,
/// this method will exit early, ignory any further raycast. /// this method will exit early, ignore any further raycast.
pub fn intersections_with_ray<'a>( pub fn intersections_with_ray<'a>(
&self, &self,
colliders: &'a ColliderSet, colliders: &'a ColliderSet,
ray: &Ray, ray: &Ray,
max_toi: Real, max_toi: Real,
solid: bool,
groups: InteractionGroups, groups: InteractionGroups,
mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool, mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool,
) { ) {
// TODO: avoid allocation? let mut leaf_callback = &mut |handle: &ColliderHandle| {
let mut inter = Vec::new(); if let Some(coll) = colliders.get(*handle) {
self.quadtree.cast_ray(ray, max_toi, &mut inter); if coll.collision_groups.test(groups) {
if let Some(hit) =
for handle in inter { coll.shape()
let collider = &colliders[handle]; .cast_ray_and_get_normal(coll.position(), ray, max_toi, solid)
{
if collider.collision_groups.test(groups) { return callback(*handle, coll, hit);
if let Some(inter) = collider.shape().cast_ray_and_get_normal(
collider.position(),
ray,
max_toi,
true,
) {
if !callback(handle, collider, inter) {
return;
} }
} }
} }
}
true
};
let mut visitor = RayIntersectionsVisitor::new(ray, max_toi, &mut leaf_callback);
self.quadtree.traverse_depth_first(&mut visitor);
} }
/// Find up to one collider intersecting the given shape. /// Find up to one collider intersecting the given shape.
@@ -235,8 +236,6 @@ impl QueryPipeline {
.map(|h| (h.1 .0)) .map(|h| (h.1 .0))
} }
// TODO: intersections_with_point (collect all colliders containing the point).
/// Projects a point on the scene. /// Projects a point on the scene.
fn project_point( fn project_point(
&self, &self,
@@ -254,6 +253,31 @@ impl QueryPipeline {
.map(|h| (h.1 .1, h.1 .0)) .map(|h| (h.1 .1, h.1 .0))
} }
/// Gets all the colliders containing the given point.
pub fn intersections_with_point<'a>(
&self,
colliders: &'a ColliderSet,
point: &Point<Real>,
groups: InteractionGroups,
mut callback: impl FnMut(ColliderHandle, &'a Collider) -> bool,
) {
let mut leaf_callback = &mut |handle: &ColliderHandle| {
if let Some(coll) = colliders.get(*handle) {
if coll.collision_groups.test(groups)
&& coll.shape().contains_point(coll.position(), point)
{
return callback(*handle, coll);
}
}
true
};
let mut visitor = PointIntersectionsVisitor::new(point, &mut leaf_callback);
self.quadtree.traverse_depth_first(&mut visitor);
}
/// Projects a point on the scene and get /// Projects a point on the scene and get
fn project_point_and_get_feature( fn project_point_and_get_feature(
&self, &self,
@@ -313,8 +337,7 @@ impl QueryPipeline {
self.quadtree.traverse_best_first(&mut visitor).map(|h| h.1) self.quadtree.traverse_best_first(&mut visitor).map(|h| h.1)
} }
/* /// Gets all the colliders containing the given shape.
/// Gets all the colliders with a shape intersecting the given `shape`.
pub fn intersections_with_shape<'a>( pub fn intersections_with_shape<'a>(
&self, &self,
colliders: &'a ColliderSet, colliders: &'a ColliderSet,
@@ -323,6 +346,26 @@ impl QueryPipeline {
groups: InteractionGroups, groups: InteractionGroups,
mut callback: impl FnMut(ColliderHandle, &'a Collider) -> bool, mut callback: impl FnMut(ColliderHandle, &'a Collider) -> bool,
) { ) {
let dispatcher = &*self.query_dispatcher;
let inv_shape_pos = shape_pos.inverse();
let mut leaf_callback = &mut |handle: &ColliderHandle| {
if let Some(coll) = colliders.get(*handle) {
if coll.collision_groups.test(groups) {
let pos12 = inv_shape_pos * coll.position();
if dispatcher.intersection_test(&pos12, shape, coll.shape()) == Ok(true) {
return callback(*handle, coll);
}
}
}
true
};
let shape_aabb = shape.compute_aabb(shape_pos);
let mut visitor = BoundingVolumeIntersectionsVisitor::new(&shape_aabb, &mut leaf_callback);
self.quadtree.traverse_depth_first(&mut visitor);
} }
*/
} }