[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16742] trunk/blender: Patch #17346: Align bones in edit mode

Joshua Leung aligorith at gmail.com
Fri Sep 26 10:51:05 CEST 2008


Revision: 16742
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16742
Author:   aligorith
Date:     2008-09-26 10:51:05 +0200 (Fri, 26 Sep 2008)

Log Message:
-----------
Patch #17346: Align bones in edit mode
Submitted by: Lorenzo Pierfederici (lento) 

This patch adds the CTRL-ALT-A hotkey to align bones in armature edit mode.

It works the same way as parenting: selected bones will be aligned with active bone, if only one bone is selected it
will be aligned with its parent (if any)

Thanks!

Modified Paths:
--------------
    trunk/blender/release/scripts/hotkeys.py
    trunk/blender/source/blender/include/BIF_editarmature.h
    trunk/blender/source/blender/src/editarmature.c
    trunk/blender/source/blender/src/space.c

Modified: trunk/blender/release/scripts/hotkeys.py
===================================================================
--- trunk/blender/release/scripts/hotkeys.py	2008-09-26 08:40:35 UTC (rev 16741)
+++ trunk/blender/release/scripts/hotkeys.py	2008-09-26 08:51:05 UTC (rev 16742)
@@ -264,6 +264,7 @@
 ['Alt-A', 'Play animation in current window'],
 ['Ctrl-A', 'Apply objects size/rotation to object data'],
 ['Ctrl-A', 'Text Editor: Select all'],
+['Ctrl-ALT-A', '3D-View: Armature Edit mode, align selected bones to active bone'],
 ['Shift-A', 'Sequencer: Add menu'],
 ['Shift-A', '3D-View: Add menu'],
 ['Shift-ALT-A', 'Play animation in all windows'],

Modified: trunk/blender/source/blender/include/BIF_editarmature.h
===================================================================
--- trunk/blender/source/blender/include/BIF_editarmature.h	2008-09-26 08:40:35 UTC (rev 16741)
+++ trunk/blender/source/blender/include/BIF_editarmature.h	2008-09-26 08:51:05 UTC (rev 16742)
@@ -139,6 +139,8 @@
 void	hide_unselected_armature_bones(void);
 void	show_all_armature_bones(void);
 
+void	align_selected_bones(void);
+
 #define	BONESEL_ROOT	0x10000000
 #define	BONESEL_TIP		0x20000000
 #define	BONESEL_BONE	0x40000000
@@ -157,3 +159,4 @@
 #endif
 
 
+

Modified: trunk/blender/source/blender/src/editarmature.c
===================================================================
--- trunk/blender/source/blender/src/editarmature.c	2008-09-26 08:40:35 UTC (rev 16741)
+++ trunk/blender/source/blender/src/editarmature.c	2008-09-26 08:51:05 UTC (rev 16742)
@@ -3310,6 +3310,143 @@
 	BIF_undo_push("Switch Direction");
 }
 
+/* editbone alignment */
+
+/* helper to fix a ebone position if its parent has moved due to alignment*/
+static void fix_connected_bone(EditBone *ebone)
+{
+	float diff[3];
+	
+	if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || VecEqual(ebone->parent->tail, ebone->head))
+		return;
+	
+	/* if the parent has moved we translate child's head and tail accordingly*/
+	VecSubf(diff, ebone->parent->tail, ebone->head);
+	VecAddf(ebone->head, ebone->head, diff);
+	VecAddf(ebone->tail, ebone->tail, diff);
+	return;
+}
+
+/* helper to recursively find chains of connected bones starting at ebone and fix their position */
+static void fix_editbone_connected_children(EditBone *ebone)
+{
+	EditBone *selbone;
+	
+	for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
+		if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
+			fix_connected_bone(selbone);
+			fix_editbone_connected_children(selbone);
+		}
+	}
+	return;
+}			
+
+static void bone_align_to_bone(EditBone *selbone, EditBone *actbone)
+{
+	float selboneaxis[3], actboneaxis[3], length;
+
+	VecSubf(actboneaxis, actbone->tail, actbone->head);
+	Normalize(actboneaxis);
+
+	VecSubf(selboneaxis, selbone->tail, selbone->head);
+	length =  VecLength(selboneaxis);
+
+	VecMulf(actboneaxis, length);
+	VecAddf(selbone->tail, selbone->head, actboneaxis);
+	selbone->roll = actbone->roll;
+	
+	/* if the bone being aligned has connected descendants they must be moved
+	according to their parent new position, otherwise they would be left
+	in an unconsistent state: connected but away from the parent*/
+	fix_editbone_connected_children(selbone);
+	return;
+}
+
+void align_selected_bones(void)
+{
+	bArmature *arm= G.obedit->data;
+	EditBone *actbone, *ebone, *selbone;
+	EditBone *flipbone, *flippar;
+	short allchildbones= 0, foundselbone= 0;
+	
+	/* find active bone to align to */
+	for (actbone = G.edbo.first; actbone; actbone=actbone->next) {
+		if (arm->layer & actbone->layer) {
+			if (actbone->flag & BONE_ACTIVE)
+				break;
+		}
+	}
+	if (actbone == NULL) {
+		error("Needs an active bone");
+		return; 
+	}
+
+	/* find selected bones */
+	for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+		if (arm->layer & ebone->layer) {
+			if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
+				foundselbone++;
+				if (ebone->parent != actbone) allchildbones= 1; 
+			}	
+		}
+	}
+	/* abort if no selected bones, and active bone doesn't have a parent to work with instead */
+	if (foundselbone==0 && actbone->parent==NULL) {
+		error("Need selected bone(s)");
+		return;
+	}
+	
+	if (foundselbone==0 && actbone->parent) {
+		/* When only the active bone is selected, and it has a parent,
+		 * align it to the parent, as that is the only possible outcome. 
+		 */
+		bone_align_to_bone(actbone, actbone->parent);
+		
+		if (arm->flag & ARM_MIRROR_EDIT) {
+			flipbone = armature_bone_get_mirrored(actbone);
+			if (flipbone)
+				bone_align_to_bone(flipbone, flipbone->parent);
+		}
+	}
+	else {
+		/* loop through all editbones, aligning all selected bones to the active bone */
+		for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
+			if (arm->layer & selbone->layer) {
+				if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
+					/* align selbone to actbone */
+					bone_align_to_bone(selbone, actbone);
+					
+					if (arm->flag & ARM_MIRROR_EDIT) {
+						/* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
+						 *	(i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+						 *	This is useful for arm-chains, for example parenting lower arm to upper arm
+						 * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+						 *	then just use actbone. Useful when doing upper arm to spine.
+						 */
+						flipbone = armature_bone_get_mirrored(selbone);
+						flippar = armature_bone_get_mirrored(actbone);
+						
+						if (flipbone) {
+							if (flippar)
+								bone_align_to_bone(flipbone, flippar);
+							else
+								bone_align_to_bone(flipbone, actbone);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	countall(); /* checks selection */
+	allqueue(REDRAWVIEW3D, 0);
+	allqueue(REDRAWBUTSEDIT, 0);
+	allqueue(REDRAWOOPS, 0);
+	BIF_undo_push("Align bones");
+
+	return;
+}
+
 /* ***************** Pose tools ********************* */
 
 void clear_armature(Object *ob, char mode)

Modified: trunk/blender/source/blender/src/space.c
===================================================================
--- trunk/blender/source/blender/src/space.c	2008-09-26 08:40:35 UTC (rev 16741)
+++ trunk/blender/source/blender/src/space.c	2008-09-26 08:51:05 UTC (rev 16742)
@@ -1864,8 +1864,11 @@
 				break;
 				
 			case AKEY:
-				if (G.obedit == 0 && G.qual == (LR_CTRLKEY|LR_ALTKEY)) {
-					alignmenu();
+				if(G.qual == (LR_CTRLKEY|LR_ALTKEY)) {
+					if(G.obedit == 0)
+						alignmenu();
+					else if(G.obedit->type==OB_ARMATURE)
+						align_selected_bones();
 				}
 				else if(G.qual & LR_CTRLKEY) { /* also with shift! */
 					apply_object();	





More information about the Bf-blender-cvs mailing list