14

I have write down a code to calculate angle between three points using their 3D coordinates.

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 

output of the code:

degree 33.4118214995

but when i used one of the software to calculate the same it gives output bit different 120 degree. please help

reference i have used to write the program:

(How to calculate bond angle in protein db file?)

3
  • 1.) You need to subtract the same point to get the vectors you are looking for (see answer to your other question). 2.) You have to normalize the vectors (that's something else than subtraction!) 3.) what other software did you use? 4.) There are python scripts avaiable at google where you can compare your solution to. Commented Feb 3, 2016 at 12:34
  • 5.) You need to use the inverse of the cosine function (acos or arccos). 6.) You have no idea what your code does, right? :) Commented Feb 3, 2016 at 12:37
  • @kazemakase yes you are right before writing the code i just follow the steps mentioned in the reference that i have added but now a read a lot and have idea what is going on. Actually i m not from the mathematics background :) Commented Feb 4, 2016 at 5:17

4 Answers 4

39

Your original code is pretty close. Adomas.m's answer is not very idiomatic 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)
Sign up to request clarification or add additional context in comments.

2 Comments

thanks Eric for your great help. kindly explain what is going on in line 10 (cosine_angle = -----), and how this code is more idiomatic numpy than adomas.m. I am very new in python. thanks
More idiomatic because of dot and array division, and because important everything into the global namespace (from x import *) is generally frowned upon. The variables in the other answer are poorly named, Division distributes over dot product, so dot(ba / q, bc / r) == dot(ba, bc) / (q * r), which also has the bonus of being faster
1

I guess numpy is quite enough:

    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

also the res can be calculated with dot:

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

4 Comments

thanks for the correction you have made. Kindly explain the lines from 10-13 if possible it would be great thanks a lot .
array([f[0] / abVec, f[1] / abVec, f[2] / abVec]) is better spelt f / abVec
Thanks Eric...adding to answer.
jax lines 10-13 means that vectors ab and bc are normalized and the distance between those are found which then with the help of arccos translates to angle. Maybe someone has a more detailed and elaborate explanation :)
0

For 2D, you can use this method using the math library.

 import math
 
def getAngle(a, b, c):
    ang = math.degrees(math.atan2(c[1]-b[1], c[0]-b[0]) - math.atan2(a[1]-b[1], a[0]-b[0]))
    return ang + 360 if ang < 0 else ang
 
print(getAngle((5, 0), (0, 0), (0, 5)))

Credits: https://manivannan-ai.medium.com/find-the-angle-between-three-points-from-2d-using-python-348c513e2cd

Comments

0

In case you have a big list of (x,y,z) coordinates, this works:

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

Above, a,b,c are presumed to be of shape (N_Points, 3). Something in TensorFlow or Torch would surely be faster, but there you go.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.