Determining Rational Quadratic Bezier Curve Weights for Circle

I am trying to create a spherical interpolation with 3 points. I'm currently using Quadratic Bezier Interpolation but have been told I should use Rational Quadratic Bezier Curve in order to get a perfectly circular curve. I have tried implementing this based on the formula I found here (3 control points A,B and C, 3 weights W1, W2, W3 and a time t):

CurvePoint = (A*W1*(1-t)^2 + B*W2*2t(1-t) + C*W3*t^2) / (W1*(1-t)^2 + W2*2t(1-t) + W3*t^2).

How do I determine the correct weight values for this to work as a circle? Is that even possible without moving the middle point? Thank you.

Here is the code I am using (with all weights set to 1.0) and the curve it produces:

def ArcPoints(node):
points = node.GetAllPoints()

# The three points of the point object
a, b, c = points[:3]

samples = 6
arcPoints = list()
for i in range(samples):
t = float(i)/(samples - 1)
w1 = 1
w2 = 1
w3 = 1
p2 = (a * w1 * (1-t) ** 2 + b * w2 * 2*t * (1-t) + c * w3 * t ** 2 ) / (w1 * (1-t) ** 2 + w2 * 2*t * (1-t) + w3 * t**2)
arcPoints.append(p)

return arcPoints • Have you read this Oct 19 '20 at 12:22
• Thanks for the comment. I haven't read the document, but I saw it in my research. I'm in a bit of a time crunch so more specificity to my issue would be greatly appreciated (in code would be even better). I don't understand mathematic symbols very well. Have you read it? If so, where does it answer how to set 3-point circular Bezier weights? Oct 20 '20 at 0:07

Check out the section on Circular Arcs and Circles, from Ching-Kuang Shene's excellent computational geometry course notes:

[G]iven three control points P0, P1 and P2 such that P0P1 = P1P2 holds, if we choose w, the weight for P1, to be sin(a), where a is the half angle at control point P1, the resulting rational Bézier curve is a circle.

The second diagram on that page is particularly useful. If P0 is at (0,0), P1 is at (1,0), and P2 is at (1,1), then the angle at P1 is 90 degrees; half that is 45, so assigning weights w0 = w2 = 1 and w1 = sin(45) = 1/sqrt(2) will produce a circle.

EDIT: To actually implement this from your code: The three points are [a,b,c]. If you know that the distance from a to b is the same as the distance from b to c, then you can set w1 and w3 to 1, and w2 to the sine of half the angle between them. Look up the half-angle formula for sine to see that sin(x/2) = sqrt((1 - cos x) / 2). The cosine of the angle between two vectors is the normalized dot product, i.e. cos x = dot(a-b,c-b) / (a-b)^2. Thus, you can do something like

ba = a - b
bc = c - b
cosx = ba.Dot(bc) / ba.Dot(ba);
w2 = math.sqrt(0.5 * (1 - cosx));

Again, this will only work if the distances ba and bc are the same. (You can still make a circle otherwise, but the weights will be more compilcated.)

• Thank you! Please excuse my ignorance, but what do I use in my code from this equation: w1 = sin(45) = 1/sqrt(2)? Having the two equal signs confuses me: is it saying that the sin(45) == 1/sqrt(2)? Oct 21 '20 at 1:28
• Yes, I was just pointing out that the sine of 45 degrees is one over the square root of two. You'd probably just write w1 = 1 / sqrt(2). Oct 21 '20 at 7:17
• Thanks for the reply. Where is the angle variable in that equation? Wouldn't w1 = sin(x) be better for a program? Maybe I'm not understanding correctly. Oct 21 '20 at 18:23
• You can still make a circle if the distances ba and bc are different?? I don’t think so. Apr 17 '21 at 11:03