Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions splib/mechanics/mass.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
# TODO : use the massDensity ONLY and deduce totalMass if necessary from it + volume

@ReusableMethod
def addMass(node, elem:ElementType, totalMass=DEFAULT_VALUE, massDensity=DEFAULT_VALUE, lumping=DEFAULT_VALUE, topology=DEFAULT_VALUE, **kwargs):
def addMass(node, elementType:ElementType, totalMass=DEFAULT_VALUE, massDensity=DEFAULT_VALUE, lumping=DEFAULT_VALUE, topology=DEFAULT_VALUE, **kwargs):
if (not isDefault(totalMass)) and (not isDefault(massDensity)) :
print("[warning] You defined the totalMass and the massDensity in the same time, only taking massDensity into account")
del kwargs["massDensity"]

if(elem !=ElementType.POINTS and elem !=ElementType.EDGES):
if(elementType is not None and elementType !=ElementType.POINTS and elementType !=ElementType.EDGES):
node.addObject("MeshMatrixMass",name="mass", totalMass=totalMass, massDensity=massDensity, lumping=lumping, topology=topology, **kwargs)
else:
if (not isDefault(massDensity)) :
Expand Down
8 changes: 4 additions & 4 deletions stlib/collision.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
from stlib.core.basePrefab import BasePrefab
from stlib.core.baseParameters import BaseParameters, Optional, dataclasses
from stlib.core.baseParameters import BaseParameters, Optional
from stlib.geometries import Geometry, GeometryParameters
from stlib.geometries.file import FileParameters
from splib.core.enum_types import CollisionPrimitive
from splib.core.utils import DEFAULT_VALUE
from splib.mechanics.collision_model import addCollisionModels
from Sofa.Core import Object

@dataclasses.dataclass
class CollisionParameters(BaseParameters):
name : str = "Collision"

primitives : list[CollisionPrimitive] = dataclasses.field(default_factory = lambda :[CollisionPrimitive.TRIANGLES])
primitives : list[CollisionPrimitive] = [CollisionPrimitive.TRIANGLES]

selfCollision : Optional[bool] = DEFAULT_VALUE
bothSide : Optional[bool] = DEFAULT_VALUE
group : Optional[int] = DEFAULT_VALUE
contactDistance : Optional[float] = DEFAULT_VALUE

geometry : GeometryParameters = dataclasses.field(default_factory = lambda : GeometryParameters())
geometry : GeometryParameters = GeometryParameters()


class Collision(BasePrefab):

def __init__(self, parameters: CollisionParameters):
BasePrefab.__init__(self, parameters)

Expand Down
28 changes: 21 additions & 7 deletions stlib/core/baseParameters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import dataclasses
from splib.core.utils import DEFAULT_VALUE

import dataclasses
from pydantic import BaseModel, ValidationError
from typing import Callable, Optional, Any
import Sofa

class BaseParameters(BaseModel):

@dataclasses.dataclass
class BaseParameters(object):
name : str = "Object"
kwargs : dict = dataclasses.field(default_factory=dict)
kwargs : dict = {}

# @classmethod
# def fromYaml(self, data: str):
# import yaml
# dataDict = yaml.safe_load(data)
# return self.fromDict(dataDict)

# @classmethod
# def fromDict(self, data: dict):
# try:
# return self.model_validate(data, strict=True)
# except ValidationError as exc:
# for error in exc.errors():
# message = error.get("loc")[0].__str__() + ": "
# message += error.get("msg")
# Sofa.msg_error(self.__name__, message)

def toDict(self):
return dataclasses.asdict(self)
17 changes: 7 additions & 10 deletions stlib/core/basePrefabParameters.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import dataclasses
from stlib.core.baseParameters import BaseParameters

@dataclasses.dataclass
class BasePrefabParameters(object):
class BasePrefabParameters(BaseParameters):
name : str = "object"
kwargs : dict = dataclasses.field(default_factory=dict)
kwargs : dict = {}

# Transformation information
# TODO: these data are going to be added in Node in SOFA (C++ implementation)
translation : list[float] = dataclasses.field(default_factory = lambda : [0., 0., 0.])
rotation : list[float] = dataclasses.field(default_factory = lambda : [0., 0., 0.])
scale : list[float] = dataclasses.field(default_factory = lambda : [1., 1., 1.])

def toDict(self):
return dataclasses.asdict(self)
translation : list[float] = [0., 0., 0.]
rotation : list[float] = [0., 0., 0.]
scale : list[float] = [1., 1., 1.]

43 changes: 23 additions & 20 deletions stlib/entities/__entity__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,29 @@
from stlib.visual import VisualParameters, Visual
from stlib.materials import Material, MaterialParameters
from stlib.geometries import Geometry
import dataclasses
from typing import Callable, Optional
from stlib.geometries import GeometryParameters
from stlib.geometries import GeometryParameters, InternalDataProvider
from splib.core.enum_types import StateType
from stlib.core.basePrefab import BasePrefab

from stlib.geometries.file import FileParameters
from stlib.materials.rigid import RigidParameters
from splib.core.enum_types import ElementType


@dataclasses.dataclass
class EntityParameters(BaseParameters):
name : str = "Entity"

stateType : StateType = StateType.VEC3
stateType : StateType = StateType.RIGID

### QUID
addCollision : Optional[Callable] = lambda x : Collision(CollisionParameters())
addVisual : Optional[Callable] = lambda x : Visual(VisualParameters())
addCollision : Optional[Callable] = Collision(CollisionParameters())
addVisual : Optional[Callable] = Visual(VisualParameters())

geometry : GeometryParameters = None
material : MaterialParameters = None
geometry : GeometryParameters = GeometryParameters(elementType = ElementType.POINTS, data = InternalDataProvider(position = [[0., 0., 0.]]))
material : MaterialParameters = RigidParameters()
collision : Optional[CollisionParameters] = None
visual : Optional[VisualParameters] = None
visual : Optional[VisualParameters] = VisualParameters(geometry = FileParameters(filename="mesh/cube.obj"))



Expand All @@ -38,20 +40,16 @@ class Entity(BasePrefab):
parameters : EntityParameters


def __init__(self, parameters=EntityParameters(), **kwargs):
def __init__(self, parameters: EntityParameters):
BasePrefab.__init__(self, parameters)


def init(self):
self.geometry = self.add(Geometry, parameters=self.parameters.geometry)

### Check compatilibility of Material
if self.parameters.material.stateType != self.parameters.stateType:
print("WARNING: imcompatibility between templates of both the entity and the material")
self.parameters.material.stateType = self.parameters.stateType
self.checkMaterialCompatibility()

self.material = self.add(Material, parameters=self.parameters.material)
self.material.States.position.parent = self.geometry.container.position.linkpath
self.material.getMechanicalState().position.parent = self.geometry.container.position.linkpath

if self.parameters.collision is not None:
self.collision = self.add(Collision, parameters=self.parameters.collision)
Expand All @@ -61,6 +59,11 @@ def init(self):
self.visual = self.add(Visual, parameters=self.parameters.visual)
self.addMapping(self.visual)

def checkMaterialCompatibility(self):
if self.parameters.material.stateType != self.parameters.stateType:
print("WARNING: imcompatibility between templates of both the entity and the material")
self.parameters.material.stateType = self.parameters.stateType


def addMapping(self, destinationPrefab):

Expand All @@ -70,12 +73,12 @@ def addMapping(self, destinationPrefab):
if( self.parameters.stateType == StateType.VEC3):
destinationPrefab.addObject("BarycentricMapping",
output=destinationPrefab.linkpath,
output_topology=destinationPrefab.Geometry.container.linkpath,
input=self.Material.linkpath,
input_topology=self.Geometry.container.linkpath,
output_topology=destinationPrefab.geometry.container.linkpath,
input=self.material.linkpath,
input_topology=self.geometry.container.linkpath,
template=template)
else:
destinationPrefab.addObject("RigidMapping",
output=destinationPrefab.linkpath,
input=self.Material.linkpath,
input=self.material.linkpath,
template=template)
32 changes: 14 additions & 18 deletions stlib/geometries/__geometry__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from stlib.core.basePrefab import BasePrefab
from stlib.core.baseParameters import BaseParameters, Optional, dataclasses, Any
from stlib.core.baseParameters import BaseParameters, Optional, Any
from splib.topology.dynamic import addDynamicTopology
from splib.topology.static import addStaticTopology
from splib.core.enum_types import ElementType
Expand All @@ -11,8 +11,7 @@

class Geometry(BasePrefab):...

@dataclasses.dataclass
class InternalDataProvider(object):
class InternalDataProvider(BaseParameters):
position : Any = None
# Topology information
edges : Any = DEFAULT_VALUE
Expand All @@ -21,12 +20,13 @@ class InternalDataProvider(object):
tetrahedra : Any = DEFAULT_VALUE
hexahedra : Any = DEFAULT_VALUE

@classmethod
def generateAttribute(self, parent : Geometry):
pass


@dataclasses.dataclass
class GeometryParameters(BaseParameters):
mytype : type = BaseParameters
name : str = "Geometry"

# Type of the highest degree element
Expand All @@ -35,10 +35,6 @@ class GeometryParameters(BaseParameters):

dynamicTopology : bool = False

def Data(self):
return InternalDataProvider()



class Geometry(BasePrefab):
# container : Object # This should be more specialized into the right SOFA type
Expand All @@ -48,8 +44,6 @@ class Geometry(BasePrefab):

def __init__(self, parameters: GeometryParameters):
BasePrefab.__init__(self, parameters)



def init(self):

Expand All @@ -59,14 +53,16 @@ def init(self):

if self.parameters.dynamicTopology :
if self.parameters.elementType is not None :
addDynamicTopology(self, elementType=self.parameters.elementType, container = {
"position": self.parameters.data.position,
"edges": self.parameters.data.edges,
"triangles": self.parameters.data.triangles,
"quads": self.parameters.data.quads,
"tetrahedra": self.parameters.data.tetrahedra,
"hexahedra": self.parameters.data.hexahedra
})
addDynamicTopology(self,
elementType=self.parameters.elementType,
container = {
"position": self.parameters.data.position,
"edges": self.parameters.data.edges,
"triangles": self.parameters.data.triangles,
"quads": self.parameters.data.quads,
"tetrahedra": self.parameters.data.tetrahedra,
"hexahedra": self.parameters.data.hexahedra
})
else:
raise ValueError
else:
Expand Down
14 changes: 3 additions & 11 deletions stlib/geometries/cube.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
from stlib.geometries import GeometryParameters
from stlib.geometries import FileParameters

class CubeParameters(GeometryParameters):
def __init__(self, center, edgeLength, pointPerEdge, dynamicTopology = False):
class CubeParameters(FileParameters):

customGeom = CubeParameters.createData(center, edgeLength, pointPerEdge)
GeometryParameters.__init__(data = customGeom, dynamicTopology = dynamicTopology)

@staticmethod
def createData(center, edgeLength, pointPerEdge) -> GeometryParameters.Data :
data = GeometryParameters.Data()
#Fill data
return data
filename : str = "mesh/cube.obj"

10 changes: 1 addition & 9 deletions stlib/geometries/extract.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from stlib.geometries import GeometryParameters, InternalDataProvider, Geometry
from stlib.core.baseParameters import dataclasses
from splib.topology.dynamic import addDynamicTopology
from splib.topology.loader import loadMesh
from splib.core.enum_types import ElementType
Expand All @@ -13,18 +12,11 @@ class ExtractInternalDataProvider(InternalDataProvider):
sourceType : ElementType
sourceName : str

def __init__(self, destinationType : ElementType, sourceType : ElementType, sourceName : str):
self.destinationType = destinationType
self.sourceType = sourceType
self.sourceName = sourceName

def __post_init__(self):
def model_post_init(self, __context):
if(not (self.sourceType == ElementType.TETRAHEDRA and self.destinationType == ElementType.TRIANGLES)
and not (self.sourceType == ElementType.HEXAHEDRA and self.destinationType == ElementType.QUADS) ):
raise ValueError("Only configuration possible are 'Tetrahedra to Triangles' and 'Hexahedra to Quads'")

InternalDataProvider.__init__(self)

def generateAttribute(self, parent : Geometry):
node = parent.addChild("ExtractedGeometry")

Expand Down
18 changes: 8 additions & 10 deletions stlib/geometries/file.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
from stlib.geometries import GeometryParameters, InternalDataProvider, Geometry
from stlib.core.baseParameters import dataclasses
from splib.topology.loader import loadMesh
from splib.core.enum_types import ElementType

from Sofa.Core import Node

@dataclasses.dataclass
class FileInternalDataProvider(InternalDataProvider):
filename : str = "mesh/cube.obj"

def __post_init__(self, **kwargs):
InternalDataProvider.__init__(self,**kwargs)

def generateAttribute(self, parent : Geometry):
loadMesh(parent, self.filename)

Expand All @@ -32,9 +27,12 @@ def generateAttribute(self, parent : Geometry):

class FileParameters(GeometryParameters):

def __init__(self, filename, dynamicTopology = False, elementType : ElementType = None ):
GeometryParameters.__init__(self,
data = FileInternalDataProvider(filename=filename),
dynamicTopology = dynamicTopology,
elementType = elementType)
filename : str = "mesh/cube.obj"
dynamicTopology : bool = False
elementType : ElementType = None

def model_post_init(self, __context):
self.data = FileInternalDataProvider(filename=self.filename)



Loading
Loading