Search code examples
pythonpython-3.xangle

Could I get a clarification to this Python code below?


I'm a beginner to Python and I'm trying to calculate the angles (-26.6 &18.4) for this figure below and so on for the rest of the squares by using Python code.

Angle range

I have found the code below and I'm trying to understand very well. How could it work here? Any clarification, please?

Python Code:

def computeDegree(a,b,c):
    babc = (a[0]-b[0])*(c[0]-b[0])+(a[1]-b[1])*(c[1]-b[1])

    norm_ba = math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
    norm_bc = math.sqrt((c[0]-b[0])**2 + (c[1]-b[1])**2)
    norm_babc = norm_ba * norm_bc

    radian = math.acos(babc/norm_babc)
    degree = math.degrees(radian)
    return round(degree, 1)

def funcAngle(p, s, sn):
    a = (s[0]-p[0], s[1]-p[1])
    b = (sn[0]-p[0], sn[1]-p[1])
    c = a[0] * b[1] - a[1] * b[0]

    if p != sn:
        d = computeDegree(s, p, sn)
    else:
        d = 0

    if c > 0:
        result = d
    elif c < 0:
        result = -d
    elif c == 0:
        result = 0
    return result

p = (1,4)
s = (2,2)
listSn= ((1,2),(2,3),(3,2),(2,1))

for sn in listSn:
    func(p,s,sn)

The results

I expected to get the angles in the picture such as -26.6, 18.4 ...


Solution

  • Essentially, this uses the definition of dot products to solve for the angle. You can read more it at this link (also where I found these images).

    Vector Graph

    To solve for the angle you first need to convert your 3 input points into two vectors.

    # Vector from b to a
    # BA = (a[0] - b[0], a[1] - b[1])
    BA = a - b
    
    # Vector from b to c
    # BC = (a[0] - c[0], a[1] - c[1])
    BC = c - b
    

    Dot Product Formulas

    Using the two vectors you can then find the angle between them by first finding the value of the dot product with the second formula.

    # babc = (a[0]-b[0])*(c[0]-b[0])+(a[1]-b[1])*(c[1]-b[1])
    dot_product = BA[0] * BC[0] + BA[1] * BC[1]
    

    Then by going back to the first definition, you can divide off the lengths of the two input vectors and the resulting value should be the cosine of the angle between the vectors. It may be hard to read with the array notation but its just using the Pythagoras theorem.

    # Length/magnitude of vector BA
    # norm_ba = math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
    length_ba = math.sqrt(BA[0]**2 + BA[1]**2)
    
    # Length/magnitude of vector BC
    # norm_bc = math.sqrt((c[0]-b[0])**2 + (c[1]-b[1])**2)
    length_bc = math.sqrt(BC[0]**2 + BC[1]**2)
    
    # Then using acos (essentially inverse of cosine), you can get the angle
    # radian = math.acos(babc/norm_babc)
    angle = Math.acos(dot_product / (length_ba * length_bc))
    

    Most of the other stuff is just there to catch cases where the program might accidentally try to divide by zero. Hopefully this helps to explain why it looks the way it does.

    Edit: I answered this question because I was bored and didn't see harm in explaining the math behind that code, however in the future try to avoid asking questions like 'how does this code work' in the future.