Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2007-01-09 08:28:37 +0300
committerCampbell Barton <ideasman42@gmail.com>2007-01-09 08:28:37 +0300
commitca97ede0cd800eb60c04f9b9e73e4be5c5dc77b7 (patch)
tree6d0607fbb6a10b9e37eff7e593766fab61823427 /release
parentfae8716c54fee52f413d9dc89d6d03729d296ee8 (diff)
fixes spelling of filename.
Window.c was calling undo_push_mesh, even for non mesh objects, exiting editmode would crash for any non mesh object (found with the armature symmetry script), bad juju.
Diffstat (limited to 'release')
-rw-r--r--release/scripts/armature_symetry.py5
-rw-r--r--release/scripts/armature_symmetry.py325
2 files changed, 329 insertions, 1 deletions
diff --git a/release/scripts/armature_symetry.py b/release/scripts/armature_symetry.py
index 4caf028631a..1e4484d0efc 100644
--- a/release/scripts/armature_symetry.py
+++ b/release/scripts/armature_symetry.py
@@ -195,10 +195,13 @@ def armature_symetry(\
if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2:
# This is a center bone, clamp and remove from the bone list so we dont use again.
+ if edit_bone.tail.x or edit_bone.head.x:
+ tot_editbones_modified += 1
+
edit_bone.tail.x= edit_bone.head.x= 0
del bones[eb_idx]
- tot_editbones_modified+=1
+
bone_comparisons= []
diff --git a/release/scripts/armature_symmetry.py b/release/scripts/armature_symmetry.py
new file mode 100644
index 00000000000..1e4484d0efc
--- /dev/null
+++ b/release/scripts/armature_symmetry.py
@@ -0,0 +1,325 @@
+#!BPY
+
+"""
+Name: 'Armature Symmetry'
+Blender: 242
+Group: 'Animation'
+Tooltip: 'Make an Armature symetrical'
+"""
+
+__author__ = "Campbell Barton"
+__url__ = ("blender", "blenderartist")
+__version__ = "1.0 2006-7-26"
+
+__doc__ = """\
+This script creates perfectly symmetrical armatures,
+based on the best fit when comparing the mirrored locations of 2 bones.
+Hidden bones are ignored, and optionally only operate on selected bones.
+"""
+
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# Script copyright (C) Campbell J Barton 2006
+#
+# 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 2
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+import Blender
+from Blender import Scene
+Vector= Blender.Mathutils.Vector
+
+
+def VecXFlip(vec):
+ '''
+ Return a copy of this vector x flipped.
+ '''
+ x,y,z= vec
+ return Vector(-x,y,z)
+
+def editbone_mirror_diff(editbone1, editbone2):
+ '''
+ X Mirror bone compare
+ return a float representing the difference between the 2 bones
+ the smaller the better the match
+ '''
+ h1= editbone1.head
+ h2= editbone2.head
+
+ t1= editbone1.tail
+ t2= editbone2.tail
+
+ # Mirror bone2's location
+ h2= VecXFlip(h2)
+ t2= VecXFlip(t2)
+
+ #return (h1-h2).length + (t1-t2).length # returns the length only
+
+ # For this function its easier to return the bones also
+ return ((h1-h2).length + (t1-t2).length)/2, editbone1, editbone2
+
+def editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L):
+ '''
+ Merge these 2 bones to their mirrored locations
+ '''
+ h1= editbone1.head
+ h2= editbone2.head
+
+ t1= editbone1.tail
+ t2= editbone2.tail
+
+ if PREF_MODE_L2R and PREF_MODE_R2L:
+ # Median, flip bone2's locations and average, then apply to editbone1, flip and apply to editbone2
+ h2_f= VecXFlip(h2)
+ t2_f= VecXFlip(t2)
+
+ h_med= (h1+h2_f)*0.5 # middle between t1 and flipped t2
+ t_med= (t1+t2_f)*0.5 # middle between h1 and flipped h2
+
+ # Apply the median to editbone1
+ editbone1.head= h_med
+ editbone1.tail= t_med
+
+ # Flip in place for editbone2
+ h_med.x= -h_med.x
+ t_med.x= -t_med.x
+
+ # Apply the median to editbone2
+ editbone2.head= h_med
+ editbone2.tail= t_med
+
+ # Average the roll, this might need some logical work, but looks good for now.
+ r1= editbone1.roll
+ r2= -editbone2.roll
+ # print 'rolls are', r1,r2
+ r_med= (r1+r2)/2
+ # print 'new roll is', r_med
+ editbone1.roll= r_med
+ editbone2.roll= -r_med # mirror roll
+
+ else: # Copy from 1 side to another
+
+ # Crafty function we can use so L>R and R>L can use the same code
+ def IS_XMIRROR_SOURCE(xval):
+ '''Source means is this the value we want to copy from'''
+
+ if PREF_MODE_L2R:
+ if xval<0: return True
+ else: return False
+ else: # PREF_MODE_R2L
+ if xval<0: return False
+ else: return True
+
+ if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2
+ editbone2.head= VecXFlip(h1)
+ else:
+ '''
+ assume h2.x<0 - not a big deal if were wrong,
+ its unlikely to ever happen because the bones would both be on the same side.
+ '''
+
+ # head bone 2s negative, so copy it to h1
+ editbone1.head= VecXFlip(h2)
+
+ # Same as above for tail
+ if IS_XMIRROR_SOURCE(t1.x):
+ editbone2.tail= VecXFlip(t1)
+ else:
+ editbone1.tail= VecXFlip(t2)
+
+ # Copy roll from 1 bone to another, use the head's location to decide which side it's on.
+ if IS_XMIRROR_SOURCE(editbone1.head):
+ editbone2.roll= -editbone1.roll
+ else:
+ editbone1.roll= -editbone2.roll
+
+
+def armature_symetry(\
+ arm_ob,\
+ PREF_MAX_DIST,\
+ PREF_XMID_SNAP,\
+ PREF_XZERO_THRESH,\
+ PREF_MODE_L2R,\
+ PREF_MODE_R2L,\
+ PREF_SEL_ONLY):
+
+ '''
+ Main function that does all the work,
+ return the number of
+ '''
+ arm_data= arm_ob.data
+ arm_data.makeEditable()
+
+ # Get the bones
+ bones= []
+ HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT
+ BONE_SELECTED= Blender.Armature.BONE_SELECTED
+
+ if PREF_SEL_ONLY:
+ for eb in arm_data.bones.values():
+ options= eb.options
+ if HIDDEN_EDIT not in options and BONE_SELECTED in options:
+ bones.append(eb)
+ else:
+ # All non hidden bones
+ for eb in arm_data.bones.values():
+ options= eb.options
+ if HIDDEN_EDIT not in options:
+ bones.append(eb)
+
+ del HIDDEN_EDIT # remove temp variables
+ del BONE_SELECTED
+
+ # Store the numder of bones we have modified for a message
+ tot_editbones= len(bones)
+ tot_editbones_modified= 0
+
+ if PREF_XMID_SNAP:
+ # Remove bones that are in the middle (X Zero)
+ # reverse loop so we can remove items in the list.
+ for eb_idx in xrange(len(bones)-1, -1, -1):
+ edit_bone= bones[eb_idx]
+ if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2:
+
+ # This is a center bone, clamp and remove from the bone list so we dont use again.
+ if edit_bone.tail.x or edit_bone.head.x:
+ tot_editbones_modified += 1
+
+ edit_bone.tail.x= edit_bone.head.x= 0
+ del bones[eb_idx]
+
+
+
+
+ bone_comparisons= []
+
+ # Compare every bone with every other bone, shouldn't be too slow.
+ # These 2 "for" loops only compare once
+ for eb_idx_a in xrange(len(bones)-1, -1, -1):
+ edit_bone_a= bones[eb_idx_a]
+ for eb_idx_b in xrange(eb_idx_a-1, -1, -1):
+ edit_bone_b= bones[eb_idx_b]
+ # Error float the first value from editbone_mirror_diff() so we can sort the resulting list.
+ bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b))
+
+
+ bone_comparisons.sort() # best matches first
+
+ # Make a dict() of bone names that have been used so we dont mirror more then once
+ bone_mirrored= {}
+
+ for error, editbone1, editbone2 in bone_comparisons:
+ # print 'Trying to merge at error %.3f' % error
+ if error > PREF_MAX_DIST:
+ # print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST
+ break
+
+ if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name):
+ # Were not used, execute the mirror
+ editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L)
+ # print 'Merging bones'
+
+ # Add ourselves so we aren't touched again
+ bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4
+ bone_mirrored[editbone2.name] = None
+
+ # If both options are enabled, then we have changed 2 bones
+ tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L
+
+ arm_data.update() # get out of armature editmode
+ return tot_editbones, tot_editbones_modified
+
+
+def main():
+ '''
+ User interface function that gets the options and calls armature_symetry()
+ '''
+
+ scn= Scene.GetCurrent()
+ arm_ob= scn.objects.active
+
+ if not arm_ob or arm_ob.type!='Armature':
+ Blender.Draw.PupMenu('No Armature object selected.')
+ return
+
+ # Cant be in editmode for armature.makeEditable()
+ is_editmode= Blender.Window.EditMode()
+ if is_editmode: Blender.Window.EditMode(0)
+ Draw= Blender.Draw
+
+ # Defaults for the user input
+ PREF_XMID_SNAP= Draw.Create(1)
+ PREF_MAX_DIST= Draw.Create(0.4)
+ PREF_XZERO_THRESH= Draw.Create(0.02)
+
+ PREF_MODE_L2R= Draw.Create(1)
+ PREF_MODE_R2L= Draw.Create(0)
+ PREF_SEL_ONLY= Draw.Create(1)
+
+ pup_block = [\
+ 'Left (-), Right (+)',\
+ ('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\
+ ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\
+ '',\
+ ('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\
+ ('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\
+ ('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\
+ ('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\
+ ]
+
+ # Popup, exit if the user doesn't click OK
+ if not Draw.PupBlock("X Mirror mesh tool", pup_block):
+ return
+
+ # Replace the variables with their button values.
+ PREF_XMID_SNAP= PREF_XMID_SNAP.val
+ PREF_MAX_DIST= PREF_MAX_DIST.val
+ PREF_MODE_L2R= PREF_MODE_L2R.val
+ PREF_MODE_R2L= PREF_MODE_R2L.val
+ PREF_XZERO_THRESH= PREF_XZERO_THRESH.val
+ PREF_SEL_ONLY= PREF_SEL_ONLY.val
+
+ # If both are off assume mid-point and enable both
+ if not PREF_MODE_R2L and not PREF_MODE_L2R:
+ PREF_MODE_R2L= PREF_MODE_L2R= True
+
+
+ tot_editbones, tot_editbones_modified = armature_symetry(\
+ arm_ob,\
+ PREF_MAX_DIST,\
+ PREF_XMID_SNAP,\
+ PREF_XZERO_THRESH,\
+ PREF_MODE_L2R,\
+ PREF_MODE_R2L,\
+ PREF_SEL_ONLY)
+
+ if is_editmode: Blender.Window.EditMode(1)
+
+ # Redraw all views before popup
+ Blender.Window.RedrawAll()
+
+ # Print results
+ if PREF_SEL_ONLY:
+ msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones)
+ else:
+ msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones)
+
+
+ Blender.Draw.PupMenu(msg)
+
+# Check for __main__ so this function can be imported by other scripts without running the script.
+if __name__=='__main__':
+ main()