raw Math

Three distinct, non-collinear points determine exactly one circle. They form a triangle, and the circle is its circumcircle. The center is the only point whose distance from all three vertices is equal.

Circle through three points A triangle with vertices P1, P2, and P3 lies on a circle. Two perpendicular bisectors meet at the circle center C. P1 P2 P3 C r
The perpendicular bisectors meet at the circumcenter \(\mathbf{C}\), which is equally distant from all three points.

Start with Equal Distances

Let the given points be \(\mathbf{P}_1\), \(\mathbf{P}_2\), and \(\mathbf{P}_3\). A center \(\mathbf{C}\) must satisfy

\[ \lVert\mathbf{C}-\mathbf{P}_1\rVert^2 =\lVert\mathbf{C}-\mathbf{P}_2\rVert^2 =\lVert\mathbf{C}-\mathbf{P}_3\rVert^2. \]

Translate the coordinate system so that \(\mathbf{P}_1\) becomes the origin. Define

\[ \mathbf{u}=\mathbf{P}_2-\mathbf{P}_1, \qquad \mathbf{v}=\mathbf{P}_3-\mathbf{P}_1, \qquad \mathbf{w}=\mathbf{C}-\mathbf{P}_1. \]

Equal distance from \(\mathbf{P}_1\) and \(\mathbf{P}_2\) now means

\[ \lVert\mathbf{w}\rVert^2=\lVert\mathbf{w}-\mathbf{u}\rVert^2. \]

Expand the right-hand side:

\[ \mathbf{w}\cdot\mathbf{w} =\mathbf{w}\cdot\mathbf{w}-2\mathbf{w}\cdot\mathbf{u}+\mathbf{u}\cdot\mathbf{u}. \]

The quadratic terms cancel, leaving the linear equation

\[ 2\mathbf{w}\cdot\mathbf{u}=\lVert\mathbf{u}\rVert^2. \]

Repeating the same argument with \(\mathbf{P}_3\) gives

\[ 2\mathbf{w}\cdot\mathbf{v}=\lVert\mathbf{v}\rVert^2. \]

Geometrically, these are the perpendicular bisectors of \(\overline{P_1P_2}\) and \(\overline{P_1P_3}\). Algebraically, they form a \(2\times2\) linear system:

\[ 2 \begin{pmatrix} u_x & u_y\\ v_x & v_y \end{pmatrix} \begin{pmatrix}w_x\\w_y\end{pmatrix} = \begin{pmatrix} \lVert\mathbf{u}\rVert^2\\ \lVert\mathbf{v}\rVert^2 \end{pmatrix}. \]

Solve the Linear System

The determinant

\[ D=\mathbf{u}\perp\mathbf{v}=u_xv_y-u_yv_x \]

is twice the signed area of triangle \(P_1P_2P_3\). It is nonzero exactly when the three points are not collinear. Applying the inverse of the \(2\times2\) matrix yields

\[ \boxed{ w_x=\frac{\lVert\mathbf{u}\rVert^2v_y-\lVert\mathbf{v}\rVert^2u_y}{2D}, \qquad w_y=\frac{u_x\lVert\mathbf{v}\rVert^2-v_x\lVert\mathbf{u}\rVert^2}{2D} }. \]

Thus the circle is

\[ \boxed{ \mathbf{C}=\mathbf{P}_1+\mathbf{w}, \qquad r=\lVert\mathbf{w}\rVert }. \]

The translation is useful beyond shortening the formula: intermediate values depend on coordinate differences rather than on large absolute coordinates squared.

Compact Vector Form

For \(\mathbf{a}=(a_x,a_y)\), let \(\mathbf{a}^{\perp}=(-a_y,a_x)\) denote a counterclockwise quarter turn. The same result can be written as

\[ \boxed{ \mathbf{w}= \frac{\lVert\mathbf{v}\rVert^2\mathbf{u}^{\perp} -\lVert\mathbf{u}\rVert^2\mathbf{v}^{\perp}} {2(\mathbf{u}\perp\mathbf{v})} }. \]

This form exposes the geometry: the center offset is assembled from directions perpendicular to the two chords. It also avoids the vertical-line singularities that appear when perpendicular bisectors are expressed through slopes.

Degenerate and Ill-Conditioned Cases

If two input points coincide, one of the direction vectors is zero and three distinct constraints are not available. If all three points are collinear, \(D=0\); no finite circle passes through them unless duplicate points reduce the problem to fewer constraints, in which case the circle is not unique.

Nearly collinear points do define a circle, but its center and radius can be extremely far away. The construction is then ill-conditioned: small coordinate errors can cause large output changes. A practical implementation should compare

\[ \frac{|\mathbf{u}\perp\mathbf{v}|}{\lVert\mathbf{u}\rVert\lVert\mathbf{v}\rVert} =|\sin\theta| \]

with an application-appropriate tolerance instead of testing the determinant against an absolute constant.

JavaScript Implementation

function circleThroughThreePoints(point1, point2, point3, epsilon = 1e-12) {
  const values = [
    point1.x, point1.y,
    point2.x, point2.y,
    point3.x, point3.y,
    epsilon
  ];

  if (!values.every(Number.isFinite) || epsilon < 0) {
    throw new TypeError("Point coordinates and epsilon must be finite and epsilon non-negative");
  }

  const vectorU = {
    x: point2.x - point1.x,
    y: point2.y - point1.y
  };
  const vectorV = {
    x: point3.x - point1.x,
    y: point3.y - point1.y
  };
  const lengthU = Math.hypot(vectorU.x, vectorU.y);
  const lengthV = Math.hypot(vectorV.x, vectorV.y);
  const length23 = Math.hypot(
    point3.x - point2.x,
    point3.y - point2.y
  );

  if (lengthU === 0 || lengthV === 0 || length23 === 0) {
    throw new RangeError("The three points must be distinct");
  }

  const determinant = vectorU.x * vectorV.y - vectorU.y * vectorV.x;
  if (Math.abs(determinant) <= epsilon * lengthU * lengthV) {
    throw new RangeError("The three points must not be collinear");
  }

  const squaredU = lengthU * lengthU;
  const squaredV = lengthV * lengthV;
  const offsetX = (squaredU * vectorV.y - squaredV * vectorU.y) /
    (2 * determinant);
  const offsetY = (vectorU.x * squaredV - vectorV.x * squaredU) /
    (2 * determinant);

  return {
    x: point1.x + offsetX,
    y: point1.y + offsetY,
    r: Math.hypot(offsetX, offsetY)
  };
}

For \(P_1=(3,2)\), \(P_2=(1,4)\), and \(P_3=(5,4)\), the function returns the center \((3,4)\) and radius \(2\).

For production use, Circle.js provides fromThreePoints(p1, p2, p3) alongside circle intersection, area, and measurement operations.