1
$\begingroup$

I need to move a bone like these pictures.

enter image description here enter image description here

There are two long bones,and in edit mode I need to put the small bone's head exactly on the place where two long bones crossed. I tried to use edge snap mode, but it didn't work. Do you know how?

$\endgroup$

1 Answer 1

2
$\begingroup$

Most of this work is knowing the coordinates to be moved. However, with the exception of the head and tail, it is rare for two bones to share exactly one point. So instead of the shared point, I decided to find for the closest one to the two bones. The following script will move the 3D cursor to the expected coordinates, then snap the destination bone to the cursor yourself.

import bpy

def closest_point_between_two_lines(va1, vb1, va2, vb2):

    from mathutils import Vector, Matrix
    
    va = [va1, va2]
    vs = [(vb1 - va1).normalized(), (vb2 - va2).normalized()]

    ma = Matrix([
                [vs[0] @ vs[0], -vs[1] @ vs[0]],
                [vs[0] @ vs[1], -vs[1] @ vs[1]]
                ])

    if not ma.determinant():
        raise

    vc = Vector([(va[0]-va[1]) @ vs[0], 
                 (va[0]-va[1]) @ vs[1]])

    # where, C + A @ R = 0
    vr = -1 * ma.inverted() @ vc
    
    vp = [0]*2
    for i in range(2):
        vp[i] = va[i] + vr[i] * vs[i]

    return 0.5 * (vp[0] + vp[1])



obj = bpy.context.object
bones = obj.data.edit_bones
bone1 = bones[0]
bone2 = bones[1]

pos = closest_point_between_two_lines(
                    bone1.head, bone1.tail, 
                    bone2.head, bone2.tail
                    )

bpy.context.scene.cursor.location = obj.matrix_world @ pos

I won't go into the details of my function, but you can find something similar with keyword "closest point between two lines".

Edit

Sorry, the desired function has already been provided in the mathutils module.
mathutils.geometry.intersect_line_line(lineA_p1, lineA_p2, lineB_p1, lineB_p2)


import mathutils
poss = mathutils.geometry.intersect_line_line(
                    bone1.head, bone1.tail, bone2.head, bone2.tail
                    )

pos = (poss[0] + poss[1]) /2
bpy.context.scene.cursor.location = obj.matrix_world @ pos
$\endgroup$
6
  • $\begingroup$ I used your script but 3D cursor is little bit away from the crossover point, why? $\endgroup$
    – Yokomizo
    Nov 25, 2022 at 11:15
  • $\begingroup$ @Yokomizo Maybe I forgot to convert to world coordinates. Edited $\endgroup$
    – tetii
    Nov 25, 2022 at 11:57
  • $\begingroup$ it works, but I have to say, I think your script only see 1st and 2nd bones of an armature, so if armature has lots of bones your script won't work. $\endgroup$
    – Yokomizo
    Nov 25, 2022 at 12:17
  • $\begingroup$ I guess this kinda thing is needed? It works. bones = [] for b in bpy.context.selected_editable_bones: bones.append(b) bone1 = bones[0] bone2 = bones[1] pos = closest_point_between_two_lines( bone1.head, bone1.tail, bone2.head, bone2.tail ) bpy.context.scene.cursor.location = bpy.context.object.matrix_world @ pos $\endgroup$
    – Yokomizo
    Nov 25, 2022 at 12:40
  • $\begingroup$ @Yokomizo Unfortunately It's impossible for me to know which pair of bones you want to use. The rest of the work is yours. $\endgroup$
    – tetii
    Nov 25, 2022 at 12:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .