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.
Distaces from points to Circle center
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.