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
path: root/source
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2008-09-26 12:51:05 +0400
committerJoshua Leung <aligorith@gmail.com>2008-09-26 12:51:05 +0400
commit1206061ed431a37c31271364c0ed346809c3abc3 (patch)
tree2dfac9ee09f607d886d9455d660df7eb19af1bdd /source
parent06a5e9b58a0c1281609ee1ddb850fc058fe56c4f (diff)
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!
Diffstat (limited to 'source')
-rw-r--r--source/blender/include/BIF_editarmature.h3
-rw-r--r--source/blender/src/editarmature.c137
-rw-r--r--source/blender/src/space.c7
3 files changed, 145 insertions, 2 deletions
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h
index fdd00a67465..d390b96f61f 100644
--- a/source/blender/include/BIF_editarmature.h
+++ b/source/blender/include/BIF_editarmature.h
@@ -139,6 +139,8 @@ void hide_selected_armature_bones(void);
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 @@ void show_all_armature_bones(void);
#endif
+
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
index 5e50c8117cc..d5e5b5a1c4a 100644
--- a/source/blender/src/editarmature.c
+++ b/source/blender/src/editarmature.c
@@ -3310,6 +3310,143 @@ void switch_direction_armature (void)
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)
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index d4460e55a3e..92b5580775e 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -1864,8 +1864,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
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();