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