Skip to content

Parse category bitmask SDF element in Surface DOM#1630

Open
iche033 wants to merge 4 commits intomainfrom
iche033/category_bitmask
Open

Parse category bitmask SDF element in Surface DOM#1630
iche033 wants to merge 4 commits intomainfrom
iche033/category_bitmask

Conversation

@iche033
Copy link
Contributor

@iche033 iche033 commented Feb 18, 2026

🎉 New feature

Summary

Parses the category_bitmask SDF element:
https://sdformat.org/spec/1.12/collision/#contact_category_bitmask

In short, collision occurs if (category_bitmask1 & collide_bitmask2) | (category_bitmask2 & collide_bitmask1)
evaluates to non-zero.

Currently in gazebo, collision occurs if (collide_bitmask1 & collide_bitmask2) evaluates to non-zero. To preserve backward compatibility, here's a proposed implementation (to be implemented in gz-physics):

  • if collide_bitmask is set and category_bitmask is not set, then category_bitmask is set to the same value as collide_bitmask

Example 1: collide_bitmask is set but category_bitmask is not for both collision entities (existing behavior in gz-physics):

  • entity1:
    • collide_bitmask1: 0x1
    • category_bitmask1: (not set, so defaults to 0x1 )
  • entity2:
    • collide_bitmask2: 0x2
    • category_bitmask2: (not set, so defaults to 0x2 )
      Result of (category_bitmask1 & collide_bitmask2) | (category_bitmask2 & collide_bitmask1): No collision. Preserves existing behavior.

Example 2: collide_bitmask and category_bitmask are set for both collision entities

  • entity1:
    • collide_bitmask1: 0x1
    • category_bitmask1:0x2
  • entity2:
    • collide_bitmask2: 0x2
    • category_bitmask2: 0x1
      Result of (category_bitmask1 & collide_bitmask2) | (category_bitmask2 & collide_bitmask1): Collision occurs!

Example 3: collide_bitmask and category_bitmask are set for one collision entity while only collide_bitmask is set for the other collision entity

  • entity1:
    • collide_bitmask1: 0x1
    • category_bitmask1: (not set, so defaults to 0x1)
  • entity2:
    • collide_bitmask2: 0x2
    • category_bitmask2: 0x1
      Result of (category_bitmask1 & collide_bitmask2) | (category_bitmask2 & collide_bitmask1): Collision occurs!

The category bitmask field in Surface DOM uses std::optional type so we are able to know if the value is set or not.

Checklist

  • Signed all commits for DCO
  • Added a screen capture or video to the PR description that demonstrates the feature
  • Added tests
  • Added example and/or tutorial
  • Updated documentation (as needed)
  • Updated migration guide (as needed)
  • Consider updating Python bindings (if the library has them)
  • codecheck passed (See contributing)
  • All tests passed (See test coverage)
  • Updated Bazel files (if adding new files). Created an issue otherwise.
  • While waiting for a review on your PR, please help review another open pull request to support the maintainers
  • Was GenAI used to generate this PR? If so, make sure to add "Generated-by" to your commits. (See this policy for more info.)

Generated-by: Remove this if GenAI was not used.

Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining Signed-off-by and Generated-by messages.

Backports: If this is a backport, please use Rebase and Merge instead.

Signed-off-by: Ian Chen <ichen@openrobotics.org>
Signed-off-by: Ian Chen <ichen@openrobotics.org>
Copy link
Collaborator

@ahcorde ahcorde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor fix, Otherwise LGTM

@github-project-automation github-project-automation bot moved this from Inbox to In review in Core development Feb 19, 2026
Signed-off-by: Ian Chen <ichen@openrobotics.org>

/// \brief Get the category bitmask parameter.
/// \return The category bitmask parameter.
public: std::optional<uint16_t> CategoryBitmask() const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make sense to return a const reference?

Suggested change
public: std::optional<uint16_t> CategoryBitmask() const;
public: const std::optional<uint16_t> &CategoryBitmask() const;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after doing some reading online and asking AI, it seems that for simple primitive types like uint16_t it's more efficient to just return by value, i.e.std::optional<uint16_t> instead of const ref.

I do see some places in sdformat that returns const std::optional & (there are also other places that just return by value), e.g.

public: const std::optional<bool> &IsStatic() const;

so I'm ok to match the style for consistency or clarity reasons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CPP core guideline F.15 suggests preferring simple and conventional ways of passing information, and the example indicate returning by value rather than a const reference. In the case where data is expensive to move, it recommends passing an input/output reference to the function

so I think you can ignore my earlier suggestion and keep it as is

I remember seeing lint warnings recommending more use of const references and I took it a little farther than necessary

@scpeters
Copy link
Member

oh I just remembered, consider updating the python bindings

Signed-off-by: Ian Chen <ichen@openrobotics.org>
@iche033
Copy link
Contributor Author

iche033 commented Feb 26, 2026

oh I just remembered, consider updating the python bindings

ah yes, thanks for the reminder. Just added. a1bbbb4

@iche033 iche033 requested a review from ahcorde February 26, 2026 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

3 participants