Skip to content
Open
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
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
// Imports for getCategories
#include <sofa/core/objectmodel/ContextObject.h>
#include <sofa/core/visual/VisualModel.h>
#include <sofa/core/visual/VisualParams.h>
#include <sofa/core/BaseMapping.h>
#include <sofa/core/BehaviorModel.h>
#include <sofa/core/CollisionModel.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 11 additions & 1 deletion bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include <pybind11/pybind11.h>
#include <pybind11/cast.h>

#include <sofa/core/visual/VisualParams.h>
#include <SofaPython3/Sofa/Core/Binding_Base.h>
#include <SofaPython3/Sofa/Core/Binding_Controller.h>
#include <SofaPython3/Sofa/Core/Binding_Controller_doc.h>
Expand All @@ -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](){
Expand Down Expand Up @@ -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);
}


Expand Down
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 @@ -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;
Expand Down
108 changes: 108 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#include <sofa/type/Quat.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/stl.h>

#include <SofaPython3/Sofa/Core/Binding_Base.h>
#include <sofa/core/visual/VisualParams.h>

#include <SofaPython3/Sofa/Core/Binding_VisualParams.h>
#include <SofaPython3/Sofa/Core/Binding_VisualParams_doc.h>

#include <SofaPython3/PythonFactory.h>
#include <sofa/core/objectmodel/Data.h>
#include <sofa/type/RGBAColor.h>

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_<VisualParams> vp(m, "VisualParams", sofapython3::doc::visualParams::baseVisualParamsClass);
vp.def("getDrawTool", [](VisualParams *self){ return self->drawTool(); },
pybind11::return_value_policy::reference);

py::class_<DrawTool> dt(m, "DrawTool", sofapython3::doc::visualParams::baseVisualParamsClass);
dt.def("drawPoints", [](DrawTool *self, const std::vector<sofa::type::Vec3> &points, float size ){
self->drawPoints(points, size, sofa::type::RGBAColor::white());
});
dt.def("drawPoints", [](DrawTool *self, BaseData* dpositions, float size ){
auto positions = dynamic_cast<Data<sofa::type::vector<sofa::type::Vec3>>*>(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<sofa::type::Vec3> &points, float size ){
self->drawLines(points, size, sofa::type::RGBAColor::white());
});
dt.def("drawFrames", [](DrawTool* self,
const std::vector<sofa::type::Vec3d>& points,
const std::vector<sofa::type::Quatd>& orientations,
const sofa::type::Vec3& size ){
for(unsigned int i=0;i<points.size();i++)
{
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<Data<sofa::type::vector<Coord>>*>(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<char, py::array::c_style | py::array::forcecast> data){
char* buffer = static_cast<char*>(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
30 changes: 30 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams.h
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#pragma once

#include <pybind11/pybind11.h>

namespace sofapython3 {

void moduleAddVisualParams(pybind11::module &m);

} /// namespace sofapython3

30 changes: 30 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_VisualParams_doc.h
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#pragma once

namespace sofapython3::doc::visualParams {

static auto baseVisualParamsClass =
R"(
TBD
)";

} // namespace sofapython3::doc::visualParams
3 changes: 3 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)

Expand Down
3 changes: 3 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ using sofa::helper::logging::Message;
#include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h>
#include <SofaPython3/Sofa/Core/Binding_Topology.h>
#include <SofaPython3/Sofa/Core/Binding_TaskScheduler.h>
#include <SofaPython3/Sofa/Core/Binding_VisualParams.h>

#include <SofaPython3/Sofa/Core/Data/Binding_DataString.h>
#include <SofaPython3/Sofa/Core/Data/Binding_DataLink.h>
#include <SofaPython3/Sofa/Core/Data/Binding_DataVectorString.h>
#include <SofaPython3/Sofa/Core/Data/Binding_DataContainer.h>


#include <sofa/core/init.h>

namespace sofapython3
Expand Down Expand Up @@ -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");
Expand Down
52 changes: 52 additions & 0 deletions examples/example-drawing-controller.py
Original file line number Diff line number Diff line change
@@ -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) )


Binary file added examples/oip.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading