Skip to content

Conversation

@adamkewley
Copy link
Contributor

@adamkewley adamkewley commented Oct 27, 2025

Fixes issue N/A

This PR adds Component::extractComponent and Component::removeComponent to the Component API.

Abstractly, the motivation for doing this is that the Component API currently only supports adding generic components via Component::addComponent but has no generic way to remove components added via that method. Therefore, if downstream code wants to use Component as a composite type (presumably intended, given the API design), that code can only use it to build trees, but can't easily edit or manipulate a built one.

Concretely, OpenSim Creator has been patching opensim-core downstream with this diff so that it can provide some basic support for deleting things from an OpenSim model (link).

The extractComponent variant allows the caller to take ownership of an object in a Component's ComponentSet. This is useful for (e.g.) moving a subcomponent from one owner to another one. OpenSim Creator uses it to support moving markers from bodies to the model's markerset at runtime (link) but it could be used, in principle, to move any subcomponent (i.e. stuff in the generic ComponentSet) from any owner to any other one.

Brief summary of changes

  • Adds Component::removeComponent and Component::extractComponent
  • Adds basic functionality tests
  • Adds Property<T>::extractComponent to the Property API, which is required because the <components> (ComponentSet) field of a Component is stored as a Property.
  • Reactors Property<T>::removeComponent to internally use extractComponent: it has the same side-effect (removal of the component) but assumes the caller wants to immediately drop the component
  • BREAKING: removes Property<T>::removeComponentVirtual and replaces it with Property<T>::extractComponentVirtual. The side-effects are the same (component removal) but the extraction method also ensures that the caller can get access to the thing that was removed. This has a small penalty (of allocation, in the simple property case), but property removal is rare (only one usage in opensim-core) and will not be part of a simulation hot loop. It is unlikely that downstream code implements its own Property<T> specialization.

Testing I've completed

  • Used in OpenSim Creator for a few months
  • Unit tests, provided in this diff
  • Unit tests in OpenSim Creator

Looking for feedback on...

CHANGELOG.md (choose one)

  • updated.

This change is Reviewable

@adamkewley
Copy link
Contributor Author

This is ready for review, perhaps @nickbianco ?

Copy link
Member

@nickbianco nickbianco left a comment

Choose a reason for hiding this comment

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

LGTM. Nice work @adamkewley, these will be super useful going forward.

I had one minor comment, but it's not blocking.

std::unique_ptr<T> extractValueAtIndexVirtual(int index) override
{
SimTK::ClonePtr<T>* p = &objects.at(index);
std::unique_ptr<T> extracted{p->release()};
Copy link
Member

Choose a reason for hiding this comment

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

You use SimTK::ClonePtr here, but not in the implementation in SimpleProperty. I'm 99% sure that's because there's no reason to use SimTK::ClonePtr for simple property types, but just double checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The storage for an ObjectProperty is Array<ClonePtr<ObjectProperty>> whereas the storage for a SimpleProperty is Array<T>, so the SimpleProperty version needs to heap-allocate in order to satisfy the uniform API of the function returning unique_ptr<T>.

The reason it returns unique_ptr<T> is so that the interface is uniform for all Ts:

extractProperty<ContactGeometry>
extractProperty<int>

etc.

Copy link
Member

Choose a reason for hiding this comment

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

Ah yes, I was looking at this backwards. Thanks for the clarification.

@nickbianco nickbianco merged commit 26a06b2 into main Oct 31, 2025
10 checks passed
@nickbianco nickbianco deleted the feature_remove-or-extract-components-from-component branch October 31, 2025 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants