def set_connection_offsets(connection_data): '''applies offset positions to the input dictionary input > [{'source':string, 'target':string, 'setPosition':bool, 'setRotation':bool}...] output > [{'source':string, 'target':string, 'setPosition':bool, 'setRotation':bool, 'offsetPosition':(3), 'offsetForward':(3), 'offsetUp':(3)}...]''' for i, connection in enumerate(connection_data): source_pos = POS.get(connection['source'], asEuclid=True) target_pos = POS.get(connection['target'], asEuclid=True) v = target_pos - source_pos connection['positionOffset'] = [v.x, v.y, v.z] v = TRANS.transformInverseDirection( connection['source'], TRANS.transformDirection(connection['target'], euclid.Vector3(0, 0, 1))) connection['offsetForward'] = [v.x, v.y, v.z] v = TRANS.transformInverseDirection( connection['source'], TRANS.transformDirection(connection['target'], euclid.Vector3(0, 1, 0))) connection['offsetUp'] = [v.x, v.y, v.z]
def get_bb_size(arg=None, shapes=False, mode=None, asEuclid=False): """ Get the bb size of a given arg :parameters: arg(str/list): Object(s) to check shapes(bool): Only check dag node shapes mode(varied): True/'max': Only return max value 'min': Only min maxFill - [max,max.max] :returns boundingBox size(list) """ _str_func = 'get_bb_size' #_arg = VALID.stringListArg(arg,False,_str_func) arg = VALID.mNodeString(arg) if shapes: log.debug("|{0}| >> shapes mode ".format(_str_func)) arg = VALID.listArg(arg) l_use = [] for o in arg: log.debug("|{0}| >> o: '{1}' ".format(_str_func, o)) l_shapes = mc.listRelatives(o, s=True, fullPath=True) or [] if l_shapes: l_use.extend(l_shapes) else: l_use.append(o) arg = l_use log.debug("|{0}| >> arg: '{1}' ".format(_str_func, arg)) _box = mc.exactWorldBoundingBox(arg) if mode == 'raw': if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_box[0], _box[1], _box[2]) return _box _res = [(_box[3] - _box[0]), (_box[4] - _box[1]), (_box[5] - _box[2])] if mode is None: if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res elif mode in [True, 'max']: return max(_res) elif mode in ['min']: return min(_res) elif mode == 'maxFill': _max = max(_res) return [_max, _max, _max] else: log.error("|{0}| >> Unknown mode. Returning default. {1} ".format( _str_func, mode)) return _res
def get_planeIntersect(planeSource=None, target=None, planeAxis='z+', objAxis='z+', mark=False): _str_func = 'get_planeIntersect' if target: mTarget = cgmMeta.asMeta(target) else: mTarget = cgmMeta.asMeta(mc.ls(sl=1)) if not mTarget: return log.error(cgmGEN.logString_msg(_str_func, 'No Target')) mTarget = mTarget[0] mObj = cgmMeta.asMeta(planeSource) planePoint = VALID.euclidVector3Arg(mObj.p_position) planeNormal = VALID.euclidVector3Arg(mObj.getAxisVector(planeAxis)) rayPoint = VALID.euclidVector3Arg(mTarget.p_position) rayDirection = VALID.euclidVector3Arg(mTarget.getAxisVector(objAxis)) plane = EUCLID.Plane( EUCLID.Point3(planePoint.x, planePoint.y, planePoint.z), EUCLID.Point3(planeNormal.x, planeNormal.y, planeNormal.z)) pos = plane.intersect( EUCLID.Line3( EUCLID.Point3(rayPoint.x, rayPoint.y, rayPoint.z), EUCLID.Vector3(rayDirection.x, rayDirection.y, rayDirection.z))) if mark: LOC.create(position=pos, name='pewpew_planeIntersect') return pos
def get_uv_normal(mesh, uvValue, asEuclid=False): """ Get a normal at a uv :parameters: mesh(string) | Surface uv resides on uValue(float) | uValue vValue(float) | vValue asEuclid(bool) - whether to return as Vector or not :returns pos(double3) """ _str_func = 'get_uv_position' _follicle = NODE.add_follicle(mesh) ATTR.set(_follicle[0], 'parameterU', uvValue[0]) ATTR.set(_follicle[0], 'parameterV', uvValue[1]) _normal = ATTR.get(_follicle[0], 'outNormal') mc.delete(_follicle) if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_normal[0], _normal[1], _normal[2]) return _normal
def transformInversePoint(node=None, v=None): """ Get local position of vector transformed from world space of Transform :parameters: node(str): Object to check v(d3): vector :returns new value(Vector3) """ _str_func = 'transformInversePoint' _node = VALID.mNodeString(node) v = euclidVector3Arg(v) log.debug("|{0}| >> node: [{1}] | {2}".format(_str_func, _node, v)) current_matrix = worldMatrix_get(_node, True) s = scaleLocal_get(_node, True) transform_matrix = EUCLID.Matrix4() transform_matrix.m = v.x transform_matrix.n = v.y transform_matrix.o = v.z scale_matrix = EUCLID.Matrix4() scale_matrix.a = s.x scale_matrix.f = s.y scale_matrix.k = s.z scale_matrix.p = 1 result_matrix = transform_matrix * current_matrix.inverse() * scale_matrix return EUCLID.Vector3(result_matrix.m, result_matrix.n, result_matrix.o)
def get_uv_position(mesh, uvValue, asEuclid=False): """ Get a uv position in world space. UV should be normalized. :parameters: mesh(string) | Surface uv resides on uValue(float) | uValue vValue(float) | vValue asEuclid(bool) - whether to return as Vector or not :returns pos(double3) """ _str_func = 'get_uv_position' _follicle = NODE.add_follicle(mesh) ATTR.set(_follicle[0], 'parameterU', uvValue[0]) ATTR.set(_follicle[0], 'parameterV', uvValue[1]) _pos = get(_follicle[1]) mc.delete(_follicle) if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_pos[0], _pos[1], _pos[2]) return _pos
def euclidVector3Arg(arg): _str_func = 'euclidVector3Arg' if not issubclass(type(arg), EUCLID.Vector3): if VALID.isListArg(arg) and len(arg) == 3: return EUCLID.Vector3(float(arg[0]), float(arg[1]), float(arg[2])) else: raise ValueError, "|{0}| >> arg: {1}".format(_str_func, arg) return arg
def storeTransformData(self, obj=None): if obj is None: obj = self.obj ct = mc.currentTime(q=True) self._prevDataDict = {} mc.refresh(su=True) for i in range(int(ct), int(mc.playbackOptions(q=True, max=True)) + 1): mc.currentTime(i) self._prevDataDict[i] = { 'p': obj.p_position, 'f': obj.getTransformDirection(EUCLID.Vector3(0, 0, 1)), 'u': obj.getTransformDirection(EUCLID.Vector3(0, 1, 0)) } mc.refresh(su=False) mc.currentTime(ct)
def euclidVector3(arg): """ Simple check to see if an arg is EULER.Vector3 arg """ try: [arg.x, arg.y, arg.z] return arg except: try: return EUCLID.Vector3(arg) except Exception, err: raise Exception, err
def bake(connection_data, start, end): bake_range = range( int(math.floor(start)), int(math.floor(end+1))) if end < start: bake_range = range(int(math.floor(end)),int(math.floor(start+1))) bake_range.reverse() for i in bake_range: mc.currentTime(i) for conn in connection_data: source_pos = POS.get(conn['source']) if conn['setPosition']: positionOffset = euclid.Vector3(0,0,0) if 'positionOffset' in conn: pos = conn['positionOffset'] positionOffset = euclid.Vector3(pos[0], pos[1], pos[2]) wanted_position = source_pos + positionOffset POS.set(conn['target'], [wanted_position.x, wanted_position.y, wanted_position.z]) mc.setKeyframe('%s.translate' % conn['target']) target_pos = POS.get(conn['target']) if conn['setRotation']: offsetForward = euclid.Vector3(0,0,1) if 'offsetForward' in conn: fwd = conn['offsetForward'] offsetForward = euclid.Vector3(fwd[0], fwd[1], fwd[2]) offsetUp = euclid.Vector3(0,1,0) if 'offsetUp' in conn: up = conn['offsetUp'] offsetUp = euclid.Vector3(up[0], up[1], up[2]) fwd = TRANS.transformDirection(conn['source'], offsetForward) up = TRANS.transformDirection(conn['source'], offsetUp) SNAP.aim_atPoint(conn['target'], target_pos + fwd, vectorUp=up, mode='matrix') mc.setKeyframe('%s.rotate' % conn['target'])
def projectOntoPlane(self, vector): _str_func = 'LiveRecord.projectOntoPlane' camPos = VALID.euclidVector3Arg(self.cam.p_position) planeNormal = self.planeNormal if self.plane in ['custom', 'object']: planeNormal = VALID.euclidVector3Arg( self._currentPlaneObject.getTransformDirection( self.planeNormal)) log.info('Current plane object : {0}'.format(self._currentPlaneObject)) self.planePoint = VALID.euclidVector3Arg( self._currentPlaneObject.p_position) rayPoint = VALID.euclidVector3Arg(self.cam.p_position) rayDirection = VALID.euclidVector3Arg(vector) plane = EUCLID.Plane( EUCLID.Point3(self.planePoint.x, self.planePoint.y, self.planePoint.z), EUCLID.Point3(planeNormal.x, planeNormal.y, planeNormal.z)) pos = plane.intersect( EUCLID.Line3( EUCLID.Point3(rayPoint.x, rayPoint.y, rayPoint.z), EUCLID.Vector3(rayDirection.x, rayDirection.y, rayDirection.z))) if self._debugPlane: self._debugPlane.p_position = self.planePoint SNAP.aim_atPoint(obj=self._debugPlane.mNode, mode='matrix', position=self.planePoint + planeNormal, aimAxis='y+', upAxis='z+', vectorUp=planeNormal.cross( EUCLID.Vector3(0, 1, .01))) return pos
def scaleLocal_get(node=None, asEuclid=False): """ Query the local scale of a given obj :parameters: node(str): node to query asEuclid(bool): whether to return a EUCLID.Vector3 :returns rotation(vector/asEuclid.Vector3) """ _str_func = 'scaleLocal_get' node = VALID.mNodeString(node) _res = ATTR.get(node, 'scale') log.debug("|{0}| >> [{2}] = {1}".format(_str_func, _res, node)) if asEuclid: return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res
def orientObject_get(node=None, asEuclid=False): """ Query the local rotation/euler of a given obj :parameters: node(str): node to query asEuclid(bool): whether to return a EUCLID.Vector3 :returns rotation(vector/asEuclid.Vector3) """ _str_func = 'orient_get' node = VALID.mNodeString(node) _res = mc.xform(node, q=True, os=True, ro=True) log.debug("|{0}| >> [{2}] = {1}".format(_str_func, _res, node)) if asEuclid: return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res
def scalePivot_get(node=None, asEuclid=False): """ Query the world space rotatePivot of a given node :parameters: node(str): node to query asEuclid(bool): whether to return a EUCLID.Vector3 :returns rotation(vector/asEuclid.Vector3) """ _str_func = 'scalePivot_get' node = VALID.mNodeString(node) _res = mc.xform(node, q=True, ws=True, sp=True) log.debug("|{0}| >> [{2}] = {1}".format(_str_func, _res, node)) if asEuclid: return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res
def get_planeIntersect(self, target=None, planeAxis='z+', objAxis='z+', mark=True): _short = self.mNode _str_func = '[{0}] get_planeIntersect'.format(_short) if target: mTarget = cgmMeta.asMeta(target) else: mTarget = cgmMeta.asMeta(mc.ls(sl=1)) if not mTarget: return log.error(cgmGEN.logString_msg(_str_func, 'No Target')) mTarget = mTarget[0] if not self.atUtils('is_rigged'): mObj = self else: mObj = self.moduleTarget.eyeLook planePoint = VALID.euclidVector3Arg(mObj.p_position) planeNormal = VALID.euclidVector3Arg(mObj.getAxisVector(planeAxis)) rayPoint = VALID.euclidVector3Arg(mTarget.p_position) rayDirection = VALID.euclidVector3Arg(mTarget.getAxisVector(objAxis)) plane = EUCLID.Plane( EUCLID.Point3(planePoint.x, planePoint.y, planePoint.z), EUCLID.Point3(planeNormal.x, planeNormal.y, planeNormal.z)) pos = plane.intersect( EUCLID.Line3( EUCLID.Point3(rayPoint.x, rayPoint.y, rayPoint.z), EUCLID.Vector3(rayDirection.x, rayDirection.y, rayDirection.z))) if mark: LOC.create(position=pos, name='pewpew') return pos
def get(obj=None, pivot='rp', space='ws', targets=None, mode='xform', asEuclid=False): """ General call for querying position data in maya. Note -- pivot and space are ingored in boundingBox mode which returns the center pivot in worldSpace :parameters: obj(str): Object to check Transform, components supported pivot(str): Which pivot to use. (rotate,scale,boundingBox) rotatePivot scalePivot boundingBox -- Returns the calculated center pivot position based on bounding box space(str): World,Object,Local mode(str): xform -- Utilizes tranditional checking with xForm or pointPosition for components asEuclid(bool) - whether to return as Vector or not :returns success(bool) """ try: _str_func = 'get_pos' _obj = VALID.mNodeString(obj) _pivot = VALID.kw_fromDict(pivot, SHARED._d_pivotArgs, noneValid=False, calledFrom=_str_func) _targets = VALID.stringListArg(targets, noneValid=True, calledFrom=_str_func) _space = VALID.kw_fromDict(space, SHARED._d_spaceArgs, noneValid=False, calledFrom=_str_func) _mode = VALID.kw_fromDict(mode, _d_pos_modes, noneValid=False, calledFrom=_str_func) _res = False if _pivot == 'boundingBox': log.debug("|{0}|...boundingBox pivot...".format(_str_func)) _res = get_bb_center(_obj) if MATH.is_vector_equivalent( _res, [0, 0, 0]) and not mc.listRelatives(_obj, s=True): _pivot = 'rp' log.warning( "|{0}|...boundingBox pivot is zero, using rp....".format( _str_func)) if '[' in _obj: log.debug("|{0}| >> component mode...".format(_str_func)) if ":" in _obj.split('[')[-1]: raise ValueError, "|{0}| >>Please specify one obj. Component list found: {1}".format( _str_func, _obj) #_cType = VALID.get_mayaType(_obj) _l_comp = VALID.get_component(_obj) _root = _l_comp[1] _cType = _l_comp[3] if not VALID.is_shape(_root): _shapes = mc.listRelatives(_root, s=True, fullPath=True) or [] if len(_shapes) > 1: log.warning( "|{0}| >>More than one shape found. To be more accurate, specify: {1} | shapes: {2}" .format(_str_func, _obj, _shapes)) _root = _shapes[0] _OBJ = '.'.join([_root, _l_comp[0]]) log.debug( "|{0}| >> obj: {1}({6}) | type: {2} | pivot: {3} | space: {4} | mode: {5}" .format(_str_func, _OBJ, _cType, _pivot, _space, _mode, _obj)) kws_pp = {'world': False, 'local': False} if _space == 'world': kws_pp['world'] = True else: kws_pp['local'] = True if _cType == 'polyVertex': _res = mc.pointPosition(_OBJ, **kws_pp) elif _cType == 'polyEdge': mc.select(cl=True) mc.select(_OBJ) mel.eval("PolySelectConvert 3") edgeVerts = mc.ls(sl=True, fl=True) posList = [] for vert in edgeVerts: posList.append(mc.pointPosition(vert, **kws_pp)) _res = MATH.get_average_pos(posList) elif _cType == 'polyFace': mc.select(cl=True) mc.select(_OBJ) mel.eval("PolySelectConvert 3") edgeVerts = mc.ls(sl=True, fl=True) posList = [] for vert in edgeVerts: posList.append(mc.pointPosition(vert, **kws_pp)) _res = MATH.get_average_pos(posList) elif _cType in [ 'surfaceCV', 'curveCV', 'editPoint', 'surfacePoint', 'curvePoint', 'cv', 'bezierCurve' ]: _res = mc.pointPosition(_OBJ, **kws_pp) #_res = mc.pointPosition(_OBJ) else: raise RuntimeError, "|{0}| >> Shouldn't have gotten here. Need another check for component type. '{1}'".format( _str_func, _cType) else: log.debug( "|{0}| >> obj: {1} | pivot: {2} | space: {3} | mode: {4} | asEuclid: {5}" .format(_str_func, _obj, _pivot, _space, _mode, asEuclid)) if _space == 'local' or _pivot == 'local': _res = ATTR.get(_obj, 'translate') #elif _pivot == 'local': #if _space == 'world': # _res = mc.xform(_obj, q=True, rp = True, ws=True ) #else: # _res = ATTR.get(_obj,'translate') else: kws = { 'q': True, 'rp': False, 'sp': False, 'os': False, 'ws': False } if _pivot == 'rp': kws['rp'] = True else: kws['sp'] = True if _space == 'object': kws['os'] = True else: kws['ws'] = True log.debug("|{0}| >> xform kws: {1}".format(_str_func, kws)) _res = mc.xform(_obj, **kws) if _res is not None: if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res raise RuntimeError, "|{0}| >> Shouldn't have gotten here: obj: {1}".format( _str_func, _obj) except Exception, err: cgmGen.cgmExceptCB(Exception, err)
def get_axisBox_size(arg=None, children=False, mode=None, asEuclid=False): """ Get the bb size of a given arg :parameters: arg(str/list): Object(s) to check shapes(bool): Only check dag node shapes mode(varied): True/'max': Only return max value 'min': Only min :returns boundingBox size(list) """ _str_func = 'get_axisBox_size' #_arg = VALID.stringListArg(arg,False,_str_func) try: log.debug("|{0}| >> shapes mode ".format(_str_func)) arg = VALID.listArg(arg) _dag = VALID.getTransform(arg[0]) if not _dag: raise ValueError, "Must have a dag node. Obj: {0}".format(_dag) if VALID.is_shape(_dag): l_shapes = [_dag] else: l_shapes = mc.listRelatives(_dag, s=True, fullPath=True) or [] _dup = mc.duplicate(l_shapes, po=False, rc=True)[0] if not children: for o in mc.listRelatives( _dup, children=True, type='transform', fullPath=True) or []: mc.delete(o) try: _dup = mc.parent(_dup, world=True)[0] except: pass #Reset our stuff before we make our bb... ATTR.reset(_dup, ['t', 'r', 'shear']) _size = get_bb_size(_dup, True) mc.delete(_dup) _res = _size if mode is None: if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res elif mode in [True, 'max']: return max(_res) elif mode in ['min']: return min(_res) else: log.error("|{0}| >> Unknown mode. Returning default. {1} ".format( _str_func, mode)) return _res except Exception, err: cgmGen.cgmExceptCB(Exception, err, msg=vars())
def get_bb_pos(arg=None, shapes=False, mode='center', mark=False, asEuclid=False): """ Get points relative to a bounding box where z is forward :parameters: arg(str/list): Object(s) to check shapes(bool): Only check dag node shapes mode(varied): center bottom top left right front back mark(bool): whether to add a locator at the position for testing asEuclid(bool) - whether to return as Vector or not :returns boundingBox size(list) """ _str_func = 'get_bb_pos' #_arg = VALID.stringListArg(arg,False,_str_func) _sel = mc.ls(sl=True) bb_raw = get_bb_size(arg, shapes, mode='raw') _mode = mode.lower() if _mode == 'center': log.debug("|{0}| >> Center mode".format(_str_func)) _res = [((bb_raw[0] + bb_raw[3]) / 2), ((bb_raw[4] + bb_raw[1]) / 2), ((bb_raw[5] + bb_raw[2]) / 2)] elif _mode in ['bottom', 'y-']: log.debug("|{0}| >> Bottom mode".format(_str_func)) _res = [((bb_raw[0] + bb_raw[3]) / 2), bb_raw[1], ((bb_raw[5] + bb_raw[2]) / 2)] elif _mode in ['top', 'y+']: log.debug("|{0}| >> Top mode".format(_str_func)) _res = [((bb_raw[0] + bb_raw[3]) / 2), bb_raw[4], ((bb_raw[5] + bb_raw[2]) / 2)] elif _mode in ['front', 'z+']: log.debug("|{0}| >> Front mode".format(_str_func)) _res = [((bb_raw[0] + bb_raw[3]) / 2), ((bb_raw[4] + bb_raw[1]) / 2), bb_raw[5]] elif _mode in ['back', 'z-']: log.debug("|{0}| >> Back mode".format(_str_func)) _res = [((bb_raw[0] + bb_raw[3]) / 2), ((bb_raw[4] + bb_raw[1]) / 2), bb_raw[2]] elif _mode in ['left', 'x+']: log.debug("|{0}| >> Left mode".format(_str_func)) _res = [ bb_raw[3], ((bb_raw[4] + bb_raw[1]) / 2), ((bb_raw[5] + bb_raw[2]) / 2) ] elif _mode in ['right', 'x-']: log.debug("|{0}| >> Right mode".format(_str_func)) _res = [ bb_raw[0], ((bb_raw[4] + bb_raw[1]) / 2), ((bb_raw[5] + bb_raw[2]) / 2) ] else: raise ValueError, "|{0}| >> Unknown mode: {1}".format(_str_func, _mode) if mark: _size = get_bb_size(arg, shapes) _loc = mc.spaceLocator()[0] ATTR.set(_loc, 'scale', [v / 4 for v in _size]) mc.move(_res[0], _res[1], _res[2], _loc, ws=True) mc.rename(_loc, '{0}_loc'.format(_mode)) if _sel: mc.select(_sel) if asEuclid: log.debug("|{0}| >> asEuclid...".format(_str_func)) return EUCLID.Vector3(_res[0], _res[1], _res[2]) return _res