# Critique round 2 (read-only): rays over each flank marking's own rectangle: where does the decal mesh not exist? import bpy, json, os, collections from mathutils import Vector from mathutils.bvhtree import BVHTree ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) dg = bpy.context.evaluated_depsgraph_get() def bvh(o): ev = o.evaluated_get(dg); me = ev.to_mesh(); M = ev.matrix_world vs = [M @ v.co for v in me.vertices]; ps = [list(p.vertices) for p in me.polygons] ev.to_mesh_clear(); return BVHTree.FromPolygons(vs, ps), vs, ps Bd, dv, dp = bvh(bpy.data.objects["SM_Grouper_Decals"]) Bh, hv, hp = bvh(bpy.data.objects["SM_Grouper_Hull"]) rep = json.load(open(os.path.join(ROOT, "build", "surfaces_report.json")))["decals"] out = {} for name, d in rep.items(): if name == "insignia_stern": continue C = Vector(d["centre"]); Dv = Vector(d["normal"]); w, h = d["size_m"] R = (-Dv).cross(Vector((0, 0, 1))).normalized(); U = Vector((0, 0, 1)) miss = []; n = 0 for i in range(41): for k in range(25): uu = (i / 40 - 0.5) * w * 0.98; vv = (k / 24 - 0.5) * h * 0.98 P = C + R * uu + U * vv o = P + Dv * 1.0 hh = Bh.ray_cast(o, -Dv, 2.0) if hh[0] is None: continue n += 1 hd = Bd.ray_cast(o, -Dv, 2.0) if hd[0] is None or hd[3] > hh[3] + 1e-4: miss.append([round(uu / w + 0.5, 2), round(vv / h + 0.5, 2), round(hh[0].x, 3), round(hh[0].y, 3), round(hh[0].z, 3), "no decal" if hd[0] is None else "decal behind hull %.1f mm" % (1000 * (hd[3] - hh[3]))]) out[name] = dict(samples=n, missing=len(miss), pct=round(100 * len(miss) / max(1, n), 1), first=miss[:6]) json.dump(out, open(os.path.join(ROOT, "critique", "round2", "decal_gaps.json"), "w"), indent=1) print("CR2 GAPS", json.dumps({k: (v["missing"], v["pct"]) for k, v in out.items()})) for k, v in out.items(): if v["missing"]: print(k, v["first"])