使用三个点的3D坐标计算它们之间夹角的Python代码

13

我已经编写了一段代码,用于计算三个点之间的夹角,使用它们的三维坐标。

import  numpy as np

a = np.array([32.49, -39.96,-3.86])

b = np.array([31.39, -39.28, -4.66])

c = np.array([31.14, -38.09,-4.49])

f = a-b # normalization of vectors
e = b-c # normalization of vectors

angle = dot(f, e) # calculates dot product 
print degrees(cos(angle))  # calculated angle in radians to degree 

代码输出结果:

degree 33.4118214995

但当我使用其中一个软件计算时,它给出了略微不同的输出:120度。请帮忙。

我用来编写程序的参考资料:

(如何在蛋白质db文件中计算键角?)


1.) 你需要减去相同的点才能得到你要找的向量(请参见你其他问题的答案)。 2.) 你必须对向量进行归一化处理(这与减法不同!) 3.) 你使用了哪些其他软件? 4.) 在谷歌上有Python脚本可供比较你的解决方案。 - MSeifert
5.) 你需要使用反余弦函数(acos或arccos)。 6.) 你不知道你的代码在做什么,对吧? :) - MB-F
@kazemakase 是的,你说得对,在编写代码之前,我只是按照我添加的参考文献中提到的步骤进行操作,但现在我已经阅读了很多资料,对正在发生的事情有了一些想法。实际上,我不是数学背景出身的 :) - jax
4个回答

38

你的原始代码已经非常接近了。Adomas.m的答案在numpy中不太符合习惯用法:

import numpy as np

a = np.array([32.49, -39.96,-3.86])
b = np.array([31.39, -39.28, -4.66])
c = np.array([31.14, -38.09,-4.49])

ba = a - b
bc = c - b

cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)

print np.degrees(angle)

感谢Eric的大力帮助。请解释一下第10行代码(cosine_angle = ------)正在发生什么,并且这段代码如何比adomas.m更符合numpy习惯。我在Python方面非常新手。谢谢。 - jax
1
由于使用了“点”和数组除法,代码更加惯用。此外,将所有内容都导入全局命名空间(from x import *)通常是不被赞同的。另一个答案中的变量命名不佳。除法分配到点积上,因此 dot(ba / q, bc / r) == dot(ba, bc) / (q * r),这也具有更快的速度。 - Eric

1

我猜numpy已经足够了:

    from numpy import *
    from numpy.linalg import norm
    a = array([32.49, -39.96,-3.86])
    b = array([31.39, -39.28, -4.66])
    c = array([31.14, -38.09,-4.49])
    f = b-a 
    e = b-c 
    abVec = norm(f)
    bcVec = norm(e)
    abNorm = f / abVec;
    bcNorm = e / bcVec;
    res = abNorm[0] * bcNorm[0] + abNorm[1] * bcNorm[1] + abNorm[2] * bcNorm[2];
    angle = arccos(res)*180.0/ pi
    print angle

同时,可以使用点运算符计算 res:

    res = abNorm[0] * bcNorm[0] + abNorm[1] * bcNorm[1] + abNorm[2] * bcNorm[2];
    res = dot(abNorm, bcNorm)

感谢您所做的更正。如果可能的话,请解释一下第10-13行,这将非常棒,非常感谢。 - jax
array([f[0] / abVec, f[1] / abVec, f[2] / abVec]) 更好的写法是 f / abVec - Eric
谢谢Eric...补充回答。 - adomas.m
jax的10-13行代码意味着向量ab和bc被归一化,并找到它们之间的距离,然后借助反余弦函数得出角度。也许有人有更详细和精细的解释 :) - adomas.m

0

0
如果你有一个大的(x,y,z)坐标列表,可以这样做:
import numpy
def compute_angle_between_3d_points(a,b,c):
    ba = a - b
    bc = c - b

    cosine_numerator = np.sum(ba*bc, axis=1)
    cosine_denominator_1 = np.linalg.norm(ba, axis=1)
    cosine_denominator_2 = np.linalg.norm(bc, axis=1)
    cosine_angle = cosine_numerator / (cosine_denominator_1 * cosine_denominator_2)
    angles = np.arccos(cosine_angle)
    degree_angles = np.rad2deg(angles)

    return degree_angles

假设a、b、c的形状为(N_Points,3)。在TensorFlow或Torch中使用一些东西肯定会更快,但这就是现状。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接