diff --git a/CMakeLists.txt b/CMakeLists.txt index d76b3e21..64ce81bd 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_BaseObject.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp index 06fe77b6..6740de72 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 884a4330..b1dd790b 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 2b4684ea..8e87c3bf 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); + }, pybind11::return_value_policy::reference); } diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.h index 0524e6f3..dee81152 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 00000000..896b2b03 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp @@ -0,0 +1,108 @@ +/****************************************************************************** +* 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 +#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; + +namespace sofapython3 { + +void moduleAddVisualParams(py::module &m) +{ + py::class_ vp(m, "VisualParams", sofapython3::doc::visualParams::baseVisualParamsClass); + 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) + 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()); + }); + 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("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) + throw std::runtime_error("Invalid argument"); + + 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, + const std::string& text) + { + 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); + }); + 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 int revision, const sofa::type::Vec3& pos, const double scale, const std::string& filename){ + self->drawRGBAImage(id, revision, pos, scale, filename); + }); + +} + +} /// 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 00000000..eab7ce4c --- /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 00000000..05962bbc --- /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 f88a0e21..26a41ddf 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 844e4c2d..b9468111 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"); diff --git a/examples/example-drawing-controller.py b/examples/example-drawing-controller.py new file mode 100644 index 00000000..957c12be --- /dev/null +++ b/examples/example-drawing-controller.py @@ -0,0 +1,52 @@ +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) + Sofa.Core.Controller.__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() + 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") + 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') + + 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, + mo=root.mo) ) + + diff --git a/examples/oip.jpeg b/examples/oip.jpeg new file mode 100644 index 00000000..fa4d58fe Binary files /dev/null and b/examples/oip.jpeg differ