Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 79 additions & 71 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,88 +35,96 @@ namespace py { using namespace pybind11; }

namespace sofapython3
{
using sofa::core::objectmodel::Event;
using sofa::core::objectmodel::BaseObject;
using sofa::core::objectmodel::Event;
using sofa::core::objectmodel::BaseObject;

void Controller_Trampoline::init()
{
PythonEnvironment::gil acquire {"Controller_init"};
PYBIND11_OVERLOAD(void, Controller, init, );
}
std::string Controller_Trampoline::getClassName() const
{
PythonEnvironment::gil acquire {"getClassName"};

void Controller_Trampoline::reinit()
{
PythonEnvironment::gil acquire {"Controller_reinit"};
PYBIND11_OVERLOAD(void, Controller, reinit, );
}
// Get the actual class name from python.
return py::str(py::cast(this).get_type().attr("__name__"));
}

void Controller_Trampoline::init()
{
PythonEnvironment::gil acquire {"Controller_init"};
PYBIND11_OVERLOAD(void, Controller, init, );
}

void Controller_Trampoline::reinit()
{
PythonEnvironment::gil acquire {"Controller_reinit"};
PYBIND11_OVERLOAD(void, Controller, reinit, );
}


/// If a method named "methodName" exists in the python controller,
/// methodName is called, with the Event's dict as argument
void Controller_Trampoline::callScriptMethod(
const py::object& self, Event* event, const std::string & methodName)
/// If a method named "methodName" exists in the python controller,
/// methodName is called, with the Event's dict as argument
void Controller_Trampoline::callScriptMethod(
const py::object& self, Event* event, const std::string & methodName)
{
if( py::hasattr(self, methodName.c_str()) )
{
if( py::hasattr(self, methodName.c_str()) )
{
py::object fct = self.attr(methodName.c_str());
fct(PythonFactory::toPython(event));
}
py::object fct = self.attr(methodName.c_str());
fct(PythonFactory::toPython(event));
}
}

void Controller_Trampoline::handleEvent(Event* event)
{
PythonEnvironment::gil acquire {"Controller_handleEvent"};

void Controller_Trampoline::handleEvent(Event* event)
py::object self = py::cast(this);
std::string name = std::string("on")+event->getClassName();
/// Is there a method with this name in the class ?
if( py::hasattr(self, name.c_str()) )
{
PythonEnvironment::gil acquire {"Controller_handleEvent"};

py::object self = py::cast(this);
std::string name = std::string("on")+event->getClassName();
/// Is there a method with this name in the class ?
if( py::hasattr(self, name.c_str()) )
{
py::object fct = self.attr(name.c_str());
if (PyCallable_Check(fct.ptr())) {
callScriptMethod(self, event, name);
return;
}
py::object fct = self.attr(name.c_str());
if (PyCallable_Check(fct.ptr())) {
callScriptMethod(self, event, name);
return;
}

/// Is the fallback method available.
callScriptMethod(self, event, "onEvent");
}

void moduleAddController(py::module &m) {
py::class_<Controller,
Controller_Trampoline,
BaseObject,
py_shared_ptr<Controller>> f(m, "Controller",
py::dynamic_attr(),
sofapython3::doc::controller::Controller);

f.def(py::init([](py::args& /*args*/, py::kwargs& kwargs)
{
auto c = sofa::core::sptr<Controller_Trampoline> (new Controller_Trampoline());
c->f_listening.setValue(true);

for(auto kv : kwargs)
{
std::string key = py::cast<std::string>(kv.first);
py::object value = py::reinterpret_borrow<py::object>(kv.second);

if( key == "name")
c->setName(py::cast<std::string>(kv.second));
try {
BindingBase::SetAttr(*c, key, value);
} catch (py::attribute_error& /*e*/) {
/// kwargs are used to set datafields to their initial values,
/// but they can also be used as simple python attributes, unrelated to SOFA.
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
}
}
return c;
}));

f.def("init", &Controller::init);
f.def("reinit", &Controller::reinit);
}
/// Is the fallback method available.
callScriptMethod(self, event, "onEvent");
}

void moduleAddController(py::module &m) {
py::class_<Controller,
Controller_Trampoline,
BaseObject,
py_shared_ptr<Controller>> f(m, "Controller",
py::dynamic_attr(),
sofapython3::doc::controller::Controller);

f.def(py::init([](py::args& /*args*/, py::kwargs& kwargs)
{
auto c = sofa::core::sptr<Controller_Trampoline> (new Controller_Trampoline());
c->f_listening.setValue(true);

for(auto kv : kwargs)
{
std::string key = py::cast<std::string>(kv.first);
py::object value = py::reinterpret_borrow<py::object>(kv.second);

if( key == "name")
c->setName(py::cast<std::string>(kv.second));
try {
BindingBase::SetAttr(*c, key, value);
} catch (py::attribute_error& /*e*/) {
/// kwargs are used to set datafields to their initial values,
/// but they can also be used as simple python attributes, unrelated to SOFA.
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
}
}
return c;
}));

f.def("init", &Controller::init);
f.def("reinit", &Controller::reinit);
}


}
2 changes: 2 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class Controller_Trampoline : public Controller
void reinit() override;
void handleEvent(sofa::core::objectmodel::Event* event) override;

std::string getClassName() const override;

private:
void callScriptMethod(const pybind11::object& self, sofa::core::objectmodel::Event* event,
const std::string& methodName);
Expand Down
112 changes: 60 additions & 52 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_DataEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,67 +34,75 @@ namespace py { using namespace pybind11; }

namespace sofapython3
{
using sofa::core::objectmodel::Event;
using sofa::core::DataEngine;
using sofa::core::objectmodel::BaseData;
using sofa::core::objectmodel::BaseObject;
using sofa::core::objectmodel::DDGNode;
using sofa::core::objectmodel::Event;
using sofa::core::DataEngine;
using sofa::core::objectmodel::BaseData;
using sofa::core::objectmodel::BaseObject;
using sofa::core::objectmodel::DDGNode;

void DataEngine_Trampoline::init()
{
PythonEnvironment::gil acquire;
PYBIND11_OVERLOAD(void, DataEngine, init, );
}
std::string DataEngine_Trampoline::getClassName() const
{
PythonEnvironment::gil acquire {"getClassName"};

// Get the actual class name from python.
return py::str(py::cast(this).get_type().attr("__name__"));
}

void DataEngine_Trampoline::init()
{
PythonEnvironment::gil acquire;
PYBIND11_OVERLOAD(void, DataEngine, init, );
}

void DataEngine_Trampoline::doUpdate()
{
PythonEnvironment::gil acquire;
py::object self = py::cast(this);
if (py::hasattr(self, "update")) {
py::object fct = self.attr("update");
try {
fct();
return;
} catch (std::exception& /*e*/) {
throw py::type_error(this->getName() + ": The DataEngine requires an update method with no parameter and no return type");
}
void DataEngine_Trampoline::doUpdate()
{
PythonEnvironment::gil acquire;
py::object self = py::cast(this);
if (py::hasattr(self, "update")) {
py::object fct = self.attr("update");
try {
fct();
return;
} catch (std::exception& /*e*/) {
throw py::type_error(this->getName() + ": The DataEngine requires an update method with no parameter and no return type");
}
throw py::type_error(this->getName() + " has no update() method.");
}
throw py::type_error(this->getName() + " has no update() method.");
}

void moduleAddDataEngine(pybind11::module &m)
{
py::class_<DataEngine,
DataEngine_Trampoline,
BaseObject,
py_shared_ptr<DataEngine>> f(m, "DataEngine",
py::dynamic_attr(),
sofapython3::doc::dataengine::DataEngine);
void moduleAddDataEngine(pybind11::module &m)
{
py::class_<DataEngine,
DataEngine_Trampoline,
BaseObject,
py_shared_ptr<DataEngine>> f(m, "DataEngine",
py::dynamic_attr(),
sofapython3::doc::dataengine::DataEngine);

f.def(py::init([](py::args& /*args*/, py::kwargs& kwargs)
{
auto c = new DataEngine_Trampoline();
f.def(py::init([](py::args& /*args*/, py::kwargs& kwargs)
{
auto c = new DataEngine_Trampoline();

for(auto kv : kwargs)
{
std::string key = py::cast<std::string>(kv.first);
py::object value = py::reinterpret_borrow<py::object>(kv.second);
for(auto kv : kwargs)
{
std::string key = py::cast<std::string>(kv.first);
py::object value = py::reinterpret_borrow<py::object>(kv.second);

if( key == "name")
c->setName(py::cast<std::string>(kv.second));
try {
BindingBase::SetAttr(*c, key, value);
} catch (py::attribute_error& /*e*/) {
/// kwargs are used to set datafields to their initial values,
/// but they can also be used as simple python attributes, unrelated to SOFA.
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
}
if( key == "name")
c->setName(py::cast<std::string>(kv.second));
try {
BindingBase::SetAttr(*c, key, value);
} catch (py::attribute_error& /*e*/) {
/// kwargs are used to set datafields to their initial values,
/// but they can also be used as simple python attributes, unrelated to SOFA.
/// thus we catch & ignore the py::attribute_error thrown by SetAttr
}
return c;
}));
}
return c;
}));

f.def("addInput", &DataEngine::addInput, sofapython3::doc::dataengine::addInput);
f.def("addOutput", &DataEngine::addOutput, sofapython3::doc::dataengine::addOutput);
}
f.def("addInput", &DataEngine::addInput, sofapython3::doc::dataengine::addInput);
f.def("addOutput", &DataEngine::addOutput, sofapython3::doc::dataengine::addOutput);
}

} /// namespace sofapython3
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DataEngine_Trampoline : public sofa::core::DataEngine
void init() override;
void doUpdate() override;

std::string getClassName() const override;
};

void moduleAddDataEngine(pybind11::module &m);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ namespace sofapython3
template<class TDOFType>
ForceField_Trampoline<TDOFType>::~ForceField_Trampoline() = default;

template<class TDOFType>
std::string ForceField_Trampoline<TDOFType>::getClassName() const
{
PythonEnvironment::gil acquire {"getClassName"};

// Get the actual class name from python.
return py::str(py::cast(this).get_type().attr("__name__"));
}

template<class TDOFType>
void ForceField_Trampoline<TDOFType>::init()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ForceField_Trampoline : public sofa::core::behavior::ForceField<TDOFType>
~ForceField_Trampoline() override;

void init() override;
std::string getClassName() const override;

void addForce(const sofa::core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v) override;
void addDForce(const sofa::core::MechanicalParams* mparams, DataVecDeriv& df, const DataVecDeriv& dx ) override;
Expand Down