Drake
CollisionFilterManager Class Reference

Detailed Description

Class for configuring "collision filters"; collision filters limit the scope of various proximity queries.

The sole source of CollisionFilterManager instances is SceneGraph. See SceneGraph's documentation for details on acquiring an instance.

A SceneGraph instance contains the set of geometry G = D ⋃ A = {g₀, g₁, ..., gₙ}, where D is the set of dynamic geometries and A is the set of anchored geometries (by definition D ⋂ A = ∅). Gₚ ⊂ G is the subset of geometries that have a proximity role (with an analogous interpretation of Dₚ and Aₚ). Many proximity queries operate on pairs of geometries (e.g., (gᵢ, gⱼ)). The set of proximity candidate pairs for such queries is initially defined as C = (Gₚ × Gₚ) - (Aₚ × Aₚ) - Fₚ - Iₚ, where:

  • Gₚ × Gₚ = {(gᵢ, gⱼ)}, ∀ gᵢ, gⱼ ∈ Gₚ is the Cartesian product of the set of SceneGraph proximity geometries.
  • Aₚ × Aₚ represents all pairs consisting only of anchored geometries; an anchored geometry is never tested against another anchored geometry.
  • Fₚ = {(gᵢ, gⱼ)} ∀ i, j, such that gᵢ, gⱼ ∈ Dₚ and frame(gᵢ) == frame(gⱼ); the pairs where both geometries are rigidly affixed to the same frame.
  • Iₚ = {(g, g)}, ∀ g ∈ Gₚ is the set of all pairs consisting of a geometry with itself; there is no meaningful proximity query on a geometry with itself.

Only pairs contained in C will be included in pairwise proximity operations.

The manager provides an interface to modify the set C. Changes to C are articulated with CollisionFilterDeclaration. Once a change has been declared it is applied via the manager's API to change the configuration of C.

There are limits to how C can be modified.

  • ∀ (gᵢ, gⱼ) ∈ C, both gᵢ and gⱼ must be registered with SceneGraph; you can't inject arbitrary ids. Attempting to do so will result in an error.
  • No pairs in Aₚ × Aₚ, Fₚ, or Iₚ can ever be added to C. Excluding those pairs is a SceneGraph invariant. Attempts to do so will be ignored.

The current configuration of C depends on the sequence of filter declarations that have been applied in the manager. Changing the order can change the end result.

A CollisionFilterManager is a view into geometry data (either that owned by a SceneGraph instance or a SceneGraph context). The manager instance can be copied or moved and the resulting instance is a view into the same data. For both the original and the copy (or just the target when moving the manager), the source data must stay alive for at least as long as the manager instance.

Warning
The effect of applying a declaration is based on the state of SceneGraph's geometry data at the time of application. More concretely:
  • For a particular FrameId in a GeometrySet instance, only those geometries attached to the identified frame with the proximity role assigned at the time of the call will be included in the filter. If geometries are subsequently added or assigned the proximity role, they will not be retroactively added to the user-declared filter.
  • If the geometry set in a declaration statement includes geometries which have not been assigned a proximity role, those geometries will be ignored. If a proximity role is subsequently assigned, those geometries will still not be part of any user-declared collision filters.
  • In general, adding collisions and assigning proximity roles should happen prior to collision filter configuration.

Transient vs Persistent changes

Collision filtering is all about defining which geometry pairs are in the set C. The simplest way to modify the set C is through persistent modifications to a "base configuration" (via calls to Apply()). However, declarations can also be applied in a transient manner. Transient declarations form a history. The current definition of the set C is the result of applying the history of collision filter declarations to the persistent base configuration in order. That history can be modified:

  • New transient declarations can be appended.
  • Arbitrary transient declarations can be removed from the sequence.
  • The current configuration (based on a history with an arbitrary number of transient declarations) can be "flattened" into the persistent base (with no history).

The table below illustrates a sequence of operations and their effect on C. We define C's initial configuration as C = {P₁, P₂, ..., Pₙ} (for n geometry pairs). Each action is described as either persistent or transient.

Line C Action
1 {P₁, P₂, ..., Pₙ} Initial condition of the persistent base
2 {P₂, ..., Pₙ} Remove P₁ from the persistent base
3 {P₂, ..., Pₙ₋₁} Remove Pₙ from the persistent base
4 {P₂} Remove all pairs except P₂ from the persistent base
5 {P₂, P₄, P₅} Transient declaration #1 puts P₄ and P₅ into C
6 {P₂, P₃, P₄, P₅} Transient declaration #2 puts P₃ and P₄ into C
7 {P₂, P₃, P₄} Remove declaration #1.
8 {P₂, P₃, P₄} Configuration flattened; #2 no longer exists

Table 1: An example sequence of operations on collision filters.

Notes:

  • lines 2 - 4 represent a series of persistent operations, filtering pairs of geometry (aka removing them from C by calling Apply()).
  • line 5: the first transient filter declaration which is assigned the id value #1 (via a call to ApplyTransient()).
  • line 6: Adds a new transient filter declaration to the sequence (assigned id #2). Note, that it redundantly declares that P₄ is a member of C just as declaration #1 did. This redundancy is fine. In fact, it may be very important (see below).
  • line 7: We remove declaration #1. Although #1 added both P₄ and P₅ to C, the result of removing this declaration from the sequence is that P₅ is no longer a member of C but P₄ is. This is because #2's declaration that P₄ is* in C preserves its membership.
  • line 8: the current configuration is "flattened" into the persistent base. All history is thrown out and any filter identifiers are rendered invalid.

This example workflow above illustrates some key ideas in using transient declarations.

  • The persistent configuration can only be modified when there is no transient history. Applying a filter declaration should have the effect of realizing that declaration. If a pair is declared to be in C, the result of the declaration is that the pair is in C (assuming that the pair can* be in C). If we allowed modifying the persistent configuration with an active transient history, there might be no discernable change in the resultant configuration state because a subsequent transient declaration may supplant it. This would lead to inscrutable bugs. Therefore, it's simply not allowed.
  • When defining a transient declaration, the declaration should include all critical pairs explicitly. This includes those pairs that should and should not be in C. Any pair not explicitly accounted for should be one whose filter status is immaterial. It might seems desirable (from an optimization perspective) to examine the current configuration of C and apply the minimum change to put it into a desired state (i.e., if a pair I need filtered is already filtered, I would omit it from the declaration). This approach is fraught with peril. If the current configuration is the result of previous transient declarations, the removal of any of those declarations could invalidate the attempted difference calculation and my declaration would no longer be sufficient to guarantee the set C required.
  • Anyone at any time can add to the history. Some code can modify C to suit its needs. However, it can also make subsequent calls into code that also modifies C with no guarantees that the called code will undo those changes. Code that modifies collision filters configuration should document that it does so. It should also have a clear protocol for cleaning up its own changes. Finally, code that applies declarations should not take for granted that its transient declarations are necessarily the last declarations in the history.

Making transient filter declarations

There is a custom API for applying a filter declaration as a transient declaration. It returns the id for the transient API (used to remove the declaration from the history sequence).

Attempting to change the persistent configuration when there are active transient declarations in the history will throw an exception.

#include <drake/geometry/collision_filter_manager.h>

Public Member Functions

void Apply (const CollisionFilterDeclaration &declaration)
 Applies the given declaration to the geometry state managed by this instance. More...
 
FilterId ApplyTransient (const CollisionFilterDeclaration &declaration)
 Applies the declaration as the newest transient modification to the collision filter configuration. More...
 
bool RemoveDeclaration (FilterId filter_id)
 Attempts to remove the transient declaration from the history for the declaration associated with the given filter_id. More...
 
bool has_transient_history () const
 Reports if there are any active transient filter declarations. More...
 
bool IsActive (FilterId filter_id) const
 Reports if the transient collision filter declaration indicated by the given filter_id is part of the history. More...
 
Implements CopyConstructible, CopyAssignable, MoveConstructible, MoveAssignable
 CollisionFilterManager (const CollisionFilterManager &)=default
 
CollisionFilterManageroperator= (const CollisionFilterManager &)=default
 
 CollisionFilterManager (CollisionFilterManager &&)=default
 
CollisionFilterManageroperator= (CollisionFilterManager &&)=default
 

Friends

template<typename >
class GeometryState
 

Constructor & Destructor Documentation

◆ CollisionFilterManager() [1/2]

◆ CollisionFilterManager() [2/2]

Member Function Documentation

◆ Apply()

void Apply ( const CollisionFilterDeclaration declaration)

Applies the given declaration to the geometry state managed by this instance.

The process of applying the collision filter data also validates it. The following polices are implemented during application:

  • Referencing an invalid id (FrameId or GeometryId): throws.
  • Declaring a filtered pair that is already filtered: no discernible change.
  • Attempts to "allow" collision between a pair that is strictly excluded (e.g., between two anchored geometries) will be ignored.
Exceptions
std::exceptionif the declaration references invalid ids or there is an active history.

◆ ApplyTransient()

FilterId ApplyTransient ( const CollisionFilterDeclaration declaration)

Applies the declaration as the newest transient modification to the collision filter configuration.

The declaration must be considered "valid", as defined for Apply().

◆ has_transient_history()

bool has_transient_history ( ) const

Reports if there are any active transient filter declarations.

◆ IsActive()

bool IsActive ( FilterId  filter_id) const

Reports if the transient collision filter declaration indicated by the given filter_id is part of the history.

◆ operator=() [1/2]

CollisionFilterManager& operator= ( CollisionFilterManager &&  )
default

◆ operator=() [2/2]

CollisionFilterManager& operator= ( const CollisionFilterManager )
default

◆ RemoveDeclaration()

bool RemoveDeclaration ( FilterId  filter_id)

Attempts to remove the transient declaration from the history for the declaration associated with the given filter_id.

Parameters
filter_idThe id of the filter declaration to remove.
Returns
true iff is_active(filter_id) returns true before calling this method (i.e., filter_id refers to an existent filter that has successfully been removed).

Friends And Related Function Documentation

◆ GeometryState

friend class GeometryState
friend

The documentation for this class was generated from the following file: