Triangle centers and formulas
Centroid, incenter, circumcenter, orthocenter, excenters, area from sides, angles and medians — all , all built from cross, dot and `PD`. Non-degenerate triangles only (collinear input makes several of these divide by zero).
PD centroid(P a, P b, P c) { return (toPD(a) + toPD(b) + toPD(c)) * (1.0 / 3); }
PD circumcenter(P a, P b, P c) {
PD ab = toPD(b - a), ac = toPD(c - a);
double d = 2 * cross(ab, ac);
PD o = {ac.y * norm2(ab) - ab.y * norm2(ac), ab.x * norm2(ac) - ac.x * norm2(ab)};
return toPD(a) + o * (1.0 / d);
}
PD circumcenter(PD a, PD b, PD c) { // same, when the vertices are already floating (e.g. mid-Welzl)
PD ab = b - a, ac = c - a;
double d = 2 * cross(ab, ac);
PD o = {ac.y * norm2(ab) - ab.y * norm2(ac), ab.x * norm2(ac) - ac.x * norm2(ab)};
return a + o * (1.0 / d);
}
PD orthocenter(P a, P b, P c) {
PD o = circumcenter(a, b, c);
return toPD(a) + toPD(b) + toPD(c) - o * 2;
}
PD incenter(P a, P b, P c) {
double la = dist(b, c), lb = dist(a, c), lc = dist(a, b);
return (toPD(a) * la + toPD(b) * lb + toPD(c) * lc) * (1.0 / (la + lb + lc));
}
PD excenter(P a, P b, P c) { // opposite a
double la = dist(b, c), lb = dist(a, c), lc = dist(a, b);
return (toPD(b) * lb + toPD(c) * lc - toPD(a) * la) * (1.0 / (lb + lc - la));
}
double inradius(P a, P b, P c) {
double la = dist(b, c), lb = dist(a, c), lc = dist(a, b);
return fabs((double)cross(a, b, c)) / (la + lb + lc);
}
double circumradius(P a, P b, P c) {
double la = dist(b, c), lb = dist(a, c), lc = dist(a, b);
return la * lb * lc / (2 * fabs((double)cross(a, b, c)));
}
double heron(double a, double b, double c) { // area from side lengths, -1 if impossible
array<double, 3> s = {a, b, c};
sort(s.rbegin(), s.rend()); // x >= y >= z
auto [x, y, z] = s;
if (z < 0 || x > y + z) return -1;
return sqrt(max(0.0, (x + (y + z)) * (z - (x - y)) * (z + (x - y)) * (x + (y - z)))) / 4;
}
double angleFromSides(double a, double b, double c) { // angle opposite side a
return acos(max(-1.0, min(1.0, (b * b + c * c - a * a) / (2 * b * c))));
}
double medianLength(double a, double b, double c) { // median to side a
return sqrt(max(0.0, 2 * b * b + 2 * c * c - a * a)) / 2;
}| Identity | Statement |
|---|---|
| Euler line | collinear, |
| Euler’s triangle formula | (so always , equality only for equilateral) |
| Area | , |
| Incenter | weighted average of vertices by the opposite side lengths |
Proof: centroid, orthocenter and the Euler line
Centroid is immediate from the definition (average of the vertices), and it is the common point of the three medians because the median from meets at its midpoint , and … more directly: the point lies on segment from to at parameter from (check: ), and symmetrically on the other two medians, so all three medians meet there, at the point from each vertex.
Orthocenter. Place the circumcenter temporarily at the coordinate origin, so . Let . Then , and , so : the line is the altitude from . By the same argument for and , lies on all three altitudes, so is the orthocenter. Undoing the shift (origin at ) gives , i.e. , which is exactly the code above.
Euler line. With and : . In particular are collinear (one is an affine combination of the other two along the same line) whenever .
Proof: inradius, circumradius, Heron, and the incenter weighted average
Inradius. The incircle touches all three sides, so it splits the triangle into three sub-triangles each with height (the inradius) over base respectively. Summing their areas: . Solving for with gives , matching the code (the code’s denominator is , and the numerator is , so the factor of 2 cancels).
Circumradius. By the law of sines, for every triangle (standard: inscribe the triangle in its circumcircle, the central angle subtending side is by the inscribed angle theorem, and the chord length is ). Also , so . Substituting: , i.e. , matching the code with .
Heron. The classical form is with ; substituting and factoring in terms of directly (Kahan’s rearrangement, sorting first) gives exactly , algebraically the same product but grouped so that each factor is a sum of non-negative quantities when and the triangle inequality holds — avoiding the catastrophic cancellation that , , can suffer for needle-shaped triangles. The classical identity itself follows from Heron’s derivation via the law of cosines: , then , which expands to the same quartic.
Incenter. By the angle bisector theorem, the bisector from meets at the point with , i.e. . The incenter lies on (it lies on every angle bisector), and by the angle bisector theorem applied in triangle to the bisector from — or directly by mass-point reasoning, placing mass at is inconsistent with the first ratio unless we place mass proportional to the opposite side at each vertex — one checks does lie on segment : substituting above, , a convex combination of and , confirming . The same check on the other two cevians (by the symmetric form of the same expression) confirms is their common point.
Proof: Euler's triangle formula
Let be the second intersection of line (the bisector from ) with the circumcircle — the midpoint of arc not containing . The incenter-excenter lemma: is equidistant from , , and , i.e. . (Proof of the lemma: since both subtend arc ; and is the external angle of triangle at… more directly, is an exterior angle of triangle equal to , while using (inscribed angle on arc ); so , making triangle isosceles with , and symmetrically .)
Now apply the power of the point with respect to the circumcircle along the chord through : (negative since is inside the circle, with the two intersection lengths measured as positive on opposite sides… using the signed/unsigned convention for inside). So .
Compute (drop the perpendicular of length from to side ; the angle at in that right triangle is ). Compute (chord subtends inscribed angle … using subtending the same arc , chord by the extended law of sines). Then .
Hence . Since , this also proves Euler’s inequality , with equality iff iff the triangle is equilateral.
Tested: circumcenter/incenter/centroid/orthocenter coincide for an equilateral triangle; orthocenter satisfies the Euler line relation on 10 random triangles; inradius/circumradius satisfy area = inradius * s = circumradius-based abc/(4R) matching the shoelace area; heron matches the shoelace area; medianLength matches the direct distance from a vertex to the opposite midpoint; angleFromSides matches the atan2(|cross|,dot) angle of Primitives; Euler’s formula checked numerically on random triangles.