Given the center, radius, and 3 points on a circle, I want to draw an arc that starts at the first point, passes through the second, and ends at the third by specifying the angle to start drawing and the amount of angle to rotate. To do this, I need to calculate the points on the arc. I want the number of points calculated to be variable so I can adjust the accuracy of the calculated arc. This means I probably need a loop that calculates each point by rotating a little after it has calculated a point. I've read the answer to this question Draw arc with 2 points and center of the circle but it only solves the problem of calculating the angles because I don't know how 'canvas.drawArc' is implemented.
1 Answers
This question has two parts:
- How to find the arc between two points that passes a third point?
- How to generate a set of points on the found arc?
Let's start with first part. Given three points A
, B
and C
on the (O, r)
circle we want to find the arc between A
and C
that passes through B
. To find the internal angle of the arc we need to calculate the oriented angles of AB
and AC
arcs. If angle of AB
was greater than AC
, we are in wrong direction:
Va.x = A.x - O.x;
Va.y = A.y - O.y;
Vb.x = B.x - O.x;
Vb.y = B.y - O.y;
Vc.x = C.x - O.x;
Vc.y = C.y - O.y;
tb = orientedAngle(Va.x, Va.y, Vb.x, Vb.y);
tc = orientedAngle(Va.x, Va.y, Vc.x, Vc.y);
if tc<tb
tc = tc - 2 * pi;
end
function t = orientedAngle(x1, y1, x2, y2)
t = atan2(x1*y2 - y1*x2, x1*x2 + y1*y2);
if t<0
t = t + 2 * pi;
end
end
Now the second part. You said:
I probably need a loop that calculates each point by rotating a little after it has calculated a point.
But the question is, how little? Since the perimeter of the circle increases as its radius increase, you cannot reach a fixed accuracy with a fixed angle. In other words, to draw two arcs with the same angle and different radii, we need a different number of points. What we can assume to be [almost] constant is the distance between these points, or the length of the segments we draw to simulate the arc:
segLen = someConstantLength;
arcLen = abs(tc)*r;
segNum = ceil(arcLen/segLen);
segAngle = tc / segNum;
t = atan2(Va.y, Va.x);
for i from 0 to segNum
P[i].x = O.x + r * cos(t);
P[i].y = O.y + r * sin(t);
t = t + segAngle;
end
Note that although in this method A
and C
will certainly be created, but point B
will not necessarily be one of the points created. However, the distance of this point from the nearest segment will be very small.

- 5,717
- 8
- 47
- 78
-
Why do I need to calculate the oriented angles? Can't I just calculate the dot product of Va, Vb and just divide the result by the product of the lengths of Va and Vb? I would then get the cos value of the angle, so I can then use acos to get the actual angle. – palapapa Jan 04 '21 at 08:10
-
2@palapapa Dot product method will give you the (smaller) internal angle of two vectors, and eventually the shortest possible arc between two points. However, sometimes `B` lies on the longer arc between `A` and `C`, just like the image in my answer. So we need a measurement that gives both direction and (angular) distance. – saastn Jan 04 '21 at 08:40
-
I don't understand why are you adding 2pi to t if it's negative. Shouldn't an oriented angle range from -pi to pi? Are you trying to get the counterclockwise angle from A to B and C? Or are you trying to make the comparison easier to write? If I'm understanding this correctly, the reason why I can't use the dot product method is because then I wouldn't be able to tell if the angle from A to B and the angle from A to C are of the same orientation. So by using oriented angles and adding 2pi to the result if the result is negative, if tb > tc then the counterclockwise rotation is wrong. – palapapa Jan 04 '21 at 13:11
-
2@pala Let me explain in my words. There is no should for rang of angles. In a trigonometric circle, the angle `a` is equal to `a+2*pi`. On the other hand, the negative value of the anti-clockwise angle is actually a positive clockwise angle. By adding it to `2*pi`, I guarantee that the output of the function is always positive, without changing the angle. Now that we are sure that both the `tb` and `tc` angles are positive and in the same side of `A`, we can safely compare them to see if we move in this direction, we will first reach `B` or `C`. If we reach `C` first, we reverse the direction. – saastn Jan 04 '21 at 13:17