-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CollisionGroup class and refactoring of CollisionDetector #631
Conversation
… existing code base
Conflicts: dart/constraint/ConstraintSolver.cpp dart/constraint/ConstraintSolver.h dart/utils/SkelParser.cpp
…ects that sharing dart::Shape
… same associated object -- not completed yet
…shapenode Conflicts: apps/rigidShapes/Main.cpp dart/collision/bullet/BulletCollisionDetector.cpp dart/collision/bullet/BulletCollisionNode.cpp dart/collision/bullet/BulletCollisionObjectData.h dart/collision/dart/DARTCollisionDetector.cpp dart/collision/fcl/FCLCollisionDetector.cpp dart/collision/fcl/FCLCollisionNode.cpp dart/collision/fcl/FCLCollisionObjectData.h dart/collision/fcl_mesh/FCLMeshCollisionNode.cpp dart/utils/SkelParser.cpp dart/utils/sdf/SoftSdfParser.cpp tutorials/tutorialBiped-Finished.cpp tutorials/tutorialBiped.cpp unittests/testConstraint.cpp
Out of curiosity, is there a particular motivation for making the |
I'm not clear on what the purpose of this would be. Does a But if we do decide that we need a special type of smart pointer for |
The motivation behind this pull request is to resolve the circular dependencies of
This would be the natural result of the separation, but this is not the main reason. |
I can understand why |
It is only valid to use a I do remember concluding that the ownership needs to be coupled, but now I can't recall why. Hopefully @jslee02 can remind us. 😓 |
I don't see a problem with having |
…ee the comment for the detail)
…stance() method in the future
public: | ||
|
||
friend class FCLCollisionDetector; | ||
friend class BulletCollisionDetector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually a bit concerned about the fact that CollisionGroup
needs to declare each collision detector engine as a friend, because this makes it impossible for a user to implement and integrate their own collision detector without modifying the definition of CollisionGroup
, and that strikes me as problematic.
I understand the desire to hide engine-related functions from the casual users, but I think we need a way to do that which doesn't prevent advanced users from plugging in their own engines. If I can think of a good way to do this, I'll post an update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make any sense to try to put the advanced methods into a member class that CollisionGroup creates as needed?
Something like:
class CollisionGroup
{
[...]
public:
CollisionGroupExtension advanced() {
return CollisionGroupExtension(this); // has advanced methods on it, is not assignable etc.
}
};
CollisionGroupPtr group;
group->advanced().adv_function();
You guys are the experts here, but it seems like it might be constructable in a way that it would be compiled out in Release
mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a good point. One simple solution I can come up with now is declaring the protected function of CollisionGroup
in each concrete collision group class (e.g., FCLCollisionGroup
) as using CollisionGroup::updateEngineData
. Then FCLCollisionDetector
could be able to call the function by downcasting collision group to FCLCollisionGroup
.
I'm not sure if this is a scalable way to resolve this kind of problem, though.
@psigen 's idea looks good for simple classes, but I think it would need careful implementation for classes with more than one class inheritances that usually introduce code complexity. We can consider using these methods once this issue becomes more general over the code base.
CollisionDetector(); | ||
/// Create CollisionObject | ||
virtual std::unique_ptr<CollisionObject> createCollisionObject( | ||
const dynamics::ShapeFrame* shapeFrame) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason that we create these as a unique_ptr
when it seems as though we always end up converting them into a shared_ptr
? Is this to make it impossible to jumble up claimCollisionObject(~)
with createCollisionObject(~)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The main motivation behind this is to make CollisionDetector
create single CollisionObject
per ShapeFrame
using RAII.
claimCollisionObject(~)
returns std::shared_ptr<CollisionObject>
. The returning pointer is either of one created from createCollisionObject
if it's not created for the passed in ShapeFrame
or one already created for the ShapeFrame
. The management of the uniquess of CollisionObject
per ShapeFrame
is done using std::map<ShapeFrame*, std::weak_ptr<CollisionObject>
in CollisionDetector
(more precisely, in CollisionDetector::SharingCollisionObjectManager
). The CollisionObject
should be removed from the map when it's not shared by any CollisionObject
. However, the thing is std::shared_ptr<CollisionObject>
will be automatically destructed when it's not referenced by any CollisionGroup
(as the map holds CollisionObject
as weak pointer), but CollisionDetector
doesn't know when it's happening.
To handle this, a custom deleter of shared pointer is used where it removes CollisionObject
from the map before it deletes CollisionObject
. I could make createCollisionObject
create shared_ptr
with the custom deleter by passing it from CollisionDetector
to each concrete collision detector, but also wondered if it's a good practice. To me, it seemed the management of collision object management should be totally the responsibility of CollisionDetector
and the each collision detector just should create the concrete collision object (e.g., FCLCollisionObject
).
I'm open to hearing better solution here.
I'm under the impression that
Mostly I think "NoneSharing" makes for an awkward class name, so I'd like to change that if we can. |
/// \brief | ||
size_t mIndex; | ||
bool isAdjacentBodies(const dynamics::BodyNode* bodyNode1, | ||
const dynamics::BodyNode* bodyNode2) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of a minor grammatical thing, but should we name the function areAdjacentBodies
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Conflicts: dart/collision/CollisionObject.h dart/collision/bullet/BulletCollisionNode.cpp
Yes, exactly. I like the new names. To me, the pair of |
Overall, I think this pull request introduces a much needed renovation of the I do have a few comments for moving forward. These certainly don't need to be addressed in this pull request, but it's something to think about (we can open issues for them later):
|
Conflicts: dart/utils/sdf/SdfParser.cpp
👍 Great work @jslee02! I am very happy with how the API turned out.
I am conflicted about this: this adds a lot of complexity and may not always have the desired effect. I'd prefer to keep Of the two options, I slightly prefer option (i) for two reasons. First, creating a CollisionObject may be expensive. It is undesirable to constantly create and delete CollisionObjects when modifying the kinematic tree. Second, signals and slots makes it much harder to reason about control flow.
I agree. This is a problem far beyond the What is the motivation/use case for having |
This sounds like a good plan to me.
These are very good points. If we're going to implement it with wrapper classes, then we could offer a wrapper for each approach if we can't make a decision between the two. But your points do make me lean more towards (i) now.
What it boils down to is the fact that The I'm open to the idea of being able to move In any case, we can move this conversation to an issue if everyone is okay with merging this pull request. |
This pull request introduces collision group feature with CollisionDetector refactoring.
An overview of the changes is:
CollisionGroup
class is added. Collision detector used to containe collision objects in it and only could check collisions for the objects. So we couldn't be able to check collisions for arbitrary (distict) collision objects.CollisionGroup
now plays the roll of collision object container, and collision detector can check collisions for object-object, object-group, and group-group.collision
is now only dependent onShape
class. So once we moveShape
and the derived classes tocommon
ormath
namespaces thencollision
would be completely independent on 'dynamics' namespace.FCLCollisionDetector
now takes the advantage of broad phase collision detectorion of FCL to avoid checking all pairs of objects.This pull request is not completed yet. The major issue remained is the ownership between
CollisionDetector
andCollisionObject
. I'm considering apply the same mechanism of the customized shared pointerBodyNodePtr
by making it general to be able to be used forCollisionObject
.Note that this pull request includes the changes of #608 .