Monocurl Essays
Series Download

The inscribed angle theorem and Thales' semicircle

From every point on one arc of a circle, a chord is seen under the same angle, half the angle at the center. Two isosceles triangles explain why.

25 min·High school·

AssumesWhy the angles of a triangle add to 180°The Pythagorean theorem: a proof you can see

A point $P$ travels around a circle while two points $A$ and $B$ on the circle stay fixed. The lengths $PA$ and $PB$, measured in radii, change all the time. The angle at $P$ stays at 50°.
Monocurl source
let A = on(220)
let B = on(320)
let View = |t| {
    let P = on(t)
    return [
        AngleMark(P, A, B, AZURE, 0.6),
        Path([A, P, B], AZURE, 4),
        Pt(P, AZURE, 0.1),
        Name("P", out(t), 0.95, AZURE),
        center{[2.35, 0.95, 0]} scale{1.6} color{AZURE} Number(rad_to_deg(angle_at(P, A, B)), 1),
        center{[2.35, -0.4, 0]} scale{1.15} color{SLATE} Number(norm(A - P) / R, 2),
        center{[2.35, -1.5, 0]} scale{1.15} color{SLATE} Number(norm(B - P) / R, 2)
    ]
}
mesh circle = Round(O, R)
mesh chord = [
    Seg(A, B, INK, 4),
    Pt(A, INK, 0.09),
    Pt(B, INK, 0.09),
    Name("A", out(220), 0.95),
    Name("B", out(320), 0.95)
]
mesh view = View(t: 25)
mesh labels = [
    center{[2.35, 1.55, 0]} Note("angle at P, in degrees", 0.74),
    center{[2.35, 0.05, 0]} Note("length of PA", 0.74),
    center{[2.35, -1.05, 0]} Note("length of PB", 0.74)
]

slide "walk"
    play Wait(1)
    view.t = 165
    play Lerp(4.5, [&view])
    play Wait(0.8)
    view.t = 105
    play Lerp(2, [&view])
    play Wait(2)

Uses the shared definitions for this lesson's figures.

Two posts, $A$ and $B$, stand on the rim of a circular pond. Walk along the rim and keep looking at them. As you go, one post comes nearer and the other recedes, and the triangle you form with them changes from tall to squat to lopsided. In the animation the two distances swing between about one radius and nearly the full width of the pond. Through all of it the angle between your two lines of sight, the angle at $P$, does not move from 50°.

Nothing in the triangle $APB$ looks constant except that one angle. Why should it be? And why 50°, when the posts could have been placed anywhere?

Is it the circle that matters?

One reaction is to doubt that the circle has much to do with it. Perhaps the angle under which you see two posts simply does not depend much on where you stand. That is easy to test: step off the rim.

The point $P$ moves along a straight path from inside the circle to outside it. The angle at $P$ is larger than 55° inside the circle, smaller outside, and equal to 55° only at the moment $P$ crosses the circle.
Monocurl source
let C = [-1.5, -0.6, 0]
let r = 1.4
let A = C + r * dir(rad(215))
let B = C + r * dir(rad(325))
let rim = C + r * dir(rad(75))
let Probe = |d| {
    let P = C + d * r * dir(rad(75))
    var col = ROSE
    if (abs(d - 1) < 0.012) {
        col = LEAF
    }
    return [
        AngleMark(P, A, B, col, 0.45),
        Path([A, P, B], col, 4),
        Pt(P, col, 0.1),
        center{[2.35, 0.75, 0]} scale{1.6} color{col} Number(rad_to_deg(angle_at(P, A, B)), 1)
    ]
}
mesh circle = Round(C, r)
mesh track = Seg(C + 0.3 * r * dir(rad(75)), C + 1.9 * r * dir(rad(75)), MIST, 2.5)
mesh chord = [
    Seg(A, B, INK, 4),
    Pt(A, INK, 0.09),
    Pt(B, INK, 0.09),
    Name("A", A + [-0.3, -0.12, 0], 0.95),
    Name("B", B + [0.3, -0.12, 0], 0.95)
]
mesh probe = Probe(d: 0.35)
mesh labels = [
    center{[2.35, 1.4, 0]} Note("angle at P, in degrees", 0.74),
    center{[2.35, -0.5, 0]} Note("at a point on the circle", 0.74),
    Name(Deg(angle_at(rim, A, B), 1), [2.35, -1.05, 0], 1.0, LEAF)
]

slide "cross"
    play Wait(0.8)
    probe.d = 1
    play Lerp(2.4, [&probe])
    play Wait(1.2)
    probe.d = 1.85
    play Lerp(2.4, [&probe])
    play Wait(0.8)
    probe.d = 1
    play Lerp(1.6, [&probe])
    play Wait(1.6)

Uses the shared definitions for this lesson's figures.

The angle is far from constant. Close to the posts it is wide, far away it is narrow, and it passes through every value in between. The circle through $A$ and $B$ is the exact boundary on which it takes one particular value, in this case 55°. So the circle is doing something precise, and we need to find out what.

The smallest case: a diameter

The plan is to start with the most symmetric arrangement and understand it completely. Put the two posts at opposite ends of a diameter.

To have numbers to work with, use coordinates. Take the circle of radius 5 centered at the origin, with $A = (-5, 0)$ and $B = (5, 0)$. The point $(3, 4)$ is on this circle, because $3^2 + 4^2 = 25$.

Pause and try

Let $P = (3, 4)$. Compute $PA^2$, $PB^2$ and $AB^2$ with the distance formula. What does the converse of the Pythagorean theorem (if $a^2 + b^2 = c^2$ in a triangle, the angle opposite $c$ is a right angle) say about triangle $APB$? Then repeat with $P = (-4, 3)$.

Show answerHide answer

For $P = (3, 4)$: $PA^2 = (3 + 5)^2 + 4^2 = 80$ and $PB^2 = (3 - 5)^2 + 4^2 = 20$, while $AB^2 = 10^2 = 100$. Since $80 + 20 = 100$, the converse of the Pythagorean theorem says the angle opposite $AB$, which is the angle at $P$, is a right angle. For $P = (-4, 3)$: $PA^2 = 1 + 9 = 10$ and $PB^2 = 81 + 9 = 90$, and again $10 + 90 = 100$.

Three points on a circle of radius 5 whose diameter AB lies along the x-axis. For each one, PA^2 + PB^2 comes to exactly 100 = AB^2, so each triangle has a right angle at the point on the circle.
Three points on a circle of radius 5 whose diameter $AB$ lies along the $x$-axis. For each one, $PA^2 + PB^2$ comes to exactly $100 = AB^2$, so each triangle has a right angle at the point on the circle.
Monocurl source
let fr = Frame(-6, 6, -0.6, 5.8, [0, -0.3, 0], 6.6, 3.52)
let A = at(fr, -5, 0)
let B = at(fr, 5, 0)
let PTS = [[-4, 3], [0, 5], [3, 4]]
let COLS = [EMBER, PLUM, AZURE]
mesh grid = GridLines(fr, range(-6, 7), range(1, 6))
mesh axes = [Axes(fr), XTicks(fr, [-4, -2, 2, 4]), YTicks(fr, [1, 3])]
mesh arc = Path(map(sample(0, PI, 96), |t| at(fr, 5 * cos(t), 5 * sin(t))), SLATE, 3)
mesh tris = block {
    for (i in range(0, 3)) {
        let P = at(fr, PTS[i][0], PTS[i][1])
        . Path([A, P, B], COLS[i], 3.5)
        . Square90(P, normalize(A - P), normalize(B - P), COLS[i], 0.2)
        . Pt(P, COLS[i], 0.09)
    }
}
mesh base = [Seg(A, B, INK, 4.5), Pt(A, INK, 0.09), Pt(B, INK, 0.09)]
mesh labels = block {
    for (i in range(0, 3)) {
        let x = PTS[i][0]
        let y = PTS[i][1]
        let pa = (x + 5) ^ 2 + y ^ 2
        let pb = (x - 5) ^ 2 + y ^ 2
        . Name(str_join([to_string(pa), " + ", to_string(pb), " = ", to_string(pa + pb)]), [2.35 * (i - 1), 1.9, 0], 0.85, COLS[i])
    }
    . Name("A", A + [-0.05, -0.33, 0], 0.9)
    . Name("B", B + [0.05, -0.33, 0], 0.9)
    . Name("(-4, 3)", at(fr, -4, 3) + [-0.55, 0.2, 0], 0.76, EMBER)
    . Name("(0, 5)", at(fr, 0, 5) + [0.6, 0.22, 0], 0.76, PLUM)
    . Name("(3, 4)", at(fr, 3, 4) + [0.5, 0.25, 0], 0.76, AZURE)
}

Uses the shared definitions for this lesson's figures.

All three points give right angles, and the algebra shows this is no accident of the chosen points. If $P = (x, y)$ is any point of the circle, so that $x^2 + y^2 = 25$, then

$$ PA^2 + PB^2 = (x + 5)^2 + y^2 + (x - 5)^2 + y^2 = 2(x^2 + y^2) + 50 = 100. $$

So the angle at $P$ is always 90°. That settles the fact, but a calculation in which the terms $10x$ and $-10x$ cancel does not show why. The reason is in the one thing a circle gives us for free: every point on it is the same distance from the center.

Draw the segment from the center $O$ to $P$. It has the same length as $OA$ and $OB$, since all three are radii, and it cuts the triangle $APB$ into two triangles that each have two equal sides.

  1. A triangle APB whose side AB is a diameter of the circle. We want the angle at P.
  2. Draw the radius OP. Now OA, OP and OB are three radii, all of the same length r.
  3. Triangle AOP has two equal sides, so its angles at A and at P are equal. Call each of them α.
  4. Triangle BOP also has two equal sides. Call its equal angles β.
  5. The angles of triangle APB are α at A, β at B and α + β at P. They add to 180°, so α + β is 90°.
The proof that an angle standing on a diameter is a right angle. The radius $OP$ cuts triangle $APB$ into two isosceles triangles, and the angle sum of triangle $APB$ then forces the angle at $P$ to be 90°.
Monocurl source
let A = on(180)
let B = on(0)
let P = on(62)
mesh circle = Round(O, R)
mesh fills = []
mesh marks = []
mesh lines = [Outline([A, B, P], INK, 3.5)]
mesh radius = []
mesh names = [
    Name("A", out(180), 0.95),
    Name("B", out(0), 0.95),
    Name("P", out(62), 0.95),
    Name("O", O + [0, 0.3, 0], 0.95),
    Pt(O, INK, 0.08)
]
mesh greek = [Name("?", inside(P, A, B, 0.55), 1.1, ROSE)]
mesh ask = [Name("\angle APB = \,?", [2.4, 0, 0], 1.0, ROSE)]
mesh panel = []

slide "A triangle APB whose side AB is a diameter of the circle. We want the angle at P."
    play Fade(0.6)

slide "Draw the radius OP. Now OA, OP and OB are three radii, all of the same length r."
    ask = []
    greek = []
    play Fade(0.3)
    radius = [
        Seg(O, P, LEAF, 4),
        Name("r", 0.5 * (O + A) + [0, -0.25, 0], 0.9, LEAF),
        Name("r", 0.5 * (O + B) + [0, -0.25, 0], 0.9, LEAF),
        Name("r", O + 0.3 * (P - O) + [0.25, -0.05, 0], 0.9, LEAF)
    ]
    panel = [Name("OA = OP = OB", [2.4, 1.4, 0], 0.9, LEAF)]
    play Fade(0.6)

slide "Triangle AOP has two equal sides, so its angles at A and at P are equal. Call each of them α."
    fills = [Region([A, O, P], tint(AZURE, 0.3))]
    marks = [AngleMark(A, O, P, AZURE, 0.6), AngleMark(P, A, O, AZURE, 0.6)]
    greek = [
        Name("\alpha", inside(A, O, P, 0.9), 0.9, AZURE),
        Name("\alpha", inside(P, A, O, 0.9), 0.9, AZURE)
    ]
    panel .= Name("\angle A = \alpha", [2.4, 0.7, 0], 0.9, AZURE)
    play Fade(0.6)

slide "Triangle BOP also has two equal sides. Call its equal angles β."
    fills .= Region([B, O, P], tint(EMBER, 0.3))
    marks .= AngleMark(B, O, P, EMBER, 0.45)
    marks .= AngleMark(P, O, B, EMBER, 0.45)
    greek .= Name("\beta", inside(B, O, P, 0.68), 0.9, EMBER)
    greek .= Name("\beta", inside(P, O, B, 0.68), 0.9, EMBER)
    panel .= Name("\angle B = \beta", [2.4, 0.1, 0], 0.9, EMBER)
    play Fade(0.6)

slide "The angles of triangle APB are α at A, β at B and α + β at P. They add to 180°, so α + β is 90°."
    panel .= Name("\angle P = \alpha + \beta", [2.4, -0.5, 0], 0.9)
    panel .= Name("\alpha + \beta = 90^\circ", [2.4, -1.3, 0], 1.05, LEAF)
    play Fade(0.6, [&panel])

Uses the shared definitions for this lesson's figures.

The figure uses one fact about triangles with two equal sides. A triangle with two equal sides is called isosceles, and its angles opposite the equal sides are equal. (This is Euclid’s Proposition 5 of Book I. One way to see it: flip the triangle over so that the two equal sides trade places. It lands exactly on itself, so the two angles at the base trade places as well, and must be equal.)

Tradition credits the theorem to Thales of Miletus, who lived around 600 BC.

The converse, and a rectangle

The theorem has a converse, and the neatest way to see both at once is to complete the picture. Continue the radius $PO$ through the center to the opposite point $P'$ of the circle.

The diameter AB and a second diameter PP'. The four-sided figure APBP' has diagonals of equal length that cut each other in half at O, and it is a rectangle.
The diameter $AB$ and a second diameter $PP'$. The four-sided figure $APBP'$ has diagonals of equal length that cut each other in half at $O$, and it is a rectangle.
Monocurl source
let A = on(180)
let B = on(0)
let P = on(62)
let Q = on(242)
let Corner = |p, a, b| Square90(p, normalize(a - p), normalize(b - p), INK, 0.2)
mesh circle = Round(O, R)
mesh rect = Shape([A, P, B, Q], AZURE, 0.25, 3.5)
mesh diag = [Seg(A, B, LEAF, 4), Seg(P, Q, LEAF, 4), Pt(O, INK, 0.08)]
mesh corners = [Corner(P, A, B), Corner(B, P, Q), Corner(Q, B, A), Corner(A, Q, P)]
mesh names = [
    Name("A", out(180), 0.95),
    Name("B", out(0), 0.95),
    Name("P", out(62), 0.95),
    Name("P'", out(242), 0.95),
    Name("O", O + [0.28, -0.22, 0], 0.95),
    Name("r", 0.5 * (O + A) + [0, 0.25, 0], 0.9, LEAF),
    Name("r", 0.5 * (O + B) + [0, 0.25, 0], 0.9, LEAF),
    Name("r", 0.5 * (O + P) + [-0.25, 0.08, 0], 0.9, LEAF),
    Name("r", 0.5 * (O + Q) + [-0.25, 0.08, 0], 0.9, LEAF),
    center{[2.4, 1.0, 0]} Note("both diagonals", 0.74),
    Name("AB = PP' = 2r", [2.4, 0.45, 0], 0.9, LEAF),
    center{[2.4, -0.45, 0]} Note("four right angles", 0.74),
    center{[2.4, -0.95, 0]} Cap("a rectangle", 0.85, AZURE)
]

Uses the shared definitions for this lesson's figures.

Thales’ theorem applies at each of the four corners, since each corner is a point of the circle looking at a diameter. So $APBP'$ has four right angles and is a rectangle. Read backward, the picture says that every right triangle is half of a rectangle, and a rectangle’s diagonals are equal and cut each other in half. That gives the converse.

Together the two theorems say that the circle with diameter $AB$ is exactly the set of points from which $AB$ is seen at a right angle, apart from $A$ and $B$ themselves.

Pause and try

The front of a building is a straight wall 30 m long. A photographer wants to stand where the wall spans an angle of exactly 90° in her view. Describe all the places she can stand. How far is each of them from the middle of the wall?

Show answerHide answer

Call the ends of the wall $A$ and $B$. By Thales’ theorem and its converse, the points with $\angle APB = 90°$ are the points of the circle with diameter $AB$. She can stand anywhere on the half of that circle in front of the building. Every such point is a radius away from the center of the circle, which is the middle of the wall: exactly 15 m, wherever she stands.

From a diameter to any chord

Now return to the pond, where the posts were not opposite each other. A segment joining two points of a circle is called a chord. In the first animation the chord $AB$ was seen from the rim at 50°, and the angle at the center, $\angle AOB$, was 100°. In the second, the rim angle was 55° and the angle at the center was 110°. For a diameter the angle at the center is a straight angle, 180°, and Thales gives 90°.

angle at the centerangle at the rim
100°50°
110°55°
180°90°

The pattern is hard to miss, and the next animation tests it by moving one of the posts.

The point $B$ moves around the circle while $A$ and $P$ stay fixed. The angle at the center $O$ and the angle at $P$ both change, and the angle at $P$ is always half of the angle at the center.
Monocurl source
let A = on(200)
let P = on(95)
let Sweep = |b| {
    let B = on(b)
    return [
        Wedge(O, rad(200), rad(b - 200), EMBER, 0.5),
        AngleMark(P, A, B, AZURE, 0.6),
        Path([A, O, B], EMBER, 4),
        Path([A, P, B], AZURE, 4),
        Pt(B, INK, 0.09),
        Name("B", out(b), 0.95),
        center{[2.4, 0.85, 0]} scale{1.6} color{EMBER} Number(b - 200, 1),
        center{[2.4, -1.05, 0]} scale{1.6} color{AZURE} Number(rad_to_deg(angle_at(P, A, B)), 1)
    ]
}
mesh circle = Round(O, R)
mesh sweep = Sweep(b: 240)
mesh fixed = [
    Pt(A, INK, 0.09),
    Pt(P, INK, 0.09),
    Pt(O, INK, 0.08),
    Name("A", out(200), 0.95),
    Name("P", out(95), 0.95),
    Name("O", O + 0.32 * dir(rad(130)), 0.95),
    center{[2.4, 1.45, 0]} Note("angle at the center O", 0.74),
    center{[2.4, -0.45, 0]} Note("angle at P", 0.74)
]

slide "sweep"
    play Wait(1)
    sweep.b = 380
    play Lerp(3.2, [&sweep])
    play Wait(1)
    sweep.b = 420
    play Lerp(1.4, [&sweep])
    play Wait(0.8)
    sweep.b = 300
    play Lerp(2.2, [&sweep])
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

If the angle at the rim is always half the angle at the center, the opening puzzle is solved at once. The angle at the center depends only on $A$, $B$ and $O$. It knows nothing about where $P$ is. Half of it is then the same for every $P$.

So the claim to prove is “half”. The proof of Thales’ theorem worked by drawing the radius to $P$, which produced isosceles triangles. The same radius is available here.

Pause and try

In the first slide of the next figure, the chord $AB$ does not pass through $O$, so the radius $OP$ no longer splits triangle $APB$ into two triangles. Extend it instead: draw the full diameter from $P$ through $O$ to the far side of the circle at $Q$. Let $\alpha = \angle APQ$. Using the isosceles triangle $AOP$, find $\angle AOQ$ in terms of $\alpha$.

Show answerHide answer

In triangle $AOP$, $OA = OP$, so the angle at $A$ equals the angle at $P$, which is $\alpha$. The third angle is $\angle AOP = 180° - 2\alpha$. The angles $\angle AOP$ and $\angle AOQ$ lie side by side along the straight line $PQ$, so $\angle AOQ = 180° - (180° - 2\alpha) = 2\alpha$. The angle at the center is twice the angle at $P$.

  1. An inscribed angle APB and the central angle AOB, both standing on the arc from A to B.
  2. Draw the diameter from P through O to Q. It splits the angle at P and the angle at O into a left part and a right part.
  3. OA and OP are radii, so triangle AOP is isosceles. Its angles at A and at P are equal: call them α.
  4. The third angle of that triangle is 180° − 2α, so the angle AOQ next to it on the straight line PQ is 2α.
  5. The same argument on the right, with the isosceles triangle BOP, gives angle QOB = 2β.
  6. Add the two parts. The central angle is 2α + 2β, twice the inscribed angle α + β.
The proof that an inscribed angle is half the central angle, in the case where the center lies inside the angle. The diameter through $P$ splits both angles in two, and on each side an isosceles triangle shows the central part is twice the inscribed part.
Monocurl source
let P = on(85)
let Q = on(265)
let A = on(205)
let B = on(330)
mesh circle = Round(O, R)
mesh fills = []
mesh marks = [Wedge(O, rad(205), rad(125), SLATE, 0.45), AngleMark(P, A, B, SLATE, 0.6)]
mesh diam = []
mesh lines = [Path([A, O, B], INK, 3.5), Path([A, P, B], INK, 3.5)]
mesh names = [
    Name("A", out(205), 0.95),
    Name("B", out(330), 0.95),
    Name("P", out(85), 0.95),
    Name("O", O + [0.3, 0.12, 0], 0.95),
    Pt(O, INK, 0.08)
]
mesh greek = []
mesh panel = [
    center{[2.45, 1.0, 0]} Note("angle at the center", 0.74),
    Name("\angle AOB", [2.45, 0.5, 0], 0.95),
    center{[2.45, -0.4, 0]} Note("angle on the circle", 0.74),
    Name("\angle APB", [2.45, -0.9, 0], 0.95)
]

slide "An inscribed angle APB and the central angle AOB, both standing on the arc from A to B."
    play Fade(0.6)

slide "Draw the diameter from P through O to Q. It splits the angle at P and the angle at O into a left part and a right part."
    diam = [Seg(P, Q, SLATE, 3), Name("Q", out(265), 0.95)]
    play Fade(0.6, [&diam])

slide "OA and OP are radii, so triangle AOP is isosceles. Its angles at A and at P are equal: call them α."
    fills = [Region([A, O, P], tint(AZURE, 0.3))]
    marks = [AngleMark(A, O, P, AZURE, 0.6), AngleMark(P, A, Q, AZURE, 0.6)]
    greek = [
        Name("\alpha", inside(A, O, P, 0.9), 0.9, AZURE),
        Name("\alpha", inside(P, A, Q, 0.92), 0.9, AZURE)
    ]
    play Fade(0.6)

slide "The third angle of that triangle is 180° − 2α, so the angle AOQ next to it on the straight line PQ is 2α."
    panel = []
    play Fade(0.3, [&panel])
    marks .= AngleMark(O, A, Q, AZURE, 0.5)
    greek .= Name("2\alpha", inside(O, A, Q, 0.82), 0.85, AZURE)
    panel = [Name("\angle AOQ = 2\alpha", [2.45, 1.1, 0], 0.9, AZURE)]
    play Fade(0.6)

slide "The same argument on the right, with the isosceles triangle BOP, gives angle QOB = 2β."
    fills .= Region([B, O, P], tint(EMBER, 0.3))
    marks .= AngleMark(B, O, P, EMBER, 0.55)
    marks .= AngleMark(P, Q, B, EMBER, 0.75)
    marks .= AngleMark(O, Q, B, EMBER, 0.42)
    greek .= Name("\beta", inside(B, O, P, 0.82), 0.9, EMBER)
    greek .= Name("\beta", inside(P, Q, B, 1.05), 0.9, EMBER)
    greek .= Name("2\beta", inside(O, Q, B, 0.75), 0.85, EMBER)
    panel .= Name("\angle QOB = 2\beta", [2.45, 0.45, 0], 0.9, EMBER)
    play Fade(0.6)

slide "Add the two parts. The central angle is 2α + 2β, twice the inscribed angle α + β."
    panel .= Name("\angle AOB = 2(\alpha + \beta)", [2.45, -0.45, 0], 0.9)
    panel .= Name("= 2\,\angle APB", [2.45, -1.05, 0], 1.0, LEAF)
    play Fade(0.6, [&panel])

Uses the shared definitions for this lesson's figures.

This is Thales’ proof with one change. There, the two central pieces $2\alpha$ and $2\beta$ lay along a straight line and added to 180°. Here they add to whatever the angle at the center happens to be.

The statement

To state the result properly we need names for the two kinds of angle, and some care about which arc is meant, because two points cut a circle into two arcs.

Case 1 is the one in the stepped figure. In the other two the center is on a side of the angle or outside it, and the same lemma does the work with a subtraction in place of the addition.

The other two cases of the proof. Left: one side of the inscribed angle passes through the center, and a single isosceles triangle is enough. Right: the center lies outside the angle, and the angle is a difference of two angles measured from the diameter PQ.
The other two cases of the proof. Left: one side of the inscribed angle passes through the center, and a single isosceles triangle is enough. Right: the center lies outside the angle, and the angle is a difference of two angles measured from the diameter $PQ$.
Monocurl source
let r = 1.4
let C1 = [-1.95, 0.35, 0]
let C2 = [1.95, 0.35, 0]
let p1 = |deg| C1 + r * dir(rad(deg))
let p2 = |deg| C2 + r * dir(rad(deg))
let o1 = |deg| C1 + (r + 0.28) * dir(rad(deg))
let o2 = |deg| C2 + (r + 0.28) * dir(rad(deg))
mesh circles = [Round(C1, r), Round(C2, r)]
mesh left = [
    Region([p1(215), C1, p1(110)], tint(AZURE, 0.3)),
    AngleMark(p1(215), C1, p1(110), AZURE, 0.5),
    AngleMark(p1(110), p1(215), p1(290), AZURE, 0.5),
    AngleMark(C1, p1(215), p1(290), EMBER, 0.4),
    Path([p1(215), p1(110), p1(290)], INK, 3.5),
    Seg(C1, p1(215), INK, 3.5),
    Pt(C1, INK, 0.08),
    Name("P", o1(110), 0.9),
    Name("A", o1(215), 0.9),
    Name("B = Q", o1(290) + [0.3, -0.05, 0], 0.9),
    Name("O", C1 + [0.28, 0.1, 0], 0.9),
    Name("\alpha", inside(p1(215), C1, p1(110), 0.78), 0.85, AZURE),
    Name("\alpha", inside(p1(110), p1(215), p1(290), 0.78), 0.85, AZURE),
    Name("2\alpha", inside(C1, p1(215), p1(290), 0.68), 0.85, EMBER)
]
let a_small = angle_at(p2(110), p2(290), p2(350))
let a_big = angle_at(p2(110), p2(290), p2(70))
mesh right = [
    Wedge(C2, rad(350), rad(80), EMBER, 0.45),
    AngleMark(p2(110), p2(350), p2(70), AZURE, 0.7),
    Seg(p2(110), p2(290), SLATE, 3),
    Path([p2(350), p2(110), p2(70)], INK, 3.5),
    Path([p2(350), C2, p2(70)], INK, 3.5),
    Pt(C2, INK, 0.08),
    Name("P", o2(110), 0.9),
    Name("Q", o2(290), 0.9),
    Name("A", o2(350), 0.9),
    Name("B", o2(70), 0.9),
    Name("O", C2 + [-0.28, 0.05, 0], 0.9)
]
mesh notes = [
    center{[C1[0], -1.9, 0]} Math("\angle AOB = 2\,\angle APB", 0.8),
    center{[C2[0], -1.9, 0]} Math(str_join(["\angle APB = ", Deg(a_big), " - ", Deg(a_small), " = ", Deg(a_big - a_small)]), 0.8)
]

Uses the shared definitions for this lesson's figures.

In the right-hand picture the arcs from $Q$ to $B$ and from $Q$ to $A$ have central angles 140° and 60°, so the inscribed angles $\angle QPB$ and $\angle QPA$ are 70° and 30°, and their difference is 40°, half of $\angle AOB = 80°$.

Thales’ theorem is the special case in which the intercepted arc is a semicircle: half of 180° is 90°.

The other side of the chord

The definition was careful about which arc is intercepted, and the reason shows up when $P$ crosses to the other side of the chord.

Pause and try

A chord $AB$ cuts off a short arc with central angle 130°. A point $P$ on the long arc sees the chord at $\frac{1}{2} \cdot 130° = 65°$. What angle does a point $P'$ on the short arc see? Which arc does its angle intercept?

Show answerHide answer

The angle at $P'$ intercepts the arc from $A$ to $B$ that does not contain $P'$, which is the long arc. Its central angle is $360° - 130° = 230°$, so $\angle AP'B = 115°$. Notice that $65° + 115° = 180°$.

A chord AB seen from a point P on the long arc and from a point P' on the short arc. The two angles intercept the two arcs that make up the whole circle, so they add to 180°.
A chord $AB$ seen from a point $P$ on the long arc and from a point $P'$ on the short arc. The two angles intercept the two arcs that make up the whole circle, so they add to 180°.
Monocurl source
let A = on(205)
let B = on(335)
let P = on(80)
let Q = on(262)
let a1 = angle_at(P, A, B)
let a2 = angle_at(Q, A, B)
mesh circle = Round(O, R)
mesh quad = Region([A, P, B, Q], tint(SLATE, 0.14))
mesh marks = [AngleMark(P, A, B, AZURE, 0.6), AngleMark(Q, A, B, EMBER, 0.4)]
mesh lines = [
    Seg(A, B, SLATE, 3),
    Path([A, P, B], AZURE, 4),
    Path([A, Q, B], EMBER, 4),
    Pt(A, INK, 0.09),
    Pt(B, INK, 0.09)
]
mesh names = [
    Name("A", out(205), 0.95),
    Name("B", out(335), 0.95),
    Name("P", out(80), 0.95),
    Name("P'", out(262), 0.95),
    Name(Deg(a1), inside(P, A, B, 0.95), 0.85, AZURE),
    Name(Deg(a2), inside(Q, A, B, 0.72), 0.85, EMBER),
    Name(str_join(["\tfrac{1}{2} \cdot ", Deg(2 * a1), " = ", Deg(a1)]), [2.4, 1.1, 0], 0.9, AZURE),
    Name(str_join(["\tfrac{1}{2} \cdot ", Deg(2 * a2), " = ", Deg(a2)]), [2.4, 0.35, 0], 0.9, EMBER),
    center{[2.4, -0.55, 0]} Note("together", 0.74),
    Name(str_join([Deg(a1), " + ", Deg(a2), " = ", Deg(a1 + a2)]), [2.4, -1.1, 0], 0.9, LEAF)
]

Uses the shared definitions for this lesson's figures.

This always happens. The two arcs make up the whole circle, so their central angles add to 360°, and the inscribed angles on them, being halves, add to 180°. The four points $A$, $P$, $B$, $P'$ form a four-sided figure with all its corners on a circle, called a cyclic quadrilateral, and we have shown that its opposite angles at $P$ and $P'$ add to 180°. The same argument with the chord $PP'$ covers the other pair, at $A$ and $B$.

So the opening claim needs a qualification. Walking around the pond, the angle stays the same as long as you stay on one side of the chord. If you pass a post and continue along the short arc, the angle jumps to 180° minus its former value.

Using the theorem

The next example is a practical trick, and it runs the theorem in the reverse direction: from a known inscribed angle to the arc.

Finding the center of a circle with a sheet of paper. With the corner of the sheet on the circle, its edges cross the circle at the two ends of a diameter. A second placement gives a second diameter, and the two diameters cross at the center.
Finding the center of a circle with a sheet of paper. With the corner of the sheet on the circle, its edges cross the circle at the two ends of a diameter. A second placement gives a second diameter, and the two diameters cross at the center.
Monocurl source
let P1 = on(120)
let A1 = on(215)
let B1 = on(35)
let P2 = on(62)
let A2 = on(172)
let B2 = on(352)
let u = normalize(A1 - P1)
let v = normalize(B1 - P1)
mesh sheet = Shape([P1, P1 + 3.0 * u, P1 + 3.0 * u + 2.8 * v, P1 + 2.8 * v], GOLD, 0.2, 2.5)
mesh circle = center{O} fill{alpha{0} PAPER} stroke{SLATE, 3.5} Circle(R, 128)
mesh second = [
    Path([A2, P2, B2], EMBER, 2.5),
    Square90(P2, normalize(A2 - P2), normalize(B2 - P2), EMBER, 0.2),
    Seg(A2, B2, EMBER, 4.5)
]
mesh first = [
    Square90(P1, u, v, INK, 0.22),
    Seg(A1, B1, AZURE, 4.5),
    Pt(A1, AZURE, 0.09),
    Pt(B1, AZURE, 0.09),
    Pt(A2, EMBER, 0.09),
    Pt(B2, EMBER, 0.09),
    Pt(O, LEAF, 0.12)
]
mesh names = [
    Name("P", out(120), 0.95),
    Name("A", out(215), 0.95),
    Name("B", out(35), 0.95),
    center{[2.5, 1.0, 0]} Cap("first diameter", 0.78, AZURE),
    center{[2.5, 0.4, 0]} Cap("second diameter", 0.78, EMBER),
    center{[2.5, -0.5, 0]} Note("they cross at", 0.74),
    center{[2.5, -1.0, 0]} Cap("the center", 0.85, LEAF)
]

Uses the shared definitions for this lesson's figures.

Where the theorem stops

The theorem needs the vertex on the circle, and the second animation showed what happens otherwise. The problems below ask you to prove that an interior point sees a chord at a larger angle and an exterior point at a smaller one.

There is also a limiting case. As $P$ slides along the arc toward $A$, the side $PB$ turns into the chord $AB$, and the side $PA$ shrinks to nothing while its direction approaches that of the tangent line at $A$. The angle keeps its value all the way, which suggests that the angle between a chord and the tangent at one of its ends equals the inscribed angle on the far side. That is true, and the last but one problem proves it directly.

Finally, the whole lesson takes place in a flat plane. The proof used the angle sum of a triangle at every step. On a sphere, where the angle sum is more than 180°, the proof breaks down, and neither Thales’ theorem nor the inscribed angle theorem holds there.

Looking back

The hard part was finding anything in the moving triangle $APB$ to hold on to. The answer was a point that is not part of the triangle at all, the center $O$. Joining it to the three points on the circle produces radii, equal radii produce isosceles triangles, and isosceles triangles produce equal angles. Almost every proof about angles in a circle starts with that move: draw the radii.

The second idea was to solve the symmetric case first. Thales’ theorem looked like a special fact about diameters, and the general theorem turned out to be the same argument with the diameter drawn through $P$ in place of the one through $A$ and $B$.

Check yourself

Points $A$ and $B$ on a circle with center $O$ satisfy $\angle AOB = 80°$. A point $P$ lies on the shorter of the two arcs from $A$ to $B$. What is $\angle APB$?

Problems

Problem 1

Points $A$ and $B$ on a circle with center $O$ satisfy $\angle AOB = 84°$. Find the angle $\angle APB$ for a point $P$ on the longer arc, and for a point $P'$ on the shorter arc.

Show solutionHide solution

For $P$ on the longer arc, the intercepted arc is the shorter one, with central angle 84°, so $\angle APB = 42°$. For $P'$ on the shorter arc, the intercepted arc is the longer one, with central angle $360° - 84° = 276°$, so $\angle AP'B = 138°$. Check: $42° + 138° = 180°$.

Problem 2

$AB$ is a diameter of a circle of radius 6.5, and $P$ is a point of the circle with $PA = 5$. Find $\angle APB$ and the length $PB$.

Show solutionHide solution

By Thales’ theorem $\angle APB = 90°$. So $APB$ is a right triangle with hypotenuse $AB = 13$ and one leg 5. By the Pythagorean theorem $PB^2 = 13^2 - 5^2 = 169 - 25 = 144$, so $PB = 12$.

Problem 3

On a clock face, a triangle has its corners at the 12, the 4 and the 9. Find its three angles.

Show solutionHide solution

The twelve hour marks divide the circle into arcs of $360° / 12 = 30°$. The angle at the 9 intercepts the arc from 12 to 4 that avoids the 9, which spans 4 hours, or 120°. So the angle at the 9 is 60°. The angle at the 12 intercepts the arc from 4 to 9 that avoids the 12: 5 hours, 150°, giving 75°. The angle at the 4 intercepts the arc from 9 to 12 that avoids the 4: 3 hours, 90°, giving 45°. Check: $60° + 75° + 45° = 180°$.

Problem 4

(a) A cyclic quadrilateral $ABCD$ has $\angle A = 70°$ and $\angle B = 95°$. Find $\angle C$ and $\angle D$. (b) Show that a parallelogram whose four corners lie on a circle must be a rectangle.

Show solutionHide solution

(a) Opposite angles of a cyclic quadrilateral add to 180°. The angle opposite $A$ is $C$, so $\angle C = 110°$, and the angle opposite $B$ is $D$, so $\angle D = 85°$. Check: the four angles add to $70° + 95° + 110° + 85° = 360°$, as the angles of any quadrilateral do.

(b) In a parallelogram, opposite angles are equal. If its corners lie on a circle, opposite angles also add to 180°. Two equal angles that add to 180° are each 90°. So all four angles are right angles and the parallelogram is a rectangle.

Problem 5

Let $A$ and $B$ be points of a circle, and let $\theta$ be the inscribed angle on the chord $AB$ from points of one of the two arcs. Let $P$ be a point on the same side of the line $AB$ as that arc. (a) Suppose $P$ is inside the circle, and let the line $AP$, continued beyond $P$, meet the arc at $P'$. Show that $\angle APB > \theta$. (b) Suppose $P$ is outside the circle. The segment from $P$ to the midpoint $M$ of $AB$ crosses the arc at a point $P'$. Continue the line $AP'$ beyond $P'$ until it meets the segment $PB$ at $N$, and show that $\angle APB < \theta$. You may use the fact that an exterior angle of a triangle equals the sum of the two interior angles at the other corners.

Show solutionHide solution

(a) The point $P'$ is on the arc, so $\angle AP'B = \theta$. Since $P$ lies on the segment $AP'$, this is also the angle of triangle $PP'B$ at $P'$. The angle $\angle APB$ is an exterior angle of triangle $PP'B$ at $P$, because $A$, $P$, $P'$ lie on a line with $P$ between. So

$$ \angle APB = \angle PP'B + \angle PBP' = \theta + \angle PBP' > \theta. $$

(b) The point $P'$ lies on the segment $PM$, which joins a corner of triangle $APB$ to a point of the opposite side. So $P'$ is inside that triangle, and the line from $A$ through $P'$ leaves it through the side $PB$, at $N$. Now $\theta = \angle AP'B$ is an exterior angle of triangle $P'NB$ at $P'$, and $\angle ANB$ is an exterior angle of triangle $APN$ at $N$. So

$$ \theta = \angle P'NB + \angle P'BN > \angle ANB = \angle APN + \angle PAN > \angle APB. $$

Together with the theorem, this shows that among points on one side of the line $AB$, the arc is exactly the set of points that see the chord at the angle $\theta$. (The exterior angle fact follows from the angle sum: the exterior angle and the interior angle beside it add to 180°, and so do all three interior angles.)

Problem 6

A line that touches a circle at a single point $A$ is called a tangent, and it is perpendicular to the radius $OA$. Let $AB$ be a chord whose shorter arc has central angle $2\theta$, with $2\theta < 180°$, and let $T$ be a point of the tangent at $A$ on the same side of the line $OA$ as $B$. Show that $\angle TAB = \theta$, the inscribed angle on the chord $AB$ from the longer arc.

Show solutionHide solution

Triangle $AOB$ is isosceles with $OA = OB$ and angle $2\theta$ at $O$. Its other two angles are equal and add to $180° - 2\theta$, so $\angle OAB = 90° - \theta$. The tangent is perpendicular to $OA$, so $\angle OAT = 90°$. The point $B$ lies on the same side of the tangent as $O$ (the whole circle does) and on the same side of $OA$ as $T$, so the ray $AB$ lies inside the right angle $\angle OAT$, and

$$ \angle TAB = \angle OAT - \angle OAB = 90° - (90° - \theta) = \theta. $$

A point of the longer arc sees the chord at half the central angle $2\theta$, which is the same $\theta$.

Two chords AB and CD of a circle cross at the point X inside it. The triangles XAC and XDB are shaded, and the angles at A and D are marked.
Two chords $AB$ and $CD$ of a circle cross at the point $X$ inside it. The triangles $XAC$ and $XDB$ are shaded, and the angles at $A$ and $D$ are marked.
Monocurl source
let s = R / 6
let d = sqrt(12)
let g = rad(40)
let X = O + s * d * dir(g)
let u = dir(g + arccos(2.5 / d))
let v = dir(g - arccos(1 / d))
let A = X + 3 * s * u
let B = X - 8 * s * u
let C = X + 4 * s * v
let D = X - 6 * s * v
mesh circle = Round(O, R)
mesh fills = [Region([X, A, C], tint(AZURE, 0.35)), Region([X, D, B], tint(EMBER, 0.3))]
mesh marks = [AngleMark(A, X, C, PLUM, 0.4), AngleMark(D, X, B, PLUM, 0.55)]
mesh lines = [
    Seg(A, B, INK, 3.5),
    Seg(C, D, INK, 3.5),
    Seg(A, C, AZURE, 3.5),
    Seg(D, B, EMBER, 3.5),
    Pt(X, INK, 0.09)
]
mesh names = [
    Name("A", A + 0.3 * normalize(A - O), 0.95),
    Name("B", B + 0.3 * normalize(B - O), 0.95),
    Name("C", C + 0.3 * normalize(C - O), 0.95),
    Name("D", D + 0.3 * normalize(D - O), 0.95),
    Name("X", X + [0.2, -0.38, 0], 0.95),
    Name("XA = 3", [2.5, 1.2, 0], 0.9),
    Name("XB = 8", [2.5, 0.6, 0], 0.9),
    Name("XC = 4", [2.5, 0.0, 0], 0.9),
    Name("XD = \,?", [2.5, -0.8, 0], 1.0, ROSE)
]

Uses the shared definitions for this lesson's figures.

Problem 7

Two chords $AB$ and $CD$ of a circle cross at a point $X$ inside the circle, as in the figure above. (a) Show that triangles $XAC$ and $XDB$ are similar. (b) Deduce that $XA \cdot XB = XC \cdot XD$. (c) If $XA = 3$, $XB = 8$ and $XC = 4$, find $XD$.

Show solutionHide solution

(a) The angle of triangle $XAC$ at $A$ is $\angle BAC$, an inscribed angle that intercepts the arc from $B$ to $C$ not containing $A$. The angle of triangle $XDB$ at $D$ is $\angle CDB$, an inscribed angle that intercepts the arc from $C$ to $B$ not containing $D$. Because the chords cross, the points come in the order $A$, $C$, $B$, $D$ around the circle, so the arc between $C$ and $B$ that avoids $A$ also avoids $D$: both angles intercept the same arc, and they are equal. The angles of the two triangles at $X$ are equal as well, because they are opposite angles where two lines cross. Two pairs of equal angles make the triangles similar: $\triangle XAC \sim \triangle XDB$, with $X$ matching $X$, $A$ matching $D$ and $C$ matching $B$.

(b) Matching sides are in the same ratio: $\dfrac{XA}{XD} = \dfrac{XC}{XB}$. Multiplying both sides by $XD \cdot XB$ gives $XA \cdot XB = XC \cdot XD$.

(c) $3 \cdot 8 = 4 \cdot XD$, so $XD = 6$. Check: $3 \cdot 8 = 24 = 4 \cdot 6$.

Shared definitions used by this lesson's figures
# house kit: prepended to every essay figure after the std imports

# palette. AZURE and EMBER are the two actors, LEAF marks an answer, ROSE a problem
let PAPER = [1, 1, 1, 1]
let INK = [0.08, 0.09, 0.11, 1]
let SLATE = [0.40, 0.44, 0.50, 1]
let MIST = [0.85, 0.86, 0.88, 1]
let AZURE = [0.13, 0.42, 0.68, 1]
let EMBER = [0.89, 0.42, 0.12, 1]
let LEAF = [0.13, 0.55, 0.36, 1]
let ROSE = [0.78, 0.22, 0.24, 1]
let PLUM = [0.47, 0.30, 0.66, 1]
let GOLD = [0.85, 0.62, 0.08, 1]

background = PAPER

# an opaque pastel of col; use for fills so overlaps do not darken
let tint = |col, amount = 0.18| [
    1 - (1 - col[0]) * amount,
    1 - (1 - col[1]) * amount,
    1 - (1 - col[2]) * amount,
    1
]

# text: Cap for labels, Note for quiet labels, Math for typeset maths
let Cap = |txt, size = 0.75, col = INK| color{col} Text(txt, size, "Charter")
let Note = |txt, size = 0.65| color{SLATE} Text(txt, size, "Charter")
let Math = |tex, size = 0.9, col = INK| color{col} Tex(tex, size)

# a paper rectangle to sit behind text that crosses lines
let Plate = |pos, size| center{pos} fill{PAPER} stroke{alpha{0} PAPER, 0} Rect(size)

# shapes with fill and stroke both set, so no stray black appears
let Pt = |pos, col = INK, r = 0.075| center{pos} fill{col} stroke{col, 1} Circle(r, 48)
let Ring = |pos, col = INK, r = 0.1, w = 3| center{pos} fill{PAPER} stroke{col, w} Circle(r, 48)
let Seg = |a, b, col = INK, w = 3| stroke{col, w} Line(a, b)
let Path = |pts, col = INK, w = 3| stroke{col, w} Polyline(pts)
let Region = |pts, col| fill{col} stroke{alpha{0} col, 0} Polygon(pts)
let Outline = |pts, col = INK, w = 3| fill{alpha{0} PAPER} stroke{col, w} Polygon(pts)
let Shape = |pts, col, amount = 0.18, w = 3| fill{tint(col, amount)} stroke{col, w} Polygon(pts)
let Disc = |pos, r, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Circle(r, 96)
let Box = |pos, size, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Rect(size)
# a line from a to b ending in a small solid arrowhead
let Tip = |a, b, col = INK, w = 3, head = 0.17| {
    let d = normalize([b[0] - a[0], b[1] - a[1], 0])
    let n = [-d[1], d[0], 0]
    let base = [b[0] - d[0] * head, b[1] - d[1] * head, 0]
    return [
        stroke{col, w} Line(a, base),
        fill{col} stroke{col, 1} Polygon([
            b,
            [base[0] + n[0] * head * 0.42, base[1] + n[1] * head * 0.42, 0],
            [base[0] - n[0] * head * 0.42, base[1] - n[1] * head * 0.42, 0]
        ])
    ]
}

# plots. a frame is [x0, x1, y0, y1, centre, width, height]: a data window and the scene box it fills
let Frame = |x0, x1, y0, y1, c = [0, 0, 0], w = 6.4, h = 3.6| [x0, x1, y0, y1, c, w, h]
let fx = |fr, x| fr[4][0] + (x - (fr[0] + fr[1]) / 2) * fr[5] / (fr[1] - fr[0])
let fy = |fr, y| fr[4][1] + (y - (fr[2] + fr[3]) / 2) * fr[6] / (fr[3] - fr[2])
let at = |fr, x, y| [fx(fr, x), fy(fr, y), 0]

# axes through the data origin (or the nearest edge of the window), with optional names
let Axes = |fr, x_name = "", y_name = "", col = SLATE| {
    let ox = clamp(fr[0], 0, fr[1])
    let oy = clamp(fr[2], 0, fr[3])
    var parts = [
        Tip(at(fr, fr[0], oy), [fx(fr, fr[1]) + 0.25, fy(fr, oy), 0], col, 2.5, 0.15),
        Tip(at(fr, ox, fr[2]), [fx(fr, ox), fy(fr, fr[3]) + 0.25, 0], col, 2.5, 0.15)
    ]
    if (x_name != "") {
        parts .= center{[fx(fr, fr[1]) + 0.5, fy(fr, oy), 0]} Math(x_name, 0.8, col)
    }
    if (y_name != "") {
        parts .= center{[fx(fr, ox), fy(fr, fr[3]) + 0.5, 0]} Math(y_name, 0.8, col)
    }
    return parts
}

# tick marks with numbers at the listed data values
let XTicks = |fr, xs, col = SLATE, places = 0| block {
    let oy = fy(fr, clamp(fr[2], 0, fr[3]))
    for (x in xs) {
        . Seg([fx(fr, x), oy - 0.07, 0], [fx(fr, x), oy + 0.07, 0], col, 2)
        . center{[fx(fr, x), oy - 0.33, 0]} Math(to_string(x, places), 0.72, col)
    }
}
let YTicks = |fr, ys, col = SLATE, places = 0| block {
    let ox = fx(fr, clamp(fr[0], 0, fr[1]))
    for (y in ys) {
        . Seg([ox - 0.07, fy(fr, y), 0], [ox + 0.07, fy(fr, y), 0], col, 2)
        . center{[ox - 0.36, fy(fr, y), 0]} Math(to_string(y, places), 0.72, col)
    }
}

# faint grid lines at the listed data values
let GridLines = |fr, xs, ys, col = MIST| block {
    for (x in xs) {
        . Seg(at(fr, x, fr[2]), at(fr, x, fr[3]), col, 1.5)
    }
    for (y in ys) {
        . Seg(at(fr, fr[0], y), at(fr, fr[1], y), col, 1.5)
    }
}

# the graph of f over [a, b], drawn in the frame. values are clamped to the window
let Graph = |fr, f, a, b, col = AZURE, w = 4, n = 160|
    stroke{col, w} Polyline(map(sample(a, b, n), |x| at(fr, x, clamp(fr[2], f(x), fr[3]))))

# the region between the graph of f and the x axis over [a, b]
let AreaUnder = |fr, f, a, b, col = AZURE, amount = 0.2, n = 80| {
    var pts = [at(fr, a, 0)]
    for (x in sample(a, b, n)) {
        pts .= at(fr, x, clamp(fr[2], f(x), fr[3]))
    }
    pts .= at(fr, b, 0)
    return fill{tint(col, amount)} stroke{alpha{0} col, 0} Polygon(pts)
}

let dir = |th| [cos(th), sin(th), 0]
let rad = |d| d * PI / 180
let heading = |p, q| arctan2(q[1] - p[1], q[0] - p[0])
let Wedge = |p, t0, sw, col, r = 0.5| fill{tint(col, 0.5)} stroke{col, 2.5} Polygon(block {
    . p
    for (t in sample(t0, t0 + sw, to_int(max(8, ceil(sw * 14))))) {
        . p + r * dir(t)
    }
})
let Name = |txt, pos, size = 0.85, col = INK| center{pos} Math(txt, size, col)
let Square90 = |p, s, t, col = INK, k = 0.2| stroke{col, 2.5} Polyline([p + k * s, p + k * s + k * t, p + k * t])
let Deg = |t, places = 0| str_join([to_string(rad_to_deg(t), places), "^\circ"])
let angle_at = |p, a, b| angle_between(a - p, b - p)
# a filled wedge marking the angle at p between the rays toward a and b
let AngleMark = |p, a, b, col, r = 0.5| {
    let t0 = heading(p, a)
    let raw = heading(p, b) - t0
    let sw = raw - TAU * floor((raw + PI) / TAU)
    if (sw < 0) {
        return Wedge(p, t0 + sw, -sw, col, r)
    }
    return Wedge(p, t0, sw, col, r)
}
# a point at distance d from p, along the bisector of the angle toward a and b
let inside = |p, a, b, d| p + d * normalize(normalize(a - p) + normalize(b - p))
let Round = |o, r| center{o} fill{tint(SLATE, 0.07)} stroke{SLATE, 3} Circle(r, 128)
let O = [-1.5, 0, 0]
let R = 1.75
let on = |deg| O + R * dir(rad(deg))
let out = |deg, d = 0.3| O + (R + d) * dir(rad(deg))