def processObject(parent, key, kv, stack, frame): global sofaComponents populateFrame(key, frame, stack) frame = {} kwargs = {} if not isinstance(kv, list): kv = [("name", kv)] properties = None for k, v in kv: if k == "properties": if properties == None: properties = v else: c = parent.createChild("[XX" + key + "XX]") Sofa.msg_error( c, pslprefix + " Unable to create an object '" + key + "' because of duplicated properties keywords.") return None elif isAStringToken(v, ('s', 'p')): v = processString(v, stack, frame) kwargs[k] = v elif isinstance(v, int): kwargs[k] = v elif isinstance(v, float): kwargs[k] = v else: c = parent.createChild("[XX" + key + "XX]") Sofa.msg_error( c, pslprefix + " Unable to create an object '" + key + "' because of invalid parameter " + str(k) + "=" + str(v)) return None stack.append(frame) frame["self"] = obj = createObject(parent, key, stack, frame, kwargs) if properties: processProperties(obj, obj.name, properties, stack, frame) ### Force all the data field into a non-persistant state. for datafield in obj.getListOfDataFields(): datafield.setPersistant(False) for link in obj.getListOfLinks(): link.setPersistant(False) ### Then revert only the ones that have been touched for dataname in kwargs: try: if dataname in datafieldQuirks: continue field = getField(obj, dataname) if field != None: field.setPersistant(True) except Exception, e: Sofa.msg_warning( obj, pslprefix + " this does not seems to be a valid field '" + str(dataname) + "'")
def getVisualsByTags(self, solidId=None, solidTags=set(), meshTags=set()): """ \return a selection of visual models, based on solidTags and meshTags an empty tag set means all solids or meshes """ visuals = list() if not solidId is None and len(solidTags): Sofa.msg_warning("sml.Model.getVisualsByTags", "solidId and solidTags both specified, solidTags ignored") solids = None if not solidId is None: solids = [self.model.solids[solidId]] elif len(solidTags) : solids = self.model.getSolidsByTags(solidTags) else : solids = self.model.solids.values() for solid in solids: if not solid.id in self.visuals: if printLog: Sofa.msg_info("SofaPython.sml", "No visual for solid "+solid.id) continue solidVisuals = self.visuals[solid.id] meshes = solid.getMeshesByTags(meshTags) if len(meshTags) else solid.mesh for mesh in meshes: if not mesh.id in solidVisuals: if printLog: Sofa.msg_info("SofaPython.sml", "No visual for solid "+solid.id+", mesh: "+mesh.id) continue visual = solidVisuals[mesh.id] visual.mesh = mesh # make sure we known which mesh is attached to this visual visuals.append(visual) return visuals
def getValueByTag(valueByTag, tags): """ look into the valueByTag dictionary for a tag contained in tags \return the corresponding value, or the "default" value if none is found \todo print a warning if several matching tags are found in valueByTag """ if "default" in tags: Sofa.msg_error( "SofaPython.sml.getValueByTag", "default tag has a special meaning, it should not be defined in {0}" .format(tags)) tag = tags & set(valueByTag.keys()) if len(tag) > 1: Sofa.msg_warning( "SofaPython.sml.getValueByTag", "sevaral tags from {0} are defined in values {1}".format( tags, valueByTag)) if not len(tag) == 0: return valueByTag[tag.pop()] else: if "default" in valueByTag: return valueByTag["default"] else: Sofa.msg_error( "SofaPython.sml.getValueByTag", "No default value, and no tag from {0} found in {1}".format( tags, valueByTag)) return None
def insertRigidScale(parentNode, solidModel, param): """ create a RigidScale.API.ShearlessAffineBody from the solidModel """ if printLog: Sofa.msg_info("RigidScale.sml", "insertRigidScale "+solidModel.name) body = RigidScale.API.ShearlessAffineBody(parentNode, solidModel.name) if (not len(solidModel.mesh)==1): Sofa.msg_warning("RigidScale.sml", "insertRigidScale support only single mesh solid (nb meshes={0}) - solid {1} ignored".format(len(solidModel.mesh), solidModel.name)) return None # TODO support multi meshes body.setFromMesh(solidModel.mesh[0].source, numberOfPoints = SofaPython.sml.getValueByTag(param.rigidScaleNbDofByTag, solidModel.tags), voxelSize = SofaPython.units.length_from_SI(param.voxelSize), density = SofaPython.units.massDensity_from_SI(1000.), offset = solidModel.position) body.addBehavior(youngModulus=SofaPython.units.elasticity_from_SI(param.rigidScaleStiffness), numberOfGaussPoint=8) cm = body.addCollisionMesh(solidModel.mesh[0].source) cm.addVisualModel() body.affineDofs.showObject=param.showAffine body.affineDofs.showObjectScale=SofaPython.units.length_from_SI(param.showAffineScale) if param.showImage: body.image.addViewer() return body
def insertMergeRigid(self, mergeNodeName="dofRigid", tags=None, rigidIndexById=None ): """ Merge all the rigids in a single MechanicalObject using a SubsetMultiMapping optionnaly give a list of tags to select the rigids which are merged return the created node""" mergeNode = None currentRigidIndex=0 input="" indexPairs="" if tags is None: _tags = self.param.rigidTags else: _tags = tags for solid in self.model.getSolidsByTags(_tags): if not solid.id in self.rigids: Sofa.msg_warning("Compliant.sml","SceneArticulatedRigid.insertMergeRigid: "+solid.name+" is not a rigid") continue rigid = self.rigids[solid.id] if mergeNode is None: mergeNode = rigid.node.createChild(mergeNodeName) else: rigid.node.addChild(mergeNode) input += '@'+rigid.node.getPathName()+" " indexPairs += str(currentRigidIndex) + " 0 " if not rigidIndexById is None: rigidIndexById[solid.id]=currentRigidIndex currentRigidIndex+=1 if input: mergeNode.createObject("MechanicalObject", template = "Rigid3", name="dofs") mergeNode.createObject('SubsetMultiMapping', template = "Rigid3,Rigid3", name="mapping", input = input , output = '@./', indexPairs=indexPairs, applyRestPosition=True ) else: Sofa.msg_warning("Compliant.sml", "insertMergeRigid: no rigid merged") return mergeNode
def createScene(node): # some code before a = 0 # w/ emitter Sofa.msg_info( "MyPythonEmitter", "my message info a="+str(a) ) Sofa.msg_warning( "MyPythonEmitter a="+str(a), "my message warning" ) Sofa.msg_error( "MyPythonEmitter", "my message error" ) Sofa.msg_fatal( "MyPythonEmitter", "my message fatal" ) # some code in between a = 2 # w/o emitter Sofa.msg_info( "my message info a="+str(a) ) Sofa.msg_warning( "my message warning" ) Sofa.msg_error( "my message error" ) Sofa.msg_fatal( "my message fatal" ) # more complex code was causing trouble, so try it model = SofaPython.sml.Model("smlSimple.sml") # # invalid calls # Sofa.msg_info( 100 ) # Sofa.msg_info( "emitter", "message", "extra" ) sys.stdout.flush()
def insertJoint(jointModel, rigids, param): """ create a StructuralAPI.GenericRigidJoint from the jointModel """ frames = list() for i, offset in enumerate(jointModel.offsets): if not jointModel.solids[i].id in rigids: Sofa.msg_warning( "Compliant.sml", "insertJoint " + jointModel.name + " failed: " + jointModel.solids[i].id + " is not a rigid body") return None rigid = rigids[jointModel.solids[i].id] # shortcut if rigid is None: Sofa.msg_warning( "Compliant.sml", "in joint {0}, solid {1} is missing, ignored".format( jointModel.name, jointModel.solids[i].id)) return if not offset is None: if offset.isAbsolute(): frames.append( rigid.addAbsoluteOffset(offset.name, offset.value)) else: frames.append(rigid.addOffset(offset.name, offset.value)) if not param is None: frames[-1].dofs.showObject = param.showOffset frames[ -1].dofs.showObjectScale = SofaPython.units.length_from_SI( param.showOffsetScale) else: frames.append(rigid) if printLog: Sofa.msg_info("Compliant.sml", "insertJoint " + jointModel.name) mask = [1] * 6 limits = [] # mask for limited dofs isLimited = True # does the joint have valid limits? for d in jointModel.dofs: if isLimited: if d.min == None or d.max == None: isLimited = False # as soon as a limit is not defined, the limits cannot work else: limits.append(d.min) limits.append(d.max) mask[d.index] = 0 joint = StructuralAPI.GenericRigidJoint( jointModel.name, frames[0].node, frames[1].node, mask, compliance=SofaPython.sml.getValueByTag(param.jointComplianceByTag, jointModel.tags), isCompliance=SofaPython.sml.getValueByTag(param.jointIsComplianceByTag, jointModel.tags)) if isLimited: joint.addLimits(limits) return joint
def processObject(parent, key, kv, stack, frame): global sofaComponents populateFrame(key, frame, stack) frame = {} kwargs = {} if not isinstance(kv, list): kv = [("name" , kv)] properties = None for k,v in kv: if k == "properties": if properties == None: properties = v else: c=parent.createChild("[XX"+key+"XX]") Sofa.msg_error(c, pslprefix+" Unable to create an object '"+key+"' because of duplicated properties keywords.") return None elif isAStringToken(v, ('s', 'p')): v = processString(v, stack, frame) kwargs[k] = v elif isinstance(v, int): kwargs[k] = v elif isinstance(v, float): kwargs[k] = v else: c=parent.createChild("[XX"+key+"XX]") Sofa.msg_error(c, pslprefix+" Unable to create an object '"+key+"' because of invalid parameter "+str(k)+"="+str(v)) return None stack.append(frame) frame["self"] = obj = createObject(parent, key, stack, frame, kwargs) if properties: processProperties(obj, obj.name, properties, stack, frame) ### Force all the data field into a non-persistant state. for datafield in obj.getListOfDataFields(): datafield.setPersistant(False) for link in obj.getListOfLinks(): link.setPersistant(False) ### Then revert only the ones that have been touched for dataname in kwargs: try: if dataname in datafieldQuirks: continue field = getField(obj, dataname) if field != None: field.setPersistant(True) except Exception,e: Sofa.msg_warning(obj, pslprefix+" this does not seems to be a valid field '"+str(dataname)+"'")
def setVisualStyles(self, displayFlags="showVisual", solidId=None, solidTags=set(), meshTags=set()): """ set visual tags to selected visual models, a visualStyle must have been already created selection is done by solidTags and meshTags, empty set means all solids or meshes """ for visual in self.getVisualsByTags(solidId, solidTags, meshTags): vs = visual.node.getObject("visualStyle") if vs is None: Sofa.msg_warning("sml.BaseScene", "Missing VisualStyle component in "+visual.node.getPathName()) continue vs.displayFlags=displayFlags if "showVisual" in displayFlags: visual.node.propagatePositionAndVelocity()
def insertRigidScale(parentNode, rigidModel, param): """ Create a RigidScale.API.ShearlessAffineBody from the solidModel """ if printLog: Sofa.msg_info("RigidScale.sml", "insertRigidScale " + rigidModel.name) body = RigidScale.API.ShearlessAffineBody(parentNode, rigidModel.name) if (not len(rigidModel.mesh) == 1): Sofa.msg_warning( "RigidScale.sml", "insertRigidScale support only single mesh solid (nb meshes={0}) - solid {1} ignored" .format(len(rigidModel.mesh), rigidModel.name)) return None # TODO support multi meshes meshFormatSupported = True for mesh in rigidModel.mesh: meshFormatSupported &= mesh.format == "obj" or mesh.format == "vtk" if len(rigidModel.mesh) > 0 and meshFormatSupported: body.setFromMesh(rigidModel.mesh[0].source, numberOfPoints=SofaPython.sml.getValueByTag( param.rigidScaleNbDofByTag, rigidModel.tags), voxelSize=SofaPython.units.length_from_SI( param.voxelSize), density=SofaPython.units.massDensity_from_SI(1000.), offset=rigidModel.position) cm = body.addCollisionMesh(rigidModel.mesh[0].source) cm.addVisualModel() else: body.setManually(offset=rigidModel.position) body.addBehavior(youngModulus=SofaPython.units.elasticity_from_SI( param.rigidScaleStiffness), numberOfGaussPoint=8) #cm = body.addCollisionMesh(rigidModel.mesh[0].source) #cm.addVisualModel() body.affineDofs.showObject = param.showAffine body.affineDofs.showObjectScale = SofaPython.units.length_from_SI( param.showAffineScale) body.rigidDofs.showObject = param.showRigid body.rigidDofs.showObjectScale = SofaPython.units.length_from_SI( param.showRigidScale) if param.showImage: body.image.addViewer() return body
def numpify(obj, name): # i very much want to alias data buffers in a read-write way without # triggering anything data-related, so please leave this be # MattN: this defeats the data graph purpose, and will generate # tons of non-debuggable bugs, a warning is mandatory. # We need to find a similar writing that triggers the data graph. # @warning read-write here is a hack Sofa.msg_warning( "SofaPython.SofaNumpy", "using read-write data incorrectly, a modification won't trigger the data-graph" " (" + obj.getLinkPath() + "." + name + ")") return as_numpy(obj.findData(name), False)
def __init__(self, node, *args, **kwargs): Sofa.msg_warning('SofaPython', 'SofaPython.Controller is intended as compatibility class only') # setting attributes from kwargs for name, value in kwargs.iteritems(): setattr(self, name, value) # call createGraph for compatibility purposes self.createGraph(node) # check whether derived class has 'onLoaded' cls = type(self) if not cls.onLoaded is Sofa.PythonScriptController.onLoaded: Sofa.msg_warning('SofaPython', '`onLoaded` is defined in subclass but will not be called in the future' )
def parseXml(self, jointXml): parseIdName(self, jointXml) parseTag(self, jointXml) solidsRef = jointXml.findall("jointSolidRef") for i in range(0,2): if not solidsRef[i].find("offset") is None: Sofa.msg_warning("SofaPython.sml","JointSpecific: offets are undesirable and won't be used.") self.offsets[i] = Model.Offset() self.offsets[i].name = "offset_{0}".format(self.name) for dof in jointXml.findall("dof"): Sofa.msg_warning("SofaPython.sml","JointSpecific: dof are undesirable and won't be used.") self.center = Tools.strToListFloat(jointXml.attrib["center"]) if "direction" in jointXml.attrib: self.direction = Tools.strToListFloat(jointXml.attrib["direction"]) self.update()
def __init__(self, node, *args, **kwargs): Sofa.msg_warning('SofaPython', 'SofaPython.DataEngine is intended as compatibility class only') # setting attributes from kwargs for name, value in kwargs.iteritems(): setattr(self, name, value) # call createGraph for compatibility purposes self.createGraph(node) # check whether derived class has 'onLoaded' cls = type(self) if not cls.onLoaded is Sofa.PythonScriptDataEngine.onLoaded: Sofa.msg_warning('SofaPython', '`onLoaded` is defined in subclass but will not be called in the future' )
def __init__(self, node, name, type="331", labelImage=None, labels=None): if (labelImage is None) != (labels is None) : Sofa.msg_warning("Flexible.API.Behavior","Invalid label input - labelImage: {0}, labels: {1}".format(labelImage,labels)) self.node = node.createChild(name) self.name = name self.labelImage = labelImage self.labels = labels self.type = type self.sampler = None self.dofs = None self.mapping = None self.strainMapping = None self.relativeStrainMapping = None self.forcefield = None self.cell = ''
def parseXml(self, meshXml): parseIdName(self,meshXml) if not meshXml.find("source") is None: self.format = meshXml.find("source").attrib["format"] self.source = meshXml.find("source").text for g in meshXml.findall("group"): self.group[g.attrib["id"]] = Model.Mesh.Group(id=g.attrib["id"]) if not g.find("index").text: Sofa.msg_warning("SofaPython.sml","Group: group '"+g.attrib["id"]+"' of mesh '"+self.name+"' is empty") else: self.group[g.attrib["id"]].index = Tools.strToListInt(g.find("index").text) for d in g.findall("data"): self.group[g.attrib["id"]].data[d.attrib["name"]]=parseData(d) parseTag(self.group[g.attrib["id"]], g)
def parseXml(self, meshXml): parseIdName(self,meshXml) self.format = meshXml.find("source").attrib["format"] self.source = meshXml.find("source").text for g in meshXml.findall("group"): self.group[g.attrib["id"]] = Model.Mesh.Group() if not g.find("index").text: Sofa.msg_warning("SofaPython.sml","Group: group '"+g.attrib["id"]+"' of mesh '"+self.name+"' is empty") else: self.group[g.attrib["id"]].index = Tools.strToListInt(g.find("index").text) for d in g.findall("data"): self.group[g.attrib["id"]].data[d.attrib["name"]]=parseData(d) parseTag(self.group[g.attrib["id"]], g)
def __init__(self, node, name, type="331", labelImage=None, labels=None): if (labelImage is None) != (labels is None) : Sofa.msg_warning("Flexible.API.Behavior","Invalid label input - labelImage: {0}, labels: {1}".format(labelImage,labels)) self.node = node.createChild(name) self.name = name self.labelImage = labelImage self.labels = labels self.type = type self.sampler = None self.dofs = None self.mapping = None self.strainDofs = None self.strainMapping = None self.relativeStrainMapping = None self.forcefield = None self.cell = ''
def importTemplates(content): templates = {} for key, value in content: if key == "Template": name = "undefined" properties = {} rvalue = [] for k,v in value: if k == "name": if isAStringToken(v, ('s')): name = processString(v, None, None) else: Sofa.msg_warning(pslprefix, " Template names must be provided.") templates[name] = value else: Sofa.msg_warning(pslprefix, " an imported file contains something that is not a Template.") return templates
def getValueByTag(valueByTag, tags): """ look into the valueByTag dictionary for a tag contained in tags \return the corresponding value, or the "default" value if none is found \todo print a warning if several matching tags are found in valueByTag """ if "default" in tags: Sofa.msg_error("SofaPython.sml.getValueByTag", "default tag has a special meaning, it should not be defined in {0}".format(tags)) tag = tags & set(valueByTag.keys()) if len(tag)>1: Sofa.msg_warning("SofaPython.sml.getValueByTag", "sevaral tags from {0} are defined in values {1}".format(tags, valueByTag)) if not len(tag)==0: return valueByTag[tag.pop()] else: if "default" in valueByTag: return valueByTag["default"] else: Sofa.msg_error("SofaPython.sml.getValueByTag", "No default value, and no tag from {0} found in {1}".format(tags, valueByTag)) return None
def __init__(self, parentNode, youngModulus=500, poissonRatio=0.3, totalMass=0.042, inverseMode=True, effectorTarget=None): self.inverseMode = inverseMode self.node = parentNode.createChild('CircularRobot') self.node.createObject('MeshVTKLoader', name="loader", filename=path+"wheel.vtk") self.node.createObject('TetrahedronSetTopologyContainer', position='@loader.position', tetrahedra="@loader.tetrahedra") self.node.createObject('TetrahedronSetTopologyModifier') self.node.createObject('MechanicalObject', name='dofs', showIndices=False, showIndicesScale=4e-5) self.node.createObject('UniformMass', totalMass=totalMass) self.node.createObject('TetrahedronFEMForceField', poissonRatio=poissonRatio, youngModulus=youngModulus) if inverseMode: if effectorTarget is None: Sofa.msg_warning("The prefab CircularRobot needs effectorTarget in inverseMode") self.node.createObject('BarycentricCenterEffector', limitShiftToTarget=True, maxShiftToTarget=5, effectorGoal=effectorTarget, axis=[1, 1, 1]) self.__addCables()
def insertJoint(jointModel, rigids, scale=1, param=None): """ create a StructuralAPI.GenericRigidJoint from the jointModel """ frames=list() for i,offset in enumerate(jointModel.offsets): if not jointModel.solids[i].id in rigids: Sofa.msg_warning("Compliant.sml","insertJoint "+jointModel.name+" failed: "+jointModel.solids[i].id+" is not a rigid body") return None rigid = rigids[jointModel.solids[i].id] # shortcut if rigid is None: Sofa.msg_warning("Compliant.sml", "in joint {0}, solid {1} is missing, ignored".format(jointModel.name, jointModel.solids[i].id)) return if not offset is None: if offset.isAbsolute(): frames.append( rigid.addAbsoluteOffset(offset.name, StructuralAPI.scaleOffset(scale,offset.value)) ) else: frames.append( rigid.addOffset(offset.name, StructuralAPI.scaleOffset(scale,offset.value)) ) if not param is None: frames[-1].dofs.showObject = param.showOffset frames[-1].dofs.showObjectScale = SofaPython.units.length_from_SI(param.showOffsetScale) else: frames.append(rigid) if printLog: Sofa.msg_info("Compliant.sml","insertJoint "+jointModel.name) mask = [1]*6 limits=[] # mask for limited dofs isLimited = True # does the joint have valid limits? for d in jointModel.dofs: if isLimited: if d.min==None or d.max==None: isLimited = False # as soon as a limit is not defined, the limits cannot work else: limits.append(d.min) limits.append(d.max) mask[d.index] = 0 joint = StructuralAPI.GenericRigidJoint(jointModel.name, frames[0].node, frames[1].node, mask, compliance=SofaPython.sml.getValueByTag(param.jointComplianceByTag, jointModel.tags), isCompliance=SofaPython.sml.getValueByTag(param.jointIsComplianceByTag, jointModel.tags)) if isLimited: joint.addLimits(limits) return joint
def insertRigidScale(parentNode, rigidModel, param): """ Create a RigidScale.API.ShearlessAffineBody from the solidModel """ if printLog: Sofa.msg_info("RigidScale.sml", "insertRigidScale "+rigidModel.name) body = RigidScale.API.ShearlessAffineBody(parentNode, rigidModel.name) if (not len(rigidModel.mesh)==1): Sofa.msg_warning("RigidScale.sml", "insertRigidScale support only single mesh solid (nb meshes={0}) - solid {1} ignored".format(len(rigidModel.mesh), rigidModel.name)) return None # TODO support multi meshes meshFormatSupported = True for mesh in rigidModel.mesh : meshFormatSupported &= mesh.format=="obj" or mesh.format=="vtk" if len(rigidModel.mesh)>0 and meshFormatSupported: body.setFromMesh(rigidModel.mesh[0].source, numberOfPoints = SofaPython.sml.getValueByTag(param.rigidScaleNbDofByTag, rigidModel.tags), voxelSize = SofaPython.units.length_from_SI(param.voxelSize), density = SofaPython.units.massDensity_from_SI(1000.), offset = rigidModel.position) else: body.setManually(offset=rigidModel.position); #body.addBehavior(youngModulus=SofaPython.units.elasticity_from_SI(param.rigidScaleStiffness), numberOfGaussPoint=8) #cm = body.addCollisionMesh(rigidModel.mesh[0].source) #cm.addVisualModel() body.affineDofs.showObject = param.showAffine body.affineDofs.showObjectScale = SofaPython.units.length_from_SI(param.showAffineScale) body.rigidDofs.showObject = param.showRigid body.rigidDofs.showObjectScale = SofaPython.units.length_from_SI(param.showRigidScale) print "affines:", body.affineDofs.showObject, body.affineDofs.showObjectScale print "rigids: ", body.rigidDofs.showObject, body.rigidDofs.showObjectScale if param.showImage: body.image.addViewer() return body
def importTemplates(content): templates = {} for key, value in content: if key == "Template": name = "undefined" properties = {} rvalue = [] for k, v in value: if k == "name": if isAStringToken(v, ('s')): name = processString(v, None, None) else: Sofa.msg_warning(pslprefix, " Template names must be provided.") templates[name] = value else: Sofa.msg_warning( pslprefix, " an imported file contains something that is not a Template.") return templates
def getFileToImportFromPartialName(parent, partialname): if partialname.endswith(".psl"): return partialname if partialname.endswith(".pslx"): return partialname if partialname.endswith(".py"): return partialname if os.path.exists(partialname + ".psl"): if os.path.exists(partialname + ".py"): Sofa.msg_warning( parent, pslprefix + "Both '" + partialname + "'.psl and " + partialname + ".py. Importing the psl version.") if os.path.exists(partialname + ".py"): Sofa.msg_warning( parent, pslprefix + "Both '" + partialname + "'.psl and " + partialname + ".pslx. Importing the psl version.") return partialname + ".psl" if os.path.exists(partialname + ".pslx"): if os.path.exists(partialname + ".py"): Sofa.msg_warning( parent, pslprefix + "Both '" + partialname + "'.pslx and " + partialname + ".py. Importing the psl version.") return partialname + ".pslx" if os.path.exists(partialname + ".py"): return partialname + ".py" return None
def getFileToImportFromPartialName(parent, partialname): if partialname.endswith(".psl"): return partialname if partialname.endswith(".pslx"): return partialname if partialname.endswith(".py"): return partialname if os.path.exists(partialname+".psl"): if os.path.exists(partialname+".py"): Sofa.msg_warning(parent, pslprefix+"Both '"+partialname+"'.psl and "+partialname+".py. Importing the psl version.") if os.path.exists(partialname+".py"): Sofa.msg_warning(parent, pslprefix+"Both '"+partialname+"'.psl and "+partialname+".pslx. Importing the psl version.") return partialname+".psl" if os.path.exists(partialname+".pslx"): if os.path.exists(partialname+".py"): Sofa.msg_warning(parent, pslprefix+"Both '"+partialname+"'.pslx and "+partialname+".py. Importing the psl version.") return partialname+".pslx" if os.path.exists(partialname+".py"): return partialname+".py" return None
def Rigidify(targetObject, sourceObject, groupIndices, frames=None, name=None, frameOrientation=None): """ Transform a deformable object into a mixed one containing both rigid and deformable parts. :param targetObject: parent node where to attach the final object. :param sourceObject: node containing the deformable object. The object should be following the ElasticMaterialObject template. :param list groupIndices: array of array indices to rigidify. The length of the array should be equal to the number of rigid component. :param list frames: array of frames. The length of the array should be equal to the number of rigid component. The orientation are given in eulerAngles (in degree) by passing three values or using a quaternion by passing four values. [[rx,ry,rz], [qx,qy,qz,w]] User can also specify the position of the frame by passing six values (position and orientation in degree) or seven values (position and quaternion). [[x,y,z,rx,ry,rz], [x,y,z,qx,qy,qz,w]] If the position is not specified, the position of the rigids will be the barycenter of the region to rigidify. :param str name: specify the name of the Rigidified object, is none provided use the name of the SOurceObject. """ # Deprecation Warning if frameOrientation is not None: Sofa.msg_warning( "The parameter frameOrientations of the function Rigidify is now deprecated. Please use frames instead." ) frames = frameOrientation if frames is None: frames = [[0., 0., 0.]] * len(groupIndices) assert len(groupIndices) == len(frames), "size mismatch." if name is None: name = sourceObject.name sourceObject.init() ero = targetObject.createChild(name) allPositions = sourceObject.container.position allIndices = map(lambda x: x[0], sourceObject.container.points) rigids = [] indicesMap = [] def mfilter(si, ai, pts): tmp = [] for i in ai: if i in si: tmp.append(pts[i]) return tmp # get all the points from the source. sourcePoints = map(Vec3, sourceObject.dofs.position) selectedIndices = [] for i in range(len(groupIndices)): selectedPoints = mfilter(groupIndices[i], allIndices, sourcePoints) if len(frames[i]) == 3: orientation = Quat.createFromEuler(frames[i], inDegree=True) poscenter = getBarycenter(selectedPoints) elif len(frames[i]) == 4: orientation = frames[i] poscenter = getBarycenter(selectedPoints) elif len(frames[i]) == 6: orientation = Quat.createFromEuler( [frames[i][3], frames[i][4], frames[i][5]], inDegree=True) poscenter = [frames[i][0], frames[i][1], frames[i][2]] elif len(frames[i]) == 7: orientation = [ frames[i][3], frames[i][4], frames[i][5], frames[i][6] ] poscenter = [frames[i][0], frames[i][1], frames[i][2]] else: Sofa.msg_error("Do not understand the size of a frame.") rigids.append(poscenter + list(orientation)) selectedIndices += map(lambda x: x, groupIndices[i]) indicesMap += [i] * len(groupIndices[i]) otherIndices = filter(lambda x: x not in selectedIndices, allIndices) Kd = {v: None for k, v in enumerate(allIndices)} Kd.update({v: [0, k] for k, v in enumerate(otherIndices)}) Kd.update({v: [1, k] for k, v in enumerate(selectedIndices)}) indexPairs = [v for kv in Kd.values() for v in kv] freeParticules = ero.createChild("DeformableParts") freeParticules.createObject( "MechanicalObject", template="Vec3", name="dofs", position=[allPositions[i] for i in otherIndices]) rigidParts = ero.createChild("RigidParts") rigidParts.createObject("MechanicalObject", template="Rigid3", name="dofs", reserve=len(rigids), position=rigids) rigidifiedParticules = rigidParts.createChild("RigidifiedParticules") rigidifiedParticules.createObject( "MechanicalObject", template="Vec3", name="dofs", position=[allPositions[i] for i in selectedIndices]) rigidifiedParticules.createObject("RigidMapping", name="mapping", globalToLocalCoords='true', rigidIndexPerPoint=indicesMap) sourceObject.removeObject(sourceObject.solver) sourceObject.removeObject(sourceObject.integration) sourceObject.removeObject(sourceObject.LinearSolverConstraintCorrection) # The coupling is made with the sourceObject. If the source object is from an ElasticMaterialObject # We need to get the owning node form the current python object (this is a hack because of the not yet # Finalized design of stlib. coupling = sourceObject if hasattr(sourceObject, "node"): coupling = sourceObject.node coupling.createObject("SubsetMultiMapping", name="mapping", template="Vec3,Vec3", input=freeParticules.dofs.getLinkPath() + " " + rigidifiedParticules.dofs.getLinkPath(), output=sourceObject.dofs.getLinkPath(), indexPairs=indexPairs) rigidifiedParticules.addChild(coupling) freeParticules.addChild(coupling) return ero
def open(self, filename): self.modelDir = os.path.dirname(filename) with open(filename,'r') as f: # TODO automatic DTD validation could go here, not available in python builtin ElementTree module modelXml = etree.parse(f).getroot() if self.name is None and "name" in modelXml.attrib: self.name = modelXml.attrib["name"] else: self.name = os.path.basename(filename) # units self.parseUnits(modelXml) # meshes for m in modelXml.iter("mesh"): if not m.find("source") is None: if m.attrib["id"] in self.meshes: Sofa.msg_warning("SofaPython.sml","Model: mesh id {0} already defined".format(m.attrib["id"]) ) mesh = Model.Mesh(m) sourceFullPath = os.path.join(self.modelDir,mesh.source) if os.path.exists(sourceFullPath): mesh.source=sourceFullPath else: Sofa.msg_warning("SofaPython.sml","Model: mesh not found: "+mesh.source ) self.meshes[m.attrib["id"]] = mesh # images for m in modelXml.iter("image"): if not m.find("source") is None: if m.attrib["id"] in self.images: Sofa.msg_warning("SofaPython.sml","Model: image id {0} already defined".format(m.attrib["id"]) ) image = Model.Image(m) sourceFullPath = os.path.join(self.modelDir,image.source) if os.path.exists(sourceFullPath): image.source=sourceFullPath else: Sofa.msg_warning("SofaPython.sml","Model: image not found: "+image.source ) self.images[m.attrib["id"]] = image # solids for objXml in modelXml.findall("solid"): if objXml.attrib["id"] in self.solids: Sofa.msg_error("SofaPython.sml","Model: solid defined twice, id:" + objXml.attrib["id"]) continue solid=Model.Solid(objXml) self.parseMeshes(solid, objXml) self.parseImages(solid, objXml) self.solids[solid.id]=solid # skinning for objXml in modelXml.findall("solid"): solid=self.solids[objXml.attrib["id"]] # TODO: support multiple meshes for skinning (currently only the first mesh is skinned) for s in objXml.findall("skinning"): if not s.attrib["solid"] in self.solids: Sofa.msg_error("SofaPython.sml","Model: skinning for solid {0}: solid {1} is not defined".format(solid.name, s.attrib["solid"]) ) continue skinning = Model.Skinning() if not s.attrib["solid"] in self.solids : Sofa.msg_error("SofaPython.sml","Model: skinning for solid {0}: bone (solid) {1} not defined".format(solid.name, s.attrib["solid"]) ) continue skinning.solid = self.solids[s.attrib["solid"]] if not s.attrib["mesh"] in self.meshes : Sofa.msg_error("SofaPython.sml","Model: skinning for solid {0}: mesh {1} not defined".format(solid.name, s.attrib["mesh"]) ) continue skinning.mesh = self.meshes[s.attrib["mesh"]] #TODO: check that this mesh is also part of the solid if not (s.attrib["group"] in skinning.mesh.group and s.attrib["weight"] in skinning.mesh.group[s.attrib["group"]].data): Sofa.msg_error("SofaPython.sml","Model: skinning for solid {0}: mesh {1} - group {2} - weight {3} is not defined".format(solid.name, s.attrib["mesh"], s.attrib["group"], s.attrib["weight"])) continue skinning.index = skinning.mesh.group[s.attrib["group"]].index skinning.weight = skinning.mesh.group[s.attrib["group"]].data[s.attrib["weight"]] solid.skinnings.append(skinning) # joints self.parseJointGenerics(modelXml) # contacts for c in modelXml.findall("surfaceLink"): if c.attrib["id"] in self.surfaceLinks: Sofa.msg_error("SofaPython.sml","Model: surfaceLink defined twice, id:", c.attrib["id"]) continue surfaceLink = Model.SurfaceLink(c) surfaces=c.findall("surface") for i,s in enumerate(surfaces): surfaceLink.surfaces[i] = Model.Surface() if s.attrib["solid"] in self.solids: surfaceLink.surfaces[i].solid = self.solids[s.attrib["solid"]] else: Sofa.msg_error("SofaPython.sml","Model: in contact {0}, unknown solid {1} referenced".format(surfaceLink.name, s.attrib["solid"])) if s.attrib["mesh"] in self.meshes: surfaceLink.surfaces[i].mesh = self.meshes[s.attrib["mesh"]] else: Sofa.msg_error("SofaPython.sml","Model: in contact {0}, unknown mesh {1} referenced".format(surfaceLink.name, s.attrib["mesh"])) if "group" in s.attrib: # optional if len(s.attrib["group"]): # discard empty string surfaceLink.surfaces[i].group = s.attrib["group"] # if "image" in s.attrib: # optional # if len(s.attrib["image"]): # discard empty string # if s.attrib["image"] in self.images: # reg.surfaces[i].image = self.images[s.attrib["image"]] self.surfaceLinks[surfaceLink.id]=surfaceLink self.updateTag()
def processNode(parent, key, kv, stack, frame, doCreate=True): global templates, aliases stack.append(frame) populateFrame(key, frame, stack) if doCreate: if parent == None: tself = Sofa.createNode("undefined") else: tself = parent.createChild("undefined") frame["self"] = tself ### Force all the data field into a non-persistant state. for datafield in tself.getListOfDataFields(): datafield.setPersistant(False) for link in tself.getListOfLinks(): link.setPersistant(False) else: tself = frame["self"] = parent try: if isinstance(kv, list): for key, value in kv: sofaAliasInitialName = None if isinstance(key, unicode): key = str(key) if key in sofaAliases: sofaAliasInitialName = key key = sofaAliases[key] if key in aliases: key = aliases[key] if key == "Import": n = processImport(tself, key, value, stack, {}) elif key == "Node": n = processNode(tself, key, value, stack, {}) elif key == "Python": processPython(tself, key, value, stack, {}) elif key == "properties": processProperties(tself, key, value, stack, {}) elif key == "Template": tself.addObject( processTemplate(tself, key, value, stack, {})) elif key == "Using": processAlias(tself, key, value, stack, frame) elif key in sofaComponents: o = processObject(tself, key, value, stack, {}) if o != None: if isinstance(sofaAliasInitialName, str): Sofa.msg_warning( o, pslprefix + "'" + key + " was created using the hard coded alias '" + str(sofaAliasInitialName) + "'" + ". \nUsing hard coded aliases is a confusing practice and we advise you to use scene specific alias with the Alias keyword." ) elif key in templates: instanciateTemplate(tself, key, value, stack, frame) else: ## we are on a cache hit...so we refresh the list. refreshComponentListFromFactory() if key in sofaComponents: o = processObject(tself, key, value, stack, {}) if o != None: tself.addObject(o) processParameter(tself, key, value, stack, frame) else: raise Exception("This shouldn't happen, expecting only list") except Exception, e: s = SofaPython.getSofaFormattedStringFromException(e) Sofa.msg_error(tself, "Problem while loading file. <br>" + s)
def open(self, filename): self.modelDir = os.path.dirname(filename) with open(filename, 'r') as f: # TODO automatic DTD validation could go here, not available in python builtin ElementTree module modelXml = etree.parse(f).getroot() if self.name is None and "name" in modelXml.attrib: self.name = modelXml.attrib["name"] else: self.name = os.path.basename(filename) # units self.parseUnits(modelXml) # meshes for m in modelXml.iter("mesh"): if not m.find("source") is None: if m.attrib["id"] in self.meshes: Sofa.msg_warning( "SofaPython.sml", "Model: mesh id {0} already defined".format( m.attrib["id"])) mesh = Model.Mesh(m) sourceFullPath = os.path.join(self.modelDir, mesh.source) if os.path.exists(sourceFullPath): mesh.source = sourceFullPath else: Sofa.msg_warning( "SofaPython.sml", "Model: mesh not found: " + mesh.source) self.meshes[m.attrib["id"]] = mesh # images for m in modelXml.iter("image"): if not m.find("source") is None: if m.attrib["id"] in self.images: Sofa.msg_warning( "SofaPython.sml", "Model: image id {0} already defined".format( m.attrib["id"])) image = Model.Image(m) sourceFullPath = os.path.join(self.modelDir, image.source) if os.path.exists(sourceFullPath): image.source = sourceFullPath else: Sofa.msg_warning( "SofaPython.sml", "Model: image not found: " + image.source) self.images[m.attrib["id"]] = image # solids for objXml in modelXml.findall("solid"): if objXml.attrib["id"] in self.solids: Sofa.msg_error( "SofaPython.sml", "Model: solid defined twice, id:" + objXml.attrib["id"]) continue solid = Model.Solid(objXml) self.parseMeshes(solid, objXml) self.parseImages(solid, objXml) self.solids[solid.id] = solid # skinning for objXml in modelXml.findall("solid"): solid = self.solids[objXml.attrib["id"]] # TODO: support multiple meshes for skinning (currently only the first mesh is skinned) for s in objXml.findall("skinning"): if not s.attrib["solid"] in self.solids: Sofa.msg_error( "SofaPython.sml", "Model: skinning for solid {0}: solid {1} is not defined" .format(solid.name, s.attrib["solid"])) continue skinning = Model.Skinning() if not s.attrib["solid"] in self.solids: Sofa.msg_error( "SofaPython.sml", "Model: skinning for solid {0}: bone (solid) {1} not defined" .format(solid.name, s.attrib["solid"])) continue skinning.solid = self.solids[s.attrib["solid"]] if not s.attrib["mesh"] in self.meshes: Sofa.msg_error( "SofaPython.sml", "Model: skinning for solid {0}: mesh {1} not defined" .format(solid.name, s.attrib["mesh"])) continue skinning.mesh = self.meshes[s.attrib["mesh"]] #TODO: check that this mesh is also part of the solid if not (s.attrib["group"] in skinning.mesh.group and s.attrib["weight"] in skinning.mesh.group[s.attrib["group"]].data): Sofa.msg_error( "SofaPython.sml", "Model: skinning for solid {0}: mesh {1} - group {2} - weight {3} is not defined" .format(solid.name, s.attrib["mesh"], s.attrib["group"], s.attrib["weight"])) continue skinning.index = skinning.mesh.group[ s.attrib["group"]].index skinning.weight = skinning.mesh.group[ s.attrib["group"]].data[s.attrib["weight"]] solid.skinnings.append(skinning) # joints self.parseJointGenerics(modelXml) # contacts for c in modelXml.findall("surfaceLink"): if c.attrib["id"] in self.surfaceLinks: Sofa.msg_error("SofaPython.sml", "Model: surfaceLink defined twice, id:", c.attrib["id"]) continue surfaceLink = Model.SurfaceLink(c) surfaces = c.findall("surface") for i, s in enumerate(surfaces): surfaceLink.surfaces[i] = Model.Surface() if s.attrib["solid"] in self.solids: surfaceLink.surfaces[i].solid = self.solids[ s.attrib["solid"]] else: Sofa.msg_error( "SofaPython.sml", "Model: in contact {0}, unknown solid {1} referenced" .format(surfaceLink.name, s.attrib["solid"])) if s.attrib["mesh"] in self.meshes: surfaceLink.surfaces[i].mesh = self.meshes[ s.attrib["mesh"]] else: Sofa.msg_error( "SofaPython.sml", "Model: in contact {0}, unknown mesh {1} referenced" .format(surfaceLink.name, s.attrib["mesh"])) if "group" in s.attrib: # optional if len(s.attrib["group"]): # discard empty string surfaceLink.surfaces[i].group = s.attrib["group"] #if "image" in s.attrib: # optional # if len(s.attrib["image"]): # discard empty string # if s.attrib["image"] in self.images: # reg.surfaces[i].image = self.images[s.attrib["image"]] self.surfaceLinks[surfaceLink.id] = surfaceLink
def processNode(parent, key, kv, stack, frame, doCreate=True): global templates, aliases stack.append(frame) populateFrame(key, frame, stack) if doCreate: if parent == None: tself = Sofa.createNode("undefined") else: tself = parent.createChild("undefined") frame["self"] = tself ### Force all the data field into a non-persistant state. for datafield in tself.getListOfDataFields(): datafield.setPersistant(False) for link in tself.getListOfLinks(): link.setPersistant(False) else: tself = frame["self"] = parent try: if isinstance(kv, list): for key,value in kv: sofaAliasInitialName = None if isinstance(key, unicode): key = str(key) if key in sofaAliases: sofaAliasInitialName = key key = sofaAliases[key] if key in aliases: key = aliases[key] if key == "Import": n = processImport(tself, key, value, stack, {}) elif key == "Node": n = processNode(tself, key, value, stack, {}) elif key == "Python": processPython(tself, key, value, stack, {}) elif key == "properties": processProperties(tself, key, value, stack, {}) elif key == "Template": tself.addObject( processTemplate(tself, key, value, stack, {}) ) elif key == "Using": processAlias(tself, key,value, stack, frame) elif key in sofaComponents: o = processObject(tself, key, value, stack, {}) if o != None: if isinstance(sofaAliasInitialName, str): Sofa.msg_warning(o, pslprefix+"'"+key+" was created using the hard coded alias '"+str(sofaAliasInitialName)+"'"+". \nUsing hard coded aliases is a confusing practice and we advise you to use scene specific alias with the Alias keyword.") elif key in templates: instanciateTemplate(tself, key,value, stack, frame) else: ## we are on a cache hit...so we refresh the list. refreshComponentListFromFactory() if key in sofaComponents: o = processObject(tself, key, value, stack, {}) if o != None: tself.addObject(o) processParameter(tself, key, value, stack, frame) else: raise Exception("This shouldn't happen, expecting only list") except Exception,e: s=SofaPython.getSofaFormattedStringFromException(e) Sofa.msg_error(tself, "Problem while loading file. <br>"+s)
def log_warning(*args): Sofa.msg_warning("Compliant.sml", ' '.join(args))
def insertRigid(parentNode, rigidModel, density, scale=1, param=None): """ create a StructuralAPI.RigidBody from the rigidModel. The model geometry is scaled with scale. The rigidMass is computed from: 1) mass, com and inertia if present 2) mesh if possible 3) default to a unit sphere TODO: is it relevant to do so ? """ if printLog: Sofa.msg_info("Compliant.sml","insertRigid "+rigidModel.name) for mesh in rigidModel.mesh : if rigidModel.meshAttributes[mesh.id].collision is True: Sofa.msg_info("Compliant.sml"," collision mesh: "+mesh.name) rigid = StructuralAPI.RigidBody(parentNode, rigidModel.name) if not rigidModel.mass is None and not rigidModel.com is None and not rigidModel.inertia is None: if not 1==scale: Sofa.msg_info("Compliant.sml","scale is not supported in that case") # all inertial data is present, let's use it massinfo = SofaPython.mass.RigidMassInfo() massinfo.mass = rigidModel.mass # TODO: convert units ? massinfo.com = rigidModel.com # TODO: convert units ? if len(rigidModel.inertia)==3 and not rigidModel.inertia_rotation is None: massinfo.diagonal_inertia = rigidModel.inertia massinfo.inertia_rotation = rigidModel.inertia_rotation else: massinfo.setFromInertia(rigidModel.inertia[0], rigidModel.inertia[1], rigidModel.inertia[2], # Ixx, Ixy, Ixz rigidModel.inertia[3], rigidModel.inertia[4], # Iyy, Iyz rigidModel.inertia[5] ) # Izz rigid.setFromRigidInfo(massinfo, offset=rigidModel.position, inertia_forces = False ) # TODO: handle inertia_forces ? elif len(rigidModel.mesh)!=0 : # get inertia from meshes and density rigid.setFromRigidInfo(rigidModel.getRigidMassInfo(density, scale), offset=StructuralAPI.scaleOffset(scale, rigidModel.position), inertia_forces = False ) # TODO: handle inertia_forces ? #if not rigidModel.mass is None : ## no density but a mesh let's normalise computed mass with specified mass #mass= SofaPython.units.mass_from_SI(rigidModel.mass) #inertia = [] #for inert,m in zip(rigid.mass.inertia, rigid.mass.mass): #for i in inert: #inertia.append( i/m[0]*mass) #rigid.mass.inertia = concat(inertia) #rigid.mass.mass = mass else: # no mesh, get mass/inertia if present, default to a unit sphere Sofa.msg_warning("Compliant.sml","insertRigid: using default rigidMass") mass = rigidModel.mass if not rigidModel.mass is None else SofaPython.units.mass_from_SI(1.) inertia = scale*scale*[1,1,1] t = scale*rigidModel.position if not rigidModel.com is None: t[0] += scale*rigidModel.com[0] t[1] += scale*rigidModel.com[1] t[2] += scale*rigidModel.com[2] rigid.setManually(t, mass, inertia) if not param is None: rigid.dofs.showObject = param.showRigid rigid.dofs.showObjectScale = SofaPython.units.length_from_SI(param.showRigidScale) # walk around to handle multiple meshes # @todo: handle them in StructuralAPI ? rigid.collisions=dict() rigid.visuals=dict() for mesh in rigidModel.mesh : if rigidModel.meshAttributes[mesh.id].collision is True: rigid.collisions[mesh.id] = rigid.addCollisionMesh(mesh.source,name_suffix='_'+mesh.name, scale3d=[scale]*3) if rigidModel.meshAttributes[mesh.id].visual is True: rigid.visuals[mesh.id] = rigid.collisions[mesh.id].addVisualModel() elif rigidModel.meshAttributes[mesh.id].visual is True: rigid.visuals[mesh.id] = rigid.addVisualModel(mesh.source,name_suffix='_'+mesh.name, scale3d=[scale]*3) return rigid
def symmetrize(self,plane_center,plane_normal): Sofa.msg_warning('SofaPython.sml','JointGeneric.symmetrize is not yet implemented')
def _setMeshDirectory(self, path, mesh): if not mesh.source is None: mesh.source = os.path.join(path, os.path.basename(mesh.source)) if not os.path.exists(mesh.source): Sofa.msg_warning("SofaPython.sml","Model: mesh not found: "+mesh.source)