Skip to main content

scene_queries_point_projection

Point projection will either project a point on the closest collider of the scene (QueryPipeline::project_pointRapierContext::project_pointWorld.projectPointr3TryProjectPointQueryPipeline.project_point), or will enumerate every collider containing given point (QueryPipeline::intersect_pointRapierContext::intersect_pointWorld.intersectionsWithPointr3IntersectPointQueryPipeline.intersect_point).

let point = Vector::new(1.0, 2.0);
let solid = true;
let max_dist = 12.0;
let filter = QueryFilter::default();

let query_pipeline = world.query_pipeline_with_filter(filter);

if let Some((handle, projection)) = query_pipeline.project_point(
point, max_dist, solid
) {
// The collider closest to the point has this `handle`.
println!("Projected point on collider {:?}. Point projection: {}", handle, projection.point);
println!("Point was inside of the collider shape: {}", projection.is_inside);
}

for (handle, _) in query_pipeline.intersect_point(point) {
// Callback called on each collider with a shape containing the point.
println!("The collider {:?} contains the point.", handle);
}
/* Project a point inside of a system. */
fn project_point(rapier_context: ReadRapierContext) {
let rapier_context = rapier_context.single().unwrap();
let point = Vec2::new(1.0, 2.0);
let max_dist = 4.0; // Colliders further than this distance are ignored.
let solid = true;
let filter = QueryFilter::default();

if let Some((entity, projection)) = rapier_context.project_point(point, max_dist, solid, filter)
{
// The collider closest to the point is attached to `entity`.
println!(
"Projected point on entity {:?}. Point projection: {}",
entity, projection.point
);
println!(
"Point was inside of the collider shape: {}",
projection.is_inside
);
}

rapier_context.intersect_point(point, filter, |entity, _collider| {
// Callback called on each collider with a shape containing the point.
println!("The entity {:?} contains the point.", entity);
// Return `false` instead if we want to stop searching for other colliders containing this point.
true
});
}

The resulting PointProjection also contains the index of the part of the shape the point was projected on (subshape) for shapes composed of several pieces (compound shapes, triangle meshes, etc.) Just like for ray-casting, the closure given to RapierContext::intersect_point is given the entity of each collider containing the point, as well as its Rapier collider, and can return false to stop the search.

let point = { x: 1.0, y: 2.0 };
let solid = true;

let proj = world.projectPoint(point, solid);
if (proj != null) {
// The collider closest to the point has this `handle`.
console.log("Projected point on collider ", proj.collider, ". Point projection: ", proj.point);
console.log("Point was inside of the collider shape: {}", proj.isInside);
}

world.intersectionsWithPoint(point, (handle) => {
// Callback called on each collider with a shape containing the point.
console.log("The collider", handle, "contains the point.");
// Return `false` instead if we want to stop searching for other colliders containing this point.
return true;
});
R2Vector point = r2Vector(1.0, 2.0);
R2Bool solid = 1;
R2Real max_dist = 12.0;
R2QueryOptions options = r2DefaultQueryOptions();

R2OptionalPointProjection result = r2TryProjectPoint(world, &options, point, max_dist, solid);
if (result.found) {
R2PointProjection projection = result.projection;
// The collider closest to the point has the handle `projection.collider`.
printf("Projected point on collider %u. Point projection: (%f, %f)\n", projection.collider.index,
(double)projection.point.x, (double)projection.point.y);
printf("Point was inside of the collider shape: %u\n", projection.is_inside);
}

// Get the number of colliders containing the point, then copy their handles.
size_t count = r2IntersectPoint(world, &options, point, NULL, 0);
R2ColliderHandle *handles = malloc(count * sizeof(*handles));
count = r2IntersectPoint(world, &options, point, handles, count);
for (size_t i = 0; i < count; i++) {
// Loop on each collider with a shape containing the point.
printf("The collider %u contains the point.\n", handles[i].index);
}
free(handles);

The resulting R3PointProjection (the projection field of the result) contains the handle of the collider the point was projected on, the projected point (in world-space), and whether the original point was inside of that collider (is_inside). If the point is inside of a shape, solid controls the result just like for ray-casting: with solid set to 1 the point is its own projection, whereas with solid set to 0 it is projected on the boundary of the shape. r3TryProjectPoint sets the found field of its result to 0 if no collider is closer than max_dist, whereas r3ProjectPoint reports this as the R3_NOT_FOUND error. Finally, r3IntersectPoint copies the handles of the colliders containing the point into a buffer given by the application, as described at the beginning of this page.

point = (1.0, 2.0, 3.0)
solid = True
max_dist = 12.0
query_filter = rp.QueryFilter()

query_pipeline = world.query_pipeline

projection = query_pipeline.project_point(point, solid, filter=query_filter, max_dist=max_dist)
if projection is not None:
handle, projection = projection
# The collider closest to the point has this `handle`.
print(f"Projected point on collider {handle}. Point projection: {projection.point}")
print(f"Point was inside of the collider shape: {projection.is_inside}")

def on_point_intersection(handle):
# Callback called on each collider with a shape containing the point.
print(f"The collider {handle} contains the point.")
return True # Return `False` to stop the search.

query_pipeline.intersect_point(point, on_point_intersection, filter=query_filter)

QueryPipeline.project_point returns None if no collider is closer than max_dist (which is unbounded if it isn't given), and the handle of the collider the point was projected on, together with a PointProjection, otherwise. This PointProjection contains the projected point (in world-space), and whether the original point was inside of that collider (is_inside). If the point is inside of a shape, solid controls the result just like for ray-casting: with solid set to True the point is its own projection, whereas with solid set to False it is projected on the boundary of the shape. QueryPipeline.project_point_and_get_feature also gives the FeatureId of the part of the shape (vertex, edge, or face) the point was projected on. Finally, QueryPipeline.intersect_point calls the given function with the handle of each collider containing the point, until this function returns False.

It is possible to only apply the scene query to a subsets of the colliders using a query filter