Skip to content

Commit 1641256

Browse files
authored
[Bindings] Utility bindings for ContactListener and Simulation (#221)
* Added ContactListener bindings and utility bindings. Added step function to simualation to animate n steps in one call. * Changed function name for coherency between the C++ function and the python binding.
1 parent 6ad5a84 commit 1641256

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ContactListener.cpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,67 @@ using sofa::core::collision::ContactListener;
3939
namespace sofapython3
4040
{
4141

42+
pybind11::dict getContactData(const ContactListener& listener){
43+
pybind11::dict contactData;
44+
const sofa::Size numberOfContacts = listener.getNumberOfContacts();
45+
contactData["numberOfContacts"] = numberOfContacts;
46+
47+
const std::vector<std::tuple<unsigned int, unsigned int, unsigned int, unsigned int>> contactElements = listener.getContactElements();
48+
const std::vector<std::tuple<unsigned int, sofa::type::Vector3, unsigned int, sofa::type::Vector3>> contactPoints = listener.getContactPoints();
49+
50+
std::vector<unsigned int> collisionElementsModel1;
51+
std::vector<unsigned int> collisionElementsModel2;
52+
collisionElementsModel1.reserve(numberOfContacts);
53+
collisionElementsModel2.reserve(numberOfContacts);
54+
55+
std::vector<sofa::type::Vector3> collisionPointsModel1;
56+
std::vector<sofa::type::Vector3> collisionPointsModel2;
57+
collisionPointsModel1.reserve(numberOfContacts);
58+
collisionPointsModel2.reserve(numberOfContacts);
59+
60+
for (unsigned int i = 0; i < numberOfContacts; i++){
61+
62+
if(std::get<0>(contactElements[i]) == 0){
63+
collisionElementsModel1.emplace_back(std::get<1>(contactElements[i]));
64+
collisionElementsModel2.emplace_back(std::get<3>(contactElements[i]));
65+
}
66+
else{
67+
collisionElementsModel1.emplace_back(std::get<3>(contactElements[i]));
68+
collisionElementsModel2.emplace_back(std::get<1>(contactElements[i]));
69+
}
70+
71+
if(std::get<0>(contactPoints[i]) == 0){
72+
collisionPointsModel1.emplace_back(std::get<1>(contactPoints[i]));
73+
collisionPointsModel2.emplace_back(std::get<3>(contactPoints[i]));
74+
}
75+
else{
76+
collisionPointsModel1.emplace_back(std::get<3>(contactPoints[i]));
77+
collisionPointsModel2.emplace_back(std::get<1>(contactPoints[i]));
78+
}
79+
}
80+
81+
contactData["collisionPointsModel1"] = collisionPointsModel1;
82+
contactData["collisionPointsModel2"] = collisionPointsModel2;
83+
84+
contactData["collisionElementsModel1"] = collisionElementsModel1;
85+
contactData["collisionElementsModel2"]= collisionElementsModel2;
86+
87+
return contactData;
88+
}
89+
90+
4291
void moduleAddContactListener(pybind11::module &m)
4392
{
4493
/// register the ContactListener binding in the pybind11 typing sytem
4594
pybind11::class_<ContactListener,
4695
sofa::core::objectmodel::BaseObject,
4796
py_shared_ptr<ContactListener>> c(m, "ContactListener", sofapython3::doc::contactListener::contactListenerClass);
4897

49-
/// Commented out until feature is in SOFA master
50-
/* c.def("getNumberOfContacts", &ContactListener::getNumberOfContacts); */
98+
c.def("getNumberOfContacts", &ContactListener::getNumberOfContacts);
99+
c.def("getContactData", &getContactData);
100+
c.def("getDistances", &sofa::core::collision::ContactListener::getDistances);
101+
c.def("getContactPoints", &sofa::core::collision::ContactListener::getContactPoints);
102+
c.def("getContactElements", &sofa::core::collision::ContactListener::getContactElements);
51103

52104
/// register the ContactListener binding in the downcasting subsystem
53105
PythonFactory::registerType<ContactListener>([](sofa::core::objectmodel::Base* object)

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ContactListener_doc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static auto contactListenerClass =
4343
collisionModel2=model2.getLinkPath(),
4444
)
4545
print(listener.getNumberOfContacts())
46+
print(listener.getDistances())
4647
)";
4748

4849
} // namespace sofapython3::doc::contactListener

bindings/Sofa/src/SofaPython3/Sofa/Simulation/Submodule_Simulation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ PYBIND11_MODULE(Simulation, simulation)
6969
return node ? py::cast(node.get()) : py::none();
7070
}, sofapython3::doc::simulation::load);
7171
simulation.def("unload", [](Node* n){ sofa::simulation::getSimulation()->unload(n); }, sofapython3::doc::simulation::unload);
72+
simulation.def("animateNSteps", [](Node *n, int n_steps, SReal dt=0.0){
73+
for (int i = 0; i < n_steps; i++)
74+
{
75+
sofa::simulation::getSimulation()->animate(n, dt); //Execute one timestep. If dt is 0, the dt parameter in the graph will be used
76+
}
77+
}, sofapython3::doc::simulation::animateNSteps, py::arg("root_node"), py::arg("n_steps") = 1, py::arg("dt") = 0.0);
7278
simulation.def("updateVisual", [](Node* n){ sofa::simulation::getSimulation()->updateVisual(n); });
7379
simulation.def("initTextures", [](Node* n)
7480
{

bindings/Sofa/src/SofaPython3/Sofa/Simulation/Submodule_Simulation_doc.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static auto Class =
5151
Sofa.Simulation.reset
5252
Sofa.Simulation.load
5353
Sofa.Simulation.unload
54+
Sofa.Simulation.animateNSteps
5455
)";
5556
static auto print =
5657
R"(
@@ -85,4 +86,12 @@ static auto unload =
8586
R"(
8687
Unload a scene from a Node.
8788
)";
89+
90+
static auto animateNSteps =
91+
R"(
92+
Advance the simulation by one time step (by default).
93+
94+
n_steps: specifies number of steps to advance the simulation by. The simulation visual is not updated between steps. Default is 1.
95+
dt: specifies the time delta between two simulation steps. Default is 0 -> uses the dt from the simulation node.
96+
)";
8897
}

0 commit comments

Comments
 (0)