def sorted_bones(selected): "Scan through selected bones to find order of bones in a a tree" selected = [ b for b in selected if (Is.posebone(b) or Is.bone(b) or Is.editbone(b)) ] bones = list() while selected: for bone in list(selected): if (bone not in selected): # a previous bone was one of this bone's parents continue for parent in bone.parent_recursive: if parent in selected: break else: bones.append(bone) selected.remove(bone) # Loop over children, which "may" result in less looping for child in bone.children_recursive: if child in selected: bones.append(child) selected.remove(child) return bones
def mirror_bone(bone): name = utils.flip_name(bone.name) if name == bone.name: return if Is.posebone(bone): return bone.id_data.pose.bones.get(name) elif Is.editbone(bone): return bone.id_data.edit_bones.get(name) elif Is.bone(bone): return bone.id_data.bones.get(name)
def matrix(src, local=False, basis=False, tail=False, copy=True): # editbone. matrix # bone. matrix, matrix_local # posebone. matrix, matrix_basis, matrix_channel # object. matrix_world, matrix_basis, matrix_local, matrix_parent_inverse if Is.posebone(src): if copy: matrix = utils.multiply_matrix(src.id_data.matrix_world, src.matrix) else: matrix = src.matrix if basis: matrix_local = src.matrix_basis else: matrix_local = src.bone.matrix_local elif Is.bone(src): matrix = src.matrix matrix_local = src.matrix_basis elif Is.editbone(src): matrix = matrix_local = src.matrix else: matrix = src.matrix_world if basis: matrix_local = src.matrix_basis else: matrix_local = src.matrix_local if copy: matrix = matrix.copy() matrix_local = matrix_local.copy() # scaled = False # if len(set(matrix.to_scale())) == 1: # matrix *= matrix.to_scale()[0] # scaled = True if (tail and hasattr(src, 'tail')): # matrix.translation += (src.tail - src.head) matrix.translation = matrix.Translation(src.tail).translation matrix_local.translation = \ matrix_local.Translation(src.tail).translation # for (i, t) in enumerate(matrix.translation): # v = (src.tail[i] - src.head[i]) * ( # 1 if scaled else matrix.to_scale()[i]) # matrix.translation[i] += v if (basis or local): return matrix_local else: return matrix
def tail(context, bone): # ------ Bones if any((Is.posebone(bone), Is.bone(bone), Is.editbone(bone))): if (Is.posebone(bone)): obj = bone.id_data else: obj = Get.rig(context, bone) if obj is None: return else: mat = Get.matrix(obj) return utils.multiply_matrix(mat, bone.tail)
def icon_from_type(src): "return an Icon id for the specified item's type" if Is.object(src): if src.type == 'LIGHT_PROBE': icon = 'LIGHTPROBE_' + src.data.type else: icon = src.type + '_DATA' elif Is.bone(src) or Is.editbone(src) or Is.posebone(src): icon = 'BONE_DATA' else: icon = 'ERROR' utils.debug("Can't find icon type for ", src, type(src)) return icon
def select(target, value=True): """Select or Deselect an item""" if Is.object(target): target.select_set(value) elif Is.posebone(target): target.bone.select = value elif Is.bone(target) or Is.editbone(target): target.select = value elif target is None: pass else: # Give error assert None, ( "Error: zpy\\Set.select() can't use the provided target \n", target, )
def rig(context, src): """ bone/editbone don't directly link to objects, just the armature.\\ So, try to find an object by using their armature instead """ is_armature = isinstance(src, bpy.types.Armature) if Is.posebone(src) or Is.armature(src.id_data): return src.id_data elif (is_armature, Is.bone(src) or Is.editbone(src)): for object in Get.objects(context): if (object.data == src.id_data): break else: object = None return object else: assert None, ("Could not find rig for", src)
def active(context, target): """Set target as active scene object or bone""" objects = Get.objects(context) # Remember previous active previous = Get.active(context) selected = Is.selected(target) # Set the active if Is.object(target): obj = target elif Is.posebone(target): obj = target.id_data obj.data.bones.active = obj.data.bones.get(target.name) elif isinstance(target, bpy.types.Armature): obj = Get.rig(context, target) elif Is.bone(target): obj = Get.rig(context, target) bones = target.id_data.bones bones.active = bones.get(target.name) elif Is.editbone(target): obj = Get.rig(context, target) if obj: in_edit = (obj.mode == 'EDIT') else: in_edit = (context.mode == 'EDIT_ARMATURE') if in_edit: bones = target.id_data.edit_bones bones.active = bones.get(target.name) elif target is None: obj = None # debug("Set.active() has None as the target") else: assert None, ("Set.active() can't use the provided target", target) if (target and Is.selected(target) != selected): # When setting a bone as active in a rig, it gets selected as well. Set.select(target, selected) objects.active = obj return previous
def sorted_chains(selected): "Scan through selected bones to find order of bones for spline_ik chains" chains = [] for bone in selected: if not any((Is.posebone(bone), Is.bone(bone), Is.editbone(bone))): continue chain = [] end = True for child in bone.children_recursive: if child in selected: end = False continue if end: for par in reversed(bone.parent_recursive): if par in selected: chain.append(par) chain.append(bone) chains.append(chain) return chains
def matrix(src, matrix, local=False, basis=False): """ Set the visual transforms for a bone or object The parameters vary, so the input matrix should too: editbone. matrix bone. matrix, matrix_local posebone. matrix, matrix_basis, matrix_channel object. matrix_world, matrix_basis, matrix_local, matrix_parent_inverse """ if Is.object(src): if basis: src.matrix_basis = matrix elif local: src.matrix_local = matrix else: src.matrix_world = matrix else: if basis or local: if Is.posebone(src): src.matrix_basis = matrix elif Is.bone(src): src.matrix_local = matrix else: src.matrix = matrix else: src.matrix = matrix
def driver(src, path, **kargs): driver_type = kargs.get('driver_type', None) # 'AVERAGE', 'Sum Values', 'SCRIPTED', 'Minimum Value', 'Maximum Value expression = kargs.get('expression', None) frames = kargs.get('frames', list()) # keyframe.co for the driver's fcurve name = kargs.get('name', "var") # Name of the variable added to the driver overwrite = kargs.get('overwrite', False) # Delete the existing driver rotation_mode = kargs.get('rotation_mode', 'AUTO') target = kargs.get('target', None) target_path = kargs.get('target_path', '') transform_space = kargs.get('transform_space', 'LOCAL_SPACE') transform_type = kargs.get('transform_type', 'LOC_X') var_type = kargs.get('var_type', None) # 'SINGLE_PROP', 'TRANSFORMS', 'Rotational Difference', 'Distance' if var_type is None: if target and (not target_path): var_type = 'TRANSFORMS' else: var_type = 'SINGLE_PROP' Driver = Get.driver(src, path) if not Driver: Driver = src.driver_add(path) overwrite = True if overwrite: while Driver.keyframe_points: Driver.keyframe_points.remove(Driver.keyframe_points[0]) if frames: if overwrite: Driver.extrapolation = 'LINEAR' while Driver.modifiers: Driver.modifiers.remove(Driver.modifiers[0]) Driver.keyframe_points.add(len(frames)) for key, co in zip(Driver.keyframe_points[:], frames): key.interpolation = 'LINEAR' key.co = co driver = Driver.driver if overwrite: if (expression is None): if (driver_type is None): driver_type = 'AVERAGE' elif (driver.type == 'SCRIPTED'): driver.expression = name while driver.variables: driver.variables.remove(driver.variables[0]) if expression is not None: driver.expression = expression if driver_type: driver.type = driver_type var = driver.variables.new() var.name = name var.type = var_type var_target = var.targets[0] if target: is_pose = Is.posebone(target) is_bone = Is.bone(target) or Is.editbone(target) is_obj = Is.object(target) if is_obj: var_target.id = target elif (is_pose or is_bone): var_target.id = target.id_data var_target.bone_target = target.name if target_path and (not target_path.startswith( ('pose.bones', 'bones'))): if is_pose: text = f'pose.bones["{target.name}"]' else: text = f'bones["{target.name}"]' if (target_path[0] != '['): text += '.' target_path = text + target_path else: try: var_target.id = target except: var_target.id = target.id_data var_target.data_path = target_path var_target.rotation_mode = rotation_mode var_target.transform_space = transform_space var_target.transform_type = transform_type return Driver
def visible(context, object, value=True, **kargs): """ Set an object's (or bone's object's) visibility to the specified value """ scn = context.scene if not Is.object(object): if isinstance(object, bpy.types.Collection): found = False def loop(root, tree=list()): nonlocal found if root.collection == object: return True for child in root.children: if loop(child, tree): found = True tree.append(child) break if found: return tree view_layer = kargs.get('view_layer', False) if not view_layer: object.hide_viewport = not value if value or view_layer: # Only enables the collection for the view layer once tree = loop(context.view_layer.layer_collection) for col in tree: if (col.exclude == value) and (col.name == object.name): # When a collection is enabled in the view layer, # all of its child collections are as well. col.exclude = not value if value and col.collection.hide_viewport: col.collection.hide_viewport = False elif Is.posebone(object): return Set.visible(context, object.id_data, value) elif Is.bone(object) or Is.editbone(object): return Set.visible(context, Get.rig(context, object), value) else: assert None, ( "Set.visible() does not work with the specified item", object, ) return Set.in_scene(context, object) is_visible = Is.visible(context, object) object_visible = not object.hide_viewport # if Is.visible(context, object) is value: # return visible while (Is.visible(context, object) is not value): "If object isn't in the desired visiblity, loop until it is" if (object.hide_viewport is value): object.hide_viewport = not value continue is_visible = object_visible view = None for collection in object.users_collection: view = context.view_layer.layer_collection.children.get( collection.name) if not view: # collection isn't in scene or whatever continue if view.hide_viewport is value: view.hide_viewport = not value break if view is None: assert None, ( "Set.visible(): Object[", object, "] \nis hidden from viewport and I don't know how to change it" ) # collection.hide_viewport = value break return is_visible