1-- The centroid and the three medians of a triangle.2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Geometry.Centroid8import Parallelogram910namespace Euclidean11exportopen Euclidean1213-- Affine balance, including collinear and collapsed triangles.14predicate Centroid (g a b c : Set) :=15 x(g) + x(g) + x(g) = x(a) + x(b) + x(c) ∧16 y(g) + y(g) + y(g) = y(a) + y(b) + y(c)1718def centroid (a b c : Set) : Set:=19 (third(x(a) + x(b) + x(c)),20 third(y(a) + y(b) + y(c)))2122-- Directed displacement AG is twice GM. This identity also allows A = G = M;23-- interpreting a quotient of nonzero lengths requires nondegeneracy separately.24predicate MedianRatio (a g m : Set) :=25 x(g) - x(a) = (x(m) - x(g)) + (x(m) - x(g)) ∧26 y(g) - y(a) = (y(m) - y(g)) + (y(m) - y(g))2728theorem centroid.point (a b c : Point)29shows Point(centroid(a, b, c))30proof31unfold centroid32exact pair.point with*3334theorem centroid.correct (a b c : Point)35shows Centroid(centroid(a, b, c), a, b, c)36proof37have horizontal := x.pair at third(x(a) + x(b) + x(c)), third(y(a) + y(b) + y(c)) with*38have vertical := y.pair at third(x(a) + x(b) + x(c)), third(y(a) + y(b) + y(c)) with*39have tripleX := third.add_self at x(a) + x(b) + x(c) with*40have tripleY := third.add_self at y(a) + y(b) + y(c) with*41constructor42 . unfold centroid43cc44 . unfold centroid45cc4647theorem centroid.rotate (a b c g : Point)48requires center : Centroid(g, a, b, c)49shows Centroid(g, b, c, a)50proof51rcases center with⟨horizontal, vertical⟩52constructor53 . linear_combination horizontal54 . linear_combination vertical5556theorem centroid.unique (a b c g h : Point)57requires first : Centroid(g, a, b, c)58requires second : Centroid(h, a, b, c)59shows g = h60proof61rcases first with⟨firstX, firstY⟩62rcases second with⟨secondX, secondY⟩63have tripledX : x(g) + x(g) + x(g) = x(h) + x(h) + x(h) bycc64have tripledY : y(g) + y(g) + y(g) = y(h) + y(h) + y(h) bycc65have horizontal := realAddValue.triple_cancel at x(g), x(h) with*66have vertical := realAddValue.triple_cancel at y(g), y(h) with*67exact point.ext with*6869theorem centroid.median_ratio (a b c g m : Point)70requires center : Centroid(g, a, b, c)71requires middle : Midpoint(m, b, c)72shows MedianRatio(a, g, m)73proof74rcases center with⟨centerX, centerY⟩75rcases middle with⟨middleX, middleY⟩76constructor77 . linear_combination centerX + middleX78 . linear_combination centerY + middleY7980theorem medianRatio.collinear (a g m : Point)81requires ratio : MedianRatio(a, g, m)82shows Collinear(a, g, m)83proof84unfold Collinear85unfold directionCross86rcases ratio with⟨horizontal, vertical⟩87linear_combination (y(m) - y(g)) * horizontal - (x(m) - x(g)) * vertical8889-- The public median argument uses affine balance and midpoint facts only.90theorem centroid.medians (a b c g m n p : Point)91requires center : Centroid(g, a, b, c)92requires first : Midpoint(m, b, c)93requires second : Midpoint(n, c, a)94requires third : Midpoint(p, a, b)95shows MedianRatio(a, g, m) ∧ MedianRatio(b, g, n) ∧ MedianRatio(c, g, p)96proof97have rotated := centroid.rotate with*98have again := centroid.rotate at b, c, a, g with*99have firstRatio := centroid.median_ratio at a, b, c, g, m with*100have secondRatio := centroid.median_ratio at b, c, a, g, n with*101have thirdRatio := centroid.median_ratio at c, a, b, g, p with*102refine⟨firstRatio, secondRatio, thirdRatio⟩103104theorem centroid.concurrency (a b c m n p : Point)105requires first : Midpoint(m, b, c)106requires second : Midpoint(n, c, a)107requires third : Midpoint(p, a, b)108shows∃ g, Point(g) ∧ Centroid(g, a, b, c) ∧109 Collinear(a, g, m) ∧ Collinear(b, g, n) ∧ Collinear(c, g, p)110proof111have point := centroid.point at a, b, c with*112have center := centroid.correct at a, b, c with*113have ratios := centroid.medians with*114rcases ratios with⟨firstRatio, secondRatio, thirdRatio⟩115have firstLine := medianRatio.collinear at a, centroid(a, b, c), m with*116have secondLine := medianRatio.collinear at b, centroid(a, b, c), n with*117have thirdLine := medianRatio.collinear at c, centroid(a, b, c), p with*118refine⟨centroid(a, b, c), point, center, firstLine, secondLine, thirdLine⟩119120-- The directed 2:1 relation implies the corresponding squared-length identity.121theorem medianRatio.length (a g m : Point)122requires ratio : MedianRatio(a, g, m)123shows Euclidean.distanceSquared(a, g) =124 Euclidean.distanceSquared(g, m) + Euclidean.distanceSquared(g, m) +125 Euclidean.distanceSquared(g, m) + Euclidean.distanceSquared(g, m)126proof127rcases ratio with⟨horizontal, vertical⟩128have doubledX : (x(m) - x(g)) + (x(m) - x(g)) = x(g) - x(a)129 symm130exact horizontal131have doubledY : (y(m) - y(g)) + (y(m) - y(g)) = y(g) - y(a)132 symm133exact vertical134have squareX := realMulValue.square_of_double at x(m) - x(g), x(g) - x(a) with*135have squareY := realMulValue.square_of_double at y(m) - y(g), y(g) - y(a) with*136have long := Euclidean.distanceSquared.coordinates at a, g with*137have short := Euclidean.distanceSquared.coordinates at g, m with*138rw [long, short, squareX, squareY]139ring140141theorem centroid.repeated (a : Point)142shows centroid(a, a, a) = a143proof144have point := centroid.point with*145have first := centroid.correct at a, a, a with*146have second : Centroid(a, a, a, a)147constructor148 . rfl149 . rfl150exact centroid.unique with*151152end Euclidean153