From 178c4e2a3f0d0637255cbb3c6ea39d6d3427f2a6 Mon Sep 17 00:00:00 2001 From: EulalieCoevoet Date: Mon, 2 Jun 2025 10:39:15 +0200 Subject: [PATCH 1/2] [stlib-splib] cleaning --- splib/core/enum_types.py | 41 ++++++++++++++-------------- splib/mechanics/collision_model.py | 24 +++++++++++----- splib/mechanics/hyperelasticity.py | 2 +- splib/mechanics/linear_elasticity.py | 6 ++-- splib/topology/dynamic.py | 8 +++--- stlib/geometry/__geometry__.py | 5 +--- stlib/geometry/extract.py | 35 ++++++++++++++++-------- stlib/geometry/file.py | 12 ++++---- stlib/prefabs/collision.py | 21 +++++++------- stlib/prefabs/visual.py | 13 ++++++++- 10 files changed, 99 insertions(+), 68 deletions(-) diff --git a/splib/core/enum_types.py b/splib/core/enum_types.py index dbce47e1..56824573 100644 --- a/splib/core/enum_types.py +++ b/splib/core/enum_types.py @@ -5,34 +5,33 @@ class ConstitutiveLaw(Enum): HYPERELASTIC = 2 class ODEType(Enum): - EXPLICIT = 1 - IMPLICIT = 2 + EXPLICIT = 1 + IMPLICIT = 2 class SolverType(Enum): - DIRECT = 1 - ITERATIVE = 2 + DIRECT = 1 + ITERATIVE = 2 class MappingType(Enum): - BARYCENTRIC = 1 - IDENTITY = 2 - RIGID = 3 - + BARYCENTRIC = 1 + IDENTITY = 2 + RIGID = 3 class ConstraintType(Enum): - PROJECTIVE = 1 - WEAK = 2 - LAGRANGIAN = 3 + PROJECTIVE = 1 + WEAK = 2 + LAGRANGIAN = 3 class CollisionPrimitive(Enum): - POINTS = 1 - LINES = 2 - TRIANGLES = 3 - SPHERES = 4 + POINTS = 1 + LINES = 2 + TRIANGLES = 3 + SPHERES = 4 class ElementType(Enum): - POINTS = 1 - EDGES = 2 - TRIANGLES = 3 - QUAD = 4 - TETRA = 5 - HEXA = 6 + POINTS = 1 + EDGES = 2 + TRIANGLES = 3 + QUADS = 4 + TETRAHEDRONS = 5 + HEXAHEDRONS = 6 diff --git a/splib/mechanics/collision_model.py b/splib/mechanics/collision_model.py index ad8effad..adc77ca0 100644 --- a/splib/mechanics/collision_model.py +++ b/splib/mechanics/collision_model.py @@ -3,21 +3,31 @@ from splib.core.enum_types import CollisionPrimitive - @ReusableMethod -def addCollisionModels(node, primitive : CollisionPrimitive, topology=DEFAULT_VALUE, selfCollision=DEFAULT_VALUE, proximity=DEFAULT_VALUE, group=DEFAULT_VALUE, contactStiffness=DEFAULT_VALUE, contactFriction=DEFAULT_VALUE,spheresRadius=DEFAULT_VALUE,**kwargs): +def addCollisionModels(node, primitive : CollisionPrimitive, + topology=DEFAULT_VALUE, + selfCollision=DEFAULT_VALUE, + proximity=DEFAULT_VALUE, + group=DEFAULT_VALUE, + contactStiffness=DEFAULT_VALUE, + contactFriction=DEFAULT_VALUE, + spheresRadius=DEFAULT_VALUE, + **kwargs): match primitive: case CollisionPrimitive.POINTS: - node.addObject("PointCollisionModel",name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) + node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) return - case CollisionPrimitive.LINES: - node.addObject("LineCollisionModel",name="EdgeCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group,**kwargs) + case CollisionPrimitive.LINES: + node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) + node.addObject("LineCollisionModel", name="EdgeCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) return case CollisionPrimitive.TRIANGLES: - node.addObject("TriangleCollisionModel",name="TriangleCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group,**kwargs) + node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) + node.addObject("LineCollisionModel", name="EdgeCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) + node.addObject("TriangleCollisionModel", name="TriangleCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group,**kwargs) return case CollisionPrimitive.SPHERES: - node.addObject("SphereCollisionModel",name="SphereCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, radius=spheresRadius, **kwargs) + node.addObject("SphereCollisionModel", name="SphereCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, radius=spheresRadius, **kwargs) return case _: return diff --git a/splib/mechanics/hyperelasticity.py b/splib/mechanics/hyperelasticity.py index 1e79c420..27c30635 100644 --- a/splib/mechanics/hyperelasticity.py +++ b/splib/mechanics/hyperelasticity.py @@ -6,7 +6,7 @@ @ReusableMethod def addHyperelasticity(node,elem:ElementType,materialName=DEFAULT_VALUE, parameterSet=DEFAULT_VALUE, matrixRegularization=DEFAULT_VALUE,**kwargs): match elem: - case ElementType.TETRA: + case ElementType.TETRAHEDRONS: node.addObject("TetrahedronHyperelasticityFEMForceField",name="constitutiveLaw", materialName=materialName, parameterSet=parameterSet, matrixRegularization=matrixRegularization, **kwargs) return case _: diff --git a/splib/mechanics/linear_elasticity.py b/splib/mechanics/linear_elasticity.py index 8675afe1..33de6189 100644 --- a/splib/mechanics/linear_elasticity.py +++ b/splib/mechanics/linear_elasticity.py @@ -12,13 +12,13 @@ def addLinearElasticity(node,elem:ElementType,youngModulus=DEFAULT_VALUE, poisso case ElementType.TRIANGLES: node.addObject("TriangleFEMForceField",name="constitutiveLaw", youngModulus=youngModulus, poissonRatio=poissonRatio, method=method,**kwargs) return - case ElementType.QUAD: + case ElementType.QUADS: node.addObject("QuadBendingFEMForceField",name="constitutiveLaw", youngModulus=youngModulus, poissonRatio=poissonRatio, method=method,**kwargs) return - case ElementType.TETRA: + case ElementType.TETRAHEDRONS: node.addObject("TetrahedronFEMForceField",name="constitutiveLaw", youngModulus=youngModulus, poissonRatio=poissonRatio, method=method,**kwargs) return - case ElementType.HEXA: + case ElementType.HEXAHEDRONS: node.addObject("HexahedronFEMForceField",name="constitutiveLaw", youngModulus=youngModulus, poissonRatio=poissonRatio, method=method,**kwargs) return case _: diff --git a/splib/topology/dynamic.py b/splib/topology/dynamic.py index b5a829c3..c84bd185 100644 --- a/splib/topology/dynamic.py +++ b/splib/topology/dynamic.py @@ -53,15 +53,15 @@ def addDynamicTopology(node,type:ElementType,**kwargs): case ElementType.TRIANGLES: addTriangleTopology(node,**kwargs) return - case ElementType.QUAD: + case ElementType.QUADS: addQuadTopology(node,**kwargs) return - case ElementType.TETRA: + case ElementType.TETRAHEDRONS: addTetrahedronTopology(node,**kwargs) return - case ElementType.HEXA: + case ElementType.HEXAHEDRONS: addHexahedronTopology(node,**kwargs) return case _: - print('Topology type should be one of the following : "ElementType.POINTS, ElementType.EDGES, ElementType.TRIANGLES, ElementType.QUAD, ElementType.TETRA, ElementType.HEXA" ') + print('Topology type should be one of the following : "ElementType.POINTS, ElementType.EDGES, ElementType.TRIANGLES, ElementType.QUADS, ElementType.TETRAHEDRONS, ElementType.HEXAHEDRONS" ') return diff --git a/stlib/geometry/__geometry__.py b/stlib/geometry/__geometry__.py index 32ed6b61..8b63a20c 100644 --- a/stlib/geometry/__geometry__.py +++ b/stlib/geometry/__geometry__.py @@ -33,11 +33,8 @@ class GeometryParameters(BaseParameters): dynamicTopology : bool = False - - - class Geometry(BasePrefab): - container : Object # This should be more specialized into the right SOFA type + container : Object # This should be more specialized into the right SOFA type modifier : Optional[Object] params : GeometryParameters diff --git a/stlib/geometry/extract.py b/stlib/geometry/extract.py index 8edba4c6..0e7c38c1 100644 --- a/stlib/geometry/extract.py +++ b/stlib/geometry/extract.py @@ -8,27 +8,32 @@ class ExtractInternalDataProvider(InternalDataProvider): - destElemType : ElementType - fromElemType : ElementType + destElementType : ElementType + fromElemenType : ElementType fromNodeName : str + def __init__(self, destElementType : ElementType, fromElementType : ElementType, fromNodeName : str): + self.destElementType = destElementType, + self.fromElementType = fromElementType, + self.fromNodeName = fromNodeName + def __post_init__(self): - if(not (self.fromElemType == ElementType.TETRA and self.destElemType == ElementType.TRIANGLES) - and not (self.fromElemType == ElementType.HEXA and self.destElemType == ElementType.QUAD) ): - raise ValueError("Only configuration possible are 'Tetra to Triangle' and 'Hexa to quad'") + if(not (self.fromElementType == ElementType.TETRAHEDRONS and self.destElementType == ElementType.TRIANGLES) + and not (self.fromElementType == ElementType.HEXAHEDRONS and self.destElementType == ElementType.QUADS) ): + raise ValueError("Only configuration possible are 'Tetrahedrons to Triangles' and 'Hexahedrons to Quads'") InternalDataProvider.__init__(self) def generateAttribute(self, parent : Geometry): - tmn = parent.addChild("topologicalMappingNode") + tmn = parent.addChild("TopologicalMappingNode") #TODO: Specify somewhere in the doc that this should only be used for mapped topologies that extract parent topology surface fromLink = parent.parents[0].parents[0].getChild(self.fromNodeName).container.linkpath - addDynamicTopology(tmn, type=self.destElemType) - if self.fromElemType == ElementType.TETRA: + addDynamicTopology(tmn, type=self.destElementType) + if self.fromElementType == ElementType.TETRAHEDRONS: tmn.addObject("Tetra2TriangleTopologicalMapping", input=fromLink, output=tmn.container.linkpath) - elif self.fromElemType == ElementType.HEXA: + elif self.fromElementType == ElementType.HEXAHEDRONS: tmn.addObject("Hexa2QuadTopologicalMapping", input=fromLink, output=tmn.container.linkpath) self.position = tmn.container.position.linkpath @@ -41,6 +46,14 @@ def generateAttribute(self, parent : Geometry): class ExtractParameters(GeometryParameters): - def __init__(self, fromGeometry : GeometryParameters, destElementType : ElementType, dynamicTopology = False, ): - GeometryParameters.__init__(data = ExtractInternalDataProvider(destElemType = destElementType, fromElemType = fromGeometry.elementType,fromNodeName = fromGeometry.name), dynamicTopology = dynamicTopology, elementType = destElementType) + def __init__(self, + fromGeometry : GeometryParameters, + destElementType : ElementType, + dynamicTopology = False, ): + GeometryParameters.__init__(self, + data = ExtractInternalDataProvider(destElementType = destElementType, + fromElementType = fromGeometry.elementType, + fromNodeName = fromGeometry.name), + dynamicTopology = dynamicTopology, + elementType = destElementType) diff --git a/stlib/geometry/file.py b/stlib/geometry/file.py index e2e4a60d..70738b02 100644 --- a/stlib/geometry/file.py +++ b/stlib/geometry/file.py @@ -12,9 +12,8 @@ class FileInternalDataProvider(InternalDataProvider): def __post_init__(self, **kwargs): InternalDataProvider.__init__(self,**kwargs) - def generateAttribute(self, parent : Geometry): - - loadMesh(parent, self.filename) + def generateAttribute(self, parent : Geometry): + loadMesh(parent, self.filename) self.position = str(parent.loader.position.linkpath) self.edges = str(parent.loader.edges.linkpath) @@ -26,6 +25,9 @@ def generateAttribute(self, parent : Geometry): class FileParameters(GeometryParameters): - def __init__(self, filename, dynamicTopology = False, elementType : ElementType = None ): - GeometryParameters.__init__(self,data = FileInternalDataProvider(filename), dynamicTopology = dynamicTopology, elementType = elementType) + def __init__(self, filename, dynamicTopology = False, elementType : ElementType = None ): + GeometryParameters.__init__(self, + data = FileInternalDataProvider(filename), + dynamicTopology = dynamicTopology, + elementType = elementType) diff --git a/stlib/prefabs/collision.py b/stlib/prefabs/collision.py index 28915629..8ed1f8a6 100644 --- a/stlib/prefabs/collision.py +++ b/stlib/prefabs/collision.py @@ -9,14 +9,10 @@ @dataclasses.dataclass class CollisionParameters(BaseParameters): - primitives : list[CollisionPrimitive] = dataclasses.field(default_factory = lambda :[CollisionPrimitive.POINTS]) + primitives : list[CollisionPrimitive] = dataclasses.field(default_factory = lambda :[CollisionPrimitive.TRIANGLES]) selfCollision : Optional[bool] = DEFAULT_VALUE - proximity : Optional[float] = DEFAULT_VALUE group : Optional[int] = DEFAULT_VALUE - contactStiffness : Optional[float] = DEFAULT_VALUE - contactFriction : Optional[float] = DEFAULT_VALUE - spheresRadius : Optional[float] = DEFAULT_VALUE geometry : GeometryParameters = dataclasses.field(default_factory = lambda : GeometryParameters()) addMapping : Optional[Callable] = None @@ -28,16 +24,12 @@ def __init__(self, params: CollisionParameters): geom = self.add(Geometry, params.geometry) - self.addObject("MechanicalObject",template="Vec3", position=f"@{params.geometry.name}/container.position") + self.addObject("MechanicalObject", template="Vec3", position=f"@{params.geometry.name}/container.position") for primitive in params.primitives: - addCollisionModels(self,primitive, + addCollisionModels(self, primitive, topology=f"@{params.geometry.name}/container", selfCollision=params.selfCollision, - proximity=params.proximity, group=params.group, - contactStiffness=params.contactStiffness, - contactFriction=params.contactFriction, - spheresRadius=params.spheresRadius, **params.kwargs) if params.addMapping is not None: @@ -50,7 +42,14 @@ def getParameters(**kwargs) -> CollisionParameters: def createScene(root): + root.addObject("VisualStyle", displayFlags="showCollisionModels") + # Create a visual from a mesh file params = Collision.getParameters() params.geometry = FileParameters(filename="mesh/cube.obj") + # Expert parameters + params.kwargs = { + "contactStiffness": 100.0, + "contactFriction": 0.5 + } root.add(Collision, params) diff --git a/stlib/prefabs/visual.py b/stlib/prefabs/visual.py index 2bf61ed9..70790463 100644 --- a/stlib/prefabs/visual.py +++ b/stlib/prefabs/visual.py @@ -1,7 +1,9 @@ from stlib.core.basePrefab import BasePrefab from stlib.core.baseParameters import BaseParameters, Callable, Optional, dataclasses, Any from stlib.geometry import Geometry, GeometryParameters +from stlib.geometry.extract import ExtractParameters from stlib.geometry.file import FileParameters +from splib.core.enum_types import ElementType from Sofa.Core import Object @dataclasses.dataclass @@ -32,6 +34,15 @@ def getParameters(**kwargs) -> VisualParameters: def createScene(root): # Create a visual from a mesh file - params = Visual.getParameters() + params = Visual.getParameters() + params.name = "VisualFromFile" params.geometry = FileParameters(filename="mesh/cube.obj") root.add(Visual, params) + + + # Create a visual from a mesh file + # params = Visual.getParameters() + # params.name = "ExtractedVisual" + # params.geometry = ExtractParameters(fromGeometry=FileParameters(filename="mesh/cube.vtk"), + # destElementType=ElementType.TRIANGLES) + # root.add(Visual, params) From d812ba780ad64934f3f866315f20f03373d903be Mon Sep 17 00:00:00 2001 From: EulalieCoevoet Date: Mon, 2 Jun 2025 14:15:31 +0200 Subject: [PATCH 2/2] revert collisionModel --- splib/mechanics/collision_model.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/splib/mechanics/collision_model.py b/splib/mechanics/collision_model.py index adc77ca0..e1abdf45 100644 --- a/splib/mechanics/collision_model.py +++ b/splib/mechanics/collision_model.py @@ -18,12 +18,9 @@ def addCollisionModels(node, primitive : CollisionPrimitive, node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) return case CollisionPrimitive.LINES: - node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) node.addObject("LineCollisionModel", name="EdgeCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) return case CollisionPrimitive.TRIANGLES: - node.addObject("PointCollisionModel", name="PointCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) - node.addObject("LineCollisionModel", name="EdgeCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group, **kwargs) node.addObject("TriangleCollisionModel", name="TriangleCollision", topology=topology, selfCollision=selfCollision, proximity=proximity, contactStiffness=contactStiffness, contactFriction=contactFriction, group=group,**kwargs) return case CollisionPrimitive.SPHERES: