Init Py
Init Py
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Parent to nearest bone",
"author": "Pablo Gentile",
"version": (0, 8, 0),
"blender": (3, 0, 0),
"location": "View3D > Object > Parent > Parent to nearest Bone",
"description": "Parents object to the nearest bone",
"warning": "",
"doc_url": "https://github.com/g3ntile/parentToNearestBone#readme",
"category": "Object",
}
import bpy
import math
from mathutils import Vector
C = bpy.context
D = bpy.data
### functions
# Object space Vector to world space Vector
def loc2world(ob, vector):
'''converts the vector from ob space to world space'''
return ob.matrix_world @ vector
# to edit mode
bpy.ops.object.mode_set(mode='EDIT')
# finds the minimum value from a list of tuples that store the distance and the
bone itself
# and stores the resulting bone
if use_center:
# use the geometric center vs bone.center method
closest = min( [ (math.dist(getGeometryCenter(ob), loc2world(ar,
bone.center)), bone) for bone in ar.data.edit_bones ])
else:
# use the object origin vs bone head method
closest = min( [ (math.dist(ob.location, loc2world(ar, bone.head)), bone)
for bone in ar.data.edit_bones ])
def getHeadPosition(ar,bone):
bpy.ops.object.mode_set(mode='EDIT')
head = ar.data.edit_bones[bone].head
bpy.ops.object.mode_set(mode='OBJECT')
return head
def getCenterPosition(ar,bone):
bpy.ops.object.mode_set(mode='EDIT')
center = ar.data.edit_bones[bone].center
bpy.ops.object.mode_set(mode='OBJECT')
return center
def getGeometryCenter(ob):
# Returns the Geometric center of
# the object calculating the average of
# the bounding box min and max
# return average
return (max+min)/2
# error message
def oops(self, context):
self.layout.label(text="Please select an Armature as active object!")
#########################
##**##**
ar = C.active_object
if ar.type == 'ARMATURE':
for ob in my_objects:
print( '–' * 80)
print (ob.name)
print( '.' * 80)
my_closest = closestBone(ob, ar, use_center)
parent2BoneKT(ob,ar,my_closest)
else :
bpy.context.window_manager.popup_menu(oops, title="Error", icon='ERROR')
##**##**
class ParentToNearestBone(bpy.types.Operator):
"""Parents all selected objects to the nearest Bone in Active Armature,
comparing the Bone's head to each Object's origin"""
bl_idname = "object.parent_to_nearest_bone"
bl_label = "Parent to nearest Bone"
@classmethod
def poll(cls, context):
return context.active_object is not None and context.active_object.type ==
'ARMATURE'
class ParentToNearestBoneCenters(bpy.types.Operator):
"""Parents all selected objects to the nearest Bone in Active Armature,
comparing the Bone's center to each Object's geometric center"""
bl_idname = "object.parent_to_nearest_bone_centers"
bl_label = "Parent to nearest Bone"
@classmethod
def poll(cls, context):
return context.active_object is not None and context.active_object.type ==
'ARMATURE'
# Register and add to the "object" menu (required to also use F3 search "Simple
Object Operator" for quick access).
# The old version of the operator is commented and not registered, just in case.
# Will be cleaned up if everything goes well in 1.0
def register():
# bpy.utils.register_class(ParentToNearestBone)
# bpy.types.VIEW3D_MT_object_parent.append(menu_func)
bpy.utils.register_class(ParentToNearestBoneCenters)
bpy.types.VIEW3D_MT_object_parent.append(menu_func_center)
def unregister():
bpy.utils.unregister_class(ParentToNearestBoneCenters)
bpy.types.VIEW3D_MT_object_parent.remove(menu_func_center)
# bpy.utils.unregister_class(ParentToNearestBone)
# bpy.types.VIEW3D_MT_object_parent.remove(menu_func)
if __name__ == "__main__":
register()