1
votes

I'm making a python script right now that is trying to find the length of an arc, where it given this information:

center of arc: x1, y1

start point of arc: x2, y2

end point of arc: x3, y3

direction, cw, ccw

so far I have been able to successfully calculate the radius, and I tried calculating the angle using the equation:

equation for angle

But for any arcs that have an angle greater than 1*pi or 180 degrees, it returns the incorrect (but correct) inside angle.

What is the correct equation knowing the radius and these three points that I can use to find the value of the angle of the arc from 0 rad/degrees to 360 degrees/2pi radians, going in either the clockwise or counterclockwise direction (it can be either or and I need to be able to calculate for both scenarios)

Code:

# code to find theta
aVector = np.array([x1 - x2, y1 - y2])
bVector = np.array([x1 - x3, y1 - y3])
aMag = np.linalg.norm(aVector)
bMag = np.linalg.norm(aVector)
theta = np.arcos(np.dot(aVector, bVector) / (aMag * bMag))

as you can see here, I'm using arccos which to my dismay only outputs 0-180 degrees

Solution/Working code:

# equation for angle using atan2
start = math.atan2(y2 - y1, x2 - x1)
end = math.atan2(y3 - y1, x3 - x1)
if gcodeAnalysis[tempLineNum][4] == "G3": # going CW
    start, end = end, start
tau = 2.0 * math.pi
theta = math.fmod(math.fmod(end - start, tau) + tau, tau)

Working Values:

X1 = 0.00048399999999998444
Y1 = 0.0002720000000007161
X2 = 0.378484
Y2 = -14.694728
X3 = 3.376
Y3 = -14.307

Proper result/value

Theta = 6.077209477545957

Assume this arc was done CCW

2
unfortunately the equation isn't fine, as arccos measures inside angle and I need total angle, but I will add my codeAlex Jones
Which is positive, cw or ccw?Mad Physicist
np.linalg.norm[aVector] is definitely a typoMad Physicist
Your radius computation looks nonsensical. Is it even relevant to the question?Mad Physicist
I'll go by right hand rule (I think I am at least in saying so) and say CCW is positiveAlex Jones

2 Answers

1
votes

As you noticed, the range of math.acos is [0, pi], making it rather useless for telling you the relative directions of the vectors. To get full circular information about a pair of angles, you can use math.atan2. While regular math.atan has a range of [-pi/2, pi/2], atan2 splits the inputs into two parts and returns an angle in the range (-pi, pi]. You can compute the angles relative to any reference, not necessarily relative to each other:

start = math.atan2(y2 - y1, x2 - x1)
end = math.atan2(y3 - y1, x3 - x1)

Now you can use some common formulae to find the difference between the angles in whatever direction you want. I've implemented some of these in a small utility library I made called haggis. The specific function you want is haggis.math.ang_diff_pos.

First, the "manual" computation:

if direction == 'cw':
    start, end = end, start
tau = 2.0 * math.pi
angle = math.fmod(math.fmod(end - start, tau) + tau, tau)

If you want to use my function, you can do

if direction == 'cw':
    start, end = end, start
angle = ang_diff_pos(start, end)

All of these operations can be easily vectorized using numpy if you find yourself dealing with many points all at once.

0
votes

You can use the cross product of the two vector to determine if the two vector need to rotate clock or counter-clock wise.

See code below:


import numpy as np
from numpy import linalg as LA


x1 = 0
y1 = 0
x2 = 2
y2 = 0
x3 = 2
y3 = -2
dir = 'ccw' # or ccw 

v1 = np.array([x2-x1,y2-y1])
v2 = np.array( [x3-x1,y3-y1])

# if the cross product is positive, then the two vector need to rotate counter clockwise
rot = np.cross(v1,v2)
vdir = 'ccw' if rot >0 else 'cw'

r = (v1[0]*v2[0]+v1[1]*v2[1])/(LA.norm(v1)*LA.norm(v2))

deg = np.arccos(r)/np.pi*180

if vdir != dir:
    deg = 360 -deg

print(deg)