Skip to content

Commit 9971a15

Browse files
committed
Modified the controller binding to make it the Component binding
1 parent f71856f commit 9971a15

6 files changed

Lines changed: 111 additions & 79 deletions

File tree

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include <SofaPython3/Sofa/Core/Binding_Base.h>
2222
#include <SofaPython3/Sofa/Core/Binding_BaseComponent.h>
2323
#include <SofaPython3/Sofa/Core/Binding_BaseComponent_doc.h>
24-
#include <SofaPython3/Sofa/Core/Binding_Controller.h>
2524
#include <SofaPython3/PythonFactory.h>
2625

2726
#include <sofa/core/ObjectFactory.h>

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp renamed to bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Component.cpp

Lines changed: 90 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
#include <pybind11/cast.h>
2323
#include <sofa/core/visual/VisualParams.h>
2424
#include <SofaPython3/Sofa/Core/Binding_Base.h>
25-
#include <SofaPython3/Sofa/Core/Binding_Controller.h>
26-
#include <SofaPython3/Sofa/Core/Binding_Controller_doc.h>
25+
#include <SofaPython3/Sofa/Core/Binding_Component.h>
26+
#include <SofaPython3/Sofa/Core/Binding_Component_doc.h>
2727

2828
#include <SofaPython3/PythonFactory.h>
2929
#include <SofaPython3/PythonEnvironment.h>
@@ -38,20 +38,20 @@ namespace sofapython3
3838
using sofa::core::objectmodel::Event;
3939
using sofa::core::objectmodel::BaseComponent;
4040

41-
Controller_Trampoline::Controller_Trampoline() = default;
41+
Component_Trampoline::Component_Trampoline() = default;
4242

43-
Controller_Trampoline::~Controller_Trampoline()
43+
Component_Trampoline::~Component_Trampoline()
4444
{
4545
// Clean up Python objects while holding the GIL
4646
if (m_cacheInitialized)
4747
{
48-
PythonEnvironment::gil acquire {"~Controller_Trampoline"};
48+
PythonEnvironment::gil acquire {"~Component_Trampoline"};
4949
m_methodCache.clear();
5050
m_pySelf = py::object();
5151
}
5252
}
5353

54-
void Controller_Trampoline::initializePythonCache()
54+
void Component_Trampoline::initializePythonCache()
5555
{
5656
if (m_cacheInitialized)
5757
return;
@@ -65,7 +65,7 @@ void Controller_Trampoline::initializePythonCache()
6565
m_cacheInitialized = true;
6666
}
6767

68-
py::object Controller_Trampoline::getCachedMethod(const std::string& methodName)
68+
py::object Component_Trampoline::getCachedMethod(const std::string& methodName)
6969
{
7070
// Must be called with GIL held and cache initialized
7171

@@ -92,7 +92,7 @@ py::object Controller_Trampoline::getCachedMethod(const std::string& methodName)
9292
return method;
9393
}
9494

95-
bool Controller_Trampoline::callCachedMethod(const py::object& method, Event* event)
95+
bool Component_Trampoline::callCachedMethod(const py::object& method, Event* event)
9696
{
9797
// Must be called with GIL held
9898
if (f_printLog.getValue())
@@ -108,7 +108,7 @@ bool Controller_Trampoline::callCachedMethod(const py::object& method, Event* ev
108108
return py::cast<bool>(result);
109109
}
110110

111-
void Controller_Trampoline::invalidateMethodCache(const std::string& methodName)
111+
void Component_Trampoline::invalidateMethodCache(const std::string& methodName)
112112
{
113113
if (!m_cacheInitialized)
114114
return;
@@ -117,7 +117,7 @@ void Controller_Trampoline::invalidateMethodCache(const std::string& methodName)
117117
m_methodCache.erase(methodName);
118118
}
119119

120-
std::string Controller_Trampoline::getClassName() const
120+
std::string Component_Trampoline::getClassName() const
121121
{
122122
PythonEnvironment::gil acquire {"getClassName"};
123123

@@ -130,32 +130,32 @@ std::string Controller_Trampoline::getClassName() const
130130
return py::str(py::type::of(py::cast(this)).attr("__name__"));
131131
}
132132

133-
void Controller_Trampoline::draw(const sofa::core::visual::VisualParams* params)
133+
void Component_Trampoline::draw(const sofa::core::visual::VisualParams* params)
134134
{
135135
PythonEnvironment::executePython(this, [this, params](){
136-
PYBIND11_OVERLOAD(void, Controller, draw, params);
136+
PYBIND11_OVERLOAD(void, Component, draw, params);
137137
});
138138
}
139139

140-
void Controller_Trampoline::init()
140+
void Component_Trampoline::init()
141141
{
142142
PythonEnvironment::executePython(this, [this](){
143143
// Initialize the Python object cache on first init
144144
initializePythonCache();
145-
PYBIND11_OVERLOAD(void, Controller, init, );
145+
PYBIND11_OVERLOAD(void, Component, init, );
146146
});
147147
}
148148

149-
void Controller_Trampoline::reinit()
149+
void Component_Trampoline::reinit()
150150
{
151151
PythonEnvironment::executePython(this, [this](){
152-
PYBIND11_OVERLOAD(void, Controller, reinit, );
152+
PYBIND11_OVERLOAD(void, Component, reinit, );
153153
});
154154
}
155155

156156
/// If a method named "methodName" exists in the python controller,
157157
/// methodName is called, with the Event's dict as argument
158-
bool Controller_Trampoline::callScriptMethod(
158+
bool Component_Trampoline::callScriptMethod(
159159
const py::object& self, Event* event, const std::string & methodName)
160160
{
161161
if(f_printLog.getValue())
@@ -177,7 +177,7 @@ bool Controller_Trampoline::callScriptMethod(
177177
return false;
178178
}
179179

180-
void Controller_Trampoline::handleEvent(Event* event)
180+
void Component_Trampoline::handleEvent(Event* event)
181181
{
182182
PythonEnvironment::executePython(this, [this, event](){
183183
// Ensure cache is initialized (in case init() wasn't called or
@@ -204,59 +204,87 @@ void Controller_Trampoline::handleEvent(Event* event)
204204
});
205205
}
206206

207-
void moduleAddController(py::module &m) {
208-
py::class_<Controller,
209-
Controller_Trampoline,
207+
208+
209+
sofa::core::sptr<Component_Trampoline> Component_Trampoline::_init_(pybind11::args& /*args*/, pybind11::kwargs& kwargs)
210+
{
211+
auto c = sofa::core::sptr<Component_Trampoline> (new Component_Trampoline());
212+
c->f_listening.setValue(true);
213+
214+
for(auto kv : kwargs)
215+
{
216+
std::string key = py::cast<std::string>(kv.first);
217+
py::object value = py::reinterpret_borrow<py::object>(kv.second);
218+
219+
if( key == "name")
220+
c->setName(py::cast<std::string>(kv.second));
221+
try {
222+
BindingBase::SetAttr(*c, key, value);
223+
} catch (py::attribute_error& /*e*/) {
224+
/// kwargs are used to set datafields to their initial values,
225+
/// but they can also be used as simple python attributes, unrelated to SOFA.
226+
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
227+
}
228+
}
229+
return c;
230+
}
231+
232+
void Component_Trampoline::_setattr_(pybind11::object self, const std::string& s, pybind11::object value)
233+
{
234+
// If the attribute starts with "on" and the new value is callable, invalidate the cached method
235+
if (s.rfind("on", 0) == 0 && PyCallable_Check(value.ptr()))
236+
{
237+
auto* trampoline = dynamic_cast<Component_Trampoline*>(py::cast<Component*>(self));
238+
if (trampoline)
239+
{
240+
trampoline->invalidateMethodCache(s);
241+
}
242+
}
243+
244+
// Delegate to the base class __setattr__
245+
BindingBase::__setattr__(self, s, value);
246+
}
247+
248+
249+
250+
void moduleAddComponent(py::module &m) {
251+
py::class_<Component,
252+
Component_Trampoline,
210253
BaseComponent,
211-
py_shared_ptr<Controller>> f(m, "Controller",
254+
py_shared_ptr<Component>> f(m, "Component",
212255
py::dynamic_attr(),
213256
sofapython3::doc::controller::controllerClass);
214257

215-
f.def(py::init([](py::args& /*args*/, py::kwargs& kwargs)
216-
{
217-
auto c = sofa::core::sptr<Controller_Trampoline> (new Controller_Trampoline());
218-
c->f_listening.setValue(true);
219-
220-
for(auto kv : kwargs)
221-
{
222-
std::string key = py::cast<std::string>(kv.first);
223-
py::object value = py::reinterpret_borrow<py::object>(kv.second);
224-
225-
if( key == "name")
226-
c->setName(py::cast<std::string>(kv.second));
227-
try {
228-
BindingBase::SetAttr(*c, key, value);
229-
} catch (py::attribute_error& /*e*/) {
230-
/// kwargs are used to set datafields to their initial values,
231-
/// but they can also be used as simple python attributes, unrelated to SOFA.
232-
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
233-
}
234-
}
235-
return c;
236-
}));
237-
238-
f.def("init", &Controller::init);
239-
f.def("reinit", &Controller::reinit);
240-
f.def("draw", [](Controller& self, sofa::core::visual::VisualParams* params){
258+
f.def(py::init(&Component_Trampoline::_init_));
259+
f.def("__setattr__",&Component_Trampoline::_setattr_);
260+
261+
f.def("init", &Component::init);
262+
f.def("reinit", &Component::reinit);
263+
f.def("draw", [](Component& self, sofa::core::visual::VisualParams* params){
241264
self.draw(params);
242265
}, pybind11::return_value_policy::reference);
243266

244-
// Override __setattr__ to invalidate the method cache when an "on*" attribute is reassigned
245-
f.def("__setattr__", [](py::object self, const std::string& s, py::object value) {
246-
// If the attribute starts with "on" and the new value is callable, invalidate the cached method
247-
if (s.rfind("on", 0) == 0 && PyCallable_Check(value.ptr()))
248-
{
249-
auto* trampoline = dynamic_cast<Controller_Trampoline*>(py::cast<Controller*>(self));
250-
if (trampoline)
251-
{
252-
trampoline->invalidateMethodCache(s);
253-
}
254-
}
267+
}
268+
269+
void moduleAddController(py::module &m) {
270+
py::class_<Component,
271+
Component_Trampoline,
272+
BaseComponent,
273+
py_shared_ptr<Component>> f(m, "Controller",
274+
py::dynamic_attr(),
275+
sofapython3::doc::controller::controllerClass);
276+
277+
f.def(py::init(&Component_Trampoline::_init_));
278+
f.def("__setattr__",&Component_Trampoline::_setattr_);
279+
280+
f.def("init", &Component::init);
281+
f.def("reinit", &Component::reinit);
282+
f.def("draw", [](Component& self, sofa::core::visual::VisualParams* params){
283+
self.draw(params);
284+
}, pybind11::return_value_policy::reference);
255285

256-
// Delegate to the base class __setattr__
257-
BindingBase::__setattr__(self, s, value);
258-
});
259286
}
260287

261288

289+
262290
}

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h renamed to bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Component.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,30 @@
2121
#pragma once
2222

2323
#include <pybind11/pybind11.h>
24-
#include <sofa/core/behavior/BaseController.h>
25-
#include <unordered_map>
24+
#include <sofa/core/objectmodel/BaseComponent.h>
2625
#include <string>
26+
#include <unordered_map>
2727

2828
namespace sofapython3 {
2929

3030
/**
31-
* Empty controller shell that allows pybind11 to bind the init and reinit methods (since BaseController doesn't have
31+
* Empty controller shell that allows pybind11 to bind the init and reinit methods (since BaseComponent doesn't have
3232
* them)
3333
*/
34-
class Controller : public sofa::core::behavior::BaseController {
34+
class Component : public sofa::core::objectmodel::BaseComponent {
3535
public:
36-
SOFA_CLASS(Controller, sofa::core::behavior::BaseController);
36+
SOFA_CLASS(Component, sofa::core::objectmodel::BaseComponent);
3737
void init() override {};
3838
void reinit() override {};
3939
};
4040

41-
class Controller_Trampoline : public Controller
41+
class Component_Trampoline : public Component
4242
{
4343
public:
44-
SOFA_CLASS(Controller_Trampoline, Controller);
44+
SOFA_CLASS(Component_Trampoline, Component);
4545

46-
Controller_Trampoline();
47-
~Controller_Trampoline() override;
46+
Component_Trampoline();
47+
~Component_Trampoline() override;
4848

4949
void init() override;
5050
void reinit() override;
@@ -57,6 +57,9 @@ class Controller_Trampoline : public Controller
5757
/// Invalidates a specific entry in the method cache (called when a user reassigns an on* attribute)
5858
void invalidateMethodCache(const std::string& methodName);
5959

60+
static sofa::core::sptr<Component_Trampoline> _init_(pybind11::args& /*args*/, pybind11::kwargs& kwargs);
61+
static void _setattr_(pybind11::object self, const std::string& s, pybind11::object value);
62+
6063
private:
6164
/// Initializes the Python object cache (m_pySelf and method cache)
6265
void initializePythonCache();
@@ -82,6 +85,7 @@ class Controller_Trampoline : public Controller
8285
bool m_cacheInitialized = false;
8386
};
8487

88+
void moduleAddComponent(pybind11::module &m);
8589
void moduleAddController(pybind11::module &m);
8690

8791
} /// namespace sofapython3

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller_doc.h renamed to bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Component_doc.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ static auto controllerClass =
4343
4444
import Sofa.Core
4545
46-
class MyController(Sofa.Core.Controller):
46+
class MyComponent(Sofa.Core.Component):
4747
def __init__(self, *args, **kwargs):
4848
## These are needed (and the normal way to override from a python class)
49-
Sofa.Core.Controller.__init__(self, *args, **kwargs)
49+
Sofa.Core.Component.__init__(self, *args, **kwargs)
5050
print(" Python::__init__::"+str(self.name))
5151
5252
def onEvent(self, event):
@@ -59,7 +59,7 @@ static auto controllerClass =
5959
print("onAnimateBeginEvent")
6060
6161
def createScene(rootNode):
62-
controller = MyController(name="MyC")
62+
controller = MyComponent(name="MyC")
6363
rootNode.addObject(controller)
6464
return rootNode
6565
)";

bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ set(HEADER_FILES
1515
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ContactListener.h
1616
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ContactListener_doc.h
1717
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Context.h
18-
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Controller.h
19-
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Controller_doc.h
18+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Component.h
19+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Component_doc.h
2020
${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataEngine.h
2121
${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataEngine_doc.h
2222
${CMAKE_CURRENT_SOURCE_DIR}/Binding_DrawTool.h
@@ -68,7 +68,7 @@ set(SOURCE_FILES
6868
${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseContext.cpp
6969
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ContactListener.cpp
7070
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Context.cpp
71-
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Controller.cpp
71+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Component.cpp
7272
${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataEngine.cpp
7373
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataContainer.cpp
7474
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataString.cpp

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ using sofa::helper::logging::Message;
3434
#include <SofaPython3/Sofa/Core/Binding_Mass.h>
3535
#include <SofaPython3/Sofa/Core/Binding_ContactListener.h>
3636
#include <SofaPython3/Sofa/Core/Binding_Context.h>
37-
#include <SofaPython3/Sofa/Core/Binding_Controller.h>
37+
#include <SofaPython3/Sofa/Core/Binding_Component.h>
3838
#include <SofaPython3/Sofa/Core/Binding_DataEngine.h>
3939
#include <SofaPython3/Sofa/Core/Binding_ObjectFactory.h>
4040
#include <SofaPython3/Sofa/Core/Binding_LinkPath.h>
@@ -142,6 +142,7 @@ PYBIND11_MODULE(Core, core)
142142
moduleAddBaseCamera(core);
143143
moduleAddContactListener(core);
144144
moduleAddContext(core);
145+
moduleAddComponent(core);
145146
moduleAddController(core);
146147
moduleAddDataEngine(core);
147148
moduleAddForceField(core);

0 commit comments

Comments
 (0)