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.)