From 4f3b9c0b6cb071be9b6e622c600c7026a49d31ca Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Wed, 11 Nov 2026 08:09:31 +0900 Subject: [PATCH 1/4] Organize component bindings following SOFA's Sofa.Component tree The bindings of SOFA components (bindings/Modules, bindings/SofaExporter) are moved to bindings/Component, mirroring SOFA's Sofa/Component layout. Each SOFA module Sofa.Component.. gets a python module of the same name: Sofa.SofaBaseTopology -> Sofa.Component.Topology.Container.Grid Sofa.SofaDeformable -> Sofa.Component.SolidMechanics.Spring Sofa.Component.SolidMechanics.FEM.Elastic Sofa.SofaLinearSolver -> Sofa.Component.LinearSolver.Iterative Sofa.SofaLinearSystem -> Sofa.Component.LinearSystem Sofa.SofaConstraintSolver -> Sofa.Component.Constraint.Lagrangian.Solver SofaExporter -> Sofa.Component.IO.Mesh Sofa.FEM and Sofa.GL are not components: their bindings (previously Sofa.SofaFEM and Sofa.SofaGL) move next to Sofa.Core in bindings/Sofa. - A binding is only built when the SOFA module it binds is available. - The old python modules are kept as deprecated aliases re-exporting the new ones, and Bindings.Modules as a cmake alias of Bindings.Component. Outdated compiled modules are removed from the build tree so they do not shadow them. - SP3_add_python_module: compute the macOS rpath to site-packages from the module depth, and set INSTALL_NAME_DIR on the module target. - Stub generation: for SOFA modules having a compiled binding, the stubs of the components without binding are merged in a .pyi next to the binding instead of a package that would shadow it. - Tests, examples and docs use the new module names. The matrix access test scenes now load the plugins they use instead of relying on test order. --- CMake/SofaPython3Tools.cmake | 15 ++-- bindings/BindingsConfig.cmake.in | 8 +- bindings/CMakeLists.txt | 6 +- .../Bindings.ComponentConfig.cmake.in} | 15 ++-- bindings/Component/CMakeLists.txt | 84 +++++++++++++++++++ .../Lagrangian/Solver/CMakeLists.txt | 16 ++++ .../Solver}/Binding_ConstraintSolver.cpp | 4 +- .../Solver}/Binding_ConstraintSolver.h | 0 .../Solver}/Binding_ConstraintSolver_doc.h | 0 .../Lagrangian/Solver/Module_Solver.cpp} | 4 +- bindings/Component/IO/Mesh/CMakeLists.txt | 19 +++++ .../IO/Mesh}/Binding_STLExporter.cpp | 6 +- .../Component/IO/Mesh}/Binding_STLExporter.h | 0 .../IO/Mesh}/Binding_STLExporter_doc.h | 4 +- .../Mesh}/Binding_VisualModelOBJExporter.cpp | 6 +- .../IO/Mesh}/Binding_VisualModelOBJExporter.h | 0 .../Binding_VisualModelOBJExporter_doc.h | 4 +- .../Sofa/Component/IO/Mesh/Module_Mesh.cpp} | 8 +- .../LinearSolver/Iterative/CMakeLists.txt | 16 ++++ .../Iterative}/Binding_LinearSolver.cpp | 4 +- .../Iterative}/Binding_LinearSolver.h | 0 .../Iterative}/Binding_LinearSolver_doc.h | 0 .../Iterative/Module_Iterative.cpp} | 4 +- .../Component/LinearSystem/CMakeLists.txt | 17 ++++ .../LinearSystem}/Binding_LinearSystem.cpp | 2 +- .../LinearSystem}/Binding_LinearSystem.h | 0 .../LinearSystem}/Binding_LinearSystem.inl | 4 +- .../LinearSystem}/Binding_LinearSystem_doc.h | 0 .../LinearSystem/Module_LinearSystem.cpp} | 4 +- .../SolidMechanics/FEM/Elastic/CMakeLists.txt | 17 ++++ .../FEM/Elastic}/Binding_CauchyStress.cpp | 2 +- .../FEM/Elastic}/Binding_CauchyStress.h | 0 .../FEM/Elastic}/Binding_LameParameters.cpp | 2 +- .../FEM/Elastic}/Binding_LameParameters.h | 0 .../FEM/Elastic/Module_Elastic.cpp | 39 +++++++++ .../SolidMechanics/Spring/CMakeLists.txt | 19 +++++ .../Spring}/Binding_LinearSpring.cpp | 12 +-- .../Spring}/Binding_LinearSpring.h | 0 .../Spring}/Binding_LinearSpring_doc.h | 6 +- .../Spring}/Binding_SpringForceField.cpp | 22 ++--- .../Spring}/Binding_SpringForceField.h | 0 .../Spring}/Binding_SpringForceField_doc.h | 10 +-- .../SolidMechanics/Spring/Module_Spring.cpp} | 10 +-- .../Topology/Container/Grid/CMakeLists.txt | 19 +++++ .../Grid}/Binding_RegularGridTopology.cpp | 4 +- .../Grid}/Binding_RegularGridTopology.h | 0 .../Grid}/Binding_RegularGridTopology_doc.h | 4 +- .../Grid}/Binding_SparseGridTopology.cpp | 16 ++-- .../Grid}/Binding_SparseGridTopology.h | 0 .../Grid}/Binding_SparseGridTopology_doc.h | 4 +- .../Topology/Container/Grid/Module_Grid.cpp} | 6 +- .../legacy/Bindings.ModulesConfig.cmake.in} | 6 +- bindings/Component/legacy/CMakeLists.txt | 48 +++++++++++ .../legacy/python/Sofa/SofaBaseTopology.py | 7 ++ .../python/Sofa/SofaConstraintSolver.py | 7 ++ .../legacy/python/Sofa/SofaDeformable.py | 8 ++ .../legacy/python/Sofa/SofaLinearSolver.py | 7 ++ .../legacy/python/Sofa/SofaLinearSystem.py | 7 ++ .../Component/legacy/python/SofaExporter.py | 7 ++ .../tests/CMakeLists.txt | 34 ++++---- .../Lagrangian/Solver}/matrix_access.py | 3 +- .../LinearSolver/Iterative}/matrix_access.py | 4 +- .../SolidMechanics/Spring/LegacyModuleName.py | 27 ++++++ .../SolidMechanics/Spring}/LinearSpring.py | 2 +- .../Spring}/SpringForceField.py | 8 +- .../{Modules => Component}/tests/main.cpp | 24 ++++-- bindings/Modules/CMakeLists.txt | 43 ---------- .../SofaBaseTopology/CMakeLists.txt | 26 ------ .../SofaConstraintSolver/CMakeLists.txt | 27 ------ .../SofaPython3/SofaDeformable/CMakeLists.txt | 36 -------- .../SofaLinearSolver/CMakeLists.txt | 27 ------ .../SofaLinearSystem/CMakeLists.txt | 28 ------- bindings/Sofa/Bindings.SofaConfig.cmake.in | 9 ++ bindings/Sofa/CMakeLists.txt | 14 ++++ bindings/Sofa/package/SofaFEM.py | 7 ++ bindings/Sofa/package/SofaGL.py | 7 ++ .../Sofa/FEM}/Binding_Quadrature.cpp | 4 +- .../Sofa/FEM}/Binding_Quadrature.h | 0 .../src/SofaPython3/Sofa/FEM}/CMakeLists.txt | 18 ++-- .../SofaPython3/Sofa/FEM/Submodule_FEM.cpp} | 4 +- .../Sofa/GL}/Binding_DrawToolGL.cpp | 8 +- .../SofaPython3/Sofa/GL}/Binding_DrawToolGL.h | 0 .../Sofa/GL}/Binding_DrawToolGL_doc.h | 4 +- .../src/SofaPython3/Sofa/GL}/CMakeLists.txt | 19 ++--- .../src/SofaPython3/Sofa/GL/Submodule_GL.cpp} | 4 +- bindings/SofaExporter/CMakeLists.txt | 32 ------- docs/README.md | 6 +- docs/sphinx/source/content/Modules.rst | 2 - .../modules/Sofa/additionalmodules.rst | 13 ++- .../source/content/modules/Sofa/index.rst | 13 ++- .../content/modules/SofaExporter/index.rst | 17 ---- examples/access_compliance_matrix.py | 2 +- examples/access_mass_matrix.py | 2 +- examples/access_matrix.py | 4 +- .../additional-examples/pygame_example.py | 6 +- examples/additional-examples/pyqt_example.py | 6 +- .../source-terms/example-quadrature-rules.py | 8 +- examples/springForceField.py | 2 +- examples/stvenant_kirchhoff.py | 4 +- scripts/generate_stubs.py | 2 +- scripts/sofaStubgen.py | 69 ++++++++++++++- scripts/utils.py | 38 +++++++-- 102 files changed, 708 insertions(+), 444 deletions(-) rename bindings/{Modules/Bindings.ModulesConfig.cmake.in => Component/Bindings.ComponentConfig.cmake.in} (60%) create mode 100644 bindings/Component/CMakeLists.txt create mode 100644 bindings/Component/Constraint/Lagrangian/Solver/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaConstraintSolver => Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver}/Binding_ConstraintSolver.cpp (94%) rename bindings/{Modules/src/SofaPython3/SofaConstraintSolver => Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver}/Binding_ConstraintSolver.h (100%) rename bindings/{Modules/src/SofaPython3/SofaConstraintSolver => Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver}/Binding_ConstraintSolver_doc.h (100%) rename bindings/{Modules/src/SofaPython3/SofaConstraintSolver/Module_SofaConstraintSolver.cpp => Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Module_Solver.cpp} (93%) create mode 100644 bindings/Component/IO/Mesh/CMakeLists.txt rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_STLExporter.cpp (92%) rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_STLExporter.h (100%) rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_STLExporter_doc.h (95%) rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_VisualModelOBJExporter.cpp (90%) rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_VisualModelOBJExporter.h (100%) rename bindings/{SofaExporter/src/SofaExporter => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh}/Binding_VisualModelOBJExporter_doc.h (95%) rename bindings/{SofaExporter/src/SofaExporter/Module_SofaExporter.cpp => Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Module_Mesh.cpp} (89%) create mode 100644 bindings/Component/LinearSolver/Iterative/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaLinearSolver => Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative}/Binding_LinearSolver.cpp (96%) rename bindings/{Modules/src/SofaPython3/SofaLinearSolver => Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative}/Binding_LinearSolver.h (100%) rename bindings/{Modules/src/SofaPython3/SofaLinearSolver => Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative}/Binding_LinearSolver_doc.h (100%) rename bindings/{Modules/src/SofaPython3/SofaLinearSolver/Module_SofaLinearSolver.cpp => Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Module_Iterative.cpp} (93%) create mode 100644 bindings/Component/LinearSystem/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaLinearSystem => Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem}/Binding_LinearSystem.cpp (99%) rename bindings/{Modules/src/SofaPython3/SofaLinearSystem => Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem}/Binding_LinearSystem.h (100%) rename bindings/{Modules/src/SofaPython3/SofaLinearSystem => Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem}/Binding_LinearSystem.inl (96%) rename bindings/{Modules/src/SofaPython3/SofaLinearSystem => Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem}/Binding_LinearSystem_doc.h (100%) rename bindings/{Modules/src/SofaPython3/SofaLinearSystem/Module_SofaLinearSystem.cpp => Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Module_LinearSystem.cpp} (93%) create mode 100644 bindings/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic}/Binding_CauchyStress.cpp (98%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic}/Binding_CauchyStress.h (100%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic}/Binding_LameParameters.cpp (97%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic}/Binding_LameParameters.h (100%) create mode 100644 bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Module_Elastic.cpp create mode 100644 bindings/Component/SolidMechanics/Spring/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_LinearSpring.cpp (89%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_LinearSpring.h (100%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_LinearSpring_doc.h (92%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_SpringForceField.cpp (85%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_SpringForceField.h (100%) rename bindings/{Modules/src/SofaPython3/SofaDeformable => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring}/Binding_SpringForceField_doc.h (85%) rename bindings/{Modules/src/SofaPython3/SofaDeformable/Module_SofaDeformable.cpp => Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Module_Spring.cpp} (83%) create mode 100644 bindings/Component/Topology/Container/Grid/CMakeLists.txt rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_RegularGridTopology.cpp (92%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_RegularGridTopology.h (100%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_RegularGridTopology_doc.h (94%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_SparseGridTopology.cpp (93%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_SparseGridTopology.h (100%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid}/Binding_SparseGridTopology_doc.h (97%) rename bindings/{Modules/src/SofaPython3/SofaBaseTopology/Module_SofaBaseTopology.cpp => Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Module_Grid.cpp} (90%) rename bindings/{SofaExporter/Bindings.SofaExporterConfig.cmake.in => Component/legacy/Bindings.ModulesConfig.cmake.in} (69%) create mode 100644 bindings/Component/legacy/CMakeLists.txt create mode 100644 bindings/Component/legacy/python/Sofa/SofaBaseTopology.py create mode 100644 bindings/Component/legacy/python/Sofa/SofaConstraintSolver.py create mode 100644 bindings/Component/legacy/python/Sofa/SofaDeformable.py create mode 100644 bindings/Component/legacy/python/Sofa/SofaLinearSolver.py create mode 100644 bindings/Component/legacy/python/Sofa/SofaLinearSystem.py create mode 100644 bindings/Component/legacy/python/SofaExporter.py rename bindings/{Modules => Component}/tests/CMakeLists.txt (54%) rename bindings/{Modules/tests/SofaConstraintSolver => Component/tests/Constraint/Lagrangian/Solver}/matrix_access.py (95%) rename bindings/{Modules/tests/SofaLinearSolver => Component/tests/LinearSolver/Iterative}/matrix_access.py (91%) create mode 100644 bindings/Component/tests/SolidMechanics/Spring/LegacyModuleName.py rename bindings/{Modules/tests/SofaDeformable => Component/tests/SolidMechanics/Spring}/LinearSpring.py (96%) rename bindings/{Modules/tests/SofaDeformable => Component/tests/SolidMechanics/Spring}/SpringForceField.py (91%) rename bindings/{Modules => Component}/tests/main.cpp (74%) delete mode 100644 bindings/Modules/CMakeLists.txt delete mode 100644 bindings/Modules/src/SofaPython3/SofaBaseTopology/CMakeLists.txt delete mode 100644 bindings/Modules/src/SofaPython3/SofaConstraintSolver/CMakeLists.txt delete mode 100644 bindings/Modules/src/SofaPython3/SofaDeformable/CMakeLists.txt delete mode 100644 bindings/Modules/src/SofaPython3/SofaLinearSolver/CMakeLists.txt delete mode 100644 bindings/Modules/src/SofaPython3/SofaLinearSystem/CMakeLists.txt create mode 100644 bindings/Sofa/package/SofaFEM.py create mode 100644 bindings/Sofa/package/SofaGL.py rename bindings/{Modules/src/SofaPython3/SofaFEM => Sofa/src/SofaPython3/Sofa/FEM}/Binding_Quadrature.cpp (98%) rename bindings/{Modules/src/SofaPython3/SofaFEM => Sofa/src/SofaPython3/Sofa/FEM}/Binding_Quadrature.h (100%) rename bindings/{Modules/src/SofaPython3/SofaFEM => Sofa/src/SofaPython3/Sofa/FEM}/CMakeLists.txt (61%) rename bindings/{Modules/src/SofaPython3/SofaFEM/Module_SofaFEM.cpp => Sofa/src/SofaPython3/Sofa/FEM/Submodule_FEM.cpp} (95%) rename bindings/{Modules/src/SofaPython3/SofaGL => Sofa/src/SofaPython3/Sofa/GL}/Binding_DrawToolGL.cpp (93%) rename bindings/{Modules/src/SofaPython3/SofaGL => Sofa/src/SofaPython3/Sofa/GL}/Binding_DrawToolGL.h (100%) rename bindings/{Modules/src/SofaPython3/SofaGL => Sofa/src/SofaPython3/Sofa/GL}/Binding_DrawToolGL_doc.h (96%) rename bindings/{Modules/src/SofaPython3/SofaGL => Sofa/src/SofaPython3/Sofa/GL}/CMakeLists.txt (64%) rename bindings/{Modules/src/SofaPython3/SofaGL/Module_SofaGL.cpp => Sofa/src/SofaPython3/Sofa/GL/Submodule_GL.cpp} (95%) delete mode 100644 bindings/SofaExporter/CMakeLists.txt delete mode 100644 docs/sphinx/source/content/modules/SofaExporter/index.rst diff --git a/CMake/SofaPython3Tools.cmake b/CMake/SofaPython3Tools.cmake index 678743f65..4a519582a 100644 --- a/CMake/SofaPython3Tools.cmake +++ b/CMake/SofaPython3Tools.cmake @@ -219,12 +219,15 @@ function(SP3_add_python_module) if (APPLE) # In MacOS, the target dependency name is RPATH/site-packages/PackageName, so we need to add - # an RPATH to the directory that contains "site-packages" + # an RPATH to the directory that contains "site-packages" (e.g. "../.." for site-packages/Sofa/Core.so, + # "../../../.." for site-packages/Sofa/Component/SolidMechanics/Spring.so) + file(RELATIVE_PATH from_target_to_python_root "${TARGET_LIBRARY_OUTPUT_DIRECTORY}" "${CMAKE_BINARY_DIR}/lib/${SP3_PYTHON_PACKAGES_DIRECTORY}/..") + file(TO_CMAKE_PATH "${from_target_to_python_root}" from_target_to_python_root) list(APPEND TARGET_DEPENDENCIES_RPATH - "$ORIGIN/../.." - "$$ORIGIN/../.." - "@loader_path/../.." - "@executable_path/../.." + "$ORIGIN/${from_target_to_python_root}" + "$$ORIGIN/${from_target_to_python_root}" + "@loader_path/${from_target_to_python_root}" + "@executable_path/${from_target_to_python_root}" ) endif() @@ -303,7 +306,7 @@ function(SP3_add_python_module) if (APPLE) set_target_properties( - ${PROJECT_NAME} + ${A_TARGET} PROPERTIES INSTALL_NAME_DIR "@rpath/${SP3_PYTHON_PACKAGES_DIRECTORY}/${DESTINATION}" ) diff --git a/bindings/BindingsConfig.cmake.in b/bindings/BindingsConfig.cmake.in index 1c73cc1f2..24c66382e 100644 --- a/bindings/BindingsConfig.cmake.in +++ b/bindings/BindingsConfig.cmake.in @@ -3,21 +3,15 @@ @PACKAGE_GUARD@ @PACKAGE_INIT@ -set(SP3_WITH_SOFAEXPORTER @SP3_WITH_SOFAEXPORTER@) - find_package(Sofa.Config QUIET REQUIRED) sofa_find_package(SofaPython3 QUIET REQUIRED COMPONENTS - Bindings.Modules + Bindings.Component Bindings.Sofa Bindings.SofaGui Bindings.SofaRuntime Bindings.SofaTypes ) -if(SP3_WITH_SOFAEXPORTER) - sofa_find_package(SofaPython3 QUIET REQUIRED COMPONENTS Bindings.SofaExporter) -endif() - # If we are importing this config file and the target is not yet there this is indicating that # target is an imported one. So we include it if(NOT TARGET @PROJECT_NAME@) diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index fbab2c18f..f8a9af2ed 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,15 +1,11 @@ project(Bindings) -set(BINDINGS_MODULE_LIST Sofa SofaRuntime SofaTypes Modules) +set(BINDINGS_MODULE_LIST Sofa SofaRuntime SofaTypes Component) if(SP3_WITH_SOFAGUI) list(APPEND BINDINGS_MODULE_LIST SofaGui) endif() -if(SP3_WITH_SOFAEXPORTER) - list(APPEND BINDINGS_MODULE_LIST SofaExporter) -endif() - # This will set rpaths relative to SP3 plugin library if(UNIX) set(CMAKE_INSTALL_RPATH diff --git a/bindings/Modules/Bindings.ModulesConfig.cmake.in b/bindings/Component/Bindings.ComponentConfig.cmake.in similarity index 60% rename from bindings/Modules/Bindings.ModulesConfig.cmake.in rename to bindings/Component/Bindings.ComponentConfig.cmake.in index 1f281c241..e417df8c8 100644 --- a/bindings/Modules/Bindings.ModulesConfig.cmake.in +++ b/bindings/Component/Bindings.ComponentConfig.cmake.in @@ -3,17 +3,16 @@ @PACKAGE_GUARD@ @PACKAGE_INIT@ +set(SP3_WITH_SOFAEXPORTER @SP3_WITH_SOFAEXPORTER@) + find_package(Sofa.Config QUIET REQUIRED) sofa_find_package(SofaPython3 QUIET REQUIRED COMPONENTS Plugin Bindings.Sofa) -# Required by Bindings.Modules.SofaBaseTopology -sofa_find_package(Sofa.Component.Topology.Container.Grid QUIET REQUIRED) - -# Required by Bindings.Modules.SofaDeformable -sofa_find_package(Sofa.Component.SolidMechanics.Spring QUIET REQUIRED) - -# Required by Bindings.Modules.SofaLinearSolver -sofa_find_package(Sofa.Component.LinearSolver.Iterative QUIET REQUIRED) +# SOFA modules bound by the Bindings.Component.* targets that were built +set(SP3_BOUND_SOFA_COMPONENT_MODULES "@COMPONENTBINDINGS_SOFA_MODULES@") +foreach(sofa_module ${SP3_BOUND_SOFA_COMPONENT_MODULES}) + sofa_find_package(${sofa_module} QUIET REQUIRED) +endforeach() # If we are importing this config file and the target is not yet there this is indicating that # target is an imported one. So we include it diff --git a/bindings/Component/CMakeLists.txt b/bindings/Component/CMakeLists.txt new file mode 100644 index 000000000..477cea752 --- /dev/null +++ b/bindings/Component/CMakeLists.txt @@ -0,0 +1,84 @@ +project(Bindings.Component) + +# Python bindings for SOFA's Sofa.Component.* modules. +# +# The directory layout mirrors SOFA's Sofa/Component tree: the bindings of the SOFA module +# Sofa.Component.. live in // and are compiled into the python module +# Sofa.Component.. (i.e. site-packages/Sofa/Component//.). +# +# A binding is only built when the SOFA module it binds is available. + +# - Create the python module binding a SOFA Sofa.Component.* module. +# +# SP3_add_component_binding( SOURCES ... HEADERS ... [DEPENDS ...]) +# The target name is the current PROJECT_NAME (Bindings.Component..), the python module is +# the last part of the SOFA module name, installed in the python package made of the other parts. +function(SP3_add_component_binding sofa_module) + cmake_parse_arguments(A "" "" "SOURCES;HEADERS;DEPENDS" ${ARGN}) + + string(REPLACE "." ";" module_path "${sofa_module}") + list(POP_BACK module_path module_name) + string(REPLACE ";" "/" module_destination "${module_path}") + + SP3_add_python_module( + TARGET ${PROJECT_NAME} + PACKAGE Bindings.Component + MODULE ${module_name} + DESTINATION ${module_destination} + SOURCES ${A_SOURCES} + HEADERS ${A_HEADERS} + DEPENDS ${sofa_module} ${A_DEPENDS} SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core + ) + set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "Bindings/Component") + set_property(GLOBAL APPEND PROPERTY SP3_COMPONENT_BINDING_TARGETS ${PROJECT_NAME}) + set_property(GLOBAL APPEND PROPERTY SP3_COMPONENT_BINDING_SOFA_MODULES ${sofa_module}) +endfunction() + +if (NOT TARGET SofaPython3::Plugin) + find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) +endif() + +set(COMPONENTBINDINGS_MODULE_LIST + Constraint/Lagrangian/Solver + LinearSolver/Iterative + LinearSystem + SolidMechanics/FEM/Elastic + SolidMechanics/Spring + Topology/Container/Grid +) +if(SP3_WITH_SOFAEXPORTER) + list(APPEND COMPONENTBINDINGS_MODULE_LIST IO/Mesh) +endif() + +set_property(GLOBAL PROPERTY SP3_COMPONENT_BINDING_TARGETS "") +set_property(GLOBAL PROPERTY SP3_COMPONENT_BINDING_SOFA_MODULES "") +foreach(binding_dir ${COMPONENTBINDINGS_MODULE_LIST}) + string(REPLACE "/" "." sofa_module "Sofa.Component.${binding_dir}") + sofa_find_package(${sofa_module} QUIET) + if(${sofa_module}_FOUND) + message(STATUS "Adding binding module ${sofa_module}") + add_subdirectory(${binding_dir}) + else() + message(STATUS "${sofa_module} not found: its python bindings will not be compiled.") + endif() +endforeach() +get_property(COMPONENTBINDINGS_TARGETS GLOBAL PROPERTY SP3_COMPONENT_BINDING_TARGETS) +get_property(COMPONENTBINDINGS_SOFA_MODULES GLOBAL PROPERTY SP3_COMPONENT_BINDING_SOFA_MODULES) + +add_library(${PROJECT_NAME} INTERFACE) +add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} INTERFACE ${COMPONENTBINDINGS_TARGETS}) + +# Deprecated names (Sofa.SofaDeformable, SofaExporter, Bindings.Modules, ...) +add_subdirectory(legacy) + +if(SP3_BUILD_TEST) + add_subdirectory(tests) +endif() + +sofa_create_component_in_package_with_targets( + COMPONENT_NAME ${PROJECT_NAME} + COMPONENT_VERSION ${SofaPython3_VERSION} + PACKAGE_NAME SofaPython3 + TARGETS ${PROJECT_NAME} + ) diff --git a/bindings/Component/Constraint/Lagrangian/Solver/CMakeLists.txt b/bindings/Component/Constraint/Lagrangian/Solver/CMakeLists.txt new file mode 100644 index 000000000..d8339a88e --- /dev/null +++ b/bindings/Component/Constraint/Lagrangian/Solver/CMakeLists.txt @@ -0,0 +1,16 @@ +project(Bindings.Component.Constraint.Lagrangian.Solver) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Module_Solver.cpp +) + +SP3_add_component_binding(Sofa.Component.Constraint.Lagrangian.Solver + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver.cpp b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.cpp similarity index 94% rename from bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver.cpp rename to bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.cpp index d81fba1a9..e07c32035 100644 --- a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver.cpp +++ b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.cpp @@ -17,8 +17,8 @@ ******************************************************************************* * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include -#include +#include +#include #include #include diff --git a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver.h b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver.h rename to bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver.h diff --git a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver_doc.h b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver_doc.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaConstraintSolver/Binding_ConstraintSolver_doc.h rename to bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Binding_ConstraintSolver_doc.h diff --git a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Module_SofaConstraintSolver.cpp b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Module_Solver.cpp similarity index 93% rename from bindings/Modules/src/SofaPython3/SofaConstraintSolver/Module_SofaConstraintSolver.cpp rename to bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Module_Solver.cpp index 15961fa4f..36268c0e6 100644 --- a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/Module_SofaConstraintSolver.cpp +++ b/bindings/Component/Constraint/Lagrangian/Solver/src/SofaPython3/Sofa/Component/Constraint/Lagrangian/Solver/Module_Solver.cpp @@ -19,12 +19,12 @@ ******************************************************************************/ #include -#include +#include namespace sofapython3 { -PYBIND11_MODULE(SofaConstraintSolver, m) +PYBIND11_MODULE(Solver, m) { m.doc() = "Implements the solver for constraint problems"; diff --git a/bindings/Component/IO/Mesh/CMakeLists.txt b/bindings/Component/IO/Mesh/CMakeLists.txt new file mode 100644 index 000000000..c28bd5907 --- /dev/null +++ b/bindings/Component/IO/Mesh/CMakeLists.txt @@ -0,0 +1,19 @@ +project(Bindings.Component.IO.Mesh) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/IO/Mesh/Module_Mesh.cpp +) + +SP3_add_component_binding(Sofa.Component.IO.Mesh + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_STLExporter.cpp b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.cpp similarity index 92% rename from bindings/SofaExporter/src/SofaExporter/Binding_STLExporter.cpp rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.cpp index 5cfba4e9c..70ba4a336 100644 --- a/bindings/SofaExporter/src/SofaExporter/Binding_STLExporter.cpp +++ b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.cpp @@ -19,8 +19,8 @@ ******************************************************************************/ #include -#include -#include +#include +#include #include #include @@ -41,7 +41,7 @@ void moduleAddSTLExporter(py::module &m) return py::cast(dynamic_cast(object)); }); - py::class_> p(m, "STLExporter", sofapython3::doc::SofaExporter::STLExporter::docstring); + py::class_> p(m, "STLExporter", sofapython3::doc::io::mesh::STLExporter::docstring); p.def("write", &STLExporter::write); } diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_STLExporter.h b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.h similarity index 100% rename from bindings/SofaExporter/src/SofaExporter/Binding_STLExporter.h rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter.h diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_STLExporter_doc.h b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter_doc.h similarity index 95% rename from bindings/SofaExporter/src/SofaExporter/Binding_STLExporter_doc.h rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter_doc.h index fbd67c76d..21c610480 100644 --- a/bindings/SofaExporter/src/SofaExporter/Binding_STLExporter_doc.h +++ b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_STLExporter_doc.h @@ -21,7 +21,7 @@ #pragma once -namespace sofapython3::doc::SofaExporter::STLExporter +namespace sofapython3::doc::io::mesh::STLExporter { static auto docstring = @@ -35,7 +35,7 @@ static auto docstring = .. code-block:: python import Sofa - import SofaExporter + import Sofa.Component.IO.Mesh # Create a new node n = Sofa.Core.Node("root"") diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter.cpp b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.cpp similarity index 90% rename from bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter.cpp rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.cpp index 3a9b4af8e..ba95d6a66 100644 --- a/bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter.cpp +++ b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.cpp @@ -19,8 +19,8 @@ ******************************************************************************/ #include -#include -#include +#include +#include #include #include @@ -39,7 +39,7 @@ void moduleAddVisualModelOBJExporter(py::module &m) return py::cast(dynamic_cast(object)); }); - py::class_> p(m, "VisualModelOBJExporter", sofapython3::doc::SofaExporter::VisualModelOBJExporter::docstring); + py::class_> p(m, "VisualModelOBJExporter", sofapython3::doc::io::mesh::VisualModelOBJExporter::docstring); p.def("write", &VisualModelOBJExporter::write); } diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter.h b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.h similarity index 100% rename from bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter.h rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter.h diff --git a/bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter_doc.h b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter_doc.h similarity index 95% rename from bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter_doc.h rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter_doc.h index 0b3ee4585..2abf5bef3 100644 --- a/bindings/SofaExporter/src/SofaExporter/Binding_VisualModelOBJExporter_doc.h +++ b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Binding_VisualModelOBJExporter_doc.h @@ -20,7 +20,7 @@ #pragma once -namespace sofapython3::doc::SofaExporter::VisualModelOBJExporter { +namespace sofapython3::doc::io::mesh::VisualModelOBJExporter { static auto docstring = R"( @@ -33,7 +33,7 @@ static auto docstring = .. code-block:: python import Sofa - import SofaExporter + import Sofa.Component.IO.Mesh # Create a new node n = Sofa.Core.Node("root"") diff --git a/bindings/SofaExporter/src/SofaExporter/Module_SofaExporter.cpp b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Module_Mesh.cpp similarity index 89% rename from bindings/SofaExporter/src/SofaExporter/Module_SofaExporter.cpp rename to bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Module_Mesh.cpp index 91db0d863..3d4090ffd 100644 --- a/bindings/SofaExporter/src/SofaExporter/Module_SofaExporter.cpp +++ b/bindings/Component/IO/Mesh/src/SofaPython3/Sofa/Component/IO/Mesh/Module_Mesh.cpp @@ -21,20 +21,20 @@ #include namespace py = pybind11; -#include -#include +#include +#include namespace sofapython3 { -PYBIND11_MODULE(SofaExporter, m) { +PYBIND11_MODULE(Mesh, m) { m.doc() = R"doc( Export in STL or OBJ from from a SOFA simulation Example: .. code-block:: python - import SofaExporter + import Sofa.Component.IO.Mesh )doc"; diff --git a/bindings/Component/LinearSolver/Iterative/CMakeLists.txt b/bindings/Component/LinearSolver/Iterative/CMakeLists.txt new file mode 100644 index 000000000..c0274563a --- /dev/null +++ b/bindings/Component/LinearSolver/Iterative/CMakeLists.txt @@ -0,0 +1,16 @@ +project(Bindings.Component.LinearSolver.Iterative) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Module_Iterative.cpp +) + +SP3_add_component_binding(Sofa.Component.LinearSolver.Iterative + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver.cpp b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.cpp similarity index 96% rename from bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver.cpp rename to bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.cpp index bdcbaabb3..356feb06e 100644 --- a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver.cpp +++ b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.cpp @@ -17,8 +17,8 @@ ******************************************************************************* * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include -#include +#include +#include #include #include diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver.h b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver.h rename to bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver.h diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver_doc.h b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver_doc.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaLinearSolver/Binding_LinearSolver_doc.h rename to bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Binding_LinearSolver_doc.h diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Module_SofaLinearSolver.cpp b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Module_Iterative.cpp similarity index 93% rename from bindings/Modules/src/SofaPython3/SofaLinearSolver/Module_SofaLinearSolver.cpp rename to bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Module_Iterative.cpp index bff4a9e20..a13a069fa 100644 --- a/bindings/Modules/src/SofaPython3/SofaLinearSolver/Module_SofaLinearSolver.cpp +++ b/bindings/Component/LinearSolver/Iterative/src/SofaPython3/Sofa/Component/LinearSolver/Iterative/Module_Iterative.cpp @@ -19,12 +19,12 @@ ******************************************************************************/ #include -#include +#include namespace sofapython3 { -PYBIND11_MODULE(SofaLinearSolver, m) +PYBIND11_MODULE(Iterative, m) { moduleAddLinearSolver(m); } diff --git a/bindings/Component/LinearSystem/CMakeLists.txt b/bindings/Component/LinearSystem/CMakeLists.txt new file mode 100644 index 000000000..071c04cf8 --- /dev/null +++ b/bindings/Component/LinearSystem/CMakeLists.txt @@ -0,0 +1,17 @@ +project(Bindings.Component.LinearSystem) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.inl + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/LinearSystem/Module_LinearSystem.cpp +) + +SP3_add_component_binding(Sofa.Component.LinearSystem + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.cpp b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.cpp similarity index 99% rename from bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.cpp rename to bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.cpp index d03773972..0d7a9cd96 100644 --- a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.cpp +++ b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.cpp @@ -17,7 +17,7 @@ ******************************************************************************* * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include +#include #include diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.h b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.h rename to bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.h diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.inl b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.inl similarity index 96% rename from bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.inl rename to bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.inl index b1f4b40f3..2b6bb828f 100644 --- a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem.inl +++ b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem.inl @@ -18,8 +18,8 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include -#include +#include +#include #include #include diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem_doc.h b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem_doc.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaLinearSystem/Binding_LinearSystem_doc.h rename to bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Binding_LinearSystem_doc.h diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Module_SofaLinearSystem.cpp b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Module_LinearSystem.cpp similarity index 93% rename from bindings/Modules/src/SofaPython3/SofaLinearSystem/Module_SofaLinearSystem.cpp rename to bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Module_LinearSystem.cpp index 2bb150c2f..1c83a905e 100644 --- a/bindings/Modules/src/SofaPython3/SofaLinearSystem/Module_SofaLinearSystem.cpp +++ b/bindings/Component/LinearSystem/src/SofaPython3/Sofa/Component/LinearSystem/Module_LinearSystem.cpp @@ -19,12 +19,12 @@ ******************************************************************************/ #include -#include +#include namespace sofapython3 { -PYBIND11_MODULE(SofaLinearSystem, m) +PYBIND11_MODULE(LinearSystem, m) { moduleAddLinearSystem(m); } diff --git a/bindings/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt b/bindings/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt new file mode 100644 index 000000000..d027702fb --- /dev/null +++ b/bindings/Component/SolidMechanics/FEM/Elastic/CMakeLists.txt @@ -0,0 +1,17 @@ +project(Bindings.Component.SolidMechanics.FEM.Elastic) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Module_Elastic.cpp +) + +SP3_add_component_binding(Sofa.Component.SolidMechanics.FEM.Elastic + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_CauchyStress.cpp b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.cpp similarity index 98% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_CauchyStress.cpp rename to bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.cpp index 2a9b22509..1b0b35db7 100644 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_CauchyStress.cpp +++ b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.cpp @@ -17,7 +17,7 @@ ******************************************************************************* * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include +#include #include diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_CauchyStress.h b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_CauchyStress.h rename to bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_CauchyStress.h diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LameParameters.cpp b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.cpp similarity index 97% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LameParameters.cpp rename to bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.cpp index 313a04600..f3ecca00d 100644 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LameParameters.cpp +++ b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.cpp @@ -20,7 +20,7 @@ #include -#include +#include #include namespace sofapython3 diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LameParameters.h b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LameParameters.h rename to bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Binding_LameParameters.h diff --git a/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Module_Elastic.cpp b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Module_Elastic.cpp new file mode 100644 index 000000000..aade619f5 --- /dev/null +++ b/bindings/Component/SolidMechanics/FEM/Elastic/src/SofaPython3/Sofa/Component/SolidMechanics/FEM/Elastic/Module_Elastic.cpp @@ -0,0 +1,39 @@ +/****************************************************************************** +* 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 + + +namespace py { using namespace pybind11; } + +namespace sofapython3 +{ + +PYBIND11_MODULE(Elastic, m) +{ + m.doc() = "Bindings for Sofa.Component.SolidMechanics.FEM.Elastic (Lamé parameters, Cauchy stress)"; + + moduleAddLameParameters(m); + moduleAddCauchyStress(m); +} + +} // namespace sofapython3 diff --git a/bindings/Component/SolidMechanics/Spring/CMakeLists.txt b/bindings/Component/SolidMechanics/Spring/CMakeLists.txt new file mode 100644 index 000000000..6d8e1e491 --- /dev/null +++ b/bindings/Component/SolidMechanics/Spring/CMakeLists.txt @@ -0,0 +1,19 @@ +project(Bindings.Component.SolidMechanics.Spring) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Module_Spring.cpp +) + +SP3_add_component_binding(Sofa.Component.SolidMechanics.Spring + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LinearSpring.cpp b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp similarity index 89% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LinearSpring.cpp rename to bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp index fbdc5180b..ae6479c0c 100644 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_LinearSpring.cpp +++ b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp @@ -22,8 +22,8 @@ #include -#include -#include +#include +#include namespace sofapython3 { @@ -34,8 +34,8 @@ typedef LinearSpring LinearSpringR; namespace py { using namespace pybind11; } void moduleAddLinearSpring(pybind11::module& m) { - // create a python binding for the C++ class LinearSpring from SofaDeformable - py::class_ s (m, "LinearSpring", sofapython3::doc::SofaDeformable::LinearSpringClass); + // create a python binding for the C++ class LinearSpring from Sofa.Component.SolidMechanics.Spring + py::class_ s (m, "LinearSpring", sofapython3::doc::solidmechanics::spring::LinearSpringClass); // initializer for the class s.def(py::init #include -#include -#include +#include +#include #include #include @@ -45,26 +45,26 @@ void bindSpringForcefield(py::module& m) { using sofa::component::solidmechanics::spring::LinearSpring; typedef LinearSpring LinearSpringR; - // create a python binding for the c++ class SpringForceField from SofaDeformable + // create a python binding for the c++ class SpringForceField from Sofa.Component.SolidMechanics.Spring // no init binding, because creation should be done via node.addObject("SpringForceField") std::string type_name = SpringForceField::GetClass()->className+"_"+ DataType::Name(); py::class_> s (m, type_name.c_str(), sofapython3::doc::SofaDeformable::SpringForceFieldClass); + py_shared_ptr> s (m, type_name.c_str(), sofapython3::doc::solidmechanics::spring::SpringForceFieldClass); // remove all springs and optionally reserve memory for #reserve springs in the vector of springs - s.def("clear", &SpringForceField::clear, py::arg("reserve") = 0, sofapython3::doc::SofaDeformable::SpringForceFieldClear); + s.def("clear", &SpringForceField::clear, py::arg("reserve") = 0, sofapython3::doc::solidmechanics::spring::SpringForceFieldClear); // directly binding this one with &SpringForceField::getSprings returns a vector including CPUMemoryManager s.def("getSprings", [](const SpringForceField& self){ std::vector springs = self.getSprings(); return springs; - }, sofapython3::doc::SofaDeformable::SpringForceFieldGetSprings); + }, sofapython3::doc::solidmechanics::spring::SpringForceFieldGetSprings); // remove the nth spring - s.def("removeSpring", &SpringForceField::removeSpring, py::arg("index"), sofapython3::doc::SofaDeformable::SpringForceFieldRemoveSpring); + s.def("removeSpring", &SpringForceField::removeSpring, py::arg("index"), sofapython3::doc::solidmechanics::spring::SpringForceFieldRemoveSpring); // remove springs specified by a list of indices s.def("removeSprings", [](SpringForceField& self, const std::vector &v){ @@ -75,10 +75,10 @@ void bindSpringForcefield(py::module& m) { for (const auto & index : indices) { self.removeSpring(index); } - }, py::arg("indices"), sofapython3::doc::SofaDeformable::SpringForceFieldRemoveSprings); + }, py::arg("indices"), sofapython3::doc::solidmechanics::spring::SpringForceFieldRemoveSprings); // add spring form a LinearSpringR - s.def("addSpring", py::overload_cast(&SpringForceField::addSpring), py::arg("spring"), sofapython3::doc::SofaDeformable::SpringForceFieldAddSpring); + s.def("addSpring", py::overload_cast(&SpringForceField::addSpring), py::arg("spring"), sofapython3::doc::solidmechanics::spring::SpringForceFieldAddSpring); // add spring from construtor arguments for a LinearSpringR s.def("addSpring", py::overload_cast(&SpringForceField::addSpring), @@ -87,14 +87,14 @@ void bindSpringForcefield(py::module& m) { py::arg("springStiffness"), py::arg("dampingFactor"), py::arg("restLength"), - sofapython3::doc::SofaDeformable::SpringForceFieldAddSpring); + sofapython3::doc::solidmechanics::spring::SpringForceFieldAddSpring); // add multiple springs at once s.def("addSprings", [](SpringForceField& self, const std::vector &v){ for (const auto spring: v){ self.addSpring(spring); } - }, py::arg("springs"), sofapython3::doc::SofaDeformable::SpringForceFieldAddSprings); + }, py::arg("springs"), sofapython3::doc::solidmechanics::spring::SpringForceFieldAddSprings); // register the binding in the downcasting subsystem diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_SpringForceField.h b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_SpringForceField.h rename to bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField.h diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_SpringForceField_doc.h b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField_doc.h similarity index 85% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Binding_SpringForceField_doc.h rename to bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField_doc.h index 5acf094c3..d69c85d95 100644 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/Binding_SpringForceField_doc.h +++ b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_SpringForceField_doc.h @@ -20,7 +20,7 @@ #pragma once -namespace sofapython3::doc::SofaDeformable { +namespace sofapython3::doc::solidmechanics::spring { static auto SpringForceFieldClass = R"( @@ -53,14 +53,14 @@ Returns all springs currently stored in the SpringForceField. static auto SpringForceFieldAddSpring = R"( -Adds a new spring to the SpringForceField. Can be done either by passing an existing Sofa.SofaDeformable.LinearSpring object, or by passing arguments to construct a new LinearSpring. +Adds a new spring to the SpringForceField. Can be done either by passing an existing Sofa.Component.SolidMechanics.Spring.LinearSpring object, or by passing arguments to construct a new LinearSpring. examples: ------------ # Adding an existing spring to the force field spring_force_field = node.addObject("SpringForceField") -spring = Sofa.SofaDeformable.LinearSpring(index1=0, index2=0, springStiffness=100, dampingFactor=5, restLength=5) +spring = Sofa.Component.SolidMechanics.Spring.LinearSpring(index1=0, index2=0, springStiffness=100, dampingFactor=5, restLength=5) spring_force_field.addSpring(spring) # Adding a new spring to the force field @@ -77,9 +77,9 @@ Like addSpring, but for a list of springs. ------------ spring_force_field = node.addObject("SpringForceField") -springs = [Sofa.SofaDeformable.LinearSpring(index1=i, index2=i, springStiffness=100, dampingFactor=5, restLength=5) for i in range(1)] +springs = [Sofa.Component.SolidMechanics.Spring.LinearSpring(index1=i, index2=i, springStiffness=100, dampingFactor=5, restLength=5) for i in range(1)] spring_force_field.addSprings(springs) )"; -} // sofapython3::doc::SofaDeformable +} // sofapython3::doc::solidmechanics::spring diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/Module_SofaDeformable.cpp b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Module_Spring.cpp similarity index 83% rename from bindings/Modules/src/SofaPython3/SofaDeformable/Module_SofaDeformable.cpp rename to bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Module_Spring.cpp index 09b58d72b..3404f52fe 100644 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/Module_SofaDeformable.cpp +++ b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Module_Spring.cpp @@ -19,10 +19,8 @@ ******************************************************************************/ #include -#include -#include -#include -#include +#include +#include namespace py { using namespace pybind11; } @@ -30,14 +28,12 @@ namespace py { using namespace pybind11; } namespace sofapython3 { -PYBIND11_MODULE(SofaDeformable, m) +PYBIND11_MODULE(Spring, m) { m.doc() = "Implements linear springs between objects"; moduleAddLinearSpring(m); moduleAddSpringForceField(m); - moduleAddLameParameters(m); - moduleAddCauchyStress(m); } } // namespace sofapython3 diff --git a/bindings/Component/Topology/Container/Grid/CMakeLists.txt b/bindings/Component/Topology/Container/Grid/CMakeLists.txt new file mode 100644 index 000000000..21916f76b --- /dev/null +++ b/bindings/Component/Topology/Container/Grid/CMakeLists.txt @@ -0,0 +1,19 @@ +project(Bindings.Component.Topology.Container.Grid) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology_doc.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Module_Grid.cpp +) + +SP3_add_component_binding(Sofa.Component.Topology.Container.Grid + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} +) diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology.cpp b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.cpp similarity index 92% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology.cpp rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.cpp index 627f2a477..4342b380a 100644 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology.cpp +++ b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.cpp @@ -36,9 +36,9 @@ namespace py { using namespace pybind11; } void moduleAddRegularGridTopology(pybind11::module& m) { py::class_> - c (m, "RegularGridTopology", doc::SofaBaseTopology::regularGridTopologyClass); + c (m, "RegularGridTopology", doc::topology::container::grid::regularGridTopologyClass); - c.def("getPoint", &RegularGridTopology::getPoint, doc::SofaBaseTopology::getPoint); + c.def("getPoint", &RegularGridTopology::getPoint, doc::topology::container::grid::getPoint); /// register the binding in the downcasting subsystem PythonFactory::registerType([](sofa::core::objectmodel::Base* object){ diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology.h b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology.h rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology.h diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology_doc.h b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology_doc.h similarity index 94% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology_doc.h rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology_doc.h index d48e90437..999eab87b 100644 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_RegularGridTopology_doc.h +++ b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_RegularGridTopology_doc.h @@ -20,7 +20,7 @@ #pragma once -namespace sofapython3::doc::SofaBaseTopology { +namespace sofapython3::doc::topology::container::grid { static auto regularGridTopologyClass = R"( @@ -37,4 +37,4 @@ Get the position of node of the grid from its index. :return: A vector3 containing the position of the given node index. :rtype: Vector3 )"; -} // sofapython3::doc::SofaBaseTopology +} // sofapython3::doc::topology::container::grid diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology.cpp b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.cpp similarity index 93% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology.cpp rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.cpp index eca392812..8cb7fbc89 100644 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology.cpp +++ b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.cpp @@ -37,12 +37,12 @@ namespace py { using namespace pybind11; } void moduleAddSparseGridTopology(pybind11::module& m) { py::class_> - c(m, "SparseGridTopology", doc::SofaBaseTopology::sparseGridTopologyClass); + c(m, "SparseGridTopology", doc::topology::container::grid::sparseGridTopologyClass); // getRegularGrid () c.def("getRegularGrid", [](SparseGridTopology & self){ return self._regularGrid.get(); - }, doc::SofaBaseTopology::getRegularGrid); + }, doc::topology::container::grid::getRegularGrid); // findCube (pos) c.def("findCube", [](SparseGridTopology & self, const py::list & l) { @@ -87,7 +87,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { } return py::make_tuple(cube_id, fx, fy, fz); - }, doc::SofaBaseTopology::findCube); + }, doc::topology::container::grid::findCube); // getRegularGridNodeIndex (sparse_grid_node_index) c.def("getRegularGridNodeIndex", [](SparseGridTopology & self, size_t sparse_grid_node_index) { @@ -99,7 +99,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { const auto pos = self.getPointPos(sparse_grid_node_index); return self._regularGrid->findPoint(pos); - }, doc::SofaBaseTopology::getRegularGridNodeIndex); + }, doc::topology::container::grid::getRegularGridNodeIndex); // getRegularGridCubeIndex (sparse_grid_cube_index) c.def("getRegularGridCubeIndex", [](SparseGridTopology & self, size_t sparse_grid_cube_index) { @@ -110,7 +110,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { } return self._indicesOfCubeinRegularGrid[sparse_grid_cube_index]; - }, doc::SofaBaseTopology::getRegularGridCubeIndex); + }, doc::topology::container::grid::getRegularGridCubeIndex); // getBoundaryCells () c.def("getBoundaryCells", [] (SparseGridTopology & self) { @@ -120,7 +120,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { indices.push_back(hexa_id); } return indices; - }, doc::SofaBaseTopology::getBoundaryCells); + }, doc::topology::container::grid::getBoundaryCells); // getBoundaryNodes () c.def("getBoundaryNodes", [] (SparseGridTopology & self) { @@ -131,7 +131,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { indices.push_back(node_id); } return indices; - }, doc::SofaBaseTopology::getBoundaryNodes); + }, doc::topology::container::grid::getBoundaryNodes); // getNodeIndicesOfCube (cube_index) c.def("getNodeIndicesOfCube", [](SparseGridTopology & self, size_t cube_index) { @@ -146,7 +146,7 @@ void moduleAddSparseGridTopology(pybind11::module& m) { indices[i] = hexa[i]; } return indices; - }, doc::SofaBaseTopology::getRegularGridCubeIndex); + }, doc::topology::container::grid::getRegularGridCubeIndex); /// register the binding in the downcasting subsystem PythonFactory::registerType([](sofa::core::objectmodel::Base* object){ diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology.h b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology.h rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology.h diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology_doc.h b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology_doc.h similarity index 97% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology_doc.h rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology_doc.h index 75c238551..9a0342ca1 100644 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Binding_SparseGridTopology_doc.h +++ b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Binding_SparseGridTopology_doc.h @@ -20,7 +20,7 @@ #pragma once -namespace sofapython3::doc::SofaBaseTopology { +namespace sofapython3::doc::topology::container::grid { static auto sparseGridTopologyClass = R"( @@ -90,4 +90,4 @@ Get the indices of the nodes of a given cube (grid cell). :rtype: list )"; -} // sofapython3::doc::SofaBaseTopology +} // sofapython3::doc::topology::container::grid diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Module_SofaBaseTopology.cpp b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Module_Grid.cpp similarity index 90% rename from bindings/Modules/src/SofaPython3/SofaBaseTopology/Module_SofaBaseTopology.cpp rename to bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Module_Grid.cpp index f208d106d..f5cbacf16 100644 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/Module_SofaBaseTopology.cpp +++ b/bindings/Component/Topology/Container/Grid/src/SofaPython3/Sofa/Component/Topology/Container/Grid/Module_Grid.cpp @@ -20,8 +20,8 @@ #include -#include -#include +#include +#include #include @@ -30,7 +30,7 @@ namespace py { using namespace pybind11; } namespace sofapython3 { -PYBIND11_MODULE(SofaBaseTopology, m) +PYBIND11_MODULE(Grid, m) { m.doc() = "Implements some topology component (Regular and SparseGridTopology)"; diff --git a/bindings/SofaExporter/Bindings.SofaExporterConfig.cmake.in b/bindings/Component/legacy/Bindings.ModulesConfig.cmake.in similarity index 69% rename from bindings/SofaExporter/Bindings.SofaExporterConfig.cmake.in rename to bindings/Component/legacy/Bindings.ModulesConfig.cmake.in index 1e13a89b4..9335be4d4 100644 --- a/bindings/SofaExporter/Bindings.SofaExporterConfig.cmake.in +++ b/bindings/Component/legacy/Bindings.ModulesConfig.cmake.in @@ -1,11 +1,11 @@ # CMake package configuration file for @PROJECT_NAME@ +# Deprecated: Bindings.Modules has been replaced by Bindings.Component. @PACKAGE_GUARD@ @PACKAGE_INIT@ -find_package(SofaPython3 QUIET REQUIRED COMPONENTS Plugin Bindings.Sofa) - -find_package(Sofa.Component.IO.Mesh QUIET REQUIRED) +find_package(Sofa.Config QUIET REQUIRED) +sofa_find_package(SofaPython3 QUIET REQUIRED COMPONENTS Bindings.Component) # If we are importing this config file and the target is not yet there this is indicating that # target is an imported one. So we include it diff --git a/bindings/Component/legacy/CMakeLists.txt b/bindings/Component/legacy/CMakeLists.txt new file mode 100644 index 000000000..a77f75fbd --- /dev/null +++ b/bindings/Component/legacy/CMakeLists.txt @@ -0,0 +1,48 @@ +project(Bindings.Modules) + +# Backward compatibility with the layout used before the bindings followed SOFA's Sofa.Component tree. +# +# - python: Sofa.SofaBaseTopology, Sofa.SofaDeformable, Sofa.SofaLinearSolver, Sofa.SofaLinearSystem, +# Sofa.SofaConstraintSolver and SofaExporter are now thin modules re-exporting the new +# Sofa.Component.* modules (with a deprecation message). +# - cmake: the Bindings.Modules component is an alias of Bindings.Component. + +SP3_add_python_package( + SOURCE_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR}/python + TARGET_DIRECTORY + . +) + +# Compiled modules left over from a previous build would shadow the python modules above (python +# loads extension modules before source files): remove them from the build tree. +set(SP3_SITE_PACKAGES_BUILD_DIR "${CMAKE_BINARY_DIR}/lib/${SP3_PYTHON_PACKAGES_DIRECTORY}") +set(SP3_LEGACY_COMPILED_MODULES + Sofa/SofaBaseTopology + Sofa/SofaConstraintSolver + Sofa/SofaDeformable + Sofa/SofaFEM + Sofa/SofaGL + Sofa/SofaLinearSolver + Sofa/SofaLinearSystem + SofaExporter +) +foreach(legacy_module ${SP3_LEGACY_COMPILED_MODULES}) + file(GLOB legacy_files "${SP3_SITE_PACKAGES_BUILD_DIR}/${legacy_module}.*") + list(FILTER legacy_files EXCLUDE REGEX "\\.py$") + if(legacy_files) + message(STATUS "Removing outdated python module ${legacy_files}") + file(REMOVE ${legacy_files}) + endif() +endforeach() + +add_library(${PROJECT_NAME} INTERFACE) +add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} INTERFACE Bindings.Component) + +sofa_create_component_in_package_with_targets( + COMPONENT_NAME ${PROJECT_NAME} + COMPONENT_VERSION ${SofaPython3_VERSION} + PACKAGE_NAME SofaPython3 + TARGETS ${PROJECT_NAME} + ) diff --git a/bindings/Component/legacy/python/Sofa/SofaBaseTopology.py b/bindings/Component/legacy/python/Sofa/SofaBaseTopology.py new file mode 100644 index 000000000..ea2234c3a --- /dev/null +++ b/bindings/Component/legacy/python/Sofa/SofaBaseTopology.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.Topology.Container.Grid instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaBaseTopology' is deprecated and will be removed: " + "use 'Sofa.Component.Topology.Container.Grid' instead.") + +from Sofa.Component.Topology.Container.Grid import * diff --git a/bindings/Component/legacy/python/Sofa/SofaConstraintSolver.py b/bindings/Component/legacy/python/Sofa/SofaConstraintSolver.py new file mode 100644 index 000000000..57fde0f12 --- /dev/null +++ b/bindings/Component/legacy/python/Sofa/SofaConstraintSolver.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.Constraint.Lagrangian.Solver instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaConstraintSolver' is deprecated and will be removed: " + "use 'Sofa.Component.Constraint.Lagrangian.Solver' instead.") + +from Sofa.Component.Constraint.Lagrangian.Solver import * diff --git a/bindings/Component/legacy/python/Sofa/SofaDeformable.py b/bindings/Component/legacy/python/Sofa/SofaDeformable.py new file mode 100644 index 000000000..05e36539d --- /dev/null +++ b/bindings/Component/legacy/python/Sofa/SofaDeformable.py @@ -0,0 +1,8 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.SolidMechanics.Spring and Sofa.Component.SolidMechanics.FEM.Elastic instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaDeformable' is deprecated and will be removed: " + "use 'Sofa.Component.SolidMechanics.Spring' and 'Sofa.Component.SolidMechanics.FEM.Elastic' instead.") + +from Sofa.Component.SolidMechanics.Spring import * +from Sofa.Component.SolidMechanics.FEM.Elastic import * diff --git a/bindings/Component/legacy/python/Sofa/SofaLinearSolver.py b/bindings/Component/legacy/python/Sofa/SofaLinearSolver.py new file mode 100644 index 000000000..8d50a6f54 --- /dev/null +++ b/bindings/Component/legacy/python/Sofa/SofaLinearSolver.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.LinearSolver.Iterative instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaLinearSolver' is deprecated and will be removed: " + "use 'Sofa.Component.LinearSolver.Iterative' instead.") + +from Sofa.Component.LinearSolver.Iterative import * diff --git a/bindings/Component/legacy/python/Sofa/SofaLinearSystem.py b/bindings/Component/legacy/python/Sofa/SofaLinearSystem.py new file mode 100644 index 000000000..c7907b333 --- /dev/null +++ b/bindings/Component/legacy/python/Sofa/SofaLinearSystem.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.LinearSystem instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaLinearSystem' is deprecated and will be removed: " + "use 'Sofa.Component.LinearSystem' instead.") + +from Sofa.Component.LinearSystem import * diff --git a/bindings/Component/legacy/python/SofaExporter.py b/bindings/Component/legacy/python/SofaExporter.py new file mode 100644 index 000000000..3575f552e --- /dev/null +++ b/bindings/Component/legacy/python/SofaExporter.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.Component.IO.Mesh instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'SofaExporter' is deprecated and will be removed: " + "use 'Sofa.Component.IO.Mesh' instead.") + +from Sofa.Component.IO.Mesh import * diff --git a/bindings/Modules/tests/CMakeLists.txt b/bindings/Component/tests/CMakeLists.txt similarity index 54% rename from bindings/Modules/tests/CMakeLists.txt rename to bindings/Component/tests/CMakeLists.txt index d1055b36a..fb96b7a7d 100644 --- a/bindings/Modules/tests/CMakeLists.txt +++ b/bindings/Component/tests/CMakeLists.txt @@ -1,18 +1,22 @@ -project(Bindings.Modules.Tests) +project(Bindings.Component.Tests) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp ) -set(PYTHON_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/SofaDeformable/LinearSpring.py - ${CMAKE_CURRENT_SOURCE_DIR}/SofaDeformable/SpringForceField.py - - ${CMAKE_CURRENT_SOURCE_DIR}/SofaLinearSolver/matrix_access.py - - ${CMAKE_CURRENT_SOURCE_DIR}/SofaConstraintSolver/matrix_access.py +# Python test directories, one per bound SOFA module (same layout as the bindings) +set(TEST_DIRECTORIES + Constraint/Lagrangian/Solver + LinearSolver/Iterative + SolidMechanics/Spring ) +set(PYTHON_FILES) +foreach(test_dir ${TEST_DIRECTORIES}) + file(GLOB test_dir_files "${CMAKE_CURRENT_SOURCE_DIR}/${test_dir}/*.py") + list(APPEND PYTHON_FILES ${test_dir_files}) +endforeach() + find_package(Sofa.Testing REQUIRED) enable_testing() @@ -29,20 +33,20 @@ sofa_auto_set_target_rpath( add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) -set(DIR_BINDING_LIST SofaBaseTopology SofaDeformable SofaLinearSolver SofaConstraintSolver) get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -foreach(dir_binding ${DIR_BINDING_LIST}) - if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${dir_binding}") +foreach(test_dir ${TEST_DIRECTORIES}) + string(REPLACE "/" "." binding_target "Bindings.Component.${test_dir}") + if (NOT TARGET ${binding_target}) continue() endif() if (_isMultiConfig) # MSVC foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) - SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${dir_binding} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${PROJECT_NAME}.d/${dir_binding}) - install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${PROJECT_NAME}.d/${dir_binding} DESTINATION ${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d) + SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${test_dir} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${PROJECT_NAME}.d/${test_dir}) + install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${config_type}/${PROJECT_NAME}.d/${test_dir}/ DESTINATION ${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${test_dir}) endforeach() else() - SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${dir_binding} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${dir_binding}) - install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${dir_binding} DESTINATION ${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d) + SP3_configure_directory(${CMAKE_CURRENT_SOURCE_DIR}/${test_dir} ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${test_dir}) + install(DIRECTORY ${CMAKE_BINARY_DIR}/${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${test_dir}/ DESTINATION ${RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}.d/${test_dir}) endif() endforeach() diff --git a/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py b/bindings/Component/tests/Constraint/Lagrangian/Solver/matrix_access.py similarity index 95% rename from bindings/Modules/tests/SofaConstraintSolver/matrix_access.py rename to bindings/Component/tests/Constraint/Lagrangian/Solver/matrix_access.py index 9dd87dd45..42a7de971 100644 --- a/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py +++ b/bindings/Component/tests/Constraint/Lagrangian/Solver/matrix_access.py @@ -1,6 +1,6 @@ import unittest import Sofa.Core -from Sofa import SofaConstraintSolver +import Sofa.Component.Constraint.Lagrangian.Solver class Test(unittest.TestCase): @@ -18,6 +18,7 @@ def simulate_pendulum(self): "Sofa.Component.Mapping.MappedMatrix", "Sofa.Component.Mass", "Sofa.Component.IntegrationScheme.Backward", + "Sofa.Component.StateContainer", "Sofa.Component.Topology.Container.Dynamic"]) root.addObject("FreeMotionAnimationLoop", solveVelocityConstraintFirst=True) diff --git a/bindings/Modules/tests/SofaLinearSolver/matrix_access.py b/bindings/Component/tests/LinearSolver/Iterative/matrix_access.py similarity index 91% rename from bindings/Modules/tests/SofaLinearSolver/matrix_access.py rename to bindings/Component/tests/LinearSolver/Iterative/matrix_access.py index cd84eb4bf..fade8eb0b 100644 --- a/bindings/Modules/tests/SofaLinearSolver/matrix_access.py +++ b/bindings/Component/tests/LinearSolver/Iterative/matrix_access.py @@ -1,6 +1,6 @@ import unittest import Sofa.Core -from Sofa import SofaLinearSolver +import Sofa.Component.LinearSolver.Iterative class Test(unittest.TestCase): @@ -15,6 +15,8 @@ def simulate_beam(self, linear_solver_template): root.addObject('RequiredPlugin', pluginName='Sofa.Component.Constraint.Projective') root.addObject('RequiredPlugin', pluginName='Sofa.Component.SolidMechanics.FEM.Elastic') root.addObject('RequiredPlugin', pluginName='Sofa.Component.Mass') + root.addObject('RequiredPlugin', pluginName='Sofa.Component.StateContainer') + root.addObject('RequiredPlugin', pluginName='Sofa.Component.Topology.Container.Grid') root.addObject('EulerImplicitIntegrationScheme', rayleighStiffness="0.1", rayleighMass="0.1") linear_solver = root.addObject('SparseLDLSolver', name='linear_solver', template=linear_solver_template) diff --git a/bindings/Component/tests/SolidMechanics/Spring/LegacyModuleName.py b/bindings/Component/tests/SolidMechanics/Spring/LegacyModuleName.py new file mode 100644 index 000000000..1ec3506bb --- /dev/null +++ b/bindings/Component/tests/SolidMechanics/Spring/LegacyModuleName.py @@ -0,0 +1,27 @@ +# coding: utf8 + +import unittest + +import Sofa.Component.SolidMechanics.Spring as Spring +import Sofa.Component.SolidMechanics.FEM.Elastic as Elastic + + +class Test(unittest.TestCase): + def __init__(self, a): + unittest.TestCase.__init__(self, a) + + def test_module_path(self): + self.assertEqual(Spring.__name__, "Sofa.Component.SolidMechanics.Spring") + self.assertEqual(Spring.LinearSpring.__module__, "Sofa.Component.SolidMechanics.Spring") + self.assertEqual(Spring.SpringForceField_Vec3d.__module__, "Sofa.Component.SolidMechanics.Spring") + + def test_deprecated_SofaDeformable(self): + # The deprecated module re-exports the bindings of both SOFA modules it used to contain + from Sofa import SofaDeformable + self.assertIs(SofaDeformable.LinearSpring, Spring.LinearSpring) + self.assertIs(SofaDeformable.SpringForceField_Vec3d, Spring.SpringForceField_Vec3d) + self.assertIs(SofaDeformable.toLameParameters3D, Elastic.toLameParameters3D) + + +if __name__ == '__main__': + unittest.main() diff --git a/bindings/Modules/tests/SofaDeformable/LinearSpring.py b/bindings/Component/tests/SolidMechanics/Spring/LinearSpring.py similarity index 96% rename from bindings/Modules/tests/SofaDeformable/LinearSpring.py rename to bindings/Component/tests/SolidMechanics/Spring/LinearSpring.py index fbd2de924..dd649d5f0 100644 --- a/bindings/Modules/tests/SofaDeformable/LinearSpring.py +++ b/bindings/Component/tests/SolidMechanics/Spring/LinearSpring.py @@ -1,7 +1,7 @@ # coding: utf8 import unittest -from Sofa.SofaDeformable import LinearSpring +from Sofa.Component.SolidMechanics.Spring import LinearSpring class Test(unittest.TestCase): diff --git a/bindings/Modules/tests/SofaDeformable/SpringForceField.py b/bindings/Component/tests/SolidMechanics/Spring/SpringForceField.py similarity index 91% rename from bindings/Modules/tests/SofaDeformable/SpringForceField.py rename to bindings/Component/tests/SolidMechanics/Spring/SpringForceField.py index 20a71fb97..2a4f3ddda 100644 --- a/bindings/Modules/tests/SofaDeformable/SpringForceField.py +++ b/bindings/Component/tests/SolidMechanics/Spring/SpringForceField.py @@ -1,6 +1,6 @@ import unittest import Sofa -from Sofa import SofaDeformable +from Sofa.Component.SolidMechanics import Spring import numpy as np @@ -76,7 +76,7 @@ def test_clear(self): def test_add_one_spring(self): self.root.spring_ff.clear() self.root.spring_ff.addSpring( - SofaDeformable.LinearSpring(index1=2, index2=2, springStiffness=1, dampingFactor=1, restLength=1, elongationOnly=True, enabled=False) + Spring.LinearSpring(index1=2, index2=2, springStiffness=1, dampingFactor=1, restLength=1, elongationOnly=True, enabled=False) ) self.assertEqual(len(self.root.spring_ff.getSprings()), 1) spring_1 = self.root.spring_ff.getSprings()[0] @@ -102,8 +102,8 @@ def test_add_one_spring(self): def test_add_many_springs(self): self.root.spring_ff.clear() self.root.spring_ff.addSprings([ - SofaDeformable.LinearSpring(index1=2, index2=2, springStiffness=1, dampingFactor=1, restLength=1, elongationOnly=True, enabled=False), - SofaDeformable.LinearSpring(index1=3, index2=3, springStiffness=2, dampingFactor=2, restLength=2, elongationOnly=False, enabled=True) + Spring.LinearSpring(index1=2, index2=2, springStiffness=1, dampingFactor=1, restLength=1, elongationOnly=True, enabled=False), + Spring.LinearSpring(index1=3, index2=3, springStiffness=2, dampingFactor=2, restLength=2, elongationOnly=False, enabled=True) ]) self.assertEqual(len(self.root.spring_ff.getSprings()), 2) spring_1 = self.root.spring_ff.getSprings()[0] diff --git a/bindings/Modules/tests/main.cpp b/bindings/Component/tests/main.cpp similarity index 74% rename from bindings/Modules/tests/main.cpp rename to bindings/Component/tests/main.cpp index daf9b21f4..376173705 100644 --- a/bindings/Modules/tests/main.cpp +++ b/bindings/Component/tests/main.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -38,18 +40,26 @@ static struct Tests : public sofapython3::PythonTestExtractor MessageDispatcher::addHandler(&MainPerComponentLoggingMessageHandler::getInstance()) ; const std::string executable_directory = sofa::helper::Utils::getExecutableDirectory(); - addTestDirectory(executable_directory+"/Bindings.Modules.Tests.d/SofaDeformable", "SofaDeformable_"); - addTestDirectory(executable_directory+"/Bindings.Modules.Tests.d/SofaLinearSolver", "SofaLinearSolver_"); - addTestDirectory(executable_directory+"/Bindings.Modules.Tests.d/SofaConstraintSolver", "SofaConstraintSolver_"); + // One directory per bound SOFA module, only present if the module bindings were built + for (const std::string module : {"Constraint/Lagrangian/Solver", "LinearSolver/Iterative", "SolidMechanics/Spring"}) + { + const std::string directory = executable_directory + "/Bindings.Component.Tests.d/" + module; + if (sofa::helper::system::FileSystem::exists(directory)) + { + std::string testgroup = module + "_"; + std::replace(testgroup.begin(), testgroup.end(), '/', '_'); + addTestDirectory(directory, testgroup); + } + } } } python_tests; /// run test list using the custom name function getTestName. /// this allows to do gtest_filter=*FileName* -class Modules : public sofapython3::PythonTest {}; +class Component : public sofapython3::PythonTest {}; INSTANTIATE_TEST_SUITE_P(SofaPython3, - Modules, + Component, ::testing::ValuesIn(python_tests.extract()), - Modules::getTestName); + Component::getTestName); -TEST_P(Modules, all_tests) { run(GetParam()); } +TEST_P(Component, all_tests) { run(GetParam()); } diff --git a/bindings/Modules/CMakeLists.txt b/bindings/Modules/CMakeLists.txt deleted file mode 100644 index e47f53071..000000000 --- a/bindings/Modules/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -project(Bindings.Modules) - -set(MODULEBINDINGS_MODULE_LIST - SofaBaseTopology - SofaDeformable - SofaLinearSolver - SofaLinearSystem - SofaConstraintSolver - SofaFEM -) - -sofa_find_package(Sofa.GL QUIET) -if(Sofa.GL_FOUND) - list(APPEND MODULEBINDINGS_MODULE_LIST SofaGL) -else() - message("Sofa.GL not detected. Python3 Bindings for Sofa.SofaGL will not be compiled.") -endif() - - -foreach(modulebindings_module ${MODULEBINDINGS_MODULE_LIST}) - message(STATUS "Adding binding module ${modulebindings_module}") - add_subdirectory(src/SofaPython3/${modulebindings_module}) -endforeach() - - -add_library(${PROJECT_NAME} INTERFACE) -add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) - -foreach(modulebindings_module ${MODULEBINDINGS_MODULE_LIST}) - target_link_libraries(${PROJECT_NAME} INTERFACE ${PROJECT_NAME}.${modulebindings_module}) - set_target_properties(${PROJECT_NAME}.${modulebindings_module} PROPERTIES FOLDER "Bindings/Modules") -endforeach() - -if(SP3_BUILD_TEST) - add_subdirectory(tests) -endif() - -sofa_create_component_in_package_with_targets( - COMPONENT_NAME ${PROJECT_NAME} - COMPONENT_VERSION ${SofaPython3_VERSION} - PACKAGE_NAME SofaPython3 - TARGETS ${PROJECT_NAME} - ) diff --git a/bindings/Modules/src/SofaPython3/SofaBaseTopology/CMakeLists.txt b/bindings/Modules/src/SofaPython3/SofaBaseTopology/CMakeLists.txt deleted file mode 100644 index 6e56ae462..000000000 --- a/bindings/Modules/src/SofaPython3/SofaBaseTopology/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -project(Bindings.Modules.SofaBaseTopology) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_RegularGridTopology.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SparseGridTopology.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaBaseTopology.cpp -) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_RegularGridTopology.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_RegularGridTopology_doc.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SparseGridTopology.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SparseGridTopology_doc.h -) - -sofa_find_package(Sofa.Component.Topology.Container.Grid REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaBaseTopology - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.Topology.Container.Grid SofaPython3::Plugin -) diff --git a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/CMakeLists.txt b/bindings/Modules/src/SofaPython3/SofaConstraintSolver/CMakeLists.txt deleted file mode 100644 index 3818293b1..000000000 --- a/bindings/Modules/src/SofaPython3/SofaConstraintSolver/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -project(Bindings.Modules.SofaConstraintSolver) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_ConstraintSolver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_ConstraintSolver_doc.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_ConstraintSolver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaConstraintSolver.cpp -) - -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() - -sofa_find_package(Sofa.Component.Constraint.Lagrangian.Solver REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaConstraintSolver - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.Constraint.Lagrangian.Solver SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core -) diff --git a/bindings/Modules/src/SofaPython3/SofaDeformable/CMakeLists.txt b/bindings/Modules/src/SofaPython3/SofaDeformable/CMakeLists.txt deleted file mode 100644 index c884ff1af..000000000 --- a/bindings/Modules/src/SofaPython3/SofaDeformable/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -project(Bindings.Modules.SofaDeformable) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_CauchyStress.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LameParameters.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSpring.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SpringForceField.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaDeformable.cpp -) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_CauchyStress.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LameParameters.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSpring.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSpring_doc.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SpringForceField.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_SpringForceField_doc.h -) - -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() - -sofa_find_package(Sofa.Component.SolidMechanics.Spring REQUIRED) -sofa_find_package(Sofa.Component.SolidMechanics.FEM.Elastic REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaDeformable - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.SolidMechanics.Spring Sofa.Component.SolidMechanics.FEM.Elastic SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core - -) diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSolver/CMakeLists.txt b/bindings/Modules/src/SofaPython3/SofaLinearSolver/CMakeLists.txt deleted file mode 100644 index 9e709544a..000000000 --- a/bindings/Modules/src/SofaPython3/SofaLinearSolver/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -project(Bindings.Modules.SofaLinearSolver) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSolver.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSolver_doc.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSolver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaLinearSolver.cpp -) - -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() - -sofa_find_package(Sofa.Component.LinearSolver.Iterative REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaLinearSolver - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.LinearSolver.Iterative SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core -) diff --git a/bindings/Modules/src/SofaPython3/SofaLinearSystem/CMakeLists.txt b/bindings/Modules/src/SofaPython3/SofaLinearSystem/CMakeLists.txt deleted file mode 100644 index fd0805488..000000000 --- a/bindings/Modules/src/SofaPython3/SofaLinearSystem/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -project(Bindings.Modules.SofaLinearSystem) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSystem.h - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSystem.inl - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSystem_doc.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinearSystem.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaLinearSystem.cpp -) - -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() - -sofa_find_package(Sofa.Component.LinearSystem REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaLinearSystem - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.LinearSystem SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core -) diff --git a/bindings/Sofa/Bindings.SofaConfig.cmake.in b/bindings/Sofa/Bindings.SofaConfig.cmake.in index 42f003bce..0affc00b8 100644 --- a/bindings/Sofa/Bindings.SofaConfig.cmake.in +++ b/bindings/Sofa/Bindings.SofaConfig.cmake.in @@ -21,6 +21,15 @@ sofa_find_package(Sofa.SimpleApi QUIET REQUIRED) # Required by Bindings.Sofa.Simulation sofa_find_package(Sofa.Simulation.Graph QUIET REQUIRED) +# Optional framework modules bound by Bindings.Sofa.FEM and Bindings.Sofa.GL +set(SP3_BINDINGS_SOFA_MODULES "@SOFABINDINGS_MODULE_LIST@") +if("FEM" IN_LIST SP3_BINDINGS_SOFA_MODULES) + sofa_find_package(Sofa.FEM QUIET REQUIRED) +endif() +if("GL" IN_LIST SP3_BINDINGS_SOFA_MODULES) + sofa_find_package(Sofa.GL QUIET REQUIRED) +endif() + # If we are importing this config file and the target is not yet there this is indicating that # target is an imported one. So we include it if(NOT TARGET @PROJECT_NAME@) diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 63227a2b9..a5d3f04da 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -7,6 +7,20 @@ set(SOFABINDINGS_MODULE_LIST Types ) +# Optional framework modules +sofa_find_package(Sofa.FEM QUIET) +if(Sofa.FEM_FOUND) + list(APPEND SOFABINDINGS_MODULE_LIST FEM) +else() + message(STATUS "Sofa.FEM not found: python bindings Sofa.FEM will not be compiled.") +endif() +sofa_find_package(Sofa.GL QUIET) +if(Sofa.GL_FOUND) + list(APPEND SOFABINDINGS_MODULE_LIST GL) +else() + message(STATUS "Sofa.GL not found: python bindings Sofa.GL will not be compiled.") +endif() + foreach(sofabindings_module ${SOFABINDINGS_MODULE_LIST}) add_subdirectory(src/SofaPython3/Sofa/${sofabindings_module}) endforeach() diff --git a/bindings/Sofa/package/SofaFEM.py b/bindings/Sofa/package/SofaFEM.py new file mode 100644 index 000000000..6a979b836 --- /dev/null +++ b/bindings/Sofa/package/SofaFEM.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.FEM instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaFEM' is deprecated and will be removed: " + "use 'Sofa.FEM' instead.") + +from Sofa.FEM import * diff --git a/bindings/Sofa/package/SofaGL.py b/bindings/Sofa/package/SofaGL.py new file mode 100644 index 000000000..e0cd5c162 --- /dev/null +++ b/bindings/Sofa/package/SofaGL.py @@ -0,0 +1,7 @@ +"""Deprecated module, kept for backward compatibility. Use Sofa.GL instead.""" +import Sofa.Helper + +Sofa.Helper.msg_deprecated("SofaPython3", "The python module 'Sofa.SofaGL' is deprecated and will be removed: " + "use 'Sofa.GL' instead.") + +from Sofa.GL import * diff --git a/bindings/Modules/src/SofaPython3/SofaFEM/Binding_Quadrature.cpp b/bindings/Sofa/src/SofaPython3/Sofa/FEM/Binding_Quadrature.cpp similarity index 98% rename from bindings/Modules/src/SofaPython3/SofaFEM/Binding_Quadrature.cpp rename to bindings/Sofa/src/SofaPython3/Sofa/FEM/Binding_Quadrature.cpp index 2ef429746..5bd782307 100644 --- a/bindings/Modules/src/SofaPython3/SofaFEM/Binding_Quadrature.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/FEM/Binding_Quadrature.cpp @@ -17,7 +17,7 @@ ******************************************************************************* * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#include +#include #include @@ -64,7 +64,7 @@ static py::tuple withElement(const std::string& element, py::ssize_t dim, Functi if (element == "Tetrahedron" && dim == 3) return f(ElementTag{}); if (element == "Hexahedron" && dim == 3) return f(ElementTag{}); - throw py::value_error("SofaFEM: unsupported element '" + element + "' for dimension " + std::to_string(dim)); + throw py::value_error("Sofa.FEM: unsupported element '" + element + "' for dimension " + std::to_string(dim)); } // Reference-space quadrature points' data for one FiniteElement specialization: diff --git a/bindings/Modules/src/SofaPython3/SofaFEM/Binding_Quadrature.h b/bindings/Sofa/src/SofaPython3/Sofa/FEM/Binding_Quadrature.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaFEM/Binding_Quadrature.h rename to bindings/Sofa/src/SofaPython3/Sofa/FEM/Binding_Quadrature.h diff --git a/bindings/Modules/src/SofaPython3/SofaFEM/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/FEM/CMakeLists.txt similarity index 61% rename from bindings/Modules/src/SofaPython3/SofaFEM/CMakeLists.txt rename to bindings/Sofa/src/SofaPython3/Sofa/FEM/CMakeLists.txt index f6111c328..464333fee 100644 --- a/bindings/Modules/src/SofaPython3/SofaFEM/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/FEM/CMakeLists.txt @@ -1,24 +1,20 @@ -project(Bindings.Modules.SofaFEM) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Quadrature.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaFEM.cpp -) +project(Bindings.Sofa.FEM) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Quadrature.h ) -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Quadrature.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_FEM.cpp +) sofa_find_package(Sofa.FEM REQUIRED) SP3_add_python_module( TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaFEM + PACKAGE Bindings.Sofa + MODULE FEM DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} diff --git a/bindings/Modules/src/SofaPython3/SofaFEM/Module_SofaFEM.cpp b/bindings/Sofa/src/SofaPython3/Sofa/FEM/Submodule_FEM.cpp similarity index 95% rename from bindings/Modules/src/SofaPython3/SofaFEM/Module_SofaFEM.cpp rename to bindings/Sofa/src/SofaPython3/Sofa/FEM/Submodule_FEM.cpp index ff000ca2c..f53de852d 100644 --- a/bindings/Modules/src/SofaPython3/SofaFEM/Module_SofaFEM.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/FEM/Submodule_FEM.cpp @@ -19,14 +19,14 @@ ******************************************************************************/ #include -#include +#include namespace py { using namespace pybind11; } namespace sofapython3 { -PYBIND11_MODULE(SofaFEM, m) +PYBIND11_MODULE(FEM, m) { m.doc() = "Bindings for the sofa::fem finite-element machinery"; diff --git a/bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL.cpp b/bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL.cpp similarity index 93% rename from bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL.cpp rename to bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL.cpp index 3c4377185..1880f4426 100644 --- a/bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL.cpp @@ -28,8 +28,8 @@ using sofa::simulation::Node; #include #include -#include -#include +#include +#include namespace sofapython3 { @@ -51,11 +51,11 @@ void moduleAddDrawToolGL(pybind11::module& m) { vparam->setSupported(sofa::core::visual::API_OpenGL); } sofa::simulation::node::draw(vparam, node); - }, doc::SofaGL::draw); + }, doc::gl::draw); m.def("glewInit", [](){ glewInit(); - }, doc::SofaGL::glewInit); + }, doc::gl::glewInit); } } // namespace sofapython3 diff --git a/bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL.h b/bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL.h similarity index 100% rename from bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL.h rename to bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL.h diff --git a/bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL_doc.h similarity index 96% rename from bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL_doc.h rename to bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL_doc.h index 085024f68..c8f47d755 100644 --- a/bindings/Modules/src/SofaPython3/SofaGL/Binding_DrawToolGL_doc.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/GL/Binding_DrawToolGL_doc.h @@ -20,7 +20,7 @@ #pragma once -namespace sofapython3::doc::SofaGL { +namespace sofapython3::doc::gl { static auto draw = R"( Draw the openGL visual loop from the provided Node. @@ -33,4 +33,4 @@ R"( Initialize GLEW. This should be called once before drawing. )"; -} // sofapython3::doc::SofaGL +} // sofapython3::doc::gl diff --git a/bindings/Modules/src/SofaPython3/SofaGL/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/GL/CMakeLists.txt similarity index 64% rename from bindings/Modules/src/SofaPython3/SofaGL/CMakeLists.txt rename to bindings/Sofa/src/SofaPython3/Sofa/GL/CMakeLists.txt index 257122946..cd2909abc 100644 --- a/bindings/Modules/src/SofaPython3/SofaGL/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/GL/CMakeLists.txt @@ -1,28 +1,23 @@ -project(Bindings.Modules.SofaGL) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Module_SofaGL.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DrawToolGL.cpp -) +project(Bindings.Sofa.GL) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DrawToolGL.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DrawToolGL_doc.h ) -if (NOT TARGET SofaPython3::Plugin) - find_package(SofaPython3 REQUIRED COMPONENTS Plugin Bindings.Sofa) -endif() +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DrawToolGL.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_GL.cpp +) sofa_find_package(Sofa.GL REQUIRED) SP3_add_python_module( TARGET ${PROJECT_NAME} - PACKAGE Bindings.Modules - MODULE SofaGL + PACKAGE Bindings.Sofa + MODULE GL DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} DEPENDS Sofa.GL SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core - ) diff --git a/bindings/Modules/src/SofaPython3/SofaGL/Module_SofaGL.cpp b/bindings/Sofa/src/SofaPython3/Sofa/GL/Submodule_GL.cpp similarity index 95% rename from bindings/Modules/src/SofaPython3/SofaGL/Module_SofaGL.cpp rename to bindings/Sofa/src/SofaPython3/Sofa/GL/Submodule_GL.cpp index b302bf801..55cbd4d15 100644 --- a/bindings/Modules/src/SofaPython3/SofaGL/Module_SofaGL.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/GL/Submodule_GL.cpp @@ -19,7 +19,7 @@ ******************************************************************************/ #include -#include +#include namespace py { using namespace pybind11; } @@ -27,7 +27,7 @@ namespace py { using namespace pybind11; } namespace sofapython3 { -PYBIND11_MODULE(SofaGL, m) +PYBIND11_MODULE(GL, m) { m.doc() = "Exposes the rendering API using OpenGL"; diff --git a/bindings/SofaExporter/CMakeLists.txt b/bindings/SofaExporter/CMakeLists.txt deleted file mode 100644 index 58a5b286c..000000000 --- a/bindings/SofaExporter/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -project(Bindings.SofaExporter) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_STLExporter.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_STLExporter_doc.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_VisualModelOBJExporter.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_VisualModelOBJExporter_doc.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_STLExporter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Binding_VisualModelOBJExporter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaExporter/Module_SofaExporter.cpp -) - -sofa_find_package(Sofa.Component.IO.Mesh REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - MODULE SofaExporter - DESTINATION . - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Component.IO.Mesh SofaPython3::Plugin SofaPython3::Bindings.Sofa.Core -) - -sofa_create_component_in_package_with_targets( - COMPONENT_NAME ${PROJECT_NAME} - COMPONENT_VERSION ${SofaPython3_VERSION} - PACKAGE_NAME SofaPython3 - TARGETS ${PROJECT_NAME} - ) diff --git a/docs/README.md b/docs/README.md index 7a67c2000..8560b5ffd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,7 +40,11 @@ Go inside the `SofaPython3/docs` directory and run ```shell pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" SofaRuntime pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" Sofa -pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" SofaExporter +for module in Sofa.FEM Sofa.GL Sofa.Component.IO.Mesh Sofa.Component.Topology.Container.Grid Sofa.Component.LinearSystem \ + Sofa.Component.LinearSolver.Iterative Sofa.Component.Constraint.Lagrangian.Solver \ + Sofa.Component.SolidMechanics.Spring Sofa.Component.SolidMechanics.FEM.Elastic; do + pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" $module +done pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" SofaTypes pybind11-stubgen -o sphinx-stubs --no-setup-py --ignore-invalid=signature --root-module-suffix="" splib ``` diff --git a/docs/sphinx/source/content/Modules.rst b/docs/sphinx/source/content/Modules.rst index 602ae0405..e0fddcbaa 100644 --- a/docs/sphinx/source/content/Modules.rst +++ b/docs/sphinx/source/content/Modules.rst @@ -8,7 +8,6 @@ Modules modules/Sofa/index modules/SofaRuntime/index - modules/SofaExporter/index The SofaPython3 binding is highly modular allowing to select only the modules strictly relevant to your needs. @@ -18,6 +17,5 @@ Most commonly used modules provided by the Sofa-consortium are: Sofa SofaRuntime - SofaExporter \ No newline at end of file diff --git a/docs/sphinx/source/content/modules/Sofa/additionalmodules.rst b/docs/sphinx/source/content/modules/Sofa/additionalmodules.rst index 8d9c5dfb0..aae086bde 100644 --- a/docs/sphinx/source/content/modules/Sofa/additionalmodules.rst +++ b/docs/sphinx/source/content/modules/Sofa/additionalmodules.rst @@ -6,7 +6,12 @@ Additional modules :template: autosummary/sub-modules.rst :recursive: - Sofa.SofaBaseTopology - Sofa.SofaConstraintSolver - Sofa.SofaDeformable - Sofa.SofaGL \ No newline at end of file + Sofa.Component.Constraint.Lagrangian.Solver + Sofa.Component.IO.Mesh + Sofa.Component.LinearSolver.Iterative + Sofa.Component.LinearSystem + Sofa.Component.SolidMechanics.FEM.Elastic + Sofa.Component.SolidMechanics.Spring + Sofa.Component.Topology.Container.Grid + Sofa.FEM + Sofa.GL diff --git a/docs/sphinx/source/content/modules/Sofa/index.rst b/docs/sphinx/source/content/modules/Sofa/index.rst index 69a69e542..b01df1c93 100644 --- a/docs/sphinx/source/content/modules/Sofa/index.rst +++ b/docs/sphinx/source/content/modules/Sofa/index.rst @@ -50,7 +50,12 @@ Sofa .. autosummary:: :template: autosummary/sub-modules.rst - SofaBaseTopology - SofaConstraintSolver - SofaDeformable - SofaGL + Component.Constraint.Lagrangian.Solver + Component.IO.Mesh + Component.LinearSolver.Iterative + Component.LinearSystem + Component.SolidMechanics.FEM.Elastic + Component.SolidMechanics.Spring + Component.Topology.Container.Grid + FEM + GL diff --git a/docs/sphinx/source/content/modules/SofaExporter/index.rst b/docs/sphinx/source/content/modules/SofaExporter/index.rst deleted file mode 100644 index 1b6896444..000000000 --- a/docs/sphinx/source/content/modules/SofaExporter/index.rst +++ /dev/null @@ -1,17 +0,0 @@ -SofaExporter -************ - -.. currentmodule:: SofaExporter - -.. automodule:: SofaExporter - -API Table of Content --------------------- - -.. autosummary:: - :toctree: generated - :template: autosummary/base.rst - :recursive: - - STLExporter - VisualModelOBJExporter diff --git a/examples/access_compliance_matrix.py b/examples/access_compliance_matrix.py index b1007a5c2..f182002ff 100644 --- a/examples/access_compliance_matrix.py +++ b/examples/access_compliance_matrix.py @@ -1,7 +1,7 @@ # Required import for python import Sofa import SofaRuntime -from Sofa import SofaConstraintSolver +import Sofa.Component.Constraint.Lagrangian.Solver import numpy as np diff --git a/examples/access_mass_matrix.py b/examples/access_mass_matrix.py index 1bd6519f4..dd6a4ceca 100644 --- a/examples/access_mass_matrix.py +++ b/examples/access_mass_matrix.py @@ -1,7 +1,7 @@ # Required import for python import Sofa import SofaRuntime -from Sofa import SofaLinearSystem +import Sofa.Component.LinearSystem from scipy import sparse from scipy import linalg from matplotlib import pyplot as plt diff --git a/examples/access_matrix.py b/examples/access_matrix.py index fd654b6ce..f1cf7068f 100644 --- a/examples/access_matrix.py +++ b/examples/access_matrix.py @@ -1,8 +1,8 @@ # Required import for python import Sofa import SofaRuntime -from Sofa import SofaLinearSystem -from Sofa import SofaLinearSolver +import Sofa.Component.LinearSystem +import Sofa.Component.LinearSolver.Iterative from scipy import sparse def createBeam(root, matrix_type): diff --git a/examples/additional-examples/pygame_example.py b/examples/additional-examples/pygame_example.py index b7f876f1f..63e9ecc5e 100644 --- a/examples/additional-examples/pygame_example.py +++ b/examples/additional-examples/pygame_example.py @@ -1,5 +1,5 @@ import Sofa -import Sofa.SofaGL +import Sofa.GL import SofaRuntime import Sofa.Simulation as sim import os @@ -19,7 +19,7 @@ def init_display(node): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glEnable(GL_LIGHTING) glEnable(GL_DEPTH_TEST) - Sofa.SofaGL.glewInit() + Sofa.GL.glewInit() Sofa.Simulation.initVisual(node) Sofa.Simulation.initTextures(node) glMatrixMode(GL_PROJECTION) @@ -44,7 +44,7 @@ def simple_render(rootNode): cameraMVM = rootNode.camera.getOpenGLModelViewMatrix() glMultMatrixd(cameraMVM) - Sofa.SofaGL.draw(rootNode) + Sofa.GL.draw(rootNode) pygame.display.get_surface().fill((0,0,0)) pygame.display.flip() diff --git a/examples/additional-examples/pyqt_example.py b/examples/additional-examples/pyqt_example.py index bde909363..6cbf4143c 100644 --- a/examples/additional-examples/pyqt_example.py +++ b/examples/additional-examples/pyqt_example.py @@ -1,7 +1,7 @@ from qtpy.QtCore import * from qtpy.QtWidgets import * from qtpy.QtOpenGL import * -import Sofa.SofaGL +import Sofa.GL import Sofa import SofaRuntime import Sofa.Simulation as sim @@ -55,7 +55,7 @@ def initializeGL(self): glEnable(GL_LIGHTING) glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LESS) - Sofa.SofaGL.glewInit() + Sofa.GL.glewInit() Sofa.Simulation.initVisual(self.visuals_node) Sofa.Simulation.initTextures(self.visuals_node) glMatrixMode(GL_PROJECTION) @@ -76,7 +76,7 @@ def paintGL(self): cameraMVM = self.visuals_node.camera.getOpenGLModelViewMatrix() glMultMatrixd(cameraMVM) - Sofa.SofaGL.draw(self.visuals_node) + Sofa.GL.draw(self.visuals_node) def get_depth_image(self): _, _, width, height = glGetIntegerv(GL_VIEWPORT) diff --git a/examples/source-terms/example-quadrature-rules.py b/examples/source-terms/example-quadrature-rules.py index 05259f5d9..3f7220ae3 100644 --- a/examples/source-terms/example-quadrature-rules.py +++ b/examples/source-terms/example-quadrature-rules.py @@ -1,6 +1,6 @@ """Solves a linear elastic problem with a prescribed load on the RHS. The load is assembled from a manufactured body-force density. The assembly is done by -integrating the density using quadrature information provided by the SofaFEM +integrating the density using quadrature information provided by the Sofa.FEM quadrature bindings. The resulting displacement should match the manufactured solution: @@ -16,7 +16,7 @@ import numpy as np import Sofa import Sofa.Core -from Sofa import SofaFEM +from Sofa import FEM AMPLITUDE = 0.03 WAVENUMBER = 2 * np.pi @@ -42,8 +42,8 @@ def assemble_nodal_force(node_coordinates, node_indices, quadrature_degree, noda F_a = sum_q w_q * measure_q * N_a(q) * r(q), with r(q) = sum_a N_a(q) * density_a""" # First get the quadrature data and mapping information for the corresponding topological element - weights, shape_functions, reference_gradients = SofaFEM.quadrature_data("Triangle", 2, quadrature_degree) - _, measures = SofaFEM.element_mapping_batch("Triangle", node_coordinates, node_indices, reference_gradients) + weights, shape_functions, reference_gradients = FEM.quadrature_data("Triangle", 2, quadrature_degree) + _, measures = FEM.element_mapping_batch("Triangle", node_coordinates, node_indices, reference_gradients) element_density = nodal_density[node_indices] # density at each element's local nodes, (E, nbNodes, dof) nb_nodes_per_element = node_indices.shape[1] diff --git a/examples/springForceField.py b/examples/springForceField.py index aa8ad9a22..a0cad0337 100644 --- a/examples/springForceField.py +++ b/examples/springForceField.py @@ -1,6 +1,6 @@ import Sofa import SofaRuntime -from Sofa import SofaDeformable +import Sofa.Component.SolidMechanics.Spring def createScene(root): diff --git a/examples/stvenant_kirchhoff.py b/examples/stvenant_kirchhoff.py index 68d78fdaa..92a84bf44 100644 --- a/examples/stvenant_kirchhoff.py +++ b/examples/stvenant_kirchhoff.py @@ -1,5 +1,5 @@ import Sofa -import Sofa.SofaDeformable +import Sofa.Component.SolidMechanics.FEM.Elastic from Sofa.Units.Definitions import s, m, cm, N, g, kg, MPa from Sofa.Units.UnitSystem import MechanicalUnitSystem @@ -44,7 +44,7 @@ def createScene(root_node): young_modulus = scene_unit(0.5, MPa) poisson_ratio = 0.45 - lame_parameters = Sofa.SofaDeformable.toLameParameters3D(young_modulus, poisson_ratio) + lame_parameters = Sofa.Component.SolidMechanics.FEM.Elastic.toLameParameters3D(young_modulus, poisson_ratio) tetra.addObject('TetrahedronHyperelasticityFEMForceField', name="FEM", topology="@Tetra_topo", ParameterSet=lame_parameters, materialName="StVenantKirchhoff") diff --git a/scripts/generate_stubs.py b/scripts/generate_stubs.py index f221ea72f..9ae946f0d 100644 --- a/scripts/generate_stubs.py +++ b/scripts/generate_stubs.py @@ -17,7 +17,7 @@ def main(site_package_dir,modules_name,use_pybind11 = False): #Generate stubs for components using the factory target_name="Sofa.Component" - generate_component_stubs(work_dir,target_name) + generate_component_stubs(work_dir, target_name, use_pybind11) diff --git a/scripts/sofaStubgen.py b/scripts/sofaStubgen.py index bc184dd54..6cf86acb9 100644 --- a/scripts/sofaStubgen.py +++ b/scripts/sofaStubgen.py @@ -300,8 +300,56 @@ def load_component_list(target_name): return selected_entries -def create_sofa_stubs(code_model, target_path): +def find_bound_modules(target_name): + """Returns the compiled python binding modules found in the package target_name. + + The bindings of a SOFA module (eg. Sofa.Component.SolidMechanics.Spring) are compiled into an extension + module with the same name (eg. Sofa/Component/SolidMechanics/Spring.). + + Returns a dict {module name: set of the names it defines}. + """ + import importlib + import importlib.machinery + + root_package, _, sub_package = target_name.partition(".") + package = importlib.import_module(root_package) + + bound_modules = {} + for package_dir in package.__path__: + search_dir = os.path.join(package_dir, *sub_package.split(".")) if sub_package else package_dir + for dirpath, _, filenames in os.walk(search_dir): + for filename in filenames: + suffix = next((s for s in importlib.machinery.EXTENSION_SUFFIXES if filename.endswith(s)), None) + if suffix is None: + continue + relative_path = os.path.relpath(os.path.join(dirpath, filename[:-len(suffix)]), package_dir) + module_name = ".".join([root_package] + relative_path.split(os.sep)) + try: + bound_modules[module_name] = set(dir(importlib.import_module(module_name))) + except ImportError as e: + print(f"Warning: cannot import the binding module '{module_name}': {e}") + bound_modules[module_name] = set() + return bound_modules + +def bound_module_stub_header(module_name): + return f""" +# Type hints for the components of {module_name} that have no dedicated python binding +from Sofa.Core import Object, LinkPath +from Sofa.Component.TypeHints import Data, Optional, SofaArray +""" + +def create_sofa_stubs(code_model, target_path, bound_modules=None): + """Writes in target_path a python stub for each component of the code model. + + Components of a SOFA module with no python binding get a stub module per component in a package named after + the SOFA module (eg. Sofa/Component/Mass/UniformMass.py). + When the SOFA module has a compiled python binding (see find_bound_modules), such a package would shadow it. + The stubs of its components without binding are then gathered in a .pyi file next to the binding + (eg. Sofa/Component/SolidMechanics/Spring.pyi), to be merged with the stubs of the binding itself. + """ blacklist = ["RequiredPlugin"] + bound_modules = bound_modules or {} + bound_module_stubs = {} template_nodes = dict() not_created_objects = list() @@ -343,6 +391,13 @@ def create_sofa_stubs(code_model, target_path): class_typehint, params_typehint, arguments_list, constructor_params_doc) + if target in bound_modules: + if class_name in bound_modules[target]: + print(f"Skipping {object_name}: already bound in {target}") + else: + bound_module_stubs.setdefault(target, []).append(code) + continue + pathname = target_path + target.replace(".","/") + "/" full_component_name = target + "." + class_name @@ -358,7 +413,15 @@ def create_sofa_stubs(code_model, target_path): if full_component_name in code_model: raise Exception("Already existing entry") - # In every directory, scan the object that are in and generates an init.py file + for module_name, codes in bound_module_stubs.items(): + pathname = target_path + module_name.replace(".", "/") + ".pyi" + os.makedirs(os.path.dirname(pathname), exist_ok=True) + with open(pathname, "wt") as outfile: + outfile.write(bound_module_stub_header(module_name)) + for code in codes: + outfile.write(code) + + # In every directory, scan the object that are in and generates an init.py file make_all_init_files(target_path) return code_model @@ -376,5 +439,5 @@ def create_sofa_stubs(code_model, target_path): print(f"Generating SOFA's components python interfaces for {target_name}") components = load_component_list(target_name) - create_sofa_stubs(components, output_directory) + create_sofa_stubs(components, output_directory, find_bound_modules(target_name)) diff --git a/scripts/utils.py b/scripts/utils.py index 223366d09..3f6e969fe 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -1,7 +1,7 @@ import sys import os import shutil -from sofaStubgen import load_component_list, create_sofa_stubs +from sofaStubgen import load_component_list, create_sofa_stubs, find_bound_modules from mypy.stubgen import parse_options, generate_stubs import argparse @@ -92,22 +92,50 @@ def generate_module_stubs(module_name, work_dir, usePybind11_stubgen = False): options = parse_options(["-v","-p",module_name,"--include-docstrings","--no-analysis", "--ignore-errors"]) generate_stubs(options) - module_out_dir = os.path.join("out", module_name) - target_dir = os.path.join(work_dir, module_name) + module_path = os.path.join(*module_name.split(".")) + module_out_dir = os.path.join("out", module_path) + target_dir = os.path.join(work_dir, module_path) if os.path.isdir(module_out_dir): + # a package: out/Sofa/... shutil.copytree(module_out_dir, target_dir, dirs_exist_ok=True) print(f"Resync terminated for copying '{module_name}' to '{target_dir}'") + elif os.path.isfile(module_out_dir + ".pyi"): + # a single module: out/Sofa/Component/SolidMechanics/Spring.pyi + os.makedirs(os.path.dirname(target_dir), exist_ok=True) + shutil.copyfile(module_out_dir + ".pyi", target_dir + ".pyi") + print(f"Resync terminated for copying '{module_name}' to '{target_dir}.pyi'") shutil.rmtree("out", ignore_errors=True) #Generate stubs for components using the factory -def generate_component_stubs(work_dir,target_name): +def generate_component_stubs(work_dir,target_name, usePybind11_stubgen = False): print(f"Generating stubgen for all components in Sofa.Components using custom sofaStubgen.py") + # SOFA modules having python bindings (eg. Sofa.Component.SolidMechanics.Spring) are compiled modules: their + # stubs are a .pyi file next to them, made of the stubs of the bindings completed by the stubs of the + # components having no binding. + bound_modules = find_bound_modules(target_name) + for module_name in bound_modules: + stale_stub_package = os.path.join(work_dir, *module_name.split(".")) + if os.path.isdir(stale_stub_package): + print(f"Warning: the directory '{stale_stub_package}' shadows the python binding '{module_name}'. " + f"It has probably been generated by a previous version of this script and should be removed.") + generate_module_stubs(module_name, work_dir, usePybind11_stubgen) + components = load_component_list(target_name) - create_sofa_stubs(components, "out/") + create_sofa_stubs(components, "out/", bound_modules) + + for module_name in bound_modules: + module_stub = os.path.join(*module_name.split(".")) + ".pyi" + out_stub = os.path.join("out", module_stub) + target_stub = os.path.join(work_dir, module_stub) + if os.path.isfile(out_stub) and os.path.isfile(target_stub): + with open(target_stub, "a") as target_file, open(out_stub) as out_file: + target_file.write("\n" + out_file.read()) + os.remove(out_stub) + print(f"Merged the stubs of the components without binding into '{target_stub}'") sofa_out_dir = os.path.join("out",*target_name.split('.')) From 04ae54678fddfb7d27d7d1ce20f7e1f2af720f89 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Wed, 11 Nov 2026 08:10:58 +0900 Subject: [PATCH 2/4] Fix the syntax of the generated component stubs Most of the stubs generated by sofaStubgen.py for Sofa.Component did not parse (309 of 362), and many of the others failed when imported: - the constructor arguments without default value followed the optional 'template' argument, and the required and optional arguments were joined without a comma: the arguments are now keyword-only, separated by commas. - data fields named after a python keyword other than the few listed (eg. 'global'), duplicated or not valid identifiers were not filtered out, and the keyword ones were written as invalid class attributes: they are now written as comments. - descriptions ending with a quote closed the docstring early, and backslashes produced invalid escape sequences: they are now escaped. - array types were annotated 'TypeHints.SofaArray' while only 'SofaArray' is imported, raising a NameError when importing the stub. All the 369 generated stubs now compile and import. --- scripts/sofaStubgen.py | 43 +++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/scripts/sofaStubgen.py b/scripts/sofaStubgen.py index 6cf86acb9..03c05bf54 100644 --- a/scripts/sofaStubgen.py +++ b/scripts/sofaStubgen.py @@ -7,6 +7,7 @@ """ import re import sys, os +import keyword import pprint import argparse @@ -39,9 +40,9 @@ def sofa_to_python_typename(name, short=False): "LinkPath" : "LinkPath" } - SofaArray = "TypeHints.SofaArray" + SofaArray = "SofaArray" if short: - SofaArray = "TypeHints.SofaArray" + SofaArray = "SofaArray" if name in t: return t[name] @@ -75,31 +76,40 @@ def sofa_datafields_to_constructor_arguments_list(data_fields, object_name, has_ # 'type': 'bool'}, required_data_fields = [] optional_data_fields = [] + argument_names = {"self", "template"} for data_field in data_fields: name = data_field["name"] - if name in reserved: + if name in reserved or keyword.iskeyword(name): print(f"Warning: {object_name} contains a the data field named '{name}' which is also a python keyword") continue - if " " in name: + if len(name) == 0: + print("Warning: empty data field empty name") + continue + + if not name.isidentifier(): print(f"Warning: this is an invalid arguments name: '{name}'") continue - if len(name) == 0: - print("Warning: empty data field empty name") + if name in argument_names: + print(f"Warning: {object_name} contains several data fields named '{name}'") continue + argument_names.add(name) if data_field["isRequired"]: required_data_fields.append(data_field) else: optional_data_fields.append(data_field) - result_params = "" + # The arguments are keyword-only (as SOFA objects are created with keyword arguments): this allows the arguments + # without default value to follow the optional template argument. + params = [] if has_template: - result_params = "template: Optional[str] = None, " - result_params += ",".join([data["name"]+": "+sofa_to_python_typename(data["type"]) for data in required_data_fields]) - result_params += ",".join([data["name"]+": Optional["+sofa_to_python_typename(data["type"])+"] = None" for data in optional_data_fields]) + params.append("template: Optional[str] = None") + params += [data["name"]+": "+sofa_to_python_typename(data["type"]) for data in required_data_fields] + params += [data["name"]+": Optional["+sofa_to_python_typename(data["type"])+"] = None" for data in optional_data_fields] + result_params = ", ".join(["*"] + params) if params else "" ordered_fields = sorted(data_fields, key=lambda x: x["name"]) @@ -125,10 +135,15 @@ def sofa_datafields_to_doc(data_fields): return p def clean_sofa_text(t): + t = t.replace("\\", "\\\\") t = t.replace("\n","") t = t.replace("'", "") return t +def escape_docstring(t): + """Makes a text usable in a triple-quoted string""" + return t.replace("\\", "\\\\").replace('"', '\\"') + def sofa_datafields_to_typehints(data_fields, mode="Sofa"): p = "" p2 = "" @@ -139,11 +154,11 @@ def sofa_datafields_to_typehints(data_fields, mode="Sofa"): if len(name) == 0: continue - if " " in name: + if not name.isidentifier(): continue - if name in reserved: - p += " " + name + ": " + help + " (NB: use the kwargs syntax as name is a reserved word in python)\n\n" + if name in reserved or keyword.iskeyword(name): + p += " # " + name + ": " + help + " (NB: use the kwargs syntax as name is a reserved word in python)\n\n" else: p += f" {name}: Data[{type}] \n '{help}'\n\n" p2 += f" {name}: Optional[{type} | LinkPath] = None \n '{help}'\n\n" @@ -192,6 +207,8 @@ def wrapper_code(class_name, description, data_list, properties_doc, constructor_params_typehints, constructor_params_docs): properties_doc = "" + description = escape_docstring(description) + constructor_params_docs = escape_docstring(constructor_params_docs) return f""" class {class_name}(Object): \"\"\"{description}\"\"\" From 48212bb60260fed28f82acad0456479a0a244582 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Wed, 11 Nov 2026 09:26:23 +0900 Subject: [PATCH 3/4] Give LinearSpring's restLength a default value in the binding restLength had no default while following arguments that have one, which made the generated stub invalid python ("parameter without a default follows parameter with a default"). Use 0, the default of the C++ constructor. --- .../Component/SolidMechanics/Spring/Binding_LinearSpring.cpp | 2 +- .../Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp index ae6479c0c..369b08119 100644 --- a/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp +++ b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring.cpp @@ -49,7 +49,7 @@ void moduleAddLinearSpring(pybind11::module& m) { py::arg("index2"), py::arg("springStiffness") = 100, py::arg("dampingFactor") = 5, - py::arg("restLength"), + py::arg("restLength") = 0, py::arg("elongationOnly") = false, py::arg("enabled") = true, sofapython3::doc::solidmechanics::spring::LinearSpringInit); diff --git a/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h index 6b1edbe19..10cfa67d0 100644 --- a/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h +++ b/bindings/Component/SolidMechanics/Spring/src/SofaPython3/Sofa/Component/SolidMechanics/Spring/Binding_LinearSpring_doc.h @@ -35,7 +35,7 @@ Create a linear spring from indices and spring parameters. :param index2: Index of the point on object 2. :param springStiffness: Stiffnes k of the spring (f = -k*x -d*v) :param dampingFactor: Damping factor d of the spring (f = -k*x -d*v) -:param restLength: Initial length of the spring, such that f = 0 +:param restLength: Initial length of the spring, such that f = 0 (default: 0) :param elongationOnly: If set to true, no compression of the spring is possible (x < 0) :param enabled: If set to false, no force will be calculated for this spring From 4844455080537b8feba1a63b8d94c8e605498630 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Wed, 11 Nov 2026 10:07:18 +0900 Subject: [PATCH 4/4] Move __future__ imports to the top of the generated stubs pybind11-stubgen can write imports such as 'import Sofa.Core' before 'from __future__ import annotations', which makes the .pyi files invalid python. After stub generation, move the __future__ imports right after the module docstring. --- scripts/utils.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/scripts/utils.py b/scripts/utils.py index 3f6e969fe..64d95d27b 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -78,6 +78,46 @@ def __call__(self,path, objectList): returnList.append(obj) return returnList +# pybind11-stubgen can write imports (e.g. 'import Sofa.Core') before 'from __future__ import annotations', +# which is a SyntaxError: move the __future__ imports right after the module docstring. +def fix_future_imports(stub_path): + import io + import tokenize + + with open(stub_path, encoding="utf-8") as f: + source = f.read() + lines = source.splitlines(keepends=True) + + # index of the first line after the module docstring (0 if there is none) + insert_at = 0 + try: + for token in tokenize.generate_tokens(io.StringIO(source).readline): + if token.type in (tokenize.ENCODING, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT): + continue + if token.type == tokenize.STRING: + insert_at = token.end[0] + break + except (tokenize.TokenError, SyntaxError): + return + + future_lines = [i for i, line in enumerate(lines) + if i >= insert_at and line.startswith("from __future__ import")] + if not future_lines: + return + + future = [line if line.endswith("\n") else line + "\n" for i, line in enumerate(lines) if i in future_lines] + others = [line for i, line in enumerate(lines) if i not in future_lines] + fixed = "".join(others[:insert_at] + future + others[insert_at:]) + if fixed != source: + with open(stub_path, "w", encoding="utf-8") as f: + f.write(fixed) + +def fix_stubs_in_directory(directory): + for root, _, files in os.walk(directory): + for file in files: + if file.endswith(".pyi"): + fix_future_imports(os.path.join(root, file)) + #Generate stubs using either pybind11-stubgen or mypy version of stubgen def generate_module_stubs(module_name, work_dir, usePybind11_stubgen = False): print(f"Generating stubgen for {module_name} in {work_dir}") @@ -92,6 +132,8 @@ def generate_module_stubs(module_name, work_dir, usePybind11_stubgen = False): options = parse_options(["-v","-p",module_name,"--include-docstrings","--no-analysis", "--ignore-errors"]) generate_stubs(options) + fix_stubs_in_directory("out") + module_path = os.path.join(*module_name.split(".")) module_out_dir = os.path.join("out", module_path) target_dir = os.path.join(work_dir, module_path)