"""Construction drawings for MultiBand HF Antenna 7el OK1M 20-15-10m.

Generates boom.png (boom to scale), build.png (elements construction drawing)
and boom_drilling.png (hole positions in the boom).

    pip install matplotlib
    python drawings.py

Dimensions: mmana/OK1M-14-21-28_7el_v0.4_20m_15m_10m.maa (rounded to mm), README.md
"""
import math
from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

OUT = Path(__file__).parent

OVERHANG = 30      # boom end past the outer elements (half of element plate width)
INSERT = 150       # telescopic overlap of element tubes
BOOM_PROF = (35, 2.0)  # one piece square tube 35x35x2, full length

TUBE = {"30/2": (30, 2.0), "25/2": (25, 2.0), "20/1.5": (20, 1.5), "16/1": (16, 1.0)}
TUBE_COLOR = {"30/2": "#7b3fa0", "25/2": "#1f6fe5", "20/1.5": "#2ca043", "16/1": "#d4a020"}
TUBE_LW = {"30/2": 6.5, "25/2": 5.5, "20/1.5": 4.5, "16/1": 3.2}
BAND_COLOR = {"20m": "#cc1111", "15m": "#0e9f6e", "10m": "#7e4fc9"}
FEED = "#e5484d"

# name, band, X from DE 20m (MMANA), half length, inner tubes [(tube, visible from center)]
# the 16/1 tip takes the rest of the half length
ELEMENTS = [
    ("REF 20m", "20m", -3000, 5487, [("30/2", 1200), ("25/2", 1200), ("20/1.5", 1200)]),
    ("REF 15m", "15m", -2591, 3565, [("20/1.5", 1500)]),
    ("REF 10m", "10m", -1548, 2599, []),
    ("DE 15m",  "15m",  -266, 3423, [("20/1.5", 1500)]),
    ("DE 20m",  "20m",     0, 5147, [("30/2", 1200), ("25/2", 1200), ("20/1.5", 1200)]),
    ("DE 10m",  "10m",   155, 2583, []),
    ("D1 10m",  "10m",  1300, 2394, []),
]
X_REF = ELEMENTS[0][2]
BOOM_LEN = ELEMENTS[-1][2] - X_REF + 2 * OVERHANG
BOOM_TXT = f"{BOOM_PROF[0]}×{BOOM_PROF[0]}×{BOOM_PROF[1]:g}"


def pos(el):
    """Element position from REF 20m."""
    return el[2] - X_REF


def boom_pos(el):
    """Element position from the rear end of the boom."""
    return pos(el) + OVERHANG


def segments(el):
    """[(tube, start, end)] of one half element, from the center outwards."""
    _, _, _, half, inner = el
    out, x = [], 0
    for tube, vis in inner:
        out.append((tube, x, x + vis))
        x += vis
    out.append(("16/1", x, half))
    return out


def cut_list():
    """{(tube, cut length): (qty, [elements])}"""
    cuts = {}

    def add(tube, length, qty, name):
        q, names = cuts.get((tube, length), (0, []))
        cuts[(tube, length)] = (q + qty, names + [name])

    for el in ELEMENTS:
        name, segs = el[0], segments(el)
        if len(segs) == 1:
            add("16/1", 2 * el[3], 1, name)
            continue
        for i, (tube, a, b) in enumerate(segs):
            if i == 0 and name == "DE 20m":
                add(tube, b - a, 2, name)            # split dipole: two halves
            elif i == 0:
                add(tube, 2 * (b - a), 1, name)      # one piece through the plate
            else:
                add(tube, b - a + INSERT, 2, name)
    return cuts


def kg_per_m(tube):
    od, wall = TUBE[tube]
    return math.pi * wall * (od - wall) * 2.7e-3


def balance_point():
    m = mx = 0.0
    for el in ELEMENTS:
        em = 0.25  # plate + U-bolts
        for i, (tube, a, b) in enumerate(segments(el)):
            em += kg_per_m(tube) * 2 * (b - a + (INSERT if i else 0)) / 1000
        m += em
        mx += em * boom_pos(el)
    a, w = BOOM_PROF
    sm = (a * a - (a - 2 * w) ** 2) * 2.7e-3 * BOOM_LEN / 1000
    m += sm
    mx += sm * BOOM_LEN / 2
    return m, mx / m


def arrow(ax, x1, x2, y, text, color="black", fs=11, weight="normal", dy=0.06, **kw):
    ax.annotate("", xy=(x1, y), xytext=(x2, y),
                arrowprops=dict(arrowstyle="<->", color=color, lw=1.5, shrinkA=0, shrinkB=0))
    ax.text((x1 + x2) / 2, y + dy, text, ha="center", va="bottom", color=color, fontsize=fs,
            fontweight=weight, **kw)


# ------------------------------------------------------------------ boom
def draw_boom():
    m_tot, cg = balance_point()
    mast = round(cg / 10) * 10
    fig, ax = plt.subplots(figsize=(16, 7))
    ax.set_xlim(-250, BOOM_LEN + 250)
    ax.set_ylim(-3.0, 2.6)
    ax.axis("off")
    fig.suptitle(f"OK1M 7el 20-15-10m — BOOM (to scale)   {BOOM_TXT} mm, one piece {BOOM_LEN} mm",
                 fontsize=17, fontweight="bold", y=0.97)

    h = 0.24
    ax.add_patch(Rectangle((0, -h), BOOM_LEN, 2 * h, fc="#3a3d44", ec="black", zorder=2))
    ax.text(2300, 0, BOOM_TXT, ha="center", va="center", color="white", fontsize=12,
            fontweight="bold", zorder=6)

    # elements: label level (to keep close labels apart)
    level = {"DE 20m": 1, "DE 10m": 2}
    for el in ELEMENTS:
        name, band = el[0], el[1]
        x, c, lv = boom_pos(el), BAND_COLOR[band], level.get(el[0], 0)
        top = 1.0 + 0.38 * lv
        bot = -1.0 - 0.38 * lv
        ax.plot([x, x], [bot, top], color=c, lw=4, solid_capstyle="round", zorder=5)
        ax.text(x, top + 0.12, name, ha="center", va="bottom", color=c, fontsize=12,
                fontweight="bold")
        ax.text(x, bot - 0.12, f"{x}", ha="center", va="top", color="#333", fontsize=11)
        if name == "DE 20m":
            ax.plot(x, 0, "o", color=FEED, ms=12, zorder=7)

    # mast plate
    ax.annotate("", xy=(mast, -h - 0.02), xytext=(mast, -1.05),
                arrowprops=dict(arrowstyle="-|>,head_width=0.5,head_length=0.8", color=FEED, lw=3))
    ax.text(mast + 130, -0.7, f"MAST PLATE\n(CoG) {mast}", ha="left", va="center", color=FEED,
            fontsize=13, fontweight="bold")

    arrow(ax, 0, BOOM_LEN, -2.55, "", fs=12)
    ax.text(BOOM_LEN / 2, -2.65, f"boom total = cut {BOOM_LEN} mm, no joints  (overhang {OVERHANG} mm "
            "each end; dimensions from rear end)", ha="center", va="top", fontsize=12)
    fig.text(0.5, 0.015, f"CoG computed from tubes + boom + plates (~{m_tot:.1f} kg, without coax/balun) — "
             "check by balancing the finished antenna before final tightening.",
             ha="center", fontsize=10, color="#555")
    fig.savefig(OUT / "boom.png", dpi=110)
    plt.close(fig)


# ------------------------------------------------------------------ elements
def draw_layout(ax):
    ax.set_title("A)  Element layout — to scale   (tubes 30 / 25 / 20 / 16 mm)", fontsize=14,
                 fontweight="bold", pad=12)
    span = pos(ELEMENTS[-1])
    ax.set_xlim(-9800, 9800)
    ax.set_ylim(span + 250, -250)
    ax.axis("off")
    ax.plot([0, 0], [-200, span + 200], ls="--", color="#888", lw=1.5)
    for el in ELEMENTS:
        name, band, _, half, _ = el
        y = pos(el)
        for tube, a, b in segments(el):
            for s in (1, -1):
                ax.plot([s * a, s * b], [y, y], color=TUBE_COLOR[tube], lw=TUBE_LW[tube],
                        solid_capstyle="round", zorder=3 if tube == "16/1" else 4)
        if name == "DE 20m":
            ax.plot(0, y, "o", color=FEED, ms=10, zorder=6)
        label = f"{name}{' (feed)' if name == 'DE 20m' else ''}   pos {y}"
        ax.text(-half - 250, y, label, ha="right", va="center", fontsize=11, fontweight="bold",
                color=BAND_COLOR[band])
        ax.text(half + 250, y, f"L={2 * half} (half {half})", ha="left", va="center", fontsize=11)
    handles = [plt.Line2D([], [], color=TUBE_COLOR[t], lw=TUBE_LW[t], label=f"Ø{t.replace('/', '×')}")
               for t in TUBE]
    ax.legend(handles=handles, loc="upper center", bbox_to_anchor=(0.5, 0.0), ncol=4, frameon=False,
              fontsize=11)


def draw_half(ax, title, segs, center_note, tips, tip_offset, feed=False):
    """Half element detail; segs = [(tube, start, end)] with the tip as the last one."""
    ax.set_title(title, fontsize=14, fontweight="bold", pad=10, loc="left")
    end = segs[-1][2]
    ax.set_xlim(-650, end + 3300)
    ax.set_ylim(-2.15, 1.25)
    ax.axis("off")
    hmax = 0.42
    for i, (tube, a, b) in enumerate(segs):
        h = hmax * TUBE[tube][0] / 30
        a0 = -500 if i == 0 else a
        ax.add_patch(Rectangle((a0, -h), b - a0, 2 * h, fc=TUBE_COLOR[tube], ec="black", zorder=2))
        ax.text((a + b) / 2 + (-150 if i == 0 else 0), 0, f"Ø{tube.replace('/', '×')}",
                ha="center", va="center", color="white", fontsize=11, fontweight="bold", zorder=5)
        if i:   # inserted part, hidden in the previous tube
            ax.add_patch(Rectangle((a - INSERT, -h), INSERT, 2 * h, fc=TUBE_COLOR[tube], ec="black",
                                   hatch="////", zorder=4))
            ax.plot([a - INSERT / 2, a - INSERT / 2], [h, 0.85], color="#333", lw=1)
            ax.text(a - INSERT / 2, 0.88, f"overlap {INSERT}", ha="center", va="bottom", fontsize=10)
            ax.text(a, -2.1, "clamp", ha="center", va="bottom", fontsize=9.5)
    ax.plot(0, 0, "o", color=FEED if feed else "#333", ms=9, zorder=6)
    ax.text(0, 0.6, center_note, ha="center", va="bottom", color=FEED if feed else "#333",
            fontsize=10)

    edges = [0] + [b for _, _, b in segs]
    for x in edges:
        ax.plot([x, x], [-0.5, -1.2], ls=":", color="#555", lw=1)
    for i, (tube, a, b) in enumerate(segs):
        if i == 0:
            txt = f"{b - a} (Ø{TUBE[tube][0]} half)"
        elif i < len(segs) - 1:
            txt = f"{b - a} (Ø{TUBE[tube][0]} exposed)"
        else:
            txt = f"tip: half − {tip_offset}"
        arrow(ax, a, b, -0.95, txt, fs=10.5, dy=0.06)
    for k, (tube, a, b) in enumerate(segs[1:]):
        c = TUBE_COLOR[tube]
        y = -1.45 - 0.35 * (k % 2)
        txt = f"Ø{TUBE[tube][0]} CUT = tip + {INSERT}" if tube == "16/1" and k == len(segs) - 2 \
            else f"Ø{TUBE[tube][0]} CUT = {b - a + INSERT}"
        arrow(ax, a - INSERT, b, y, txt, color=c, fs=10.5, dy=0.05)

    lines = [f"Ø16 tip CUT (=half−{tip_offset}+{INSERT}):"]
    for name, half in tips:
        lines.append(f"  {name}: {half}−{tip_offset}+{INSERT} = {half - tip_offset + INSERT} mm")
    ax.text(end + 250, 0.6, "\n".join(lines), ha="left", va="top", family="monospace", fontsize=10.5)


def draw_10m_and_cuts(ax_10, ax_cut):
    ax_10.set_title("D)  10 m elements — one Ø16×1 tube, full length", fontsize=14,
                    fontweight="bold", pad=10, loc="left")
    els = [e for e in ELEMENTS if e[1] == "10m"]
    ax_10.set_xlim(-3300, 3300)
    ax_10.set_ylim(len(els) - 0.3, -0.8)
    ax_10.axis("off")
    ax_10.plot([0, 0], [-0.6, len(els) - 0.5], ls="--", color="#888", lw=1.2)
    for i, el in enumerate(els):
        ax_10.plot([-el[3], el[3]], [i, i], color=TUBE_COLOR["16/1"], lw=TUBE_LW["16/1"],
                   solid_capstyle="round")
        ax_10.text(-el[3] - 120, i, el[0], ha="right", va="center", fontsize=11, fontweight="bold",
                   color=BAND_COLOR["10m"])
        ax_10.text(el[3] + 120, i, f"CUT {2 * el[3]}", ha="left", va="center", fontsize=11)

    ax_cut.set_title("E)  Cut list — complete antenna", fontsize=14, fontweight="bold", pad=10,
                     loc="left")
    ax_cut.axis("off")
    rows, total = [], {}
    order = list(TUBE)
    for (tube, length), (qty, names) in sorted(cut_list().items(),
                                               key=lambda kv: (order.index(kv[0][0]), -kv[0][1])):
        rows.append(f"Ø{tube.replace('/', '×'):<7} {qty:>2} × {length:>5}   {', '.join(dict.fromkeys(names))}")
        total[tube] = total.get(tube, 0) + qty * length
    rows.append("")
    rows += [f"Ø{t.replace('/', '×'):<7} total {v / 1000:5.2f} m" for t, v in total.items()]
    rows += ["", f"Boom  {BOOM_TXT}  1 × {BOOM_LEN} (one piece)",
             "Plates  element 200×60×5 ×6, dipole 300×60×5 ×1,",
             "        mast-boom 180×100×4 ×1  (see HW/)"]
    ax_cut.text(0, 1, "\n".join(rows), ha="left", va="top", family="monospace", fontsize=10,
                transform=ax_cut.transAxes)


def draw_build():
    fig = plt.figure(figsize=(16, 24))
    fig.suptitle("OK1M 7el 20-15-10m — CONSTRUCTION DRAWING\n"
                 f"tubes 30/2 + 25/2 + 20/1.5 + 16/1 mm, overlap {INSERT} mm", fontsize=17,
                 fontweight="bold", y=0.985)
    gs = fig.add_gridspec(4, 2, height_ratios=[3.1, 1.25, 1.25, 1.5], hspace=0.28, wspace=0.05,
                          left=0.03, right=0.97, top=0.93, bottom=0.02)
    draw_layout(fig.add_subplot(gs[0, :]))

    by_name = {e[0]: e for e in ELEMENTS}
    draw_half(fig.add_subplot(gs[1, :]),
              "B)  20 m half-element build detail  (length to scale, tube Ø exaggerated) — symmetric, both sides",
              segments(by_name["REF 20m"]),
              "center\nREF: Ø30 one piece 2400\nDE: 2× 1200, split, feed",
              [("REF 20m", 5487), ("DE 20m", 5147)], 3600, feed=True)
    draw_half(fig.add_subplot(gs[2, :]),
              "C)  15 m half-element build detail  (length to scale, tube Ø exaggerated) — symmetric, both sides",
              segments(by_name["REF 15m"]),
              "center\nØ20 one piece 3000",
              [("REF 15m", 3565), ("DE 15m", 3423)], 1500)
    draw_10m_and_cuts(fig.add_subplot(gs[3, 0]), fig.add_subplot(gs[3, 1]))
    fig.savefig(OUT / "build.png", dpi=100)
    plt.close(fig)


# ------------------------------------------------------------------ boom drilling
PLATE_W = 60          # element plate width along the boom
PLATE_HOLE = 20       # plate fixing holes ±20 mm from the element axis
MAST_HOLES = (-80, -40, 40, 80)   # horizontal holes of the mast plate from the mast axis
SPLIT = 2200          # the boom is drawn in two rows, split at this position
WINDOWS = [("1", "REAR part", 0, SPLIT + 50), ("2", "FRONT part", SPLIT - 50, BOOM_LEN)]


def boom_holes():
    """[(boom position, element)] of the vertical element plate holes"""
    holes = []
    for el in ELEMENTS:
        b = boom_pos(el)
        holes += [(b - PLATE_HOLE, el), (b + PLATE_HOLE, el)]
    return holes


def draw_window(ax, num, title, lo, hi, mast):
    """Top view of the boom from lo to hi; dimensions from the rear end of the boom."""
    ax.set_xlim(lo - 260, lo + SPLIT + 300)
    ax.set_ylim(-2.0, 2.2)
    ax.axis("off")
    ax.set_title(f"{num})  {title} {lo}–{hi} — TOP VIEW, vertical holes Ø5.5 (M5), "
                 "dimensions from the REAR END", fontsize=13.5, fontweight="bold", loc="left")
    h = 0.32
    ax.add_patch(Rectangle((lo, -h), hi - lo, 2 * h, fc="#3a3d44", ec="none", zorder=2))
    ax.plot([lo, hi], [h, h], color="black", lw=1.2, zorder=3)
    ax.plot([lo, hi], [-h, -h], color="black", lw=1.2, zorder=3)
    for x in (lo, hi):   # real ends solid, break lines dashed
        real = x in (0, BOOM_LEN)
        ax.plot([x, x], [-h - (0 if real else 0.1), h + (0 if real else 0.1)], color="black",
                lw=1.2, ls="-" if real else "--", zorder=3)
    ax.plot([lo - 60, hi + 60], [0, 0], ls=(0, (8, 3, 2, 3)), color="#888", lw=0.8, zorder=3)

    last = ly = None
    for el in ELEMENTS:
        x = boom_pos(el)
        if not (lo <= x <= hi):
            continue
        c = BAND_COLOR[el[1]]
        # close elements (DE 20m / DE 10m): second label one line lower
        y = -1.22 if last is not None and x - last < 250 and ly == -0.82 else -0.82
        last, ly = x, y
        ax.add_patch(Rectangle((x - PLATE_W / 2, -0.62), PLATE_W, 1.24, fc="none", ec=c, ls="--",
                               lw=1, zorder=4))
        ax.plot([x, x], [min(-0.75, y + 0.02), 0.75], color=c, lw=1.2, ls=(0, (6, 2, 1, 2)), zorder=4)
        ax.text(x, y, f"{el[0]}\naxis {x}", ha="center", va="top", fontsize=10,
                color=c, fontweight="bold")

    for x, el in boom_holes():
        if not (lo <= x <= hi):
            continue
        ax.plot(x, 0, "o", ms=8, mfc="white", mec="black", mew=1.4, zorder=6)
        ax.plot([x, x], [h + 0.05, 0.95], color="#666", lw=0.7, zorder=1)
        ax.text(x, 1.0, f"{x}", rotation=90, ha="center", va="bottom", fontsize=11, fontweight="bold")

    if lo == 0:
        ax.annotate("", xy=(0, 1.0), xytext=(-170, 1.0),
                    arrowprops=dict(arrowstyle="-|>", color="black", lw=1.4))
        ax.text(-180, 1.18, "measure\nfrom here", ha="center", va="bottom", fontsize=9.5)
        ax.text(-30, 0, "0", ha="right", va="center", fontsize=12, fontweight="bold")
        ax.text(0, -1.55, "rear end of boom", ha="left", va="top", fontsize=9.5, color="#333")
    if hi == BOOM_LEN:
        ax.text(BOOM_LEN + 30, 0, f"{BOOM_LEN}", ha="left", va="center", fontsize=12, fontweight="bold")
        ax.text(BOOM_LEN, -1.55, "front end", ha="right", va="top", fontsize=9.5, color="#333")
    if lo <= mast <= hi:
        ax.annotate("", xy=(mast, -h - 0.02), xytext=(mast, -0.95),
                    arrowprops=dict(arrowstyle="-|>,head_width=0.4,head_length=0.6", color=FEED, lw=2.5))
        ax.text(mast, -1.0, f"mast axis {mast}", ha="center", va="top", color=FEED, fontsize=10.5,
                fontweight="bold")


def draw_mast_side(ax, mast):
    lo, hi = mast - 600, mast + 600
    ax.set_xlim(mast - 1100 - 260, mast - 1100 + SPLIT + 300)
    ax.set_ylim(-1.5, 1.7)
    ax.axis("off")
    ax.set_title("3)  SIDE VIEW at the mast plate — horizontal holes Ø6 through both side walls, "
                 "dimensions from the REAR END", fontsize=13.5, fontweight="bold", loc="left")
    h = 0.36
    ax.add_patch(Rectangle((lo, -h), hi - lo, 2 * h, fc="#3a3d44", ec="none", zorder=2))
    ax.plot([lo, hi], [h, h], color="black", lw=1.2, zorder=3)
    ax.plot([lo, hi], [-h, -h], color="black", lw=1.2, zorder=3)
    for x in (lo, hi):
        ax.plot([x, x], [-h - 0.1, h + 0.1], color="black", lw=1, ls="--", zorder=3)
    ax.plot([lo - 60, hi + 60], [0, 0], ls=(0, (8, 3, 2, 3)), color="#888", lw=0.8, zorder=3)
    ax.add_patch(Rectangle((mast - 90, -0.9), 180, 1.8, fc="none", ec=FEED, ls="--", lw=1.2, zorder=4))
    ax.text(mast + 100, 0.85, "mast plate 180×100", ha="left", va="top", fontsize=10, color=FEED)
    ax.plot([mast, mast], [-1.1, 1.1], color=FEED, lw=1.2, ls=(0, (6, 2, 1, 2)))
    for d in MAST_HOLES:
        x = mast + d
        ax.plot(x, 0, "o", ms=8, mfc="white", mec="black", mew=1.4, zorder=6)
        ax.plot([x, x], [h + 0.05, 1.0], color="#666", lw=0.7)
        ax.text(x, 1.05, f"{x}", rotation=90, ha="center", va="bottom", fontsize=11, fontweight="bold")
    ax.text(mast, -1.15, f"mast axis {mast}  (holes ±40, ±80)", ha="center", va="top",
            color=FEED, fontsize=10.5, fontweight="bold")


def draw_boom_drilling():
    m_tot, cg = balance_point()
    mast = round(cg / 10) * 10
    fig = plt.figure(figsize=(16, 17))
    fig.suptitle("OK1M 7el 20-15-10m — BOOM DRILLING (build drawing)\n"
                 f"one piece {BOOM_TXT}, cut {BOOM_LEN} mm — all dimensions in mm from the REAR END "
                 "(reflector side)", fontsize=17, fontweight="bold", y=0.985)
    gs = fig.add_gridspec(4, 1, height_ratios=[1, 1, 0.75, 0.9], hspace=0.32,
                          left=0.03, right=0.97, top=0.915, bottom=0.01)
    for k, (num, title, lo, hi) in enumerate(WINDOWS):
        draw_window(fig.add_subplot(gs[k]), num, title, lo, hi, mast)
    draw_mast_side(fig.add_subplot(gs[2]), mast)

    ax = fig.add_subplot(gs[3])
    ax.axis("off")
    holes = [(x, "Ø5.5 vertical  ", f"{el[0]} (axis {boom_pos(el)})") for x, el in boom_holes()]
    holes += [(mast + d, "Ø6 horizontal  ", f"mast plate (axis {mast})") for d in MAST_HOLES]
    rows = [f"  {x:>5}  {kind}{what}" for x, kind, what in sorted(holes)]
    half = (len(rows) + 1) // 2
    col1 = ["HOLE TABLE (from the rear end)", f"{BOOM_TXT}, cut {BOOM_LEN}", ""] + rows[:half]
    col2 = ["", "", ""] + rows[half:]
    for x, r in ((0, col1), (0.33, col2)):
        ax.text(x, 1, "\n".join(r), ha="left", va="top", family="monospace", fontsize=10,
                transform=ax.transAxes)

    notes = [
        "NOTES",
        f"• One piece {BOOM_TXT}, no joints.",
        f"• Element plate {PLATE_W} mm wide, 2 fixing holes {2 * PLATE_HOLE} mm",
        f"  apart (±{PLATE_HOLE} from the element axis), M5 bolts",
        "  vertically through the boom.",
        "• Mast plate: 4 horizontal M6 bolts through the side walls.",
        "• Mark the centre line on the top face, measure all holes",
        "  from the rear end (no chained dimensions), centre punch,",
        "  drill square to the face through both walls.",
        "• Do not over-tighten — the square tube can be crushed.",
        "",
        f"Total {BOOM_LEN} mm, mast axis {mast} mm from the rear end.",
    ]
    ax.text(0.66, 1, "\n".join(notes), ha="left", va="top", fontsize=10.5, transform=ax.transAxes)
    fig.savefig(OUT / "boom_drilling.png", dpi=100)
    plt.close(fig)


if __name__ == "__main__":
    draw_boom()
    draw_build()
    draw_boom_drilling()
    m, cg = balance_point()
    print(f"boom {BOOM_LEN} mm, CoG {cg:.0f} mm from rear end, mass {m:.1f} kg")
