"""Grouper: what each seat sees (read-only): blender.exe -b Tender_Grouper.blend --python build/gr_view_check.py After the Spearfish's view_check.py. The design's requirement (the user's, from the Spearfish: "each should can see the sea from the window front"): from each seat's eye (SOCKET_Seat_L_Eye, SOCKET_Seat_R_Eye) the straight-ahead ray leaves through the glass, and at least half the rays over yaw -40..+40 deg (+ = outboard, toward the seat's own side), pitch -25..+15 deg, 5 deg steps. A ray whose first hit is the glass leaves the cabin that way. -> build/checks/view.json""" import bpy, math, os, json from mathutils import Vector, Matrix HERE = os.path.dirname(os.path.abspath(__file__)) os.makedirs(os.path.join(HERE, "checks"), exist_ok=True) sc = bpy.context.scene for o in bpy.data.objects: if o.name.startswith("UCX_"): o.hide_set(True) o.hide_viewport = True dg = bpy.context.evaluated_depsgraph_get() GLASS = {"SM_Grouper_Glass"} def first_hit(o, d): ok, loc, nrm, idx, ob, mx = sc.ray_cast(dg, o, d) return (ob.name if ok else None), ((loc - o).length if ok else None) out = {} for nm, s in (("SOCKET_Seat_L_Eye", 1), ("SOCKET_Seat_R_Eye", -1)): eye = bpy.data.objects[nm].matrix_world.translation.copy() grid, hits = [], {} through = total = 0 for pitch in range(-25, 16, 5): row = "" for yaw in range(-40, 41, 5): d = Matrix.Rotation(math.radians(yaw * s), 3, 'Z') @ Vector((0, -1, 0)) d = Matrix.Rotation(math.radians(pitch), 3, d.cross(Vector((0, 0, 1))).normalized()) @ d ob, dist = first_hit(eye, d.normalized()) total += 1 if ob in GLASS: through += 1 row += "o" else: row += "." hits[ob] = hits.get(ob, 0) + 1 grid.append("%+03d %s" % (pitch, row)) ahead, dist = first_hit(eye, Vector((0, -1, 0))) ahead_down, _ = first_hit(eye, Matrix.Rotation(math.radians(-10), 3, Vector((1, 0, 0))) @ Vector((0, -1, 0))) out[nm] = {"eye": [round(c, 3) for c in eye], "straight_ahead": ahead, "straight_ahead_m": round(dist or 0.0, 3), "ahead_10deg_down": ahead_down, "through_glass_pct": round(100.0 * through / total, 1), "first_hits": hits, "map (rows pitch -25..+15, columns yaw -40..+40 (+ outboard), o = glass)": grid} ok = all(v["straight_ahead"] in GLASS and v["through_glass_pct"] >= 50.0 for v in out.values()) json.dump({"requirement_met": ok, "seats": out}, open(os.path.join(HERE, "checks", "view.json"), "w"), indent=1) print("VIEW", ok, json.dumps({k: {kk: v[kk] for kk in ("eye", "straight_ahead", "ahead_10deg_down", "through_glass_pct")} for k, v in out.items()}))