diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseComponent.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseComponent.cpp index 3e0c6d82..da4bfe54 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseComponent.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseComponent.cpp @@ -120,15 +120,15 @@ py::object getTarget(BaseComponent *self) { if (!self) return py::none(); - sofa::core::ObjectFactory::ClassEntry entry = sofa::core::ObjectFactory::getInstance()->getEntry(self->getClassName()); - if (!entry.creatorMap.empty()) + + sofa::core::objectmodel::BaseObjectDescription arg; + arg.setAttribute("type", self->getClassName()); + arg.setAttribute("template", self->getTemplateName()); + if (auto component = sofa::core::MainComponentFactory::getInstance()->findComponent(self->getContext(), &arg)) { - sofa::core::ObjectFactory::CreatorMap::iterator it = entry.creatorMap.find(self->getTemplateName()); - if (it != entry.creatorMap.end() && *it->second->getTarget()) - { - return py::cast(it->second->getTarget()) ; - } + return py::cast(component->componentModule); } + return py::none() ; } diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp index 1d85042d..5c155b9d 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp @@ -33,7 +33,7 @@ namespace sofapython3 { std::string __repr__(const ObjectFactory::ClassEntry & entry) { std::ostringstream s; - s << "<" << entry.className << " at " << std::hex << &entry << ">"; + s << entry; return s.str(); } diff --git a/bindings/Sofa/tests/Binding_BaseObject_MockComponent.cpp b/bindings/Sofa/tests/Binding_BaseObject_MockComponent.cpp index 8d25080f..55a62968 100644 --- a/bindings/Sofa/tests/Binding_BaseObject_MockComponent.cpp +++ b/bindings/Sofa/tests/Binding_BaseObject_MockComponent.cpp @@ -19,7 +19,7 @@ ******************************************************************************/ #include "Binding_BaseObject_MockComponent.h" -#include +#include Binding_BaseObject_MockComponent::Binding_BaseObject_MockComponent(): @@ -56,7 +56,13 @@ void Binding_BaseObject_MockComponent::reinit(){ d_test.setValue("reinit"); } +bool registerComponent() +{ + sofa::core::MainComponentFactory::getInstance()->registerComponent( + sofa::core::CreateComponent("Binding_BaseObject_MockComponent") + .withModule("SofaPython3") + .withDescription("This component is used to test several functions of Binding_BaseObject")); + return true; +} - -static int Binding_BaseObject_MockComponentClass = sofa::core::RegisterObject("This component is used to test several functions of Binding_BaseObject") - .add< Binding_BaseObject_MockComponent >(); +bool b = registerComponent(); diff --git a/bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Mat.cpp b/bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Mat.cpp index bbe05361..bafceff7 100644 --- a/bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Mat.cpp +++ b/bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Mat.cpp @@ -21,6 +21,7 @@ #include "Binding_Mat.h" #include #include +#include #define BINDING_MAT_MAKE_NAME(R, C) \ std::string(std::string("Mat") + std::to_string(R) + "x" + std::to_string(C)) @@ -59,6 +60,31 @@ static void addMat(py::module & /*m*/, py::class_> &p) { typedef typename MatClass::Line Row; p.def(py::init()); p.def(py::init()); + p.def(py::init([](py::buffer b) { + + /* Request a buffer descriptor from Python */ + py::buffer_info info = b.request(); + + /* Some basic validation checks ... */ + if (!info.item_type_is_equivalent_to()) + throw std::runtime_error( + "Incompatible format: expected a double array!"); + + if (info.ndim != 2) + throw std::runtime_error("Incompatible buffer dimension!"); + + return Mat(static_cast(info.ptr)); + })); + p.def_buffer([](Mat& self) -> py::buffer_info { + return py::buffer_info( + self.elems.data(), // pointer + sizeof(double), // itemsize + py::format_descriptor::format(), // format + 2, // ndim + {static_cast(R), static_cast(C)}, // shape + {sizeof(double) * static_cast(C), sizeof(double)} // strides (row-major) + ); + }); p.def_property_readonly("rows", &MatClass::getNbLines); p.def_property_readonly("cols", &MatClass::getNbCols); p.def("clear", &MatClass::clear); @@ -184,7 +210,7 @@ static void addMatProduct(py::module & /*m*/, py::class_> template struct MATRIX { static void addMat(py::module &m) { typedef Mat MatClass; - py::class_ p(m, BINDING_MAT_MAKE_NAME(R, C).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(R, C).c_str(), py::buffer_protocol()); ::addMat(m, p); } }; @@ -203,7 +229,7 @@ template <> struct MATRIX<1, 1> { // typedef typename MatClass::Line Row; // typedef typename MatClass::Col Col; - py::class_ p(m, BINDING_MAT_MAKE_NAME(1, 1).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(1, 1).c_str(), py::buffer_protocol()); p.def(py::init([](py::list l) { MatClass *mat = new MatClass(sofa::type::NOINIT); if (py::isinstance(l[0])) // 2D array @@ -233,7 +259,7 @@ template <> struct MATRIX<2, 2> { typedef typename MatClass::Line Row; // typedef typename MatClass::Col Col; - py::class_ p(m, BINDING_MAT_MAKE_NAME(2, 2).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(2, 2).c_str(), py::buffer_protocol()); p.def(py::init()); p.def(py::init([](py::list l) { MatClass *mat = new MatClass(sofa::type::NOINIT); @@ -264,7 +290,7 @@ template <> struct MATRIX<3, 3> { typedef typename MatClass::Line Row; // typedef typename MatClass::Col Col; - py::class_ p(m, BINDING_MAT_MAKE_NAME(3, 3).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(3, 3).c_str(), py::buffer_protocol()); p.def(py::init()); p.def(py::init([](py::list l) { MatClass *mat = new MatClass(sofa::type::NOINIT); @@ -295,7 +321,7 @@ template <> struct MATRIX<4, 4> { typedef typename MatClass::Line Row; // typedef typename MatClass::Col Col; - py::class_ p(m, BINDING_MAT_MAKE_NAME(4, 4).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(4, 4).c_str(), py::buffer_protocol()); p.def(py::init()); p.def(py::init([](py::list l) { MatClass *mat = new MatClass(sofa::type::NOINIT); @@ -326,7 +352,7 @@ template <> struct MATRIX<3, 4> { typedef typename MatClass::Line Row; // typedef typename MatClass::Col Col; - py::class_ p(m, BINDING_MAT_MAKE_NAME(3, 4).c_str()); + py::class_ p(m, BINDING_MAT_MAKE_NAME(3, 4).c_str(), py::buffer_protocol()); p.def(py::init()); p.def(py::init([](py::list l) { MatClass *mat = new MatClass(sofa::type::NOINIT); diff --git a/bindings/SofaTypes/tests/pyfiles/mat_test.py b/bindings/SofaTypes/tests/pyfiles/mat_test.py index a45b5657..5abb37cf 100644 --- a/bindings/SofaTypes/tests/pyfiles/mat_test.py +++ b/bindings/SofaTypes/tests/pyfiles/mat_test.py @@ -4,6 +4,8 @@ import Sofa from SofaTypes import Mat1x1, Mat2x2, Mat3x3, Vec2d +import numpy as np + class TestMaterialMatrix(unittest.TestCase): def test_Constructors(self): @@ -62,3 +64,23 @@ def test_Operators(self): m_test /= 2.0 expected_inplace_div = Mat2x2([[0.5, 1.0], [1.5, 2.0]]) self.assertEqual(m_test, expected_inplace_div) + + def test_to_numpy(self): + m1 = Mat2x2([[1.0, 2.0], [3.0, 4.0]]) + n1 = np.array(m1, copy = False) #n1 is a view on m1 + n1[0, 0] = 9.0 + self.assertEqual(m1[0][0], 9.0) + + m2 = Mat2x2([[5.0, 6.0], [7.0, 8.0]]) + n2 = np.array(m2, copy = False) + + prod = n1 @ n2 + expected_prod = np.array([[59.0, 70.0], [43.0, 50.0]]) + np.testing.assert_array_equal(prod, expected_prod) + + m3_prod = Mat2x2(prod) + + self.assertEqual(m3_prod[0][0], prod[0,0]) + self.assertEqual(m3_prod[0][1], prod[0,1]) + self.assertEqual(m3_prod[1][0], prod[1,0]) + self.assertEqual(m3_prod[1][1], prod[1,1])