def __set_attr_keyframes(node, attr_name, keyframes, before_value=None, after_value=None, reduce_keys=None): """ Set keyframes on a node.attribute, from a KeyframeData instance. :param node: Node to set data on. :type node: str :param attr_name: Attribute (on 'node') to set keyframes. :type attr_name: str :param keyframes: The keyframe information. :type keyframes: KeyframeData :param before_value: Value to set before the first keyframe. :type before_value: int, float or bool :param after_value: Value to set after the first keyframe. :type after_value: int, float or bool :param reduce_keys: Allow reducing the keyframes, potentially deleting all keyframes. Values will NEVER be changed, only duplicate keyframe data is removed. :type reduce_keys: bool :returns: Maya API (version 1) MFnAnimCurve object. :rtype: maya.OpenMaya.MFnAnimCurve """ if isinstance(keyframes, interface.KeyframeData) is False: msg = 'keyframes must be type %r' raise TypeError(msg % interface.KeyframeData.__name__) if reduce_keys is None: reduce_keys = False if isinstance(reduce_keys, bool) is False: msg = "reduce_keys must be type 'bool'" raise TypeError(msg) times, values = keyframes.get_times_and_values() assert len(times) == len(values) # Set an extra value before/after the first/last keyframe. if len(times) > 0: if before_value is not None: start_time = times[0] times = [start_time - 1] + times values = [before_value] + values if after_value is not None: end_time = times[-1] times = times + [end_time + 1] values = values + [after_value] # Reduce keyframes, we don't need per-frame keyframes if the data # is the same. Change the times/values just before we set the # keyframes if reduce_keys is True: tmp_times = list(times) tmp_values = list(values) times = [] values = [] prev_t = None prev_v = None for t, v in zip(tmp_times, tmp_values): if prev_v is None: times.append(t) values.append(v) elif interface.float_is_equal(prev_v, v) is False: times.append(prev_t) values.append(prev_v) times.append(t) values.append(v) prev_t = t prev_v = v node_attr = node + '.' + attr_name anim_fn = anim_utils.create_anim_curve_node_apione(times, values, node_attr) if reduce_keys is True: locked = maya.cmds.getAttr(node_attr, lock=True) maya.cmds.setAttr(node_attr, lock=False) maya.cmds.delete(node_attr, staticChannels=True) maya.cmds.setAttr(node_attr, lock=locked) return anim_fn
def calculate_overscan_ratio(cam, mkr_grp, camera_fov): """Calculate overscan with camera and FOV. Query the overscan of cam by comparing to the camera_fov field of view. :param cam: The mmSolver.api.Camera object to query field of view from. :type cam: Camera :param camera_fov: Tuple of camera field of view per-frame values X and Y. :type camera_fov: [(int, float, float), ..] :param mkr_grp: The mmapi MarkerGroup object, to be used additionally to the provided camera to calculate the overscan. :type mkr_grp: MarkerGroup or None :returns: Overscan X and Y values. :rtype: (float, float) """ assert isinstance(cam, mmapi.Camera) assert isinstance(camera_fov, list) assert mkr_grp is None or isinstance(mkr_grp, mmapi.MarkerGroup) cam_shp = cam.get_shape_node() frames = [f for f, _, _ in camera_fov] maya_camera_fov = get_camera_field_of_view(cam_shp, frames) x = 1.0 y = 1.0 all_same_ratio_x = True all_same_ratio_y = True last_ratio_x = None last_ratio_y = None for file_fov, maya_fov in zip(camera_fov, maya_camera_fov): file_frame, file_angle_x, file_angle_y = file_fov maya_frame, maya_angle_x, maya_angle_y = maya_fov file_fov_x = math.tan(math.radians(file_angle_x * 0.5)) file_fov_y = math.tan(math.radians(file_angle_y * 0.5)) maya_fov_x = math.tan(math.radians(maya_angle_x * 0.5)) maya_fov_y = math.tan(math.radians(maya_angle_y * 0.5)) ratio_x = maya_fov_x / file_fov_x ratio_y = maya_fov_y / file_fov_y if last_ratio_x is None and last_ratio_y is None: last_ratio_x = ratio_x last_ratio_y = ratio_y ratio_same_x = interface.float_is_equal(ratio_x, last_ratio_x) ratio_same_y = interface.float_is_equal(ratio_y, last_ratio_y) if not ratio_same_x: all_same_ratio_x = False if not ratio_same_y: all_same_ratio_y = False if all_same_ratio_x is True or all_same_ratio_y is True: x = ratio_x y = ratio_y else: x = 1.0 y = 1.0 break # Account for MarkerGroup overscan. # # NOTE: We assume that the overscanX/Y values are NOT changing # over time. mkr_grp_overscan_x = 1.0 mkr_grp_overscan_y = 1.0 if mkr_grp is not None: mkr_grp_node = mkr_grp.get_node() if mkr_grp_node is not None: attr_x = mkr_grp_node + '.overscanX' attr_y = mkr_grp_node + '.overscanY' mkr_grp_overscan_x = maya.cmds.getAttr(attr_x) mkr_grp_overscan_y = maya.cmds.getAttr(attr_y) x = mkr_grp_overscan_x / x y = mkr_grp_overscan_y / y return x, y