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
99 changes: 39 additions & 60 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ForceField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ namespace sofapython3
using sofa::core::behavior::MultiMatrixAccessor;
using sofa::core::behavior::ForceField;
using sofa::defaulttype::Vec3dTypes;
using sofa::defaulttype::Vec2dTypes;
using sofa::defaulttype::Vec1dTypes;
using sofa::defaulttype::Rigid3dTypes;
using sofa::defaulttype::Rigid2dTypes;

template<class TDOFType>
ForceField_Trampoline<TDOFType>::ForceField_Trampoline() = default;
Expand Down Expand Up @@ -163,68 +166,44 @@ namespace sofapython3
}
}

void moduleAddForceField(py::module &m) {
py::class_<ForceField<Vec3dTypes>,
BaseObject, ForceField_Trampoline<Vec3dTypes>,
py_shared_ptr<ForceField<Vec3dTypes>>> f(m, "ForceField",
py::dynamic_attr(),
sofapython3::doc::forceField::forceFieldClass);

f.def(py::init([](py::args &args, py::kwargs &kwargs) {
auto ff = sofa::core::sptr<ForceField_Trampoline<Vec3dTypes>> (new ForceField_Trampoline<Vec3dTypes>());

ff->f_listening.setValue(true);

if (args.size() == 1) ff->setName(py::cast<std::string>(args[0]));

py::object cc = py::cast(ff);
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") {
if (args.size() != 0) {
throw py::type_error("The name is setted twice as a "
"named argument='" + py::cast<std::string>(value) + "' and as a"
"positional argument='" +
py::cast<std::string>(args[0]) + "'.");
}
}
BindingBase::SetAttr(cc, key, value);
}
return ff;
}));


py::class_<ForceField<Rigid3dTypes>,
BaseObject, ForceField_Trampoline<Rigid3dTypes>,
py_shared_ptr<ForceField<Rigid3dTypes>>> f2(m, "ForceFieldRigid3",
py::dynamic_attr(),
py::multiple_inheritance(),
sofapython3::doc::forceField::forceFieldClass);


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

if (args.size() == 1) c->setName(py::cast<std::string>(args[0]));

py::object cc = py::cast(c);
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") {
if (args.size() != 0) {
throw py::type_error("The name is setted twice as a "
"named argument='" + py::cast<std::string>(value) + "' and as a"
"positional argument='" +
py::cast<std::string>(args[0]) + "'.");

template<class TDOFType>
void declare_forcefield(py::module &m, std::string typestr) {
std::string pyclass_name = std::string("ForceField") + typestr;
py::class_<ForceField<TDOFType>, BaseObject, ForceField_Trampoline<TDOFType>, py_shared_ptr<ForceField<TDOFType>>> f(m, pyclass_name.c_str(), py::dynamic_attr(), py::multiple_inheritance(), sofapython3::doc::forceField::forceFieldClass);

f.def(py::init([](py::args &args, py::kwargs &kwargs) {
auto ff = sofa::core::sptr<ForceField_Trampoline<TDOFType>> (new ForceField_Trampoline<TDOFType>());

ff->f_listening.setValue(true);

if (args.size() == 1) ff->setName(py::cast<std::string>(args[0]));

py::object cc = py::cast(ff);
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") {
if (args.size() != 0) {
throw py::type_error("The name is set twice as a "
"named argument='" + py::cast<std::string>(value) + "' and as a"
"positional argument='" +
py::cast<std::string>(args[0]) + "'.");
}
}
BindingBase::SetAttr(cc, key, value);
}
BindingBase::SetAttr(cc, key, value);
}
return c;
}));
return ff;
}));
}


void moduleAddForceField(py::module &m) {
declare_forcefield<Vec3dTypes>(m, "Vec3d");
declare_forcefield<Vec2dTypes>(m, "Vec2d");
declare_forcefield<Vec1dTypes>(m, "Vec1d");
declare_forcefield<Rigid3dTypes>(m, "Rigid3d");
declare_forcefield<Rigid2dTypes>(m, "Rigid2d");
}

} // namespace sofapython3
1 change: 1 addition & 0 deletions bindings/Sofa/tests/Core/ForceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def createParticle(node, node_name, use_implicit_scheme, use_iterative_solver):

def rssffScene(use_implicit_scheme=True, use_iterative_solver=True):
node = Sofa.Core.Node("root")
node.addObject("RequiredPlugin", name="SofaBaseMechanics")
node.addObject("RequiredPlugin", name="SofaSparseSolver")
node.addObject("RequiredPlugin", name="SofaExplicitOdeSolver")
node.addObject("RequiredPlugin", name="SofaImplicitOdeSolver")
Expand Down
4 changes: 2 additions & 2 deletions bindings/Sofa/tests/Core/MyRestShapeForceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import Sofa.Core
import numpy as np

class NaiveRestShapeSpringsForcefield(Sofa.Core.ForceField):
class NaiveRestShapeSpringsForcefield(Sofa.Core.ForceFieldVec3d):
def __init__(self, *args, **kwargs):
Sofa.Core.ForceField.__init__(self, *args, **kwargs)
Sofa.Core.ForceFieldVec3d.__init__(self, *args, **kwargs)
self.addData(name="stiffness", value=kwargs.get("stiffness"), type="double",
help="scalar value representing the stiffness between"
"the actual position and the rest shape position")
Expand Down
5 changes: 3 additions & 2 deletions bindings/Sofa/tests/Core/PythonRestShapeForceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import Sofa.Core
import numpy as np

class MyForceField(Sofa.Core.ForceField):
class MyForceField(Sofa.Core.ForceFieldVec3d):
def __init__(self, *args, **kwargs):
kwargs["ks"] = kwargs.get("ks", 1.0)
kwargs["kd"] = kwargs.get("kd", 0.1)
Sofa.Core.ForceField.__init__(self, *args, **kwargs)
Sofa.Core.ForceFieldVec3d.__init__(self, *args, **kwargs)

def init(self):
self.initpos = self.mstate.position.array().copy()
Expand Down Expand Up @@ -38,6 +38,7 @@ def RestShapeObject(impl, name="unnamed", position=[]):
return node

def createScene(node):
node.addObject("RequiredPlugin", name="SofaBaseMechanics")
node.addObject("RequiredPlugin", name="SofaBaseLinearSolver")
node.addObject("RequiredPlugin", name="SofaImplicitOdeSolver")
node.addObject("DefaultAnimationLoop", name="loop")
Expand Down
4 changes: 2 additions & 2 deletions examples/emptyForceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

# This python script shows the functions to be implemented
# in order to create your ForceField in python
class EmptyForceField(Sofa.Core.ForceField):
class EmptyForceField(Sofa.Core.ForceFieldVec3d):
def __init__(self, *args, **kwargs):
Sofa.Core.ForceField.__init__(self, *args, **kwargs)
Sofa.Core.ForceFieldVec3d.__init__(self, *args, **kwargs)
pass

# Function called at the component initialization
Expand Down
4 changes: 2 additions & 2 deletions examples/example-forcefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import numpy as np


class RestShapeForceField(Sofa.Core.ForceField):
class RestShapeForceField(Sofa.Core.ForceFieldVec3d):
"""Implementation of a RestShapeForceField in python"""
def __init__(self, ks=1.0, kd=1.0, *args, **kwargs):
Sofa.Core.ForceField.__init__(self, *args, **kwargs)
Sofa.Core.ForceFieldVec3d.__init__(self, *args, **kwargs)
self.addData("ks", type="float", value=ks, help="The stiffness spring", group="Spring's Properties")
self.addData("kd", type="float", value=kd, help="The damping spring", group="Spring's Properties")

Expand Down