""" Draws a metre grid with coordinates over a plan render made by bl_render.py (needs the .png.json next to it). python build/annotate_plan.py [step_m] [out.png] [labels.json] labels.json (optional): [{"x": 0, "y": 0, "text": "HUB"}, ...] in Blender metres. """ import json import os import sys from PIL import Image, ImageDraw, ImageFont src = sys.argv[1] step = float(sys.argv[2]) if len(sys.argv) > 2 else 5.0 dst = sys.argv[3] if len(sys.argv) > 3 else os.path.splitext(src)[0] + "_grid.png" labels = json.load(open(sys.argv[4], "r", encoding="utf-8")) if len(sys.argv) > 4 else [] with open(src + ".json", "r", encoding="utf-8") as f: v = json.load(f) im = Image.open(src).convert("RGB") W, H = im.size x0, x1 = v["cx"] - v["width"] / 2, v["cx"] + v["width"] / 2 y0, y1 = v["cy"] - v["height"] / 2, v["cy"] + v["height"] / 2 def px(x, y): return (x - x0) / (x1 - x0) * W, (y1 - y) / (y1 - y0) * H d = ImageDraw.Draw(im, "RGBA") try: font = ImageFont.truetype("arial.ttf", max(11, W // 110)) big = ImageFont.truetype("arialbd.ttf", max(14, W // 70)) except Exception: # noqa: BLE001 font = big = ImageFont.load_default() import math # noqa: E402 gx = math.ceil(x0 / step) * step while gx <= x1: p = px(gx, 0)[0] d.line([(p, 0), (p, H)], fill=(255, 60, 60, 110 if abs(gx) > 1e-6 else 230), width=1 if abs(gx) > 1e-6 else 2) d.text((p + 3, 2), "x %g" % gx, fill=(200, 0, 0, 255), font=font) gx += step gy = math.ceil(y0 / step) * step while gy <= y1: p = px(0, gy)[1] d.line([(0, p), (W, p)], fill=(40, 90, 255, 110 if abs(gy) > 1e-6 else 230), width=1 if abs(gy) > 1e-6 else 2) d.text((2, p + 2), "y %g" % gy, fill=(0, 40, 200, 255), font=font) gy += step for lab in labels: p = px(lab["x"], lab["y"]) tw = d.textlength(lab["text"], font=big) d.rectangle([p[0] - tw / 2 - 4, p[1] - 12, p[0] + tw / 2 + 4, p[1] + 12], fill=(255, 255, 255, 215)) d.text((p[0] - tw / 2, p[1] - 10), lab["text"], fill=(0, 0, 0, 255), font=big) im.save(dst) print("wrote", dst)