From e39feb57ebc0641bf3ac28dc53455d75b119c3b4 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 27 Aug 2025 15:23:12 +0200 Subject: [PATCH 1/7] Add binding for Controller::draw() and drawTools() So it become possible to draw from python. --- .../Sofa/Core/Binding_BaseObject.cpp | 1 + .../Sofa/Core/Binding_BaseObject_doc.h | 5 ++ .../Sofa/Core/Binding_Controller.cpp | 12 ++++- .../Sofa/Core/Binding_Controller.h | 2 + .../Sofa/Core/Binding_VisualParams.cpp | 54 +++++++++++++++++++ .../Sofa/Core/Binding_VisualParams.h | 30 +++++++++++ .../Sofa/Core/Binding_VisualParams_doc.h | 30 +++++++++++ .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 3 ++ .../SofaPython3/Sofa/Core/Submodule_Core.cpp | 3 ++ 9 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.h create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams_doc.h diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp index 06fe77b6f..6740de72b 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp @@ -29,6 +29,7 @@ // Imports for getCategories #include #include +#include #include #include #include diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject_doc.h index 884a4330f..b1dd790ba 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject_doc.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject_doc.h @@ -45,6 +45,11 @@ static auto Class = root.obj.position.value # Access the position of the object )"; +static auto draw = + R"( + Implement this function to draw an object in the 3D view. + )"; + static auto init = R"( Initialization method called at graph creation and modification, during top-down traversal.Initialize data. diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp index 2b4684ea4..c55d5303a 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp @@ -20,7 +20,7 @@ #include #include - +#include #include #include #include @@ -45,6 +45,13 @@ std::string Controller_Trampoline::getClassName() const return py::str(py::cast(this).get_type().attr("__name__")); } +void Controller_Trampoline::draw(const sofa::core::visual::VisualParams* params) +{ + PythonEnvironment::executePython(this, [this, params](){ + PYBIND11_OVERLOAD(void, Controller, draw, params); + }); +} + void Controller_Trampoline::init() { PythonEnvironment::executePython(this, [this](){ @@ -131,6 +138,9 @@ void moduleAddController(py::module &m) { f.def("init", &Controller::init); f.def("reinit", &Controller::reinit); + f.def("draw", [](Controller& self, sofa::core::visual::VisualParams* params){ + self.draw(params); + }); } diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h index 0524e6f3a..dee81152f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h @@ -43,6 +43,8 @@ class Controller_Trampoline : public Controller void init() override; void reinit() override; + void draw(const sofa::core::visual::VisualParams* params) override; + void handleEvent(sofa::core::objectmodel::Event* event) override; std::string getClassName() const override; diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp new file mode 100644 index 000000000..f46c5c168 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -0,0 +1,54 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include ; + +namespace py { using namespace pybind11; } +using sofa::core::objectmodel::BaseObject; +using sofa::core::visual::VisualParams; +using sofa::core::visual::DrawTool; + +namespace sofapython3 { + +void moduleAddVisualParams(py::module &m) +{ + py::class_ vp(m, "VisualParams", sofapython3::doc::visualParams::baseVisualParamsClass); + vp.def("getDrawTool", [](VisualParams *self){ return self->drawTool() ;}); + + py::class_ dt(m, "DrawTool", sofapython3::doc::visualParams::baseVisualParamsClass); + dt.def("drawPoints", [](DrawTool *self, const std::vector &points, float size ){ + self->drawPoints(points, size, sofa::type::RGBAColor::white()); + }); +} + +} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.h new file mode 100644 index 000000000..eab7ce4ca --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.h @@ -0,0 +1,30 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +#include + +namespace sofapython3 { + +void moduleAddVisualParams(pybind11::module &m); + +} /// namespace sofapython3 + diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams_doc.h new file mode 100644 index 000000000..05962bbc9 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams_doc.h @@ -0,0 +1,30 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +namespace sofapython3::doc::visualParams { + +static auto baseVisualParamsClass = + R"( + TBD + )"; + +} // namespace sofapython3::doc::visualParams diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index f88a0e21f..26a41ddf6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -51,6 +51,8 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseMeshTopology.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_VisualParams.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_VisualParams_doc.h ) set(SOURCE_FILES @@ -83,6 +85,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Topology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseMeshTopology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_VisualParams.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp ) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp index 844e4c2d9..b9468111f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp @@ -48,12 +48,14 @@ using sofa::helper::logging::Message; #include #include #include +#include #include #include #include #include + #include namespace sofapython3 @@ -153,6 +155,7 @@ PYBIND11_MODULE(Core, core) moduleAddBaseMeshTopology(core); moduleAddPointSetTopologyModifier(core); moduleAddTaskScheduler(core); + moduleAddVisualParams(core); // called when the module is unloaded auto atexit = py::module_::import("atexit"); From ef123a2cdc8004b8d32b3a851796d5b3253bc08f Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 27 Aug 2025 22:54:49 +0200 Subject: [PATCH 2/7] Add drawFrames, drawLines, drawPoints and an example --- .../Sofa/Core/Binding_Controller.cpp | 2 +- .../Sofa/Core/Binding_VisualParams.cpp | 33 ++++++++++++++++-- examples/example-drawing-controller.py | 34 +++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 examples/example-drawing-controller.py diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp index c55d5303a..8e87c3bf4 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp @@ -140,7 +140,7 @@ void moduleAddController(py::module &m) { f.def("reinit", &Controller::reinit); f.def("draw", [](Controller& self, sofa::core::visual::VisualParams* params){ self.draw(params); - }); + }, pybind11::return_value_policy::reference); } diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index f46c5c168..f161395f7 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -30,10 +30,12 @@ #include #include - -#include ; +#include +#include namespace py { using namespace pybind11; } +using sofa::core::objectmodel::BaseData; +using sofa::core::objectmodel::Data; using sofa::core::objectmodel::BaseObject; using sofa::core::visual::VisualParams; using sofa::core::visual::DrawTool; @@ -43,12 +45,37 @@ namespace sofapython3 { void moduleAddVisualParams(py::module &m) { py::class_ vp(m, "VisualParams", sofapython3::doc::visualParams::baseVisualParamsClass); - vp.def("getDrawTool", [](VisualParams *self){ return self->drawTool() ;}); + vp.def("getDrawTool", [](VisualParams *self){ return self->drawTool(); }, + pybind11::return_value_policy::reference); py::class_ dt(m, "DrawTool", sofapython3::doc::visualParams::baseVisualParamsClass); dt.def("drawPoints", [](DrawTool *self, const std::vector &points, float size ){ self->drawPoints(points, size, sofa::type::RGBAColor::white()); }); + dt.def("drawPoints", [](DrawTool *self, BaseData* dpositions, float size ){ + auto positions = dynamic_cast>*>(dpositions); + if(positions) + self->drawPoints(positions->getValue(), size, sofa::type::RGBAColor::white()); + }); + dt.def("drawLines", [](DrawTool *self, const std::vector &points, float size ){ + self->drawLines(points, size, sofa::type::RGBAColor::white()); + }); + dt.def("drawFrames", [](DrawTool* self, + const std::vector& points, + const std::vector& orientations, + const sofa::type::Vec3& size ){ + for(unsigned int i=0;idrawFrame(points[i], orientations[i], size); + } + }); + dt.def("draw3DText", [](DrawTool* self, + const sofa::type::Vec3d& point, + const float size, + const std::string& text) + { + self->draw3DText(point, size, sofa::type::RGBAColor::white(), text.c_str()); + }); } } /// namespace sofapython3 diff --git a/examples/example-drawing-controller.py b/examples/example-drawing-controller.py new file mode 100644 index 000000000..7d9b168d8 --- /dev/null +++ b/examples/example-drawing-controller.py @@ -0,0 +1,34 @@ +import Sofa +import SofaTypes + +class DrawingExamples(Sofa.Core.Controller): + def __init__(self, *args, **kwargs): + # These are needed (and the normal way to override from a python class) + Sofa.Core.Controller.__init__(self, *args, **kwargs) + + self.target = kwargs.get("target", None) + + def draw(self, visual_context): + dt = visual_context.getDrawTool() + dt.drawPoints([SofaTypes.Vec3d(-1.5,0,-1)], 5.0) + dt.drawPoints([SofaTypes.Vec3d(-1.3,0,-1), SofaTypes.Vec3d(1.3,0,-1)], 5.0) + dt.drawLines([SofaTypes.Vec3d(-1.3,0,-1), SofaTypes.Vec3d(1.3,0,-1)], 1.0) + dt.drawFrames([SofaTypes.Vec3d(-1.5,0.1,-1)], [SofaTypes.Quat(0.0,0,0,1.0)], SofaTypes.Vec3d(0.1,0.1,0.1)) + + if self.target is not None: + dt.drawPoints(self.target.position, 2.0) + + dt.draw3DText(SofaTypes.Vec3d(-2.0,0.0,0.0), 0.5, "This is not a raptor") + +def createScene(root): + root.dt = 0.01 + root.bbox = [[-1,-1,-1],[1,1,1]] + root.addObject('DefaultVisualManagerLoop') + root.addObject('DefaultAnimationLoop') + + root.addObject("MeshOBJLoader", name="loader", filename="mesh/raptor_35kp.obj") + + # Add our python controller in the scene + root.addObject( DrawingExamples(name="DrawingController2", target=root.loader) ) + + From 965aa453de5e1e18e225a8524bf91c33c3aa35f3 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Thu, 28 Aug 2025 15:57:07 +0200 Subject: [PATCH 3/7] Add drawFrame(Data>) So we can print all the dof of a mechanical object without copy --- CMakeLists.txt | 4 ++-- .../SofaPython3/Sofa/Core/Binding_VisualParams.cpp | 13 +++++++++++++ examples/example-drawing-controller.py | 12 +++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d76b3e21a..64ce81bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,8 +84,8 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Enable use of folder for IDE like VS set_property(GLOBAL PROPERTY USE_FOLDERS ON) -# Set the minimum python version to 3.7 -set(PYBIND11_PYTHON_VERSION 3.7) +# Set the minimum python version to 3.13 +set(PYBIND11_PYTHON_VERSION 3.13) # Find Python3 find_package(Python ${PYBIND11_PYTHON_VERSION} COMPONENTS Interpreter Development REQUIRED) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index f161395f7..44ca26559 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -69,6 +69,19 @@ void moduleAddVisualParams(py::module &m) self->drawFrame(points[i], orientations[i], size); } }); + dt.def("drawFrames", [](DrawTool* self, BaseData* dpositions, const sofa::type::Vec3& size ){ + using sofa::defaulttype::Rigid3Types; + using Coord = sofa::defaulttype::Rigid3Types::Coord; + auto positions = dynamic_cast>*>(dpositions); + if(positions) + { + for(auto& position : positions->getValue()) + { + self->drawFrame(Rigid3Types::getCPos(position), + Rigid3Types::getCRot(position), size); + } + } + }); dt.def("draw3DText", [](DrawTool* self, const sofa::type::Vec3d& point, const float size, diff --git a/examples/example-drawing-controller.py b/examples/example-drawing-controller.py index 7d9b168d8..f1d2c42b9 100644 --- a/examples/example-drawing-controller.py +++ b/examples/example-drawing-controller.py @@ -7,6 +7,7 @@ def __init__(self, *args, **kwargs): Sofa.Core.Controller.__init__(self, *args, **kwargs) self.target = kwargs.get("target", None) + self.mo = kwargs.get("mo", None) def draw(self, visual_context): dt = visual_context.getDrawTool() @@ -20,6 +21,8 @@ def draw(self, visual_context): dt.draw3DText(SofaTypes.Vec3d(-2.0,0.0,0.0), 0.5, "This is not a raptor") + dt.drawFrames(self.mo.position, SofaTypes.Vec3d(0.1,0.1,0.1)) + def createScene(root): root.dt = 0.01 root.bbox = [[-1,-1,-1],[1,1,1]] @@ -28,7 +31,14 @@ def createScene(root): root.addObject("MeshOBJLoader", name="loader", filename="mesh/raptor_35kp.obj") + root.addObject("MechanicalObject", + name="mo", + template="Rigid3", + position=[[float(i)/10.0, 0.0,0.0, 0.0, 0.0, 0.0, 1.0] for i in range(0,10)]) + # Add our python controller in the scene - root.addObject( DrawingExamples(name="DrawingController2", target=root.loader) ) + root.addObject( DrawingExamples(name="DrawingController2", + target=root.loader, + mo=root.mo) ) From f35409ff928d33db30cc275b66ae2328e003c6e8 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Thu, 28 Aug 2025 23:27:36 +0200 Subject: [PATCH 4/7] Cosmetic improvement of Binding_VisualParams --- .../Sofa/Core/Binding_VisualParams.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index 44ca26559..3a76f68ec 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -54,8 +54,10 @@ void moduleAddVisualParams(py::module &m) }); dt.def("drawPoints", [](DrawTool *self, BaseData* dpositions, float size ){ auto positions = dynamic_cast>*>(dpositions); - if(positions) - self->drawPoints(positions->getValue(), size, sofa::type::RGBAColor::white()); + if(!positions) + throw std::runtime_error("Invalid argument"); + + self->drawPoints(positions->getValue(), size, sofa::type::RGBAColor::white()); }); dt.def("drawLines", [](DrawTool *self, const std::vector &points, float size ){ self->drawLines(points, size, sofa::type::RGBAColor::white()); @@ -73,13 +75,13 @@ void moduleAddVisualParams(py::module &m) using sofa::defaulttype::Rigid3Types; using Coord = sofa::defaulttype::Rigid3Types::Coord; auto positions = dynamic_cast>*>(dpositions); - if(positions) + if(!positions) + throw std::runtime_error("Invalid argument"); + + for(auto& position : positions->getValue()) { - for(auto& position : positions->getValue()) - { - self->drawFrame(Rigid3Types::getCPos(position), - Rigid3Types::getCRot(position), size); - } + self->drawFrame(Rigid3Types::getCPos(position), + Rigid3Types::getCRot(position), size); } }); dt.def("draw3DText", [](DrawTool* self, From 6bd294b7964160bf71c85e82d60037b5e26fab1d Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Thu, 28 Aug 2025 23:32:11 +0200 Subject: [PATCH 5/7] Add binding for DrawTool::drawText --- .../Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp | 4 ++++ examples/example-drawing-controller.py | 1 + 2 files changed, 5 insertions(+) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index 3a76f68ec..9b2175cac 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -91,6 +91,10 @@ void moduleAddVisualParams(py::module &m) { self->draw3DText(point, size, sofa::type::RGBAColor::white(), text.c_str()); }); + + dt.def("drawText", [](DrawTool* self, int x, int y, int fontSize, char* text){ + self->writeOverlayText(x,y, fontSize, sofa::type::RGBAColor::white(), text); + }); } } /// namespace sofapython3 diff --git a/examples/example-drawing-controller.py b/examples/example-drawing-controller.py index f1d2c42b9..7d23b6f2a 100644 --- a/examples/example-drawing-controller.py +++ b/examples/example-drawing-controller.py @@ -20,6 +20,7 @@ def draw(self, visual_context): dt.drawPoints(self.target.position, 2.0) dt.draw3DText(SofaTypes.Vec3d(-2.0,0.0,0.0), 0.5, "This is not a raptor") + dt.drawText(10,10, 12, "Overlay text") dt.drawFrames(self.mo.position, SofaTypes.Vec3d(0.1,0.1,0.1)) From e916e24e3f7dc420d058ba347a0cb3d89df3f133 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Tue, 2 Sep 2025 14:16:14 +0200 Subject: [PATCH 6/7] Add python binding for DrawTool::drawRGBAImage() --- .../Sofa/Core/Binding_VisualParams.cpp | 7 +++++++ examples/example-drawing-controller.py | 7 +++++++ examples/oip.jpeg | Bin 0 -> 24594 bytes 3 files changed, 14 insertions(+) create mode 100644 examples/oip.jpeg diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index 9b2175cac..52f25d89b 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -95,6 +95,13 @@ void moduleAddVisualParams(py::module &m) dt.def("drawText", [](DrawTool* self, int x, int y, int fontSize, char* text){ self->writeOverlayText(x,y, fontSize, sofa::type::RGBAColor::white(), text); }); + dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const sofa::type::Vec3& pos, const int w, const int h, const int mode, const char* data){ + self->drawRGBAImage(id, pos, w, h, mode, data); + }); + dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const sofa::type::Vec3& pos, const std::string& filename){ + self->drawRGBAImage(id, pos, filename); + }); + } } /// namespace sofapython3 diff --git a/examples/example-drawing-controller.py b/examples/example-drawing-controller.py index 7d23b6f2a..957c12be3 100644 --- a/examples/example-drawing-controller.py +++ b/examples/example-drawing-controller.py @@ -1,6 +1,8 @@ import Sofa import SofaTypes +from PIL import Image + class DrawingExamples(Sofa.Core.Controller): def __init__(self, *args, **kwargs): # These are needed (and the normal way to override from a python class) @@ -8,6 +10,7 @@ def __init__(self, *args, **kwargs): self.target = kwargs.get("target", None) self.mo = kwargs.get("mo", None) + self.img = Image.open("oip.jpeg").convert("RGBA") def draw(self, visual_context): dt = visual_context.getDrawTool() @@ -23,10 +26,14 @@ def draw(self, visual_context): dt.drawText(10,10, 12, "Overlay text") dt.drawFrames(self.mo.position, SofaTypes.Vec3d(0.1,0.1,0.1)) + w,h = self.img.size + dt.drawRGBAImage("memory", SofaTypes.Vec3d(0.0,0.0,0.0), w ,h, 32, self.img.tobytes()) + #dt.drawRGBAImage("image", SofaTypes.Vec3d(0.0,0.0,0.0), "oip.jpeg") def createScene(root): root.dt = 0.01 root.bbox = [[-1,-1,-1],[1,1,1]] + root.addObject('RequiredPlugin', name="Sofa.GL.Component.Shader") root.addObject('DefaultVisualManagerLoop') root.addObject('DefaultAnimationLoop') diff --git a/examples/oip.jpeg b/examples/oip.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..fa4d58fe5093f7a00f1dcd421c483cc067547bc0 GIT binary patch literal 24594 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 Date: Wed, 3 Sep 2025 09:05:29 +0200 Subject: [PATCH 7/7] Update DrawTool binding for new drawRGBAImage --- .../src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp index 52f25d89b..896b2b03e 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -95,11 +95,12 @@ void moduleAddVisualParams(py::module &m) dt.def("drawText", [](DrawTool* self, int x, int y, int fontSize, char* text){ self->writeOverlayText(x,y, fontSize, sofa::type::RGBAColor::white(), text); }); - dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const sofa::type::Vec3& pos, const int w, const int h, const int mode, const char* data){ - self->drawRGBAImage(id, pos, w, h, mode, data); + dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const int revision, const sofa::type::Vec3& pos, const double scale, const int w, const int h, const int mode, py::array_t data){ + char* buffer = static_cast(data.request().ptr); + self->drawRGBAImage(id, revision, pos, scale, w, h, mode, buffer); }); - dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const sofa::type::Vec3& pos, const std::string& filename){ - self->drawRGBAImage(id, pos, filename); + dt.def("drawRGBAImage", [](DrawTool* self, const std::string& id, const int revision, const sofa::type::Vec3& pos, const double scale, const std::string& filename){ + self->drawRGBAImage(id, revision, pos, scale, filename); }); }