# -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # # Script copyright (C) Bassam Kurdali # # 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 ***** # -------------------------------------------------------------------------- # copyright 2009 Bassam Kurdali # thanks to Martin Poirier for code reviews, fixes and advice import Blender from Blender import Armature from Blender.Mathutils import * def RULEcopy(self, component, targets, target_component, axis): ''' copy copies stuff from the targets to the self bone. self is an editbone component is a string can be "head", "tail", "roll","" targets is a list of edit bones target_component is string like component. axis is unused. if you have more than one target, the result is averaged. you can copy head to tail, tail to tail, roll to roll, or all to all if you change the head, the tail is offset by the same amount. ''' if not component or component == "head": self.tail=self.tail - self.head if axis[0] == axis[1] == axis[2] ==0: self.head=Vector([0,0,0]) fac = Vector([1,1,1]) else: fac = axis for n in range(0,3): self.head[n] = self.head[n] * ( 1 - axis[n] ) for target in targets : if not target_component or target_component == "head": self.head = self.head + Vector ([target.head[0]*fac[0],target.head[1]*fac[1],target.head[2]*fac[2]]) elif target_component == "tail": self.head = self.head + Vector ([target.tail[0]*fac[0],target.tail[1]*fac[1],target.tail[2]*fac[2]]) self.head = self.head / len(targets) self.tail = self.tail + self.head if not component or component == "tail": if axis[0] == axis[1] == axis[2] == 0: self.tail = Vector([0,0,0]) fac = Vector([1,1,1]) else: fac = axis for n in range(0,3): self.tail[n] = self.tail[n] * (1 - axis[n] ) for target in targets : if not target_component or target_component == "tail": self.tail = self.tail + Vector ([target.tail[0]*fac[0],target.tail[1]*fac[1],target.tail[2]*fac[2]]) elif target_component == "head": self.tail = self.tail + Vector ([target.head[0]*fac[0],target.head[1]*fac[1],target.head[2]*fac[2]]) self.tail = self.tail / len(targets) if not component or component == "roll": roll = 0 for target in targets : if not target_component or target_component == "roll": roll += target.roll self.roll = roll / len(targets) return def RULEalign(self,component,targets,target_component, axis): ''' aline aligns the bone with the axis or targets. self is an editbone axis is a Vector (Blender Mathutils Vector) targets is a list of editbones. if targets is empty, aligns to axis, otherwise aligns to average of targets. ''' if targets: vec = Vector([0,0,0]) for target in targets: vec += target.tail - target.head vec /= len(targets) else : vec = axis vec = vec.normalize() length = (self.head-self.tail).length self.tail = self.head + length * vec roll = 0 if targets : for target in targets : roll += target.roll roll /= len(targets) self.roll = roll return def RULEoffset(self,component,targets,target_component, offset): ''' offset offsets either on own axis, or using targets (just uses one) self is an editbone targets is a list of editbones (we only care about the first) offset is a Blender.Mathutils.Vector ''' if targets : offset = offset * targets[0].matrix self.tail = self.tail + offset self.head = self.head + offset return def RULErotate(self,component,targets,target_component, axis): rotmat=Euler([axis.x,axis.y,axis.z]).toMatrix() self.matrix=rotmat*self.matrix return def RULEenplane(self,component,targets,target_component, axis): ''' enplane aligns the roll with the normal of the plane defined by two bones in a chain you must call it with targets[0]being the parent, and targets[1] being the connected child. self is an editbone targets is a list of editbones axis should either be 0,0,1 or 1,0,0 and is a Blender.Mathutils.Vector ''' # get the normal to the targets. if len(targets) == 2 : plane_normal = TriangleNormal(targets[0].head,targets[0].tail,targets[1].tail) plane_normal.normalize() if axis[0]: l = self.matrix[0].length x_axis = l * plane_normal l = self.matrix[2].length z_axis = CrossVecs(x_axis, self.matrix[1]) z_axis.normalize() z_axis *= l self.matrix = Matrix(x_axis, self.matrix[1], z_axis) elif axis[2]: l = self.matrix[2].length z_axis = l * plane_normal l = self.matrix[0].length x_axis = CrossVecs(self.matrix[1], z_axis) x_axis.normalize() x_axis *= l self.matrix = Matrix(x_axis, self.matrix[1], z_axis) return def RULEfliproll(self,component,targets,target_component, axis): ''' enplane aligns the roll with the normal of the plane defined by two bones in a chain you must call it with targets[0]being the parent, and targets[1] being the connected child. self is an editbone targets is a list of editbones axis should either be 0,0,1 or 1,0,0 and is a Blender.Mathutils.Vector ''' self.roll = self.roll + 180 return def RULEsize(self,component,targets,target_component, axis): ''' uses the Y number in axis to determine the length of the bone in blender units. ''' vecme = self.tail-self.head vecme.normalize() vecme = axis[1]*vecme self.tail = self.head + vecme return