"""Sliding pressure door for the vessel's main entrance (models/pressure-door-sliding), after the user's two reference renders and the video Assets/0080.mp4 (2026-10-15): a double-leaf sliding door in a rounded-rectangle bezel with white light strips, a split lock ring on the seam (red locked, green unlocked; the bar across it does not turn in the video), a grab rail at each side, a sign over the door, a camera, a console on a swing arm at the left, a service column at the right, cables draped along the top and a floor cable. The user: a PRESSURE door, not an airlock; it competes with the hinged door (models/pressure-door) for the same gate, so it is a stand-alone module like that one. Built headless (another Blender instance, not the MCP's): blender.exe -b --python sd_run.py -- build Frame: metres, Z up, floor at z = 0. The plain wall's front face is y = 0; the front is -Y (the side the references show); +X is right seen from the front. Door axis at x = 0, the opening's centre at z = ZC. How it moves (separate objects, origin on the part; see sd_rig.py): SM_PDSliding_LeafL / LeafR slide 0.72 m along -X / +X into pockets inside the door plate (a slot y in [Y_SF, Y_SB]) M_PDS_Lock (material) the ring's light: red -> amber -> green as the slider goes 0 -> 0.30 SM_PDSliding_Monitor console (monitor, arm, tray) yaws about its post SM_PDSliding_Camera the camera yaws on its ball Opening: 1.40 x 2.20 m clear with 0.30 m corners, its bottom 0.16 m above the floor (the bezel's lower band and light strip sit between it and the floor). The leaves are 0.04 m larger than the opening all round (the rebate behind the dark lip) and run in a 0.105 m slot through the plate; nothing on a leaf stands closer than 1 cm to the slot's walls. """ import bpy, bmesh, math, os from mathutils import Vector, Matrix BUILD = r"D:\HADAL - The Descent\models\pressure-door-sliding\build" exec(open(os.path.join(BUILD, "sd_lib.py"), encoding="utf-8").read()) # ------------------------------------------------------------------ dimensions (metres) OW, OH = 0.70, 1.10 # opening half-width, half-height (1.40 x 2.20 clear) OZ0 = 0.16 # opening bottom (sill) ZC = OZ0 + OH # 1.26: the opening's centre, the lock ring's height OR = 0.30 # opening corner radius REB = 0.04 # leaf rebate behind the lip SEG = 8 # points per corner on the lofted loops Y_LF, Y_LB = -0.030, 0.040 # leaf front / back faces Y_SF, Y_SB = -0.055, 0.050 # the slot's front / back walls Y_LIP, Y_BEZ = -0.095, -0.125 # dark lip face, bezel front Y_PAN, Y_PLATE = -0.087, -0.075 # surround panel face, door plate face Y_WB = 0.30 # wall back Y_COL = -0.045 # the side columns' face PX, PZ0, PZ1 = 1.52, 0.0, 3.00 # door plate: x +-PX, z PZ0..PZ1 SLOT_X, SLOT_Z0, SLOT_Z1 = 1.49, 0.11, 2.41 TRAVEL = 0.72 # each leaf's slide SEAM = 0.002 # half the gap between the leaves R_NOTCH, R_RING_IN, R_RING_OUT = 0.105, 0.10, 0.15 Y_FLOOR, Y_FIELD, Y_BAND, Y_RING = -0.018, -0.034, -0.039, -0.044 # recess floor, raised field, diagonal band, ring top BAND_ANG = math.radians(-55.0) # the band and the bar: upper left to lower right LIP_W, BEZ_W = 0.06, 0.18 # the dark lip band and the bezel, as offsets from the opening P_LEAF = {-1: Vector((-0.37, 0.005, ZC)), 1: Vector((0.37, 0.005, ZC))} # leaf pivots P_MON = Vector((-1.90, -0.18, 1.26)) # console post axis (the swing pivot) P_CAM = Vector((0.80, -0.16, 2.80)) # camera ball MON_TILT = math.radians(8.0) CAM_PITCH = math.radians(20.0) CLIPS_X = [-2.15, -1.45, -0.75, -0.05, 0.65, 1.35, 2.05] # screens (for the UV mapping in sd_surfaces): name -> (centre, u axis, v axis, width, height, atlas region) SCREENS = {} MAT_NAMES = ["M_PDS_Paint", "M_PDS_Dark", "M_PDS_Steel", "M_PDS_Rubber", "M_PDS_CableRed", "M_PDS_Orange", "M_PDS_Light", "M_PDS_Lock", "M_PDS_LampRed", "M_PDS_LampGreen", "M_PDS_Screen", "M_PDS_SignText", "M_PDS_Glass"] PAINT, DARK, STEEL, RUBBER, CRED, ORANGE, LIGHT, LOCK, LRED, LGREEN, SCREEN, SIGNTXT, GLASS = range(len(MAT_NAMES)) PREVIEW = {"M_PDS_Paint": ((0.46, 0.47, 0.48), 0.0, 0.45), "M_PDS_Dark": ((0.035, 0.037, 0.04), 0.3, 0.5), "M_PDS_Steel": ((0.62, 0.63, 0.64), 1.0, 0.25), "M_PDS_Rubber": ((0.02, 0.02, 0.022), 0.0, 0.8), "M_PDS_CableRed": ((0.30, 0.03, 0.02), 0.0, 0.7), "M_PDS_Orange": ((0.80, 0.30, 0.05), 0.0, 0.45), "M_PDS_Light": ((1.0, 1.0, 1.0), 0.0, 0.3), "M_PDS_Lock": ((1.0, 0.1, 0.05), 0.0, 0.3), "M_PDS_LampRed": ((0.9, 0.05, 0.03), 0.0, 0.3), "M_PDS_LampGreen": ((0.05, 0.8, 0.2), 0.0, 0.3), "M_PDS_Screen": ((0.03, 0.15, 0.18), 0.0, 0.2), "M_PDS_SignText": ((0.2, 0.9, 1.0), 0.0, 0.3), "M_PDS_Glass": ((0.6, 0.7, 0.75), 0.0, 0.05)} GLOW = {"M_PDS_Light": ((1.0, 0.97, 0.92), 12.0), "M_PDS_LampRed": ((1.0, 0.06, 0.03), 6.0), "M_PDS_LampGreen": ((0.08, 1.0, 0.25), 6.0), "M_PDS_SignText": ((0.25, 0.95, 1.0), 6.0)} def get_mats(): out = [] for n in MAT_NAMES: m = bpy.data.materials.get(n) if m is None: m = bpy.data.materials.new(n) m.use_nodes = True b = m.node_tree.nodes.get("Principled BSDF") col, met, rough = PREVIEW[n] b.inputs["Base Color"].default_value = (*col, 1) b.inputs["Metallic"].default_value = met b.inputs["Roughness"].default_value = rough m.diffuse_color = (*col, 1) if n in GLOW: b.inputs["Emission Color"].default_value = (*GLOW[n][0], 1) b.inputs["Emission Strength"].default_value = GLOW[n][1] b.inputs["Base Color"].default_value = (0.03, 0.03, 0.03, 1) if n == "M_PDS_Lock": lock_nodes(m) out.append(m) return out def lock_nodes(m): """the ring light's colour comes from a ramp (red, amber, green) whose Fac the rig drives from the open slider""" nt = m.node_tree b = nt.nodes.get("Principled BSDF") ramp = nt.nodes.get("LockRamp") or nt.nodes.new('ShaderNodeValToRGB') ramp.name = ramp.label = "LockRamp" ramp.location = (-400, 0) cr = ramp.color_ramp cr.interpolation = 'LINEAR' while len(cr.elements) > 2: cr.elements.remove(cr.elements[-1]) cr.elements[0].position, cr.elements[0].color = 0.0, (1.0, 0.03, 0.02, 1) cr.elements[1].position, cr.elements[1].color = 1.0, (0.08, 1.0, 0.18, 1) mid = cr.elements.new(0.5) mid.color = (1.0, 0.45, 0.04, 1) ramp.inputs[0].default_value = 0.0 nt.links.new(ramp.outputs["Color"], b.inputs["Emission Color"]) b.inputs["Emission Strength"].default_value = 7.0 b.inputs["Base Color"].default_value = (0.03, 0.03, 0.03, 1) b.inputs["Roughness"].default_value = 0.3 return ramp def coll(name, parent=None): c = bpy.data.collections.get(name) if c is None: c = bpy.data.collections.new(name) (parent or bpy.context.scene.collection).children.link(c) return c def add_mesh(bm, me, M, mat): v0, f0 = len(bm.verts), len(bm.faces) bm.from_mesh(me) bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() for i in range(v0, len(bm.verts)): bm.verts[i].co = M @ bm.verts[i].co for i in range(f0, len(bm.faces)): bm.faces[i].material_index = mat def text_mesh(body, size, extrude): cu = bpy.data.curves.new("sd_tmp_text", 'FONT') cu.body = body cu.size = size cu.extrude = extrude cu.align_x = 'CENTER' cu.align_y = 'CENTER' cu.resolution_u = 3 ob = bpy.data.objects.new("sd_tmp_text", cu) bpy.context.scene.collection.objects.link(ob) dg = bpy.context.evaluated_depsgraph_get() me = bpy.data.meshes.new_from_object(ob.evaluated_get(dg)) bpy.data.objects.remove(ob) bpy.data.curves.remove(cu) return me def text_at(bm, body, size, x, y, z, mat, extrude=0.0006): """lettering standing on a face at y, `extrude` proud, facing -Y (text in XZ: rotate the XY text onto XZ)""" me = text_mesh(body, size, extrude) M = Matrix.Translation((x, y - extrude, z)) @ Matrix.Rotation(math.pi / 2, 4, 'X') add_mesh(bm, me, M, mat) bpy.data.meshes.remove(me) def bolt_head(bm, M, r=0.016, mat=STEEL, n=10): """socket cap screw facing local -Y""" p = [(r, 0.003), (r, -0.008), (r * 0.75, -0.013), (r * 0.35, -0.013), (r * 0.35, -0.010), (0.0, -0.010)] lathe(bm, p, n, axis='Y', mat=mat, M=M) def ball(bm, c, r, mat, n=12): prof = [(r * math.sin(a), r * math.cos(a)) for a in [math.pi * k / 8 for k in range(9)]] lathe(bm, prof, n, center=c, axis='Y', mat=mat) def dome_lamp(bm, c, mat_lens, r=0.022): """a round lamp facing -Y at c: dark bezel ring and a domed lens""" lathe(bm, [(r + 0.008, 0.0), (r + 0.008, -0.012), (r + 0.002, -0.016), (r, -0.016)], 16, center=c, axis='Y', mat=DARK) lathe(bm, [(r, -0.016), (r * 0.72, -0.024), (0.0, -0.028)], 16, center=c, axis='Y', mat=mat_lens) def op_loop(d, seg=SEG): """the opening's outline offset outward by d""" return rr_loop(0.0, ZC, OW + d, OH + d, OR + d, seg) def pan_loop(d, seg=SEG): """the surround panel's outline (x +-1.44, z 0.06..2.96) offset by d""" return rr_loop(0.0, 1.51, 1.44 + d, 1.45 + d, 0.10 + d, seg) # ================================================================== FRAME (static): door plate, bezel, rails, sign def build_frame(mats, C): bm = bmesh.new() r = 0.012 L0 = op_loop(0.0) # --- front body: reveal, dark lip, bezel, surround panel, plate skin; its back face is the slot's front wall lv = [(L0, Y_SF, None), (L0, Y_LIP, 'in'), (op_loop(LIP_W), Y_LIP, 'front'), (op_loop(LIP_W), Y_BEZ, 'in'), (op_loop(BEZ_W - r), Y_BEZ, 'front')] lv += round_levels(op_loop, BEZ_W, Y_BEZ, Y_PAN, r) lv += [(op_loop(BEZ_W), Y_PAN, 'out'), (pan_loop(-r), Y_PAN, 'front')] lv += round_levels(pan_loop, 0.0, Y_PAN, Y_PLATE, r) RECT = rect_from_loop(pan_loop(0.0), 0.0, 1.51, -PX, PX, PZ0, PZ1) lv += [(pan_loop(0.0), Y_PLATE, 'out'), (RECT, Y_PLATE, 'front'), (RECT, Y_SF, 'out'), (L0, Y_SF, 'back')] mb = [DARK, DARK] + [PAINT] * (len(lv) - 4) + [DARK] loft(bm, lv, mats=mb, center=(0.0, ZC)) # --- spacer round the slot (the pockets' top, bottom and ends), between the front and back bodies O = rect_poly(0.0, (PZ0 + PZ1) / 2, PX, (PZ1 - PZ0) / 2) S = rect_poly(0.0, (SLOT_Z0 + SLOT_Z1) / 2, SLOT_X, (SLOT_Z1 - SLOT_Z0) / 2) loft(bm, [(S, Y_SF, None), (O, Y_SF, 'front'), (O, Y_SB, 'out'), (S, Y_SB, 'back'), (S, Y_SF, 'in')], mats=[PAINT, PAINT, PAINT, DARK], center=(0.0, ZC)) # --- back body: the slot's back wall, the reveal through the rest of the wall, the ship-side face RB = rect_from_loop(L0, 0.0, ZC, -PX, PX, PZ0, PZ1) loft(bm, [(L0, Y_SB, None), (RB, Y_SB, 'front'), (RB, Y_WB, 'out'), (op_loop(0.08), Y_WB, 'back'), (op_loop(0.08), Y_WB + 0.03, 'out'), (op_loop(0.0), Y_WB + 0.03, 'back'), (L0, Y_SB, 'in')], mats=[DARK, PAINT, PAINT, PAINT, PAINT, DARK], center=(0.0, ZC)) # the ship-side back bezel stands 3 cm proud # --- light strips on the dark lip, top and bottom for z in (OZ0 + 2 * OH + LIP_W / 2, OZ0 - LIP_W / 2): box_at(bm, (0.0, Y_LIP - 0.002, z), (0.56, 0.004, 0.022), r=0.0015, seg=1, mat=LIGHT) # --- grab rails on the surround panel, each on three brackets for sx in (-1, 1): x = sx * 0.98 tube(bm, [(x, -0.145, 0.50), (x, -0.145, 2.02)], 0.017, 14, caps=('dome', 'dome'), mat=DARK) for z in (0.56, 1.26, 1.96): box_at(bm, (x, -0.110, z), (0.05, 0.05, 0.04), r=0.004, mat=STEEL) # --- sign over the door: a rounded bezel, a dark screen, lettering poly_slab(bm, rr_loop(0.0, 2.74, 0.34, 0.09, 0.04, 6), Y_PAN, Y_PAN - 0.014, r=0.006, mat=PAINT) box_at(bm, (0.0, Y_PAN - 0.016, 2.74), (0.60, 0.004, 0.12), r=0.002, seg=1, mat=SCREEN) SCREENS["sign"] = ((0.0, Y_PAN - 0.018, 2.74), (1, 0, 0), (0, 0, 1), 0.60, 0.12, "sign") text_at(bm, "PRESSURE DOOR", 0.058, 0.0, Y_PAN - 0.018, 2.74, SIGNTXT) # --- screws on the surround panel's corners and the bezel's shoulders for (x, z) in ((-1.38, 0.14), (1.38, 0.14), (-1.38, 2.88), (1.38, 2.88), (-1.38, 1.51), (1.38, 1.51), (-0.80, 2.66)): bolt_head(bm, Matrix.Translation((x, Y_PAN, z)), 0.011, STEEL) # --- camera bracket: a block on the panel, a stub and the ball the camera turns on box_at(bm, (P_CAM.x, Y_PAN - 0.02, P_CAM.z), (0.06, 0.04, 0.06), r=0.004, mat=PAINT) tube(bm, [(P_CAM.x, Y_PAN - 0.035, P_CAM.z), (P_CAM.x, P_CAM.y, P_CAM.z)], 0.010, 10, caps=(None, None), mat=STEEL) ball(bm, P_CAM, 0.022, STEEL) return finish(bm, "SM_PDSliding_Frame", C, mats) # ================================================================== WALL (static): columns, trough, console mount, cables def build_wall(mats, C): bm = bmesh.new() for sx in (-1, 1): box_at(bm, (sx * 1.91, (Y_COL + Y_WB) / 2, 1.50), (0.78, Y_WB - Y_COL, 3.00), r=0.008, mat=PAINT) box_at(bm, (0.0, 0.18, 3.20), (4.60, 0.24, 0.40), r=0.006, mat=DARK) # cable trough, y 0.06..0.30 box_at(bm, (0.0, 0.04, 3.30), (4.60, 0.04, 0.04), r=0.004, mat=PAINT) # rail at the trough's mouth # --- right column: service hatch, four lamps, warning / vent panel, floor grille cx = 1.91 poly_slab(bm, rr_loop(cx, 2.50, 0.28, 0.12, 0.03, 6), Y_COL, Y_COL - 0.020, r=0.006, mat=PAINT) box_at(bm, (cx - 0.11, Y_COL - 0.021, 2.50), (0.10, 0.004, 0.03), r=0.002, seg=1, mat=DARK) for (dx, dz) in ((-0.24, -0.08), (0.24, -0.08), (-0.24, 0.08), (0.24, 0.08)): bolt_head(bm, Matrix.Translation((cx + dx, Y_COL - 0.020, 2.50 + dz)), 0.009, STEEL) poly_slab(bm, rr_loop(cx, 2.10, 0.30, 0.07, 0.03, 6), Y_COL, Y_COL - 0.012, r=0.005, mat=PAINT) for dx in (-0.21, -0.07, 0.07, 0.21): dome_lamp(bm, (cx + dx, Y_COL - 0.012, 2.10), LRED) poly_slab(bm, rr_loop(cx, 1.42, 0.25, 0.23, 0.03, 6), Y_COL, Y_COL - 0.016, r=0.006, mat=PAINT) box_at(bm, (cx - 0.12, Y_COL - 0.0175, 1.42), (0.16, 0.003, 0.30), r=0.001, seg=1, mat=DARK) for k in range(9): box_at(bm, (cx - 0.12, Y_COL - 0.021, 1.42 + (k - 4) * 0.032), (0.14, 0.005, 0.012), r=0.002, seg=1, mat=PAINT) box_at(bm, (cx + 0.11, Y_COL - 0.0175, 1.52), (0.14, 0.003, 0.09), r=0.001, seg=1, mat=DARK) box_at(bm, (cx + 0.11, Y_COL - 0.0195, 1.555), (0.14, 0.002, 0.012), r=0.001, seg=1, mat=ORANGE) box_at(bm, (cx, Y_COL - 0.004, 0.30), (0.66, 0.008, 0.42), r=0.002, seg=1, mat=DARK) for k in range(11): box_at(bm, (cx, Y_COL - 0.011, 0.30 + (k - 5) * 0.036), (0.62, 0.006, 0.018), r=0.002, seg=1, mat=PAINT) # --- left column: conduits with clamp straps, the console's wall bracket and clamp ring, junction box, floor cable for k in range(5): x = -2.22 + 0.034 * k path = fillet3([(x, -0.080, 0.42), (x, -0.080, 3.10), (x, 0.12, 3.26)], 0.06, 4) tube(bm, path, 0.014, 10, caps=('flat', 'dome'), mat=PAINT if k % 2 == 0 else DARK) for z in (0.95, 1.85, 2.75): box_at(bm, (-2.1525, -0.101, z), (0.235, 0.010, 0.022), r=0.002, seg=1, mat=STEEL) for x in (-2.255, -2.05): box_at(bm, (x, -0.075, z), (0.03, 0.06, 0.022), r=0.002, seg=1, mat=STEEL) box_at(bm, (P_MON.x, -0.090, P_MON.z), (0.18, 0.09, 0.22), r=0.006, mat=PAINT) tube(bm, [(P_MON.x, -0.13, P_MON.z), (P_MON.x, P_MON.y + 0.024, P_MON.z)], 0.016, 12, caps=(None, None), mat=STEEL) lathe(bm, [(0.028, P_MON.z + 0.04), (0.028, P_MON.z - 0.04), (0.0195, P_MON.z - 0.04), (0.0195, P_MON.z + 0.04), (0.028, P_MON.z + 0.04)], 20, center=(P_MON.x, P_MON.y, 0.0), axis='Z', mat=STEEL) box_at(bm, (-2.08, -0.075, 0.30), (0.34, 0.06, 0.26), r=0.006, mat=PAINT) for k, m in enumerate((LRED, LRED, LGREEN, LRED)): lathe(bm, [(0.006, 0.0), (0.0045, -0.004), (0.0, -0.0055)], 8, center=(-2.20 + 0.03 * k, -0.105, 0.36), axis='Y', mat=m) box_at(bm, (-1.97, -0.112, 0.235), (0.04, 0.014, 0.03), r=0.002, seg=1, mat=DARK) path = fillet3([(-1.97, -0.115, 0.235), (-1.97, -0.20, 0.17), (-1.95, -0.30, 0.012), (-1.40, -0.42, 0.010), (-0.30, -0.47, 0.010), (0.90, -0.42, 0.010), (1.95, -0.30, 0.010), (2.30, -0.26, 0.010)], 0.08, 4) tube(bm, path, 0.009, 10, caps=('flat', 'dome'), mat=RUBBER) # --- cables along the top: clips on the rail, bundles sagging between them for x in CLIPS_X: box_at(bm, (x, -0.01, 3.30), (0.035, 0.06, 0.07), r=0.003, seg=1, mat=DARK) offs = [(-0.016, 0.004), (-0.028, 0.010), (-0.022, -0.010), (-0.038, -0.004), (-0.012, -0.016), (-0.034, 0.016), (-0.046, 0.002)] rads = [0.009, 0.011, 0.008, 0.010, 0.007, 0.009, 0.008] mats_c = [RUBBER, RUBBER, CRED, RUBBER, RUBBER, RUBBER, CRED] for k, ((dy, dz), rr, m) in enumerate(zip(offs, rads, mats_c)): path = [] for i in range(len(CLIPS_X) - 1): x0, x1 = CLIPS_X[i], CLIPS_X[i + 1] sag = 0.10 + 0.05 * ((k * 7 + i * 3) % 5) / 4.0 side = 0.02 + 0.015 * ((k * 3 + i) % 3) / 2.0 seg = sag_path((x0, dy, 3.28 + dz), (x1, dy, 3.28 + dz), sag, 10, side) path += seg if i == 0 else seg[1:] tube(bm, path, rr, 8, caps=('dome', 'dome'), mat=m) return finish(bm, "SM_PDSliding_Wall", C, mats) # ================================================================== LEAVES (moving) def leaf_outline(side): return clip_poly(rr_loop(0.0, ZC, OW + REB, OH + REB, OR + REB, SEG), halfplane(side, side * SEAM)) def field_outline(side): return clip_poly(rr_loop(0.0, ZC, OW - 0.04, OH - 0.04, OR - 0.04, SEG), halfplane(side, side * 0.012)) def band_piece(side): """the raised diagonal band: a long strip along BAND_ANG from 0.17 m past the ring, clipped to the field""" s0, s1, hw = 0.17, 3.0, 0.07 ang = BAND_ANG if side > 0 else BAND_ANG + math.pi rect = [Vector((s0, -hw)), Vector((s1, -hw)), Vector((s1, hw)), Vector((s0, hw))] poly = [Vector((0.0, ZC)) + Matrix.Rotation(ang, 2) @ p for p in rect] poly = clip_poly(poly, field_outline(side)) return clip_poly(poly, halfplane(side, side * 0.012)) def bar_piece(side): rect = [Vector((-0.088, -0.020)), Vector((0.088, -0.020)), Vector((0.088, 0.020)), Vector((-0.088, 0.020))] poly = [Vector((0.0, ZC)) + Matrix.Rotation(BAND_ANG, 2) @ p for p in rect] return clip_poly(poly, halfplane(side, side * 0.003)) def build_leaf(side, mats, C): bm = bmesh.new() base = leaf_outline(side) poly_slab(bm, base, Y_FLOOR, Y_LB, r=0.010, mat=PAINT) # back layer, rounded back edge; its front is the recess floor poly_slab(bm, notch_edge(base, side * SEAM, ZC, R_NOTCH, side), Y_FLOOR, Y_LF, r=0.006, mat=PAINT) # front layer with the lock notch poly_slab(bm, notch_edge(field_outline(side), side * 0.012, ZC, R_NOTCH, side), Y_LF, Y_FIELD, r=0.003, mat=PAINT) # raised field poly_slab(bm, band_piece(side), Y_FIELD, Y_BAND, r=0.003, mat=PAINT) # diagonal band # the lock ring's half: dark ring with the light channel, stopping 1 mm short of the seam delta = math.asin(0.003 / R_RING_OUT) a0, a1 = (math.pi / 2 + delta, 3 * math.pi / 2 - delta) if side < 0 else (-math.pi / 2 + delta, math.pi / 2 - delta) prof = [(R_RING_OUT, Y_FIELD), (R_RING_OUT, Y_RING + 0.004), (R_RING_OUT - 0.004, Y_RING), (R_RING_IN + 0.004, Y_RING), (R_RING_IN, Y_RING + 0.004), (R_RING_IN, Y_FLOOR)] _, rows = lathe(bm, prof, 24, center=(0.0, 0.0, ZC), axis='Y', a0=a0, a1=a1, mat=DARK) for col in (0, -1): face(bm, [rows[i][col] for i in range(len(prof))], DARK, out=Vector((-side, 0, 0))) lathe(bm, [(R_RING_IN + 0.024, Y_RING - 0.0005), (R_RING_IN + 0.006, Y_RING - 0.0005)], 24, center=(0.0, 0.0, ZC), axis='Y', a0=a0, a1=a1, mat=LOCK) lathe(bm, [(R_RING_IN - 0.004, Y_FLOOR - 0.0008), (0.0, Y_FLOOR - 0.0008)], 24, center=(side * 0.0025, 0.0, ZC), axis='Y', a0=a0, a1=a1, mat=DARK) # dark floor of the recess poly_slab(bm, bar_piece(side), Y_FLOOR, Y_RING + 0.0005, r=0.004, mat=PAINT) # the bar across the recess (its half), flush with the ring # markings and small parts if side < 0: text_at(bm, "< < <", 0.034, -0.30, Y_FIELD, 2.22, ORANGE) box_at(bm, (-0.47, Y_FIELD - 0.002, 2.13), (0.064, 0.004, 0.094), r=0.002, seg=1, mat=DARK) box_at(bm, (-0.47, Y_FIELD - 0.0045, 2.13), (0.046, 0.001, 0.072), r=0.0005, seg=1, mat=SCREEN) SCREENS["keypad"] = ((-0.47, Y_FIELD - 0.005, 2.13), (1, 0, 0), (0, 0, 1), 0.046, 0.072, "keypad") else: text_at(bm, "> > >", 0.034, 0.30, Y_FIELD, 2.22, ORANGE) text_at(bm, "PRESSURE DOOR", 0.030, 0.40, Y_FIELD, 2.06, ORANGE) text_at(bm, "01", 0.17, 0.40, Y_FIELD, 1.88, ORANGE) poly_slab(bm, rr_loop(side * 0.16, 0.48, 0.07, 0.07, 0.02, 4), Y_FIELD, Y_FIELD - 0.006, r=0.003, mat=PAINT) box_at(bm, (side * 0.16, Y_FIELD - 0.007, 0.48), (0.09, 0.003, 0.016), r=0.001, seg=1, mat=DARK) box_at(bm, (side * 0.14, Y_FIELD - 0.002, 2.27), (0.07, 0.004, 0.012), r=0.002, seg=1, mat=DARK) name = "SM_PDSliding_LeafL" if side < 0 else "SM_PDSliding_LeafR" ob = finish(bm, name, C, mats, origin=P_LEAF[side]) ob["closed_location"] = list(ob.location) ob["slide_x"] = side * TRAVEL return ob # ================================================================== CONSOLE (moving): post, neck, monitor, tray def build_monitor(mats, C): bm = bmesh.new() px, py, pz = P_MON tube(bm, [(px, py, 1.10), (px, py, 1.42)], 0.017, 14, caps=('dome', 'dome'), mat=STEEL) tube(bm, fillet3([(px, py, 1.40), (px, py, 1.49), (px, py - 0.085, 1.50)], 0.04, 4), 0.014, 12, caps=(None, 'dome'), mat=STEEL) R = Matrix.Rotation(MON_TILT, 4, 'X') c = Vector((px, py - 0.105, 1.52)) box_at(bm, c, (0.50, 0.03, 0.34), r=0.008, seg=2, mat=DARK, rot=R) sc = c + R.to_3x3() @ Vector((0, -0.0165, 0)) box_at(bm, sc, (0.46, 0.004, 0.30), r=0.0008, seg=1, mat=SCREEN, rot=R) u, v = Vector((1, 0, 0)), R.to_3x3() @ Vector((0, 0, 1)) SCREENS["monitor"] = (tuple(sc + R.to_3x3() @ Vector((0, -0.002, 0))), tuple(u), tuple(v), 0.46, 0.30, "monitor") box_at(bm, c + R.to_3x3() @ Vector((0, 0, -0.19)), (0.08, 0.03, 0.04), r=0.004, mat=DARK, rot=R) # the monitor's chin tube(bm, fillet3([(px, py, 1.12), (px, py - 0.06, 1.12), (px, py - 0.13, 1.09)], 0.03, 4), 0.012, 10, caps=(None, 'dome'), mat=STEEL) box_at(bm, (px, py - 0.15, 1.075), (0.40, 0.14, 0.016), r=0.004, mat=PAINT) box_at(bm, (px, py - 0.155, 1.085), (0.32, 0.09, 0.004), r=0.001, seg=1, mat=DARK) for k in range(10): for j in range(3): box_at(bm, (px - 0.135 + 0.03 * k, py - 0.125 - 0.03 * j, 1.0885), (0.024, 0.024, 0.003), r=0.001, seg=1, mat=DARK) ob = finish(bm, "SM_PDSliding_Monitor", C, mats, origin=P_MON) ob["closed_rotation"] = [0.0, 0.0, 0.0] return ob # ================================================================== CAMERA (moving) def build_camera(mats, C): bm = bmesh.new() M = Matrix.Translation(P_CAM) @ Matrix.Rotation(CAM_PITCH, 4, 'X') axis = lambda t: M @ Vector((0, -t, 0)) tube(bm, [axis(0.060), axis(0.20)], 0.028, 16, caps=('dome', 'flat'), mat=PAINT) # its back dome stops 1 cm short of the ball lathe(bm, [(0.016, -0.025), (0.016, -0.045), (0.0, -0.045)], 12, center=(0, 0, 0), axis='Y', mat=STEEL, M=M) # the neck from the ball lathe(bm, [(0.034, -0.16), (0.034, -0.215), (0.028, -0.215), (0.028, -0.16)], 16, center=(0, 0, 0), axis='Y', mat=DARK, M=M) # hood lathe(bm, [(0.019, -0.200), (0.019, -0.206), (0.0, -0.206)], 16, center=(0, 0, 0), axis='Y', mat=GLASS, M=M) # lens lathe(bm, [(0.004, -0.199), (0.004, -0.203), (0.0, -0.203)], 8, center=(0, 0, 0), axis='Y', mat=LRED, M=M @ Matrix.Translation((0.022, 0, 0.0))) ob = finish(bm, "SM_PDSliding_Camera", C, mats, origin=P_CAM) ob["closed_rotation"] = [0.0, 0.0, 0.0] return ob # ================================================================== assemble def build_all(): mats = get_mats() top = coll("PressureDoorSliding") cs, cm = coll("PDS | static", top), coll("PDS | moving", top) root = bpy.data.objects.get("PressureDoorSliding_Root") if root is None: root = bpy.data.objects.new("PressureDoorSliding_Root", None) root.empty_display_type = 'ARROWS' root.empty_display_size = 0.5 top.objects.link(root) obs = [build_frame(mats, cs), build_wall(mats, cs)] movers = [build_leaf(-1, mats, cm), build_leaf(1, mats, cm), build_monitor(mats, cm), build_camera(mats, cm)] for ob in obs + movers: ob.parent = root ob.matrix_parent_inverse = Matrix.Identity(4) root["screens"] = {k: {"c": list(v[0]), "u": list(v[1]), "v": list(v[2]), "w": v[3], "h": v[4], "region": v[5]} for k, v in SCREENS.items()} return dict(objects=[audit(o) for o in obs + movers]) if not globals().get("SD_NO_AUTORUN"): RESULT = build_all()