G.597 construct an icosahedron and comprehend it in a — Code

XIII.16

Construct an icosahedron and comprehend it in a sphere, like the aforesaid figures; and to prove that the side of the icosahedron is the irrational segment called minor.
R Q L F E M Z P W A' V X G K S U N O H T A C D B
"""Programmatic construction for Book XIII, Proposition 16 (XIII.16).

        Euclid's construction of the regular icosahedron inscribed in a sphere of
        diameter AB, showing the semicircle ADB (with AC = 4 CB) and the plan projection
        of the circular section EFGHK (centre V), regular pentagons EFGHK, LMNOP, QRSTU,
        and axis XZ with points V, A', W.
        """

        from __future__ import annotations

        import math
        from geometor.model import Model


        def construct_g1() -> Model:
            """Construct the figure 0485.g1 using geometor.model."""
            model = Model("XIII.16")

            # Right sub-figure: Sphere diameter AB divided at C (AC = 4 CB) and semicircle ADB
            A = model.set_point(504.0, -28.0, classes=["given"], ID="A")
            B = model.set_point(504.0, -333.0, classes=["given"], ID="B")
            C = model.set_point(504.0, -271.0, classes=["constructed"], ID="C")
            D = model.set_point(629.0, -271.0, classes=["constructed"], ID="D")
            O_ab = model.set_point(504.0, -180.5, classes=["auxiliary"], ID="O_ab")
            model.construct_circle(O_ab, A)

            # Left sub-figure: Centre V and concentric projection circles
            cx, cy = 216.0, -216.0
            r_in, r_out = 136.5, 206.0
            V = model.set_point(cx, cy, classes=["given"], ID="V")

            # 10 vertices on inner circle EFGHK / LMNOP
            in_labels = ["L", "E", "P", "K", "O", "H", "N", "G", "M", "F"]
            in_pts = {}
            for i, name in enumerate(in_labels):
                ang = math.radians(-90.0 + i * 36.0)
                x = round(cx + r_in * math.cos(ang), 1)
                y = round(cy - r_in * math.sin(ang), 1)
                in_pts[name] = model.set_point(x, y, classes=["constructed"], ID=name)

            L, E, P, K, O, H, N, G, M, F = (in_pts[k] for k in in_labels)
            model.construct_circle(V, L)

            # 5 vertices on outer circle QRSTU
            out_specs = [("Q", -54.0), ("U", 18.0), ("T", 90.0), ("S", 162.0), ("R", -126.0)]
            out_pts = {}
            for name, deg in out_specs:
                ang = math.radians(deg)
                x = round(cx + r_out * math.cos(ang), 1)
                y = round(cy - r_out * math.sin(ang), 1)
                out_pts[name] = model.set_point(x, y, classes=["constructed"], ID=name)

            Q, U, T, S, R = (out_pts[k] for k, _ in out_specs)
            model.construct_circle(V, T)

            # Axis points X, A', W, Z
            X = model.set_point(180.0, -249.0, classes=["constructed"], ID="X")
            A_prime = model.set_point(238.0, -195.8, classes=["constructed"], ID="A'")
            W = model.set_point(260.0, -175.7, classes=["constructed"], ID="W")
            Z = model.set_point(289.0, -149.1, classes=["constructed"], ID="Z")

            # Polygons (Pentagons and Equilateral Triangles)
            model.set_polygon([E, F, G, H, K])
            model.set_polygon([L, M, N, O, P])
            model.set_polygon([Q, R, S, T, U])
            for tri in [
                (Q, P, U), (Q, L, R), (R, M, S), (S, N, T), (T, O, U),
                (Q, L, P), (L, R, M), (M, S, N), (N, T, O), (O, U, P),
                (Q, U, Z), (L, M, X), (X, E, Z), (V, E, Z),
            ]:
                model.set_polygon(list(tri))

            # Segments
            for p1, p2 in [
                (A, B), (A, C), (C, B), (C, D), (D, B),
                (E, F), (F, G), (G, H), (H, K), (K, E),
                (L, M), (M, N), (N, O), (O, P), (P, L),
                (E, P), (P, K), (K, O), (O, H), (H, N), (N, G), (G, M), (M, F), (F, L), (L, E),
                (Q, R), (R, S), (S, T), (T, U), (U, Q),
                (E, Q), (F, R), (G, S), (H, T), (K, U),
                (Q, L), (L, R), (R, M), (M, S), (S, N), (N, T), (T, O), (O, U), (U, P), (P, Q),
                (V, E), (V, F), (V, L), (V, M), (V, K),
                (X, Z), (V, Z), (V, X), (V, W), (W, Z), (X, W),
                (V, A_prime), (A_prime, W), (Z, A_prime),
                (Q, Z), (Q, W), (U, Z), (W, U), (L, X), (X, M), (E, Z), (Q, X),
            ]:
                model.set_segment(p1, p2)

            return model


        if __name__ == "__main__":
            construct_g1()