Armature Editing: select shortest path (Ctrl+RMB matching mesh operator)

Patch originally from Terry Struven, modified to use more generic functions.
This commit is contained in:
Campbell Barton 2013-11-22 08:36:48 +11:00
parent 41e563594d
commit a08750addf
5 changed files with 166 additions and 0 deletions

View File

@ -68,6 +68,7 @@ void ARMATURE_OT_select_less(struct wmOperatorType *ot);
void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
void ARMATURE_OT_select_linked(struct wmOperatorType *ot);
void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
void ARMATURE_OT_delete(struct wmOperatorType *ot);
void ARMATURE_OT_duplicate(struct wmOperatorType *ot);

View File

@ -64,6 +64,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_select_hierarchy);
WM_operatortype_append(ARMATURE_OT_select_linked);
WM_operatortype_append(ARMATURE_OT_select_similar);
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
WM_operatortype_append(ARMATURE_OT_delete);
WM_operatortype_append(ARMATURE_OT_duplicate);
@ -264,6 +265,8 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_delete", DELKEY, KM_PRESS, 0, 0);

View File

@ -1120,3 +1120,123 @@ void ARMATURE_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
/****************** Select Path ****************/
static bool armature_shortest_path_select(bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child,
bool use_parent, bool is_test)
{
do {
if (!use_parent && (ebone_child == ebone_parent))
break;
if (is_test) {
if (!EBONE_SELECTABLE(arm, ebone_child)) {
return false;
}
}
else {
ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
}
if (ebone_child == ebone_parent)
break;
ebone_child = ebone_child->parent;
} while (true);
return true;
}
static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
bArmature *arm = obedit->data;
EditBone *ebone_src, *ebone_dst;
EditBone *ebone_isect_parent = NULL;
EditBone *ebone_isect_child[2];
bool change;
view3d_operator_needs_opengl(C);
ebone_src = arm->act_edbone;
ebone_dst = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
return OPERATOR_PASS_THROUGH;
}
ebone_isect_child[0] = ebone_src;
ebone_isect_child[1] = ebone_dst;
/* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */
if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) {
/* pass */
}
else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) {
SWAP(EditBone *, ebone_src, ebone_dst);
}
else if ((ebone_isect_parent = ED_armature_bone_find_shared_parent(ebone_isect_child, 2))) {
/* pass */
}
else {
/* disconnected bones */
return OPERATOR_CANCELLED;
}
if (ebone_isect_parent) {
if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) &&
armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true))
{
armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false);
armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false);
change = true;
}
else {
/* unselectable */
change = false;
}
}
else {
if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) {
armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false);
change = true;
}
else {
/* unselectable */
change = false;
}
}
if (change) {
arm->act_edbone = ebone_dst;
ED_armature_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
return OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain");
return OPERATOR_CANCELLED;
}
}
void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Pick Shortest Path";
ot->idname = "ARMATURE_OT_shortest_path_pick";
ot->description = "Select shortest path between two bones";
/* api callbacks */
ot->invoke = armature_shortest_path_pick_invoke;
ot->poll = ED_operator_editarmature;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}

View File

@ -156,6 +156,47 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
return false;
}
/**
* Finds the first parent shared by \a ebone_child
*
* \param ebone_child Children bones to search
* \param ebone_child_tot Size of the ebone_child array
* \return The shared parent or NULL.
*/
EditBone *ED_armature_bone_find_shared_parent(EditBone *ebone_child[], const unsigned int ebone_child_tot)
{
unsigned int i;
EditBone *ebone_iter;
#define EBONE_TEMP_UINT(ebone) (*((unsigned int *)(&((ebone)->temp))))
/* clear all */
for (i = 0; i < ebone_child_tot; i++) {
for (ebone_iter = ebone_child[i]; ebone_iter; ebone_iter = ebone_iter->parent) {
EBONE_TEMP_UINT(ebone_iter) = 0;
}
}
/* accumulate */
for (i = 0; i < ebone_child_tot; i++) {
ebone_iter = ebone_child[i];
for (ebone_iter = ebone_child[i]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
EBONE_TEMP_UINT(ebone_iter) += 1;
}
}
/* only need search the first chain */
for (ebone_iter = ebone_child[0]->parent; ebone_iter; ebone_iter = ebone_iter->parent) {
if (EBONE_TEMP_UINT(ebone_iter) == ebone_child_tot) {
return ebone_iter;
}
}
#undef EBONE_TEMP_UINT
return NULL;
}
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3])
{
float delta[3];

View File

@ -138,6 +138,7 @@ struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *na
void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child);
EditBone *ED_armature_bone_find_shared_parent(EditBone *ebone_child[], const unsigned int ebone_child_tot);
void ED_armature_ebone_to_mat3(EditBone *ebone, float mat[3][3]);
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4]);