Example #1
0
class VisualModel(SofaObject):
    """VisualModel Prefab

       This prefab is creating a VisualModel.

       Arguments:
            parent
            surfaceMeshFileName
            name
            color
            rotation
            translation
            scale

       Content:
           Node
           {
                name : 'Visual'
                MeshLoader : 'loader'
                OglModel : "model'
           }
    """
    def __init__(self,
                 parent,
                 surfaceMeshFileName,
                 name="VisualModel",
                 color=[1., 1., 1.],
                 rotation=[0., 0., 0.],
                 translation=[0., 0., 0.],
                 scale=[1., 1., 1.]):
        self.node = Node(parent, name)

        if surfaceMeshFileName.endswith(".stl"):
            self.loader = self.node.createObject('MeshSTLLoader',
                                                 name="loader",
                                                 filename=surfaceMeshFileName)
        elif surfaceMeshFileName.endswith(".obj"):
            self.loader = self.node.createObject('MeshObjLoader',
                                                 name="loader",
                                                 filename=surfaceMeshFileName)
        else:
            print(
                "Extension not handled in STLIB/python/stlib/visuals for file: "
                + str(surfaceMeshFileName))

        self.model = self.node.createObject('OglModel',
                                            name="model",
                                            src="@loader",
                                            rotation=rotation,
                                            translation=translation,
                                            scale3d=scale,
                                            color=color,
                                            updateNormals=False)
Example #2
0
def StringSensor(parentNode=None,
                 name="StringSensor",
                 cableGeometry=[[1.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
                 rotation=[0.0, 0.0, 0.0],
                 translation=[0.0, 0.0, 0.0],
                 uniformScale=1.0):
    """One line documentation used in the summary

    Args:


    Structure:
        .. sourcecode:: qml

            Node : {
                    name : "StringSensor"
                    SensorEngine
            }

    Example:
        .. sourcecode::python


        def createScene(rootNode):
            from stlib.scene import MainHeader
            MainHeader(rootNode)

            f = Node(rootNode, "Finger")
            StringSensor(f)

    """
    cable = Node(parentNode, "StringSensor")

    # This create a MechanicalObject, a componant holding the degree of freedom of our
    # mechanical modelling. In the case of a cable it is a set of positions specifying
    # the points where the cable is passing by.
    cable.createObject('MechanicalObject',
                       position=cableGeometry,
                       rotation=rotation,
                       translation=translation,
                       scale=uniformScale)

    cable.createObject("SensorEngine",
                       name="SensorEngine",
                       indices=range(len(cableGeometry)))

    # This create a BarycentricMapping. A BarycentricMapping is a key element as it will create a bi-directional link
    # between the cable's DoFs and the parents's ones so that movements of the cable's DoFs will be mapped
    # to the finger and vice-versa;
    cable.createObject('BarycentricMapping',
                       name="Mapping",
                       mapForces=False,
                       mapMasses=False)

    return ss
Example #3
0
class ElasticMaterialObject(SofaObject):
    def __init__(self,
                 attachedTo=None,
                 volumeMeshFileName=None,
                 name="ElasticMaterialObject",
                 rotation=[0.0, 0.0, 0.0],
                 translation=[0.0, 0.0, 0.0],
                 surfaceMeshFileName=None,
                 collisionMesh=None,
                 withConstrain=True,
                 surfaceColor=[1.0, 1.0, 1.0],
                 poissonRatio=0.3,
                 youngModulus=18000,
                 totalMass=1.0,
                 solver=None):

        self.node = Node(attachedTo, name)
        ElasticMaterialObject.createPrefab(self, volumeMeshFileName, name,
                                           rotation, translation,
                                           surfaceMeshFileName, collisionMesh,
                                           withConstrain, surfaceColor,
                                           poissonRatio, youngModulus,
                                           totalMass, solver)

    @staticmethod
    def createPrefab(self,
                     volumeMeshFileName=None,
                     name="ElasticMaterialObject",
                     rotation=[0.0, 0.0, 0.0],
                     translation=[0.0, 0.0, 0.0],
                     surfaceMeshFileName=None,
                     collisionMesh=None,
                     withConstrain=True,
                     surfaceColor=[1.0, 1.0, 1.0],
                     poissonRatio=0.3,
                     youngModulus=18000,
                     totalMass=1.0,
                     solver=None):
        if self.node == None:
            Sofa.msg_error(
                "Unable to create the elastic object because it is not attached to any node. Please fill the attachedTo parameter"
            )
            return None

        if volumeMeshFileName == None:
            Sofa.msg_error(
                self.node,
                "Unable to create an elastic object because there is no volume mesh provided."
            )
            return None

        if volumeMeshFileName.endswith(".msh"):
            self.loader = self.node.createObject('MeshGmshLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)
        elif volumeMeshFileName.endswith(".gidmsh"):
            self.loader = self.node.createObject('GIDMeshLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)
        else:
            self.loader = self.node.createObject('MeshVTKLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)

        if solver == None:
            self.integration = self.node.createObject('EulerImplicit',
                                                      name='integration')
            self.solver = self.node.createObject('SparseLDLSolver',
                                                 name="solver")

        self.container = self.node.createObject(
            'TetrahedronSetTopologyContainer', src='@loader', name='container')
        self.dofs = self.node.createObject('MechanicalObject',
                                           template='Vec3d',
                                           name='dofs')

        ## To be properly simulated and to interact with gravity or inertia forces, an elasticobject
        ## also needs a mass. You can add a given mass with a uniform distribution for an elasticobject
        ## by adding a UniformMass component to the elasticobject node
        self.mass = self.node.createObject('UniformMass',
                                           totalMass=totalMass,
                                           name='mass')

        ## The next component to add is a FEM forcefield which defines how the elasticobject reacts
        ## to a loading (i.e. which deformations are created from forces applied onto it).
        ## Here, because the elasticobject is made of silicone, its mechanical behavior is assumed elastic.
        ## This behavior is available via the TetrahedronFEMForceField component.
        self.forcefield = self.node.createObject('TetrahedronFEMForceField',
                                                 template='Vec3d',
                                                 method='large',
                                                 name='forcefield',
                                                 poissonRatio=poissonRatio,
                                                 youngModulus=youngModulus)

        if withConstrain:
            self.node.createObject('LinearSolverConstraintCorrection',
                                   solverName=self.solver.name)

        if collisionMesh:
            self.addCollisionModel(collisionMesh, rotation, translation)

        if surfaceMeshFileName:
            self.addVisualModel(surfaceMeshFileName, surfaceColor, rotation,
                                translation)

    def addCollisionModel(self,
                          collisionMesh,
                          rotation=[0.0, 0.0, 0.0],
                          translation=[0.0, 0.0, 0.0]):
        self.collisionmodel = self.node.createChild('CollisionModel')
        self.collisionmodel.createObject('MeshSTLLoader',
                                         name='loader',
                                         filename=collisionMesh,
                                         rotation=rotation,
                                         translation=translation)
        self.collisionmodel.createObject('TriangleSetTopologyContainer',
                                         src='@loader',
                                         name='container')
        self.collisionmodel.createObject('MechanicalObject',
                                         template='Vec3d',
                                         name='dofs')
        self.collisionmodel.createObject('Triangle')
        self.collisionmodel.createObject('Line')
        self.collisionmodel.createObject('Point')
        self.collisionmodel.createObject('BarycentricMapping')

    def addVisualModel(self, filename, color, rotation, translation):
        self.visualmodel = VisualModel(parent=self.node,
                                       surfaceMeshFileName=filename,
                                       color=color,
                                       rotation=rotation,
                                       translation=translation)

        ## Add a BarycentricMapping to deform the rendering model to follow the ones of the
        ## mechanical model.
        self.visualmodel.mapping = self.visualmodel.node.createObject(
            'BarycentricMapping', name='mapping')
Example #4
0
class VisualModel(SofaObject):
    """VisualModel Prefab

       This prefab is creating a VisualModel.

       Arguments:
            parent
            surfaceMeshFileName
            name
            color
            rotation
            translation
            scale

       Content:
           Node
           {
                name : 'Visual'
                MeshLoader : 'loader'
                OglModel : "model'
           }
    """
    def __init__(self,
                 parent,
                 surfaceMeshFileName,
                 name="VisualModel",
                 color=[1., 1., 1.],
                 rotation=[0., 0., 0.],
                 translation=[0., 0., 0.],
                 scale=[1., 1., 1.]):
        self.node = Node(parent, name)

        if not self.getRoot().getObject("SofaOpenglVisual", warning=False):
            if not self.getRoot().getObject("/Config/SofaOpenglVisual",
                                            warning=False):
                Sofa.msg_info(
                    "Missing RequiredPlugin SofaOpenglVisual in the scene, add it from Prefab VisualModel."
                )
                self.getRoot().createObject("RequiredPlugin",
                                            name="SofaOpenglVisual")

        if surfaceMeshFileName.endswith(".stl"):
            self.loader = self.node.createObject('MeshSTLLoader',
                                                 name="loader",
                                                 filename=surfaceMeshFileName)
        elif surfaceMeshFileName.endswith(".obj"):
            self.loader = self.node.createObject('MeshObjLoader',
                                                 name="loader",
                                                 filename=surfaceMeshFileName)
        else:
            print(
                "Extension not handled in STLIB/python/stlib/visuals for file: "
                + str(surfaceMeshFileName))

        self.model = self.node.createObject('OglModel',
                                            name="model",
                                            src="@loader",
                                            rotation=rotation,
                                            translation=translation,
                                            scale3d=scale,
                                            color=color,
                                            updateNormals=False)
Example #5
0
class ServoWheel(SofaObject):
    def __init__(self, parentNode):
        self.node = Node(parentNode, "ServoWheel")
        self.dofs = self.node.createObject("MechanicalObject", size=1, template='Rigid3',
                                           showObject=True, showObjectScale=15, name="dofs")
        self.node.createObject("RigidRigidMapping", name="map", applyRestPosition=True)
Example #6
0
class ServoMotor(SofaObject):
    """A S90 servo motor

    This prefab is implementing a S90 servo motor.
    https://servodatabase.com/servo/towerpro/sg90

    The prefab ServoMotor is composed of:
    - a visual model
    - a mechanical model composed two rigids. One rigid is for the motor body
      while the other is implementing the servo rotating wheel.
    - a KinematicMotorController to compute from an input angle the new orientation of the
      servo wheel according to its parent frame.

    The prefab has the following parameters:
    - translation       to change default location of the servo (default [0.0,0.0,0.0])
    - rotation          to change default rotation of the servo (default [0.0,0.0,0.0,1])
    - scale             to change default scale of the servo (default 1)
    - doAddVisualModel  to control wether a visual model is added (default True)

    The prefab have the following property:
    - angle     use this to specify the angle of rotation of the servo motor

    Example of use in a Sofa scene:

    def createScene(root):
        ...
        servo = ServoMotor(root)

        ## Direct access to the components
        servo.node.angle = 1.0
        servo.dofs.showObjects = False

        ## Indirect access to the components
        get(servo.node, "dofs.showObjects").value = False
        get(servo.node, "servowheel.dofs.showObjects").value = False
    """

    def __init__(self, parent, translation=[0.0, 0.0, 0.0], rotation=[0.0, 0.0, 0.0], scale=[1.0, 1.0, 1.0], doAddVisualModel=True):
        self.node = Node(parent, "ServoMotor")
        self.node.addNewData("angle",
                             "ServoMotor Properties",
                             "The angular position of the motor (in radians)", "double", 0.0)
        self.angle = self.node.findData("angle")

        self.dofs = self.node.createObject("MechanicalObject", size=1,
                                           name="dofs",
                                           translation=translation, rotation=rotation, scale3d=scale,
                                           template='Rigid3', showObject=True, showObjectScale=15)

        self.servowheel = ServoWheel(self.node)
        self.controller = KinematicMotorController(self.node, self.dofs, self.servowheel.dofs,
                                                   self.servowheel.node.map,
                                                   angleValue=self.angle.getLinkPath())

        if doAddVisualModel:
            self.addVisualModel()

    def addVisualModel(self):
        visual = self.node.createChild("VisualModel")
        visual.createObject("MeshSTLLoader", name="loader", filename="../data/mesh/SG90_servomotor.stl")
        visual.createObject("MeshTopology", src="@loader")
        visual.createObject("OglModel", color=[0.15, 0.45, 0.75, 0.7], writeZTransparent=True)
        visual.createObject("RigidMapping", index=0)