From dc61a999373d3ed696738bc96cb2110b401c62a8 Mon Sep 17 00:00:00 2001 From: p-shg Date: Fri, 9 Oct 2026 16:50:17 +0200 Subject: [PATCH] SofaPython3 import leads to segfault MainHeader, Scene.addMainHeader and Settings always appended "SofaPython3" to the plugins list. When a scene is built from a Python script (import Sofa) and not from runSofa, this RequiredPlugin loads libSofaPython3.so a second time through the PluginManager, and the process segfaults at interpreter exit. --- .../stlib3/communication/UDP_controller.py | 1 - python3/src/stlib3/scene/contactheader.py | 30 +-- python3/src/stlib3/scene/mainheader.py | 36 ++-- python3/src/stlib3/scene/scene.py | 173 +++++++++--------- 4 files changed, 122 insertions(+), 118 deletions(-) diff --git a/python3/src/stlib3/communication/UDP_controller.py b/python3/src/stlib3/communication/UDP_controller.py index 55feca8..4352a62 100644 --- a/python3/src/stlib3/communication/UDP_controller.py +++ b/python3/src/stlib3/communication/UDP_controller.py @@ -53,7 +53,6 @@ def createScene(rootNode): rootNode.findData('gravity').value=[0., 0., -9810] rootNode.findData('dt').value=0.01 rootNode.addObject('RequiredPlugin', name='SoftRobots') - rootNode.addObject('RequiredPlugin', name='SofaPython3') rootNode.addObject('FreeMotionMasterSolver') rootNode.addObject('BlockGaussSeidelConstraintSolver',maxIterations=1000 ,tolerance=0.001) diff --git a/python3/src/stlib3/scene/contactheader.py b/python3/src/stlib3/scene/contactheader.py index 9eb9d62..5fdb4d0 100644 --- a/python3/src/stlib3/scene/contactheader.py +++ b/python3/src/stlib3/scene/contactheader.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- + def ContactHeader(applyTo, alarmDistance, contactDistance, frictionCoef=0.0): - ''' + """ Args: applyTo (Sofa.Node): the node to attach the object to @@ -24,25 +25,27 @@ def ContactHeader(applyTo, alarmDistance, contactDistance, frictionCoef=0.0): RuleBasedContactManager, LocalMinDistance } - ''' + """ if applyTo.hasObject("CollisionPipeline") is False: - applyTo.addObject('CollisionPipeline') + applyTo.addObject("CollisionPipeline") - applyTo.addObject('BruteForceBroadPhase') - applyTo.addObject('BVHNarrowPhase') + applyTo.addObject("BruteForceBroadPhase") + applyTo.addObject("BVHNarrowPhase") - applyTo.addObject('RuleBasedContactManager', responseParams="mu="+str(frictionCoef), - name='Response', response='FrictionContactConstraint') - applyTo.addObject('LocalMinDistance', - alarmDistance=alarmDistance, contactDistance=contactDistance, - angleCone=0.01) + applyTo.addObject( + "RuleBasedContactManager", + responseParams="mu=" + str(frictionCoef), + name="Response", + response="FrictionContactConstraint", + ) + applyTo.addObject("LocalMinDistance", alarmDistance=alarmDistance, contactDistance=contactDistance, angleCone=0.01) if applyTo.hasObject("FreeMotionAnimationLoop") is False: - applyTo.addObject('FreeMotionAnimationLoop') + applyTo.addObject("FreeMotionAnimationLoop") if applyTo.hasObject("BlockGaussSeidelConstraintSolver") is False: - applyTo.addObject('BlockGaussSeidelConstraintSolver', tolerance=1e-6, maxIterations=1000) + applyTo.addObject("BlockGaussSeidelConstraintSolver", tolerance=1e-6, maxIterations=1000) return applyTo @@ -51,5 +54,6 @@ def ContactHeader(applyTo, alarmDistance, contactDistance, frictionCoef=0.0): def createScene(rootnode): import os from mainheader import MainHeader - MainHeader(rootnode, plugins=["SofaPython3"], repositoryPaths=[os.getcwd()]) + + MainHeader(rootnode, plugins=[], repositoryPaths=[os.getcwd()]) ContactHeader(rootnode, alarmDistance=1, contactDistance=0.1, frictionCoef=1.0) diff --git a/python3/src/stlib3/scene/mainheader.py b/python3/src/stlib3/scene/mainheader.py index a98f172..222f050 100644 --- a/python3/src/stlib3/scene/mainheader.py +++ b/python3/src/stlib3/scene/mainheader.py @@ -3,8 +3,9 @@ from splib3.animation import AnimationManager import platform + def MainHeader(node, gravity=[0.0, -9.8, 0.0], dt=0.01, plugins=[], repositoryPaths=[], doDebug=False): - ''' + """ Args: gravity (vec3f): define the gravity vector. @@ -29,36 +30,36 @@ def MainHeader(node, gravity=[0.0, -9.8, 0.0], dt=0.01, plugins=[], repositoryPa DiscreteIntersection } - ''' - node.addObject('VisualStyle') - node.findData('gravity').value = gravity - node.findData('dt').value = dt + """ + node.addObject("VisualStyle") + node.findData("gravity").value = gravity + node.findData("dt").value = dt - node.addObject('DefaultVisualManagerLoop') + node.addObject("DefaultVisualManagerLoop") if not isinstance(plugins, list): - Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got "+str(type(plugins))) + Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got " + str(type(plugins))) return node - if "SofaPython3" not in plugins: - plugins.append("SofaPython3") - confignode = node.addChild("Config") for name in plugins: - confignode.addObject('RequiredPlugin', name=name, printLog=False) + confignode.addObject("RequiredPlugin", name=name, printLog=False) - i=0 + i = 0 for repository in repositoryPaths: - confignode.addObject('AddDataRepository', name="AddDataRepository"+str(i), path=repository) - i+=1 + confignode.addObject("AddDataRepository", name="AddDataRepository" + str(i), path=repository) + i += 1 if platform.system() != "Darwin": - confignode.addObject('OglSceneFrame', style="Arrows", alignment="TopRight") + confignode.addObject("OglSceneFrame", style="Arrows", alignment="TopRight") else: - Sofa.msg_warning("MainHeader", "MacOs detected, removing OglSceneFrame from the Settings because of compatibility problem.") + Sofa.msg_warning( + "MainHeader", "MacOs detected, removing OglSceneFrame from the Settings because of compatibility problem." + ) if doDebug: from splib3.debug import DebugManager + DebugManager(node) AnimationManager(node) @@ -68,4 +69,5 @@ def MainHeader(node, gravity=[0.0, -9.8, 0.0], dt=0.01, plugins=[], repositoryPa ### This function is just an example on how to use the DefaultHeader function. def createScene(rootNode): import os - MainHeader(rootNode, plugins=["SofaPython3"], repositoryPaths=[os.getcwd()]) + + MainHeader(rootNode, plugins=[], repositoryPaths=[os.getcwd()]) diff --git a/python3/src/stlib3/scene/scene.py b/python3/src/stlib3/scene/scene.py index 5160d66..7f008eb 100644 --- a/python3/src/stlib3/scene/scene.py +++ b/python3/src/stlib3/scene/scene.py @@ -5,106 +5,105 @@ from splib3.animation import AnimationManager from stlib3.scene import ContactHeader + class SofaRuntime(object): - class PluginManager(object): - loadedPlugins = ["SofaPython3"] + class PluginManager(object): + loadedPlugins = ["SofaPython3"] + def Settings(plugins=[], repositoryPaths=[]): - self = Sofa.Core.Node("Settings") + self = Sofa.Core.Node("Settings") + + if not isinstance(plugins, list): + Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got " + str(type(plugins))) + return node + + plugin = self.addChild("Plugins") + for name in plugins: + plugin.addObject("RequiredPlugin", name=name, printLog=False) + + i = 0 + for repository in repositoryPaths: + self.addObject("AddResourceRepository", name="AddResourceRepository" + str(i), path=repository) + i += 1 + + if platform.system() != "Darwin": + self.addObject("OglSceneFrame", style="Arrows", alignment="TopRight") + else: + Sofa.msg_warning( + self, "MacOs detected, removing OglSceneFrame from the Settings because of compatibility problem." + ) + self.addObject("AttachBodyButtonSetting", name="mouseButton") + return self + + +def Scene(root, gravity=[0.0, -9.81, 0.0], dt=0.01, plugins=[], repositoryPaths=[], iterative=True): + + def addMainHeader(plugins=plugins, repositoryPaths=repositoryPaths, doDebug=False): if not isinstance(plugins, list): - Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got "+str(type(plugins))) - return node + Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got " + str(type(plugins))) + return + + if "Sofa.Component.IntegrationScheme.Backward" not in plugins: + plugins.append("Sofa.Component.IntegrationScheme.Backward") + + if doDebug: + from splib3.debug import DebugManager - if "SofaPython3" not in plugins: - plugins.append("SofaPython3") + DebugManager(root) - plugin = self.addChild("Plugins") - for name in plugins: - plugin.addObject('RequiredPlugin', name=name, printLog=False) + root.addObject(AnimationManager(root)) - i=0 - for repository in repositoryPaths: - self.addObject('AddResourceRepository', name="AddResourceRepository"+str(i), path=repository) - i+=1 + addSettings(plugins=plugins, repositoryPaths=repositoryPaths) + addModelling() + addSimulation() - if platform.system() != "Darwin": - self.addObject('OglSceneFrame', style="Arrows", alignment="TopRight") + def addDefaultSolver(node): + node.addObject("EulerImplicitIntegrationScheme", name="TimeIntegrationSchema") + if iterative: + node.addObject("CGLinearSolver", name="LinearSolver", iterations=25, tolerance=1e-5, threshold=1e-5) else: - Sofa.msg_warning(self, "MacOs detected, removing OglSceneFrame from the Settings because of compatibility problem.") - self.addObject('AttachBodyButtonSetting', name="mouseButton") - - return self - -def Scene(root, gravity=[0.0,-9.81,0.0], - dt=0.01, plugins=[], repositoryPaths=[], iterative=True): - from stlib3.scene import contactheader - - def addMainHeader(plugins=plugins, repositoryPaths=repositoryPaths, doDebug=False): - if not isinstance(plugins, list): - Sofa.msg_error("MainHeader", "'plugins' expected to be a list, got "+str(type(plugins))) - return - - if "SofaPython3" not in plugins: - plugins.append("SofaPython3") - - if "Sofa.Component.IntegrationScheme.Backward": - plugins.append("Sofa.Component.IntegrationScheme.Backward") - - if doDebug: - from splib3.debug import DebugManager - DebugManager(root) - - root.addObject(AnimationManager(root)) - - addSettings(plugins=plugins, repositoryPaths=repositoryPaths) - addModelling() - addSimulation() - - def addDefaultSolver(node): - node.addObject('EulerImplicitIntegrationScheme', name='TimeIntegrationSchema') - if iterative: - node.addObject('CGLinearSolver', name='LinearSolver', iterations=25, tolerance=1e-5, threshold=1e-5) - else: - node.addObject('SparseLDLSolver', name='LinearSolver', template='CompressedRowSparseMatrixd') - return node - - def addContactHeader(alarmDistance=1.0 , contactDistance = 0.1, frictionCoef= 1.0): - ContactHeader(root, alarmDistance=alarmDistance , contactDistance=contactDistance , frictionCoef= frictionCoef) - return root - - def addModelling(): - root.addChild("Modelling") - return root - - def addSimulation(): - simulation = root.addChild("Simulation") - addDefaultSolver(simulation) - return root - - def addSettings(plugins=plugins, repositoryPaths=repositoryPaths): - root.addChild(Settings(plugins=plugins, repositoryPaths=repositoryPaths)) - return root - - root.gravity.value = gravity - root.dt.value = dt - root.addObject('VisualStyle') - root.addMainHeader = addMainHeader - root.addSettings = addSettings - root.addSolver = addDefaultSolver - root.addContact = addContactHeader - root.addModelling = addModelling - root.addSimulation = addSimulation - + node.addObject("SparseLDLSolver", name="LinearSolver", template="CompressedRowSparseMatrixd") + return node + + def addContactHeader(alarmDistance=1.0, contactDistance=0.1, frictionCoef=1.0): + ContactHeader(root, alarmDistance=alarmDistance, contactDistance=contactDistance, frictionCoef=frictionCoef) + return root + + def addModelling(): + root.addChild("Modelling") + return root + + def addSimulation(): + simulation = root.addChild("Simulation") + addDefaultSolver(simulation) return root + def addSettings(plugins=plugins, repositoryPaths=repositoryPaths): + root.addChild(Settings(plugins=plugins, repositoryPaths=repositoryPaths)) + return root + + root.gravity.value = gravity + root.dt.value = dt + root.addObject("VisualStyle") + root.addMainHeader = addMainHeader + root.addSettings = addSettings + root.addSolver = addDefaultSolver + root.addContact = addContactHeader + root.addModelling = addModelling + root.addSimulation = addSimulation + + return root + def createScene(root): - import os - scene = Scene(root) + import os + + scene = Scene(root) - scene.addSettings(repositoryPaths=[os.getcwd()]) - scene.addModelling() - scene.addSimulation() + scene.addSettings(repositoryPaths=[os.getcwd()]) + scene.addModelling() + scene.addSimulation() - scene.Simulation.addChild(scene.Modelling) + scene.Simulation.addChild(scene.Modelling)