raw math

Create a circle out of three points

Robert Eisele

A circle is a set of infinite points in two dimensions. However, a circle is clearly described by three of such points. The opposite direction is also correct as long as not all three points are on a straight line.

CC
rr
P1P_1
P2P_2
P3P_3

The question now is, how can we find the center CC and radius rr of a circle, given three points P1,P2P_1, P_2 and P3P_3? Typically, a circle at position (x,y)(x', y') with radius rr' can be described with the equation

(xx)2+(yy)2=r2(x-x')^2+(y-y')^2=r'^2

When multiplied out, we get the following form:

1=a(x2+y2)+(2x)=bx+(2y)=cy+(x2+y2r2)=d=0\underbrace{1}_{=a} \cdot (x^2 + y^2) + \underbrace{(- 2x')}_{=b}x + \underbrace{( - 2y')}_{=c}y + \underbrace{(x'^2 + y'^2 - r'^2)}_{=d} = 0

From which is clear, that we can parametrize a circle in the general way with

a(x2+y2)+bx+cy+d=0a(x^2+y^2)+bx+cy+d=0

If we now bring the given points P1,P2P_1, P_2 and P3P_3 with their points (x1,y1),(x2,y2)(x_1, y_1), (x_2, y_2) and (x3,y3) (x_3, y_3) in the following set of equations:

x2+y2xy1x12+y12x1y11x22+y22x2y21x32+y32x3y31=0\left|\begin{array}{cccc} x^2+y^2 & x & y & 1\\ x_1^2+y_1^2 & x_1 & y_1 & 1\\ x_2^2+y_2^2 & x_2 & y_2 & 1\\ x_3^2+y_3^2 & x_3 & y_3 & 1\\ \end{array}\right| = 0

it can be shown, that the circle can be parametrized using Laplace expansion as follows:

a=x1y11x2y21x3y31,b=x12+y12y11x22+y22y21x32+y32y31,c=x12+y12x11x22+y22x21x32+y32x31,d=x12+y12x1y1x22+y22x2y2x32+y32x3y3 a = \left|\begin{array}{ccc} x_1 & y_1 & 1\\ x_2 & y_2 & 1\\ x_3 & y_3 & 1\\ \end{array}\right|, b = -\left|\begin{array}{ccc} x_1^2 + y_1^2 & y_1 & 1\\ x_2^2 + y_2^2 & y_2 & 1\\ x_3^2 + y_3^2 & y_3 & 1\\ \end{array}\right|, c = \left|\begin{array}{ccc} x_1^2 + y_1^2 & x_1 & 1\\ x_2^2 + y_2^2 & x_2 & 1\\ x_3^2 + y_3^2 & x_3 & 1\\ \end{array}\right|, d = -\left|\begin{array}{ccc} x_1^2 + y_1^2 & x_1 & y_1\\ x_2^2 + y_2^2 & x_2 & y_2\\ x_3^2 + y_3^2 & x_3 & y_3\\ \end{array}\right|

After solving the determinants, we get the following equations:

a=x1(y2y3)y1(x2x3)+x2y3x3y2b=(x12+y12)(y3y2)+(x22+y22)(y1y3)+(x32+y32)(y2y1)c=(x12+y12)(x2x3)+(x22+y22)(x3x1)+(x32+y32)(x1x2)d=(x12+y12)(x3y2x2y3)+(x22+y22)(x1y3x3y1)+(x32+y32)(x2y1x1y2)\begin{array}{rl} a =& x_1(y_2-y_3)-y_1(x_2-x_3)+x_2y_3-x_3y_2\\ b =& (x_1^2+y_1^2)(y_3-y_2)+(x_2^2+y_2^2)(y_1-y_3)+(x_3^2+y_3^2)(y_2-y_1)\\ c =& (x_1^2+y_1^2)(x_2-x_3)+(x_2^2+y_2^2)(x_3-x_1)+(x_3^2+y_3^2)(x_1-x_2)\\ d =& (x_1^2+y_1^2)(x_3y_2-x_2y_3)+(x_2^2+y_2^2)(x_1y_3-x_3y_1)+(x_3^2+y_3^2)(x_2y_1-x_1y_2) \end{array}

The center CC with its coordinate (x,y)(x,y) and radius rr, calculated by the three points (x1,y1),(x2,y2)(x_1, y_1), (x_2, y_2) and (x3,y3)(x_3, y_3) is now:

x=(x12+y12)(y2y3)+(x22+y22)(y3y1)+(x32+y32)(y1y2)2(x1(y2y3)y1(x2x3)+x2y3x3y2)=b2ay=(x12+y12)(x3x2)+(x22+y22)(x1x3)+(x32+y32)(x2x1)2(x1(y2y3)y1(x2x3)+x2y3x3y2)=c2ar=(xx1)2+(yy1)2=b2+c24ad4a2\begin{array}{rll} x =& \frac{(x_1^2+y_1^2)(y_2-y_3)+(x_2^2+y_2^2)(y_3-y_1)+(x_3^2+y_3^2)(y_1-y_2)}{2(x_1(y_2-y_3)-y_1(x_2-x_3)+x_2y_3-x_3y_2)} &= -\frac{b}{2a}\\ y =& \frac{(x_1^2+y_1^2)(x_3-x_2)+(x_2^2+y_2^2)(x_1-x_3)+(x_3^2+y_3^2)(x_2-x_1)}{2(x_1(y_2-y_3)-y_1(x_2-x_3)+x_2y_3-x_3y_2)} &= -\frac{c}{2a}\\ r =& \sqrt{(x-x_1)^2 + (y-y_1)^2} &= \sqrt{\frac{b^2+c^2-4ad}{4a^2}} \end{array}

This top-down attempt works totally fine and can be implemeted straight ahead and is now part of Circle.js.

function circleFromThreePoints(p1, p2, p3) {

  var x1 = p1.x;
  var y1 = p1.y;
  var x2 = p2.x;
  var y2 = p2.y;
  var x3 = p3.x;
  var y3 = p3.y;

  var a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2;

  var b = (x1 * x1 + y1 * y1) * (y3 - y2) 
        + (x2 * x2 + y2 * y2) * (y1 - y3)
        + (x3 * x3 + y3 * y3) * (y2 - y1);
 
  var c = (x1 * x1 + y1 * y1) * (x2 - x3) 
        + (x2 * x2 + y2 * y2) * (x3 - x1) 
        + (x3 * x3 + y3 * y3) * (x1 - x2);
 
  var x = -b / (2 * a);
  var y = -c / (2 * a);

  return {
    x: x,
    y: y,
    r: Math.hypot(x - x1, y - y1)
  };
}

Geometric solution

An alternative way of deriving the solution is this: If we draw a line aa through points P1P_1 and P2P_2 and another line bb through points P2P_2 and P3P_3, it is obvious that their perpendicular lines crossing them at the middle of the points will meet exactly in the midpoint of the circle. The problem with this approach is, that the slope of the lines is ma=y2y1x2x1m_a = \frac{y_2-y_1}{x_2-x_1} and mb=y3y2x3x2 m_b = \frac{y_3-y_2}{x_3-x_2}. Therefore for the lines ya=ma(xx1)+y1y_a = m_a (x - x_1) + y_1 and yb=mb(xx2)+y2y_b=m_b(x-x_2)+y_2 and their perpendicular counter parts

ya=1ma(xx1+x22)+y1+y22yb=1mb(xx2+x32)+y2+y32\begin{array}{rl} y_{a'} = -\frac{1}{m_a}\left(x-\frac{x_1+x_2}{2}\right) + \frac{y_1+y_2}{2}\\ y_{b'} = -\frac{1}{m_b}\left(x-\frac{x_2+x_3}{2}\right) + \frac{y_2+y_3}{2}\\ \end{array}

we have discontinuities as long as we don't simplify the equation for x=mamb(y1y3)+mb(x1+x2)ma(x2+x3)2(mbma)x =\frac{m_am_b(y_1-y_3) + m_b(x_1 + x_2) - m_a(x_2 + x_3)}{2(m_b-m_a)}, which we got by setting the two equations equal. If we simplify the equations with Wolframalpha, we arrive at the same equations as as with the determinant solution.