"""Writes room names onto the two plan renders (previews/Vessel_01..., Vessel_02...) -> *_labelled.png. python build/annotate_plan.py Positions are ship metres; each plan's .png.json (written by bl_render.py) says what the picture covers. """ import json import os from PIL import Image, ImageDraw, ImageFont HERE = os.path.dirname(os.path.abspath(__file__)) PREV = os.path.join(os.path.dirname(HERE), "previews") LABELS = { "Vessel_01_plan_main_deck": [ ("ENGINE\nCONTROL", -44.5, 0.0), ("REACTOR\nGALLERY", -36.6, 3.6), ("WORKS HALL\ncargo ore processing fabrication", -20.4, 0.0), ("boarding gate\n(port service hatch)", -20.4, 9.6), ("service gate", -20.4, -9.6), ("SUB BAY", 3.0, 5.6), ("well", 3.0, -1.6), ("launch arm\n(Tender at BOARD)", 3.0, -8.9), ("stair to the\ncommand deck", 9.0, 8.0), ("FORE PASSAGE", 26.7, 0.0), ("GALLEY", 21.3, 5.2), ("QUARTERS A", 30.3, 5.2), ("HABITATION", 21.3, -5.2), ("QUARTERS B", 30.3, -5.2), ("SENSOR\nROOM", 40.0, 3.4), ], "Vessel_02_plan_command_deck": [ ("(works hall below)", -20.4, 9.6), ("TENDER CAROUSEL\nhub on the centre line", 3.0, 8.9), ("gallery", 13.8, -5.0), ("CIC\nsonar table", 23.0, 3.6), ("BRIDGE", 36.0, 0.0), ("helm dais", 43.3, 5.6), ], } def font(size): for name in ("arialbd.ttf", "arial.ttf", "DejaVuSans-Bold.ttf"): try: return ImageFont.truetype(name, size) except OSError: continue return ImageFont.load_default() for base, labels in LABELS.items(): png = os.path.join(PREV, base + ".png") if not os.path.isfile(png): continue with open(png + ".json", "r", encoding="utf-8") as f: cov = json.load(f) im = Image.open(png).convert("RGB") W, H = im.size d = ImageDraw.Draw(im) ft = font(max(14, W // 150)) for text, x, y in labels: px = (x - (cov["cx"] - cov["width"] / 2)) / cov["width"] * W py = ((cov["cy"] + cov["height"] / 2) - y) / cov["height"] * H box = d.multiline_textbbox((px, py), text, font=ft, anchor="mm", align="center", spacing=2) d.rectangle([box[0] - 5, box[1] - 3, box[2] + 5, box[3] + 3], fill=(12, 16, 22)) d.multiline_text((px, py), text, font=ft, fill=(255, 235, 150), anchor="mm", align="center", spacing=2) d.text((12, H - 26), "bow to the right, port at the top", font=font(max(12, W // 200)), fill=(40, 40, 40)) out = os.path.join(PREV, base + "_labelled.png") im.save(out) print("wrote", out)