def objectSet(self, dataID, setIndex, autoCreate=True): """Get an object set identified with setIndex at the given dataId :param dataID: id identifying the storage plug on this node :param setIndex: logical index at which the set will be connected to our message plug array :param autoCreate: if True, a set will be created if it does not yet exist :raises ValueError: if a set does not exist at setIndex and autoCreate is False :raises AttributeError: if the plug did not exist ( and autocreate is False ) :note: method is implicitly undoable if autoCreate is True, this also means that you cannot explicitly undo this operation as you do not know if undo has been queued or not :note: newly created sets will automatically use partitions if one of the sets does""" mp = self.storagePlug(dataID, self.kMessage, autoCreate=autoCreate) # array plug having our sets setplug = mp.elementByLogicalIndex(setIndex) inputplug = setplug.minput() if inputplug.isNull(): if not autoCreate: raise AttributeError( "Set at %s[%i] did not exist on %r" % (self._attrprefix + dataID, setIndex, self)) su = undo.StartUndo() # make the following operations atomic objset = createNode(dataID + "Set", "objectSet", forceNewLeaf=True) inputplug = objset.message inputplug.mconnectTo(setplug) # hook it up to the partition if self.partition(dataID): self.setPartition(dataID, True) # END create set as needed # return actual object set return inputplug.mwrappedNode()
def setPartition( self, dataID, state ): """Make all sets in dataID use a partition or not :param dataID: id identifying the storage plug :param state: if True, a partition will be used, if False, it will be disabled :note: this method makes sure that all sets are hooked up to the partition :raise ValueError: If we did not have a single set to which to add to the partition :raise AttributeError: If the dataID has never had sets :return: if state is True, the name of the possibly created ( or existing ) partition""" sets = self.setsByID( dataID ) partition = self.partition( dataID ) if state: if partition is None: if not sets: raise ValueError("Cannot create partition as data %r did not have any connected sets" % dataID) # END check sets exist # create partition partition = createNode( "storagePartition", "partition", forceNewLeaf=True ) tattr = api.MFnTypedAttribute( ) attr = tattr.create( self._partitionIdAttr, "pid", api.MFnData.kString ) partition.addAttribute( attr ) # END create partition # make sure all sets are members of our partition partition.addSets( sets ) return partition else: if partition: # delete partition # have to clear partition as, for some reason, or own node will be killed as well ! partition.clear() delete( partition )
def objectSet( self, dataID, setIndex, autoCreate = True ): """Get an object set identified with setIndex at the given dataId :param dataID: id identifying the storage plug on this node :param setIndex: logical index at which the set will be connected to our message plug array :param autoCreate: if True, a set will be created if it does not yet exist :raises ValueError: if a set does not exist at setIndex and autoCreate is False :raises AttributeError: if the plug did not exist ( and autocreate is False ) :note: method is implicitly undoable if autoCreate is True, this also means that you cannot explicitly undo this operation as you do not know if undo has been queued or not :note: newly created sets will automatically use partitions if one of the sets does""" mp = self.storagePlug( dataID, self.kMessage, autoCreate = autoCreate ) # array plug having our sets setplug = mp.elementByLogicalIndex( setIndex ) inputplug = setplug.minput() if inputplug.isNull(): if not autoCreate: raise AttributeError( "Set at %s[%i] did not exist on %r" % ( self._attrprefix + dataID, setIndex, self ) ) su = undo.StartUndo() # make the following operations atomic objset = createNode( dataID + "Set", "objectSet", forceNewLeaf = True ) inputplug = objset.message inputplug.mconnectTo(setplug) # hook it up to the partition if self.partition( dataID ): self.setPartition( dataID, True ) # END create set as needed # return actual object set return inputplug.mwrappedNode()
def setPartition(mdplug, state): """Make all sets of the given data message plug use a partition or not :param state: if True, a partition will be used, if False, it will be disabled :note: this method makes sure that all sets are hooked up to the partition :raise ValueError: If we did not have a single set to which to add to the partition :raise AttributeError: If the dataID has never had sets :return: if state is True, the name of the possibly created (or existing) partition""" sets = setsByPlug(mdplug) pt = partition(mdplug) if state: if pt is None: if not sets: raise ValueError("Cannot create partition as plug %s did not have any connected sets" % mdplug) # END check sets exist # create partition pt = createNode("storagePartition", "partition", forceNewLeaf=True) tattr = api.MFnTypedAttribute() attr = tattr.create(StorageBase.kPartitionIdAttr, "pid", api.MFnData.kString) pt.addAttribute(attr) # END create partition # make sure all sets are members of our partition pt.addSets(sets) return pt else: if pt: # delete partition # have to clear partition as, for some reason, or own node will be killed as well ! pt.clear() delete(pt)
def objectSet(mdplug, setIndex, autoCreate=True, setPrefix=''): """Get an object set identified with setIndex at the given dataId :param mdplug: data message plug whose object set to handle :param setIndex: logical index at which the set will be connected to our message plug array :param autoCreate: if True, a set will be created if it does not yet exist :param setPrefix: if given, the string will be used as prefix for the name of newly created object sets :raises ValueError: if a set does not exist at setIndex and autoCreate is False :raises AttributeError: if the plug did not exist (and autocreate is False) :note: method is implicitly undoable if autoCreate is True, this also means that you cannot explicitly undo this operation as you do not know if undo has been queued or not :note: newly created sets will automatically use partitions if one of the sets does""" mp = mdplug # array plug having our sets setplug = mp.elementByLogicalIndex(setIndex) inputplug = setplug.minput() if inputplug.isNull(): if not autoCreate: raise AttributeError("Set at %s[%i] did not exist" % (mp.name(), setIndex)) su = undo.StartUndo() # make the following operations atomic objset = createNode(setPrefix + "Set", "objectSet", forceNewLeaf = True) inputplug = objset.message inputplug.mconnectTo(setplug) # hook it up to the partition if partition(mdplug): setPartition(mdplug, True) # END create set as needed # return actual object set return inputplug.mwrappedNode()
def setPartition(self, dataID, state): """Make all sets in dataID use a partition or not :param dataID: id identifying the storage plug :param state: if True, a partition will be used, if False, it will be disabled :note: this method makes sure that all sets are hooked up to the partition :raise ValueError: If we did not have a single set to which to add to the partition :raise AttributeError: If the dataID has never had sets :return: if state is True, the name of the possibly created ( or existing ) partition""" sets = self.setsByID(dataID) partition = self.partition(dataID) if state: if partition is None: if not sets: raise ValueError( "Cannot create partition as data %r did not have any connected sets" % dataID) # END check sets exist # create partition partition = createNode("storagePartition", "partition", forceNewLeaf=True) tattr = api.MFnTypedAttribute() attr = tattr.create(self._partitionIdAttr, "pid", api.MFnData.kString) partition.addAttribute(attr) # END create partition # make sure all sets are members of our partition partition.addSets(sets) return partition else: if partition: # delete partition # have to clear partition as, for some reason, or own node will be killed as well ! partition.clear() delete(partition)
def resetTweaks(self, tweak_type=eComponentType.vertex, keep_tweak_result=False): """Reset the tweaks on the given mesh shape :param tweak_type: the component type(s) whose tweaks are to be removed, valid values are 'vertex' and 'uv' members of the eComponentType enumeration. Pass in a scalar value or a list of tweak types :param keep_tweak_result: if True, the effect of the tweak will be kept. If False, it will be removed. What actually happens depends on the context * [referenced] mesh *without* history: copy outMesh to inMesh, resetTweaks if referenced, plenty of reference edits are generated, ideally one operates on non-referenced geomtry * [referenced] mesh *with* history: put tweakNode into mesh history, copy tweaks onto tweak node :note: currently vertex and uv tweaks will be removed if keep is enabled, thus they must both be specified""" check_types = (isinstance(tweak_type, (list, tuple)) and tweak_type) or [tweak_type] type_map = { self.eComponentType.vertex: ("pnts", api.MFnNumericData.k3Float, "polyTweak", api.MFn.kPolyTweak, "tweak"), self.eComponentType.uv: ("uvpt", api.MFnNumericData.k2Float, "polyTweakUV", api.MFn.kPolyTweakUV, "uvTweak") } mia = api.MIntArray() for reset_this_type in check_types: try: attrname, datatype, tweak_node_type, tweak_node_type_API, tweakattr = type_map[ reset_this_type] except KeyError: raise ValueError("Tweak type %s is not supported" % reset_this_type) # KEEP MODE ############# if keep_tweak_result: input_plug = self.inMesh.minput() # history check if input_plug.isNull(): # assert as we had to make the handling much more complex to allow this to work right as we copy the whole mesh here # containing all tweaks , not only one type if not (self.eComponentType.vertex in check_types and self.eComponentType.uv in check_types): log.warn( "Currently vertex AND uv tweaks will be removed if a mesh has no history and a reset is requested" ) # END print warning # take the output mesh, and stuff it into the input, then proceed # with the reset. This implies that all tweaks have to be removed out_mesh = self.outMesh.asMObject() self.inMesh.msetMObject(out_mesh) self.cachedInMesh.msetMObject(out_mesh) # finally reset all tweeaks return self.resetTweaks(check_types, keep_tweak_result=False) else: # create node of valid type tweak_node = input_plug.mwrappedNode() # create node if there is none as direct input if not tweak_node.hasFn(tweak_node_type_API): tweak_node = base.createNode("polyTweak", tweak_node_type, forceNewLeaf=1) # hook the node into the history input_plug.mconnectTo(tweak_node.inputPolymesh) tweak_node.output.mconnectTo(self.inMesh) # setup uvset tweak location to tell uvset where to get tweaks from if tweak_node_type_API == api.MFn.kPolyTweakUV: names = list() self.getUVSetNames(names) index = names.index(self.currentUVSetName()) own_tweak_location_plug = self.uvSet.elementByLogicalIndex( index).mchildByName('uvSetTweakLocation') tweak_node.uvTweak.elementByLogicalIndex( index).mconnectTo(own_tweak_location_plug) # END uv special setup # END create tweak node dtweak_plug = tweak_node.findPlug(tweakattr) stweak_plug = self.findPlug(attrname) # copy the tweak values - iterate manually as the plug tends to # report incorrect values if history is present - its odd stweak_plug.evaluateNumElements() mia.clear() stweak_plug.getExistingArrayAttributeIndices(mia) for i in mia: try: tplug = stweak_plug.elementByLogicalIndex(i) except RuntimeError: continue else: dtweak_plug.elementByLogicalIndex(i).msetMObject( tplug.asMObject()) # END exception handling # END for each tweak plug # proceed with reset of tweaks pass # END history handling # END keep tweak result handling arrayplug = self.findPlug(attrname) dataobj = api.MFnNumericData().create(datatype) # reset values, do it for all components at once using a data object try: for p in arrayplug: p.msetMObject(dataobj) except RuntimeError: # especially uvtweak array plugs return incorrect lengths, thus we may # fail once we reach the end of the iteration. # uvpt appears to display a lenght equalling the number of uvpoints in the mesh # possibly only for the current uvset pass
def resetTweaks( self, tweak_type = eComponentType.vertex, keep_tweak_result = False ): """Reset the tweaks on the given mesh shape :param tweak_type: the component type(s) whose tweaks are to be removed, valid values are 'vertex' and 'uv' members of the eComponentType enumeration. Pass in a scalar value or a list of tweak types :param keep_tweak_result: if True, the effect of the tweak will be kept. If False, it will be removed. What actually happens depends on the context * [referenced] mesh *without* history: copy outMesh to inMesh, resetTweaks if referenced, plenty of reference edits are generated, ideally one operates on non-referenced geomtry * [referenced] mesh *with* history: put tweakNode into mesh history, copy tweaks onto tweak node :note: currently vertex and uv tweaks will be removed if keep is enabled, thus they must both be specified""" check_types = ( isinstance( tweak_type, ( list, tuple ) ) and tweak_type ) or [ tweak_type ] type_map = { self.eComponentType.vertex : ( "pnts", api.MFnNumericData.k3Float, "polyTweak", api.MFn.kPolyTweak, "tweak" ), self.eComponentType.uv : ( "uvpt", api.MFnNumericData.k2Float, "polyTweakUV", api.MFn.kPolyTweakUV, "uvTweak" ) } mia = api.MIntArray() for reset_this_type in check_types: try: attrname, datatype, tweak_node_type, tweak_node_type_API, tweakattr = type_map[ reset_this_type ] except KeyError: raise ValueError( "Tweak type %s is not supported" % reset_this_type ) # KEEP MODE ############# if keep_tweak_result: input_plug = self.inMesh.minput() # history check if input_plug.isNull(): # assert as we had to make the handling much more complex to allow this to work right as we copy the whole mesh here # containing all tweaks , not only one type if not ( self.eComponentType.vertex in check_types and self.eComponentType.uv in check_types ): log.warn("Currently vertex AND uv tweaks will be removed if a mesh has no history and a reset is requested") # END print warning # take the output mesh, and stuff it into the input, then proceed # with the reset. This implies that all tweaks have to be removed out_mesh = self.outMesh.asMObject() self.inMesh.msetMObject( out_mesh ) self.cachedInMesh.msetMObject( out_mesh ) # finally reset all tweeaks return self.resetTweaks( check_types, keep_tweak_result = False ) else: # create node of valid type tweak_node = input_plug.mwrappedNode() # create node if there is none as direct input if not tweak_node.hasFn( tweak_node_type_API ): tweak_node = base.createNode( "polyTweak", tweak_node_type, forceNewLeaf = 1 ) # hook the node into the history input_plug.mconnectTo(tweak_node.inputPolymesh) tweak_node.output.mconnectTo(self.inMesh) # setup uvset tweak location to tell uvset where to get tweaks from if tweak_node_type_API == api.MFn.kPolyTweakUV: names = list() self.getUVSetNames( names ) index = names.index( self.currentUVSetName( ) ) own_tweak_location_plug = self.uvSet.elementByLogicalIndex( index ).mchildByName('uvSetTweakLocation') tweak_node.uvTweak.elementByLogicalIndex( index ).mconnectTo(own_tweak_location_plug) # END uv special setup # END create tweak node dtweak_plug = tweak_node.findPlug(tweakattr) stweak_plug = self.findPlug(attrname) # copy the tweak values - iterate manually as the plug tends to # report incorrect values if history is present - its odd stweak_plug.evaluateNumElements() mia.clear() stweak_plug.getExistingArrayAttributeIndices(mia) for i in mia: try: tplug = stweak_plug.elementByLogicalIndex(i) except RuntimeError: continue else: dtweak_plug.elementByLogicalIndex(i).msetMObject(tplug.asMObject()) # END exception handling # END for each tweak plug # proceed with reset of tweaks pass # END history handling # END keep tweak result handling arrayplug = self.findPlug(attrname) dataobj = api.MFnNumericData().create( datatype ) # reset values, do it for all components at once using a data object try: for p in arrayplug: p.msetMObject( dataobj ) except RuntimeError: # especially uvtweak array plugs return incorrect lengths, thus we may # fail once we reach the end of the iteration. # uvpt appears to display a lenght equalling the number of uvpoints in the mesh # possibly only for the current uvset pass