diff options
Diffstat (limited to 'src/pipeline/query_pipeline.rs')
| -rw-r--r-- | src/pipeline/query_pipeline.rs | 444 |
1 files changed, 322 insertions, 122 deletions
diff --git a/src/pipeline/query_pipeline.rs b/src/pipeline/query_pipeline.rs index cb56141..31bf3a4 100644 --- a/src/pipeline/query_pipeline.rs +++ b/src/pipeline/query_pipeline.rs @@ -1,9 +1,14 @@ -use crate::dynamics::RigidBodySet; +use crate::data::{BundleSet, ComponentSet, ComponentSetOption}; +use crate::dynamics::{ + IslandManager, RigidBodyColliders, RigidBodyForces, RigidBodyMassProps, RigidBodyPosition, + RigidBodyVelocity, +}; use crate::geometry::{ - Collider, ColliderHandle, ColliderSet, InteractionGroups, PointProjection, Ray, - RayIntersection, SimdQuadTree, AABB, + ColliderGroups, ColliderHandle, ColliderParent, ColliderPosition, ColliderShape, + InteractionGroups, PointProjection, Ray, RayIntersection, AABB, QBVH, }; use crate::math::{Isometry, Point, Real, Vector}; +use parry::partitioning::QBVHDataGenerator; use parry::query::details::{ IntersectionCompositeShapeShapeBestFirstVisitor, NonlinearTOICompositeShapeShapeBestFirstVisitor, PointCompositeShapeProjBestFirstVisitor, @@ -18,6 +23,9 @@ use parry::query::{DefaultQueryDispatcher, NonlinearRigidMotion, QueryDispatcher use parry::shape::{FeatureId, Shape, TypedSimdCompositeShape}; use std::sync::Arc; +#[cfg(feature = "default-sets")] +use crate::{dynamics::RigidBodySet, geometry::ColliderSet}; + /// A pipeline for performing queries on all the colliders of a scene. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[derive(Clone)] @@ -27,16 +35,16 @@ pub struct QueryPipeline { serde(skip, default = "crate::geometry::default_query_dispatcher") )] query_dispatcher: Arc<dyn QueryDispatcher>, - quadtree: SimdQuadTree<ColliderHandle>, + quadtree: QBVH<ColliderHandle>, tree_built: bool, dilation_factor: Real, } -struct QueryPipelineAsCompositeShape<'a> { +struct QueryPipelineAsCompositeShape<'a, Colliders> { query_pipeline: &'a QueryPipeline, - colliders: &'a ColliderSet, + colliders: &'a Colliders, query_groups: InteractionGroups, - filter: Option<&'a dyn Fn(ColliderHandle, &Collider) -> bool>, + filter: Option<&'a dyn Fn(ColliderHandle) -> bool>, } /// Indicates how the colliders position should be taken into account when @@ -55,7 +63,12 @@ pub enum QueryPipelineMode { }, } -impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> { +impl<'a, Colliders> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a, Colliders> +where + // TODO ECS: make everything optional but the shape? + Colliders: + ComponentSet<ColliderGroups> + ComponentSet<ColliderPosition> + ComponentSet<ColliderShape>, +{ type PartShape = dyn Shape; type PartId = ColliderHandle; @@ -64,11 +77,15 @@ impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> { shape_id: Self::PartId, mut f: impl FnMut(Option<&Isometry<Real>>, &Self::PartShape), ) { - if let Some(collider) = self.colliders.get(shape_id) { - if collider.collision_groups.test(self.query_groups) - && self.filter.map(|f| f(shape_id, collider)).unwrap_or(true) + let co_groups: Option<&ColliderGroups> = self.colliders.get(shape_id.0); + + if let Some(co_groups) = co_groups { + if co_groups.collision_groups.test(self.query_groups) + && self.filter.map(|f| f(shape_id)).unwrap_or(true) { - f(Some(collider.position()), collider.shape()) + let (co_pos, co_shape): (&ColliderPosition, &ColliderShape) = + self.colliders.index_bundle(shape_id.0); + f(Some(co_pos), &**co_shape) } } } @@ -81,7 +98,7 @@ impl<'a> TypedSimdCompositeShape for QueryPipelineAsCompositeShape<'a> { self.map_typed_part_at(shape_id, f); } - fn typed_quadtree(&self) -> &SimdQuadTree<ColliderHandle> { + fn typed_quadtree(&self) -> &QBVH<ColliderHandle> { &self.query_pipeline.quadtree } } @@ -98,12 +115,12 @@ impl QueryPipeline { Self::with_query_dispatcher(DefaultQueryDispatcher) } - fn as_composite_shape<'a>( + fn as_composite_shape<'a, Colliders>( &'a self, - colliders: &'a ColliderSet, + colliders: &'a Colliders, query_groups: InteractionGroups, - filter: Option<&'a dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> QueryPipelineAsCompositeShape<'a> { + filter: Option<&'a dyn Fn(ColliderHandle) -> bool>, + ) -> QueryPipelineAsCompositeShape<'a, Colliders> { QueryPipelineAsCompositeShape { query_pipeline: self, colliders, @@ -122,7 +139,7 @@ impl QueryPipeline { { Self { query_dispatcher: Arc::new(d), - quadtree: SimdQuadTree::new(), + quadtree: QBVH::new(), tree_built: false, dilation_factor: 0.01, } @@ -133,53 +150,152 @@ impl QueryPipeline { &*self.query_dispatcher } + #[cfg(feature = "default-sets")] /// Update the acceleration structure on the query pipeline. - pub fn update(&mut self, bodies: &RigidBodySet, colliders: &ColliderSet) { - self.update_with_mode(bodies, colliders, QueryPipelineMode::CurrentPosition) + pub fn update( + &mut self, + islands: &IslandManager, + bodies: &RigidBodySet, + colliders: &ColliderSet, + ) { + self.update_generic(islands, bodies, colliders); } /// Update the acceleration structure on the query pipeline. - pub fn update_with_mode( + pub fn update_generic<Bodies, Colliders>( &mut self, - bodies: &RigidBodySet, - colliders: &ColliderSet, + islands: &IslandManager, + bodies: &Bodies, + colliders: &Colliders, + ) where + Bodies: ComponentSet<RigidBodyPosition> + + ComponentSet<RigidBodyColliders> + + ComponentSet<RigidBodyVelocity> + + ComponentSet<RigidBodyMassProps> + + ComponentSet<RigidBodyForces>, + Colliders: ComponentSet<ColliderShape> + + ComponentSet<ColliderPosition> + + ComponentSetOption<ColliderParent>, + { + self.update_with_mode( + islands, + bodies, + colliders, + QueryPipelineMode::CurrentPosition, + ) + } + + /// Update the acceleration structure on the query pipeline. + pub fn update_with_mode<Bodies, Colliders>( + &mut self, + islands: &IslandManager, + bodies: &Bodies, + colliders: &Colliders, mode: QueryPipelineMode, - ) { - if !self.tree_built { - match mode { - QueryPipelineMode::CurrentPosition => { - let data = colliders.iter().map(|(h, c)| (h, c.compute_aabb())); - self.quadtree.clear_and_rebuild(data, self.dilation_factor); - } - QueryPipelineMode::SweepTestWithNextPosition => { - let data = colliders.iter().map(|(h, c)| { - let next_position = - bodies[c.parent()].next_position * c.position_wrt_parent(); - (h, c.compute_swept_aabb(&next_position)) - }); - self.quadtree.clear_and_rebuild(data, self.dilation_factor); - } - QueryPipelineMode::SweepTestWithPredictedPosition { dt } => { - let data = colliders.iter().map(|(h, c)| { - let next_position = bodies[c.parent()] - .predict_position_using_velocity_and_forces(dt) - * c.position_wrt_parent(); - (h, c.compute_swept_aabb(&next_position)) - }); - self.quadtree.clear_and_rebuild(data, self.dilation_factor); + ) where + Bodies: ComponentSet<RigidBodyPosition> + + ComponentSet<RigidBodyColliders> + + ComponentSet<RigidBodyVelocity> + + ComponentSet<RigidBodyMassProps> + + ComponentSet<RigidBodyForces>, + Colliders: ComponentSet<ColliderShape> + + ComponentSet<ColliderPosition> + + ComponentSetOption<ColliderParent>, + { + struct DataGenerator<'a, Bs, Cs> { + bodies: &'a Bs, + colliders: &'a Cs, + mode: QueryPipelineMode, + } + + impl<'a, Bs, Cs> QBVHDataGenerator<ColliderHandle> for DataGenerator<'a, Bs, Cs> + where + Bs: ComponentSet<RigidBodyPosition> + + ComponentSet<RigidBodyMassProps> + + ComponentSet<RigidBodyVelocity> + + ComponentSet<RigidBodyForces>, + Cs: ComponentSet<ColliderShape> + + ComponentSet<ColliderPosition> + + ComponentSetOption<ColliderParent>, + { + fn size_hint(&self) -> usize { + ComponentSet::<ColliderShape>::size_hint(self.colliders) + } + + #[inline(always)] + fn for_each(&mut self, mut f: impl FnMut(ColliderHandle, AABB)) { + match self.mode { + QueryPipelineMode::CurrentPosition => { + self.colliders.for_each(|h, co_shape: &ColliderShape| { + let co_pos: &ColliderPosition = self.colliders.index(h); + f(ColliderHandle(h), co_shape.compute_aabb(&co_pos)) + }) + } + QueryPipelineMode::SweepTestWithNextPosition => { + self.colliders.for_each(|h, co_shape: &ColliderShape| { + let co_parent: Option<&ColliderParent> = self.colliders.get(h); + let co_pos: &ColliderPosition = self.colliders.index(h); + + if let Some(co_parent) = co_parent { + let rb_pos: &RigidBodyPosition = + self.bodies.index(co_parent.handle.0); + let next_position = rb_pos.next_position * co_parent.pos_wrt_parent; + + f( + ColliderHandle(h), + co_shape.compute_swept_aabb(&co_pos, &next_position), + ) + } else { + f(ColliderHandle(h), co_shape.compute_aabb(&co_pos)) + } + }) + } + QueryPipelineMode::SweepTestWithPredictedPosition { dt } => { + self.colliders.for_each(|h, co_shape: &ColliderShape| { + let co_parent: Option<&ColliderParent> = self.colliders.get(h); + let co_pos: &ColliderPosition = self.colliders.index(h); + + if let Some(co_parent) = co_parent { + let (rb_pos, vels, forces, mprops): ( + &RigidBodyPosition, + &RigidBodyVelocity, + &RigidBodyForces, + &RigidBodyMassProps, + ) = self.bodies.index_bundle(co_parent.handle.0); + let predicted_pos = rb_pos + .integrate_forces_and_velocities(dt, forces, vels, mprops); + + let next_position = predicted_pos * co_parent.pos_wrt_parent; + f( + ColliderHandle(h), + co_shape.compute_swept_aabb(&co_pos, &next_position), + ) + } else { + f(ColliderHandle(h), co_shape.compute_aabb(&co_pos)) + } + }) + } } } + } + + if !self.tree_built { + let generator = DataGenerator { + bodies, + colliders, + mode, + }; + self.quadtree + .clear_and_rebuild(generator, self.dilation_factor); // FIXME: uncomment this once we handle insertion/removals properly. // self.tree_built = true; return; } - for (_, body) in bodies - .iter_active_dynamic() - .chain(bodies.iter_active_kinematic()) - { - for handle in &body.colliders { + for handle in islands.iter_active_bodies() { + let body_colliders: &RigidBodyColliders = bodies.index(handle.0); + for handle in &body_colliders.0 { self.quadtree.pre_update(*handle) } } @@ -187,17 +303,28 @@ impl QueryPipeline { match mode { QueryPipelineMode::CurrentPosition => { self.quadtree.update( - |handle| colliders[*handle].compute_aabb(), + |handle| { + let (co_pos, co_shape): (&ColliderPosition, &ColliderShape) = + colliders.index_bundle(handle.0); + co_shape.compute_aabb(&co_pos) + }, self.dilation_factor, ); } QueryPipelineMode::SweepTestWithNextPosition => { self.quadtree.update( |handle| { - let co = &colliders[*handle]; - let next_position = - bodies[co.parent()].next_position * co.position_wrt_parent(); - co.compute_swept_aabb(&next_position) + let co_parent: Option<&ColliderParent> = colliders.get(handle.0); + let (co_pos, co_shape): (&ColliderPosition, &ColliderShape) = + colliders.index_bundle(handle.0); + + if let Some(co_parent) = co_parent { + let rb_pos: &RigidBodyPosition = bodies.index(co_parent.handle.0); + let next_position = rb_pos.next_position * co_parent.pos_wrt_parent; + co_shape.compute_swept_aabb(&co_pos, &next_position) + } else { + co_shape.compute_aabb(&co_pos) + } }, self.dilation_factor, ); @@ -205,11 +332,26 @@ impl QueryPipeline { QueryPipelineMode::SweepTestWithPredictedPosition { dt } => { self.quadtree.update( |handle| { - let co = &colliders[*handle]; - let next_position = bodies[co.parent()] - .predict_position_using_velocity_and_forces(dt) - * co.position_wrt_parent(); - co.compute_swept_aabb(&next_position) + let co_parent: Option<&ColliderParent> = colliders.get(handle.0); + let (co_pos, co_shape): (&ColliderPosition, &ColliderShape) = + colliders.index_bundle(handle.0); + + if let Some(co_parent) = co_parent { + let (rb_pos, vels, forces, mprops): ( + &RigidBodyPosition, + &RigidBodyVelocity, + &RigidBodyForces, + &RigidBodyMassProps, + ) = bodies.index_bundle(co_parent.handle.0); + + let predicted_pos = + rb_pos.integrate_forces_and_velocities(dt, forces, vels, mprops); + + let next_position = predicted_pos * co_parent.pos_wrt_parent; + co_shape.compute_swept_aabb(&co_pos, &next_position) + } else { + co_shape.compute_aabb(&co_pos) + } }, self.dilation_factor, ); @@ -232,15 +374,20 @@ impl QueryPipeline { /// - `filter`: a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn cast_ray( + pub fn cast_ray<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, ray: &Ray, max_toi: Real, solid: bool, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, Real)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, Real)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = RayCompositeShapeToiBestFirstVisitor::new(&pipeline_shape, ray, max_toi, solid); @@ -263,15 +410,20 @@ impl QueryPipeline { /// - `filter`: a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn cast_ray_and_get_normal( + pub fn cast_ray_and_get_normal<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, ray: &Ray, max_toi: Real, solid: bool, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, RayIntersection)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, RayIntersection)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = RayCompositeShapeToiAndNormalBestFirstVisitor::new( &pipeline_shape, @@ -301,26 +453,31 @@ impl QueryPipeline { /// - `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`, /// this method will exit early, ignore any further raycast. - pub fn intersections_with_ray<'a>( + pub fn intersections_with_ray<'a, Colliders>( &self, - colliders: &'a ColliderSet, + colliders: &'a Colliders, ray: &Ray, max_toi: Real, solid: bool, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - mut callback: impl FnMut(ColliderHandle, &'a Collider, RayIntersection) -> bool, - ) { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + mut callback: impl FnMut(ColliderHandle, RayIntersection) -> bool, + ) where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let mut leaf_callback = &mut |handle: &ColliderHandle| { - if let Some(coll) = colliders.get(*handle) { - if coll.collision_groups.test(query_groups) - && filter.map(|f| f(*handle, coll)).unwrap_or(true) + let co_shape: Option<&ColliderShape> = colliders.get(handle.0); + if let Some(co_shape) = co_shape { + let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + colliders.index_bundle(handle.0); + if co_groups.collision_groups.test(query_groups) + && filter.map(|f| f(*handle)).unwrap_or(true) { - if let Some(hit) = - coll.shape() - .cast_ray_and_get_normal(coll.position(), ray, max_toi, solid) + if let Some(hit) = co_shape.cast_ray_and_get_normal(co_pos, ray, max_toi, solid) { - return callback(*handle, coll, hit); + return callback(*handle, hit); } } } @@ -343,14 +500,19 @@ impl QueryPipeline { /// * `filter` - a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn intersection_with_shape( + pub fn intersection_with_shape<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, shape_pos: &Isometry<Real>, shape: &dyn Shape, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<ColliderHandle> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<ColliderHandle> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = IntersectionCompositeShapeShapeBestFirstVisitor::new( &*self.query_dispatcher, @@ -379,14 +541,19 @@ impl QueryPipeline { /// * `filter` - a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn project_point( + pub fn project_point<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, point: &Point<Real>, solid: bool, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, PointProjection)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, PointProjection)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = PointCompositeShapeProjBestFirstVisitor::new(&pipeline_shape, point, solid); @@ -408,21 +575,30 @@ impl QueryPipeline { /// is either `None` or returns `true`. /// * `callback` - A function called with each collider with a shape /// containing the `point`. - pub fn intersections_with_point<'a>( + pub fn intersections_with_point<'a, Colliders>( &self, - colliders: &'a ColliderSet, + colliders: &'a Colliders, point: &Point<Real>, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - mut callback: impl FnMut(ColliderHandle, &'a Collider) -> bool, - ) { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + mut callback: impl FnMut(ColliderHandle) -> bool, + ) where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let mut leaf_callback = &mut |handle: &ColliderHandle| { - if let Some(coll) = colliders.get(*handle) { - if coll.collision_groups.test(query_groups) - && filter.map(|f| f(*handle, coll)).unwrap_or(true) - && coll.shape().contains_point(coll.position(), point) + let co_shape: Option<&ColliderShape> = colliders.get(handle.0); + + if let Some(co_shape) = co_shape { + let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + colliders.index_bundle(handle.0); + + if co_groups.collision_groups.test(query_groups) + && filter.map(|f| f(*handle)).unwrap_or(true) + && co_shape.contains_point(co_pos, point) { - return callback(*handle, coll); + return callback(*handle); } } @@ -451,13 +627,18 @@ impl QueryPipeline { /// * `filter` - a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn project_point_and_get_feature( + pub fn project_point_and_get_feature<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, point: &Point<Real>, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, PointProjection, FeatureId)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, PointProjection, FeatureId)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = PointCompositeShapeProjWithFeatureBestFirstVisitor::new(&pipeline_shape, point, false); @@ -493,16 +674,21 @@ impl QueryPipeline { /// * `filter` - a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn cast_shape<'a>( + pub fn cast_shape<'a, Colliders>( &self, - colliders: &'a ColliderSet, + colliders: &'a Colliders, shape_pos: &Isometry<Real>, shape_vel: &Vector<Real>, shape: &dyn Shape, max_toi: Real, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, TOI)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, TOI)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let mut visitor = TOICompositeShapeShapeBestFirstVisitor::new( &*self.query_dispatcher, @@ -535,17 +721,22 @@ impl QueryPipeline { /// * `filter` - a more fine-grained filter. A collider is taken into account by this query if /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. - pub fn nonlinear_cast_shape( + pub fn nonlinear_cast_shape<Colliders>( &self, - colliders: &ColliderSet, + colliders: &Colliders, shape_motion: &NonlinearRigidMotion, shape: &dyn Shape, start_time: Real, end_time: Real, stop_at_penetration: bool, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - ) -> Option<(ColliderHandle, TOI)> { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + ) -> Option<(ColliderHandle, TOI)> + where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { let pipeline_shape = self.as_composite_shape(colliders, query_groups, filter); let pipeline_motion = NonlinearRigidMotion::identity(); let mut visitor = NonlinearTOICompositeShapeShapeBestFirstVisitor::new( @@ -574,27 +765,36 @@ impl QueryPipeline { /// its `contact_group` is compatible with the `query_groups`, and if this `filter` /// is either `None` or returns `true`. /// * `callback` - A function called with the handles of each collider intersecting the `shape`. - pub fn intersections_with_shape<'a>( + pub fn intersections_with_shape<'a, Colliders>( &self, - colliders: &'a ColliderSet, + colliders: &'a Colliders, shape_pos: &Isometry<Real>, shape: &dyn Shape, query_groups: InteractionGroups, - filter: Option<&dyn Fn(ColliderHandle, &Collider) -> bool>, - mut callback: impl FnMut(ColliderHandle, &'a Collider) -> bool, - ) { + filter: Option<&dyn Fn(ColliderHandle) -> bool>, + mut callback: impl FnMut(ColliderHandle) -> bool, + ) where + Colliders: ComponentSet<ColliderGroups> + + ComponentSet<ColliderPosition> + + ComponentSet<ColliderShape>, + { 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(query_groups) - && filter.map(|f| f(*handle, coll)).unwrap_or(true) + let co_shape: Option<&ColliderShape> = colliders.get(handle.0); + + if let Some(co_shape) = co_shape { + let (co_groups, co_pos): (&ColliderGroups, &ColliderPosition) = + colliders.index_bundle(handle.0); + + if co_groups.collision_groups.test(query_groups) + && filter.map(|f| f(*handle)).unwrap_or(true) { - let pos12 = inv_shape_pos * coll.position(); + let pos12 = inv_shape_pos * co_pos.as_ref(); - if dispatcher.intersection_test(&pos12, shape, coll.shape()) == Ok(true) { - return callback(*handle, coll); + if dispatcher.intersection_test(&pos12, shape, &**co_shape) == Ok(true) { + return callback(*handle); } } } |
