Circle-Line
Circle centre , radius ; line through with direction .
The method
- Find the foot of the perpendicular from to the line.
- Compare its distance to : greater no intersection; equal tangent; less two points.
- Step along the line by in both directions.
vector<PD> circleLine(PD c, double r, PD a, PD b) {
PD d = b - a;
double t = dot(c - a, d) / norm2(d); // parameter of the foot
PD foot = a + d * t;
double distSq = norm2(foot - c);
if (distSq > r * r + EPS) return {}; // no intersection
double h = sqrt(max(0.0, r * r - distSq)) / abs_(d);
if (h < EPS) return {foot}; // tangent
return {foot - d * h, foot + d * h};
}For a segment
Compute the line intersections, then keep only those with parameter — equivalently, check `onSegment`-style dot(p-a,p-b) <= 0 for each candidate point.
Exact tests without constructing points
Many questions do not need the intersection points at all:
| Question | Exact test |
|---|---|
| Does the line meet the circle? | |
| Is the line tangent? | equality above |
| Is point inside the circle? | |
| Does the segment meet the circle? | [[19-geometry/01-primitives |
| Is the circle entirely inside a polygon? | centre inside and distance to every edge |
With integer input these are all exact — no epsilon required. Prefer them.
Proof: the squared line-distance test
up to sign, where is the perpendicular distance from to the line (the cross product is base height of the parallelogram spanned by and , proved in Primitives). So , and “the line meets the circle” is , i.e. , i.e. — the stated test, with every quantity a sum of integer products when the input is integral.
Chord length
where is the distance from the centre to the line. The circular segment cut off has area
which is what you need for circle-polygon intersection areas.
Proof: chord length and segment area
The half-chord has length by Pythagoras in the right triangle formed by the centre, the foot of the perpendicular, and one chord endpoint (hypotenuse , one leg ) — doubling gives . The half-angle subtended at the centre by the half-chord satisfies (adjacent over hypotenuse in the same right triangle), giving . The segment’s area is the circular sector’s area () minus the triangle formed by the centre and the two chord endpoints (, since that triangle is isosceles with the two radius sides and included angle ) — giving .
Circle-polygon intersection area
A standard and genuinely useful routine: the area of the intersection of a circle with a polygon. Decompose the polygon into triangles from the circle’s centre, and for each triangle compute the signed circle-triangle intersection area:
- both points inside the whole triangle;
- both outside and the edge misses the circle a circular sector;
- otherwise a mixture of sectors and triangles, split at the chord intersections (found by
circleLineabove).
Sum with signs (using the cross product orientation) and the outside parts cancel — the same principle as the shoelace formula. The full case analysis, generalised to a union of circles, is its own note.
Numerical care
Tangency is fragile
distSq == r*ralmost never holds exactly in floating point. Usemax(0.0, r*r - distSq)before the square root to avoidNaNfrom a tiny negative value, and treat as tangency.
If the input is integral, do the decision in exact integers and only then construct the points in floating point.
Related constructions
| Task | Method |
|---|---|
| Circle through 3 points | intersect two perpendicular bisectors — circumcenter |
| Circle through 2 points with radius | midpoint perpendicular offset |
| Circle-circle intersection | radical line, then circle-line |
| Tangent lines from a point | Tangents |
| Smallest circle enclosing points | Welzl |
| Point on the circle nearest to |
Circle-Circle
Circles and with .
The cases
| Condition | Result |
|---|---|
| separate — 0 points | |
| externally tangent — 1 point | |
| 2 points | |
| , | internally tangent — 1 point |
| one inside the other — 0 points | |
| , | identical — infinitely many |
Test with squared distances to stay exact: compare against and .
The construction
Both intersection points lie on the radical line, perpendicular to . Let
Then the base point is with , and the intersections are .
vector<PD> circleCircle(PD c1, double r1, PD c2, double r2) {
PD u = c2 - c1;
double d2 = norm2(u), d = sqrt(d2);
if (d < EPS) return {}; // concentric
if (d > r1 + r2 + EPS) return {};
if (d < fabs(r1 - r2) - EPS) return {};
double a = (d2 + r1 * r1 - r2 * r2) / (2 * d);
double h2 = r1 * r1 - a * a;
PD base = c1 + u * (a / d);
if (h2 < EPS) return {base}; // tangent
double h = sqrt(h2);
PD perpU = perp(u) * (h / d);
return {base - perpU, base + perpU};
}Proof: the circle-circle construction
Place the intersection point so , . Writing for the unit vector along (so is the component along the centre line and perpendicular to it): and . Subtracting: , matching the formula; then from the first equation. Both signs of give the two intersection points (or the one tangent point when ), and the three early-return cases are exactly the case table’s non-2-point conditions (concentric, separate too far, or one strictly inside the other), each checked with the equivalent squared-distance comparison.
Tested: circleLine and circleCircle’s returned points checked to lie on both input curves (distance to each centre matches its radius within ) and matched against a fine brute-force sweep along the line / around one circle for the number and approximate location of intersections, across all cases in both tables (0, 1, 2 intersections, tangent, concentric, nested).
The radical line and radical centre
The radical axis of two circles is the locus of points with equal power to both:
Setting the two powers equal gives a line (the terms cancel):
For three circles the three radical axes meet at the radical centre — the point from which tangent lengths to all three are equal. This is the clean way to solve “find the point equidistant in tangent length” problems, and it reduces circle problems to line intersections.
Proof: the radical axis is a line, and the radical centre exists
. Expanding , the terms on both sides cancel, leaving , i.e. — linear in , hence a line (or empty/everything only in the degenerate case ). For three circles, the three pairwise radical axes (of , , ) satisfy: a point on both the and axes has and , hence also — automatically on the axis too. So the three lines are concurrent (or all parallel, in the degenerate case of collinear centres) at a single radical centre, where the tangent length to all three circles is equal.
Areas
Lens (intersection) area of two overlapping circles:
with and symmetrically for (swap the roles of ).
Proof: the lens area
The lens is the union of two circular segments, one cut from each circle by the radical line (the common chord). The segment from circle 1 has half-angle given by where is the same quantity from the circle-circle construction above (the signed distance along to the chord’s foot) — substituting gives , and doubling the half-angle formula (the standard identity relates this to the form stated) gives as written. The segment area formula from above applies to each side, and the two segments together exactly tile the lens (they meet precisely at the common chord, with no gap or overlap, since both circles’ boundaries bound the lens on their respective sides of the chord).
Union of circles: for each circle, walk its boundary and determine which arcs are not covered by any other circle; then apply a Green’s-theorem-style sum over arcs and chords. — see 13-circle-union-and-angular-sweep.
Related constructions
| Task | Method |
|---|---|
| Circle through 3 points | perpendicular bisectors, or the determinant formula |
| Circle tangent to 2 circles with radius | intersect circles of radii and |
| Apollonius circle | the locus with |
| Common tangent lines | Tangents |
| Circle inversion | maps circles and lines to circles and lines |
| Smallest enclosing circle | Welzl |
Precision
Near-tangency
When is close to , is a tiny difference of large numbers and loses most of its significant digits. Always clamp with
max(0.0, h2)before the square root, and decide the case using exact integer comparisons on squared quantities when the input is integral.
Circle Inversion
Inversion in a circle : maps points, and circles / lines to circles / lines, turning tangency problems into line problems.
PD invertPoint(PD p, PD o, double r) { PD d = p - o; return o + d * (r * r / norm2(d)); } // |oq| * |op| = r^2, p != o
// image of a circle (center c, radius rc): {isLine, c2, r2, a, b}
// isLine: the circle passed through o and the image is the line through a, b; else the image is circle (c2, r2)
tuple<bool, PD, double, PD, PD> invertCircle(PD c, double rc, PD o, double r) {
PD d = c - o;
double dist = abs_(d);
if (fabs(dist - rc) < 1e-9) { // circle through o -> line
PD u = d * (1.0 / dist);
PD far = invertPoint(o + u * (2 * rc), o, r); // the antipode of o maps to the closest point of the image line
PD pr = perp(u);
return {true, PD{}, 0, far, far + pr};
}
PD u = d * (1.0 / dist);
PD p1 = invertPoint(o + u * (dist - rc), o, r), p2 = invertPoint(o + u * (dist + rc), o, r);
return {false, (p1 + p2) * 0.5, abs_(p1 - p2) * 0.5, PD{}, PD{}};
}
pair<PD, double> invertLine(PD a, PD b, PD o, double r) { // image of a line not through o: a circle through o
PD ab = b - a;
PD foot = a + ab * (dot(o - a, ab) / norm2(ab)); // closest point of the line to o
PD img = invertPoint(foot, o, r); // farthest point of the image circle from o
return {(o + img) * 0.5, abs_(img - o) * 0.5};
}Complexity: . Circles through the centre become lines and vice versa; tangency and angles are preserved. Typical use: circles tangent to two circles through a common point (Apollonius-like problems) become lines tangent to two circles (common tangents), then invert back.
Proof:
invertPoint,invertCircle,invertLine
invertPoint. By definition, inversion sends to the point on ray with : where , — simplifying , exactly the code.
invertCircle— the line case. A circle through has as one of its own points; every other point on it inverts to some image point, and since inversion maps circles-and-lines to circles-and-lines, and a “circle through ” has no well-defined inverse image AT (inversion isn’t defined at the center), the image must be the degenerate case: a line. That line is perpendicular to (by the general conformal/symmetry property of inversion: the image of a curve symmetric about line is itself symmetric about the same line, and a circle through is symmetric about ; a line symmetric about that doesn’t pass through must be perpendicular to it) and passes through the inverted image of the circle’s farthest point from (the antipode , at distance from along the circle’s diameter through ) — this farthest point maps, under inversion, to the closest point of the image line to (inversion reverses near/far along each ray), which is exactly the foot of the perpendicular from to the image line — so that single inverted point plus the perpendicular directionperp(u)fully determines the image line, matching the code’sfarandfar + pr.
invertCircle— the circle case. A circle not through is still symmetric about line , so its image (itself a circle, by inversion’s general circle/line-preservation property) is also symmetric about , hence centred on it. The two points of the original circle that lie exactly on line — at distances and from — invert to the two points of the image circle that also lie on , which (being symmetric about the image’s own centre) are exactly the image circle’s own diameter endpoints on that line. So the image centre is their midpoint and the image radius is half their distance, exactly the code’s final return.
invertLine. A line not through inverts to a circle through (the reverse of the first case, by the involutive symmetry of inversion — applying it twice returns the original). The point of the line closest to (the foot of the perpendicular) is on the line of symmetry through perpendicular to the original line, and inverts to the point of the image circle farthest from along that same line — i.e. the diametrically opposite point from on the image circle. So and that inverted point are the two endpoints of a diameter, giving the image centre as their midpoint and radius as half their distance — exactly the code.
Tested: invertPoint is self-inverse (invertPoint(invertPoint(p,o,r),o,r) == p) and preserves ; invertCircle and invertLine checked by sampling many points on the original circle/line, inverting each individually with invertPoint, and confirming they all lie on the claimed image circle or line (and that the two routines are mutual inverses: inverting the image of a circle-through- as a line, then inverting that line back, recovers the original circle).