"""Door robot arm: the turret (J1), rebuilt in Coder stage 2 after CRITIQUE_1 item 2 (and item 8: belt drive, bundle). Arm frame A at rest (metres): X forward, Y the arm's left, Z up from the turntable face; J2 at (-0.341, 0, 0.517). ref1 px -> A: X = (1000 - x) * 0.0022, Z = (1550 - y) * 0.0022. What the pictures show (ref1 x 765-1225, y 1200-1395; ref3, ref4, ref7) and how it is built here: - one long, low housing on each side, X -0.50..+0.515, Z 0.345..0.742: chamfered front top, a stepped top line with a long diagonal seam, raised lids, the J2 motor cap set into its rounded rear end. In front of the drum (X > -0.035) the housing is one block across the width (|Y| <= 0.30); behind that only the two side housings (cheeks, |Y| 0.215..0.30) stand beside the drum, so the drum's perforated side face shows behind them (ref3). - J2 motor caps: cylinder stacks standing 0.098 proud of the cheeks, faces at |Y| 0.398 (ref7: inside the carriage's width; the old pods put them at 0.543). - lower block: three stacked rounded slabs, Z 0.06..0.348, 0.60 m wide at the bottom; the middle slab sticks out at the front (the lip), a recessed slot, a raised tab and screws on the sides; the top tier stands only under the housing, never under the drum (the drum and the lower arm's root band turn there). - belt drive (item 8): the white ringed J1 motor with a dark lens stands outboard in front; a wide black belt with big lugs runs on a dark sprocket inboard of it, in two runs back into a pocket in the lower block's front. - cable bundle (item 8): a flat band of seven cables with white clips from a flat gland on the front chamfer down to the clamp over the motor. """ import math import bmesh from mathutils import Vector, Matrix from dra_lib import (Link, lathe, slab, rbox, tube, knurl, merge, xform, frame, basis, mirror_y, fillet, ccw, inset_poly, clip_half, face, W, G, S, R, O, GL, LA, TAU, decal_strip, decal_poly, path_frames, fillet3d) from dra_shapes import (rrect, stadium, xz_slab, yz_slab, xy_slab, screw, dome, hexbolt, ring, cyl, grooved_cyl, holed_plate) from dra_lib import stack as rings_stack J2 = Vector((-0.341, 0.0, 0.517)) HW = 0.292 EDGE = 0.026 # stage 3: the rounded transition from the side faces into the top, front and back # housing core side face; raised panels to 0.300 PANEL = 0.008 CHEEK_IN = 0.215 # cheeks' inner faces (the drum's side faces are at |Y| 0.200, its hubs 0.208) XB = -0.035 # the front block's back face between the cheeks Z_BOT = 0.345 # housing bottom CAP_BASE = HW + PANEL # 0.300 # side outline of the housing (X, Z, round), counter-clockwise. Stage 3 shape pass: behind the stepped top the housing # steps down and ends in an arc round the J2 cap (R_REAR about J2): its top above the cap at Z 0.70 (ref1 x_img 1155: # y_img 1234), so the drum stands 0.06 above it as in ref7 R_REAR = 0.185 def _rear_arc(): out = [] for k in range(13): a = math.radians(74 + (228 - 74) * k / 12) out.append((J2.x + R_REAR * math.cos(a), J2.z + R_REAR * math.sin(a), 0.0)) return out H_OUT = [ (0.515, 0.345, 0.010), (0.515, 0.600, 0.012), (0.452, 0.700, 0.012), (0.240, 0.700, 0.010), (0.192, 0.742, 0.010), (-0.135, 0.742, 0.030), (-0.232, 0.700, 0.020)] + _rear_arc() + [(-0.420, 0.345, 0.030)] def poly_of(outline, n=3): return ccw([p for p, _ in fillet(outline, closed=True, n=n)]) def clip(P, halfplanes): """P (CCW Vector2 list) cut by half planes ((nx, nz), d): keep n . p <= d""" for (nx, nz), d in halfplanes: if len(P) < 3: return [] P = clip_half(P, Vector((nx, nz)), d) return P def to_pts(P, r=0.0): return [(p.x, p.y, r) for p in P] def sided(L, bm, s, pid, mat, seats=()): if s < 0: mirror_y(bm) L.put(bm, mat=mat, pid=pid + ('.L' if s > 0 else '.R'), seats=seats) # ------------------------------------------------------------------ lower block def _lower_block(L): # B1 bottom slab (widest), sits on the turning race T01 (top 0.059) L.put(xy_slab(rrect(0.760, 0.600, 0.070, -0.020, 0.0), 0.060, 0.140, 0.004, 0.006), mat=W, pid='T02', seats=('T01',)) # B2 middle slab: the lip sticks out at the front; a pocket for the belt (Y 0.028..0.114) at the front b2 = [(-0.375, -0.268, 0.060), (0.400, -0.268, 0.075), (0.400, 0.028, 0.006), (0.190, 0.028, 0.008), (0.190, 0.114, 0.008), (0.400, 0.114, 0.006), (0.400, 0.268, 0.075), (-0.375, 0.268, 0.060)] L.put(xy_slab(b2, 0.144, 0.252, 0.005, 0.006), mat=W, pid='T02m', seats=('T02',)) # groove bead between B1 and B2 (dark), a little inside L.put(xy_slab(rrect(0.730, 0.560, 0.055, -0.005, 0.0), 0.139, 0.146, 0.0, 0.0), mat=G, pid='T02g', seats=('T02', 'T02m')) # B3 top tier: in front of the drum across the width (pocket for the belt), and under each cheek b3 = [(XB, -0.262, 0.020), (0.330, -0.262, 0.045), (0.330, 0.028, 0.004), (0.190, 0.028, 0.006), (0.190, 0.114, 0.006), (0.330, 0.114, 0.004), (0.330, 0.262, 0.045), (XB, 0.262, 0.020)] L.put(xy_slab(b3, 0.256, 0.348, 0.005, 0.0), mat=W, pid='T02t', seats=('T02m', 'T03', 'T03c.L', 'T03c.R')) for s in (1, -1): bm = xy_slab(rrect(0.370, 0.063, 0.020, -0.215, 0.2535), 0.256, 0.348, 0.005, 0.0) # 5 mm into the front piece sided(L, bm, s, 'T02t', W, seats=('T02m', 'T03c', 'T02t')) # pocket floor/walls are the slabs themselves; a dark back wall in the pocket L.put(rbox((0.012, 0.086, 0.196), 0.002), Matrix.Translation((0.196, 0.071, 0.248)), G, 'T02p', seats=('T02m', 'T02t', 'T02', 'T03')) # side details: recessed slot on B1, raised tab on B1, slot panel on B2, warning stripes (markings, later) for s in (1, -1): sd = '.L' if s > 0 else '.R' sp = rbox((0.150, 0.040, 0.006), 0.0015, ops=[('+z', -0.066, 0.066, -0.012, 0.012, -0.004)], rbev=0.001) L.put(sp, frame((0.205, s * 0.2985, 0.100), (0, s, 0), spin=math.pi / 2 if s > 0 else -math.pi / 2), G, 'T02c' + sd, seats=('T02',)) L.put(rbox((0.050, 0.014, 0.070), 0.004, rv=0.010, vax=1), Matrix.Translation((0.055, s * 0.302, 0.100)), W, 'T02x' + sd, seats=('T02',)) sp2 = rbox((0.17, 0.056, 0.005), 0.002, ops=[('+z', -0.077, 0.077, -0.020, 0.020, -0.0035)], rbev=0.004, rim_segs=2) L.put(sp2, frame((-0.170, s * 0.2665, 0.198), (0, s, 0)), W, 'T02f' + sd, seats=('T02m',)) # the rear corner glands where the side cable pairs end (B1's sides) L.put(rings_stack([(0.066, 0.016, 'paint_white'), (0.048, 0.030, 'rubber')], 24, base=0.004), frame((-0.280, s * 0.2985, 0.100), (0, s, 0)), None, 'T02d' + sd, seats=('T02',)) # front corner screws on B2's front corners for z in (0.170, 0.200, 0.228): L.put(screw(0.0055), frame((0.3998, s * 0.215, z), 'X'), None, 'T02e' + sd, seats=('T02m',)) # back screw strips on B1 + B2's back faces L.put(rbox((0.006, 0.0396, 0.176), 0.0015), Matrix.Translation((-0.3775, s * 0.114, 0.158)), W, 'T02a' + sd, seats=('T02', 'T02m', 'T02g')) for z in (0.095, 0.158, 0.221): L.put(screw(0.0055), frame((-0.3805, s * 0.114, z), '-X'), None, 'T02a' + sd, seats=('T02a' + sd,)) # back latch: slot plate with a bent tab over its top (ref7 middle) lp = rbox((0.110, 0.180, 0.006), 0.0015, ops=[('+z', -0.022, 0.022, -0.075, 0.075, -0.004)], rbev=0.001) L.put(lp, frame((-0.3785, 0, 0.160), '-X', spin=math.pi / 2), G, 'T02b', seats=('T02', 'T02m', 'T02g')) tab = [(-0.3865, 0, 0.215), (-0.405, 0, 0.215), (-0.405, 0, 0.258), (-0.370, 0, 0.258)] for yy in (-0.016, 0.016): L.put(tube([(x, yy, z) for x, _, z in tab], 0.0045, 10, 0.008), None, S, 'T02b', seats=('T02b', 'T02m')) # dot vent on B3's front face (beside the belt pocket) vent = holed_plate(0.090, 0.056, 0.004, 6, 4, 0.0122, 0.0032, 0.003, mat=G) L.put(vent, frame((0.3295, -0.150, 0.302), 'X', spin=math.pi / 2), None, 'T16', seats=('T02t',)) # ------------------------------------------------------------------ housing def _housing(L): P = poly_of(H_OUT) front = clip(P, [((-1, 0), -XB)]) # X >= XB rear = clip(P, [((1, 0), XB + 0.010)]) # X <= XB + 0.01 (overlaps the block 10 mm: its seat) L.put(xz_slab(to_pts(front), -HW, HW, EDGE, EDGE, n=1, steps=3), mat=W, pid='T03', seats=('T02t',)) for s in (1, -1): bm = xz_slab(to_pts(rear), CHEEK_IN, HW, 0.008, EDGE, n=1, steps=3) sided(L, bm, s, 'T03c', W, seats=('T03', 'T02t')) # raised side panels (8 mm) cut into pieces by the seams of ref1: a horizontal seam at Z 0.575, the long diagonal # down from the step, a vertical seam before the cap, one in front of the connector boss Pi = inset_poly(P, EDGE + 0.006) # the panels sit inside the rounded edges g = 0.002 d1 = Vector((0.192, 0.742)) - Vector((0.090, 0.578)) nd = Vector((d1.y, -d1.x)).normalized() # right of the diagonal (toward +X) cd = nd.dot(Vector((0.090, 0.578))) pieces = [ ("cap", clip(Pi, [((1, 0), -0.175 - g)])), ("upmid", clip(Pi, [((-1, 0), 0.175 - g), ((0, -1), -0.575 - g), ((nd.x, nd.y), cd - g)])), ("upfront", clip(Pi, [((0, -1), -0.575 - g), ((-nd.x, -nd.y), -cd - g)])), ("lowmid", clip(Pi, [((-1, 0), 0.175 - g), ((0, 1), 0.575 - g), ((1, 0), 0.330 - g)])), ("lowfront", clip(Pi, [((0, 1), 0.575 - g), ((-1, 0), -0.330 - g)])), ] for s in (1, -1): for nm, pc in pieces: if len(pc) < 3: continue bm = xz_slab(to_pts(pc), HW - 0.002, HW + PANEL, 0.0, 0.004, n=1, steps=2) sided(L, bm, s, 'T03p', W, seats=('T03', 'T03c', 'T03p')) # a skirt ledge along the housing's foot, standing out 16 mm (a stepped lower edge, ref1 and ref4) led = [(-0.395, 0.350, 0.004), (0.430, 0.350, 0.004), (0.430, 0.372, 0.006), (-0.395, 0.372, 0.006)] bm = xz_slab(led, HW - 0.010, HW + 0.016, 0.0, 0.004, n=1, steps=2) sided(L, bm, s, 'T03f', W, seats=('T03', 'T03c', 'T03p', 'T02t')) # a raised lid along each housing's top behind the step, bent round the cap's arc (ref1: the stepped top line) lid_pts = [(-0.150, 0.744, 0.0), (-0.226, 0.708, 0.0)] + [ (J2.x + (R_REAR + 0.006) * math.cos(math.radians(a)), J2.z + (R_REAR + 0.006) * math.sin(math.radians(a)), 0.0) for a in range(80, 150, 10)] lid_in = [(J2.x + (R_REAR - 0.030) * math.cos(math.radians(a)), J2.z + (R_REAR - 0.030) * math.sin(math.radians(a)), 0.0) for a in range(140, 70, -10)] + [(-0.236, 0.680, 0.0), (-0.152, 0.718, 0.0)] for s in (1, -1): bm = xz_slab(lid_pts + lid_in, CHEEK_IN + 0.030, HW - 0.016, 0.006, 0.006, n=1, steps=2) sided(L, bm, s, 'T03k', W, seats=('T03c', 'T03', 'T03p')) # lids on top: a thin lid on the front top and the raised block behind the step (ref1 x 955-1000) L.put(rbox((0.150, 0.420, 0.016), 0.004, rv=0.02, vax=2), Matrix.Translation((0.365, 0, 0.707)), W, 'T03l', seats=('T03',)) L.put(rbox((0.120, 0.300, 0.034), 0.006, rv=0.03, vax=2), Matrix.Translation((0.040, 0, 0.756)), W, 'T03l', seats=('T03',)) L.put(rings_stack([(0.055, 0.016, 'paint_white'), (0.036, 0.006, 'gunmetal')], 24, base=0.002), frame((0.330, -0.100, 0.715)), None, 'T03a', seats=('T03l',)) # J2 motor caps set into the cheeks' rear ends (ref1: white bezel, dark ring of slots, thin ORANGE ring, dark hub # with rings, hex bolt); they stand 0.098 proud (ref7) for s in (1, -1): sd = '.L' if s > 0 else '.R' Mc = frame((J2.x, s * CAP_BASE, J2.z), (0, s, 0)) cap = rings_stack([(0.280, 0.030, 'paint_white'), (0.262, 0.006, 'paint_white'), (0.226, 0.016, 'gunmetal'), (0.140, 0.010, 'gunmetal'), (0.128, 0.004, 'orange'), (0.118, 0.010, 'gunmetal'), (0.100, 0.008, 'gunmetal'), (0.084, 0.006, 'gunmetal')], 32, base=0.004) L.put(cap, Mc, None, 'T04a' + sd, seats=('T03p' + sd, 'T03c' + sd)) L.put(hexbolt(0.036, 0.016), Mc @ Matrix.Translation((0, 0, 0.090)), None, 'T04b' + sd, seats=('T04a' + sd,)) # ring of slots in the dark ring (12 short notches) for k in range(12): a = TAU * (k + 0.5) / 12 M = Mc @ Matrix.Translation((0.095 * math.cos(a), 0.095 * math.sin(a), 0.0505)) @ Matrix.Rotation(a, 4, 'Z') L.put(rbox((0.020, 0.008, 0.004), 0.001, segs=1), M, G, 'T04n' + sd, seats=('T04a' + sd,)) for k in range(8): a = TAU * (k + 0.5) / 8 L.put(screw(0.005), Mc @ Matrix.Translation((0.123 * math.cos(a), 0.123 * math.sin(a), 0.036)), None, 'T04s' + sd, seats=('T04a' + sd,)) # connector boss (left), cable port glands (both), vent slots (both) L.put(rings_stack([(0.115, 0.020, 'paint_white'), (0.090, 0.006, 'gunmetal'), (0.064, 0.018, 'gunmetal'), (0.030, 0.006, 'steel')], 28, base=0.003), frame((0.385, CAP_BASE, 0.452), 'Y'), None, 'T05', seats=('T03p.L',)) for s in (1, -1): sd = '.L' if s > 0 else '.R' L.put(rings_stack([(0.106, 0.026, 'paint_white'), (0.080, 0.006, 'paint_white'), (0.070, 0.040, 'rubber')], 24, base=0.003), frame((0.160, s * CAP_BASE, 0.445), (0, s, 0)), None, 'T06' + sd, seats=('T03p' + sd,)) sl = rbox((0.036, 0.100, 0.006), 0.0015, ops=[('+z', -0.010, 0.010, -0.040, 0.040, -0.004)], rbev=0.001) L.put(sl, frame((0.461, s * (CAP_BASE - 0.001), 0.420), (0, s, 0)), G, 'T17' + sd, seats=('T03p' + sd,)) # three screw domes along the lower panel's bottom edge for x in (-0.12, 0.05, 0.25): L.put(dome(0.008, 0.005, W), frame((x, s * CAP_BASE, 0.394), (0, s, 0)), None, 'T03s' + sd, seats=('T03p' + sd,)) # ------------------------------------------------------------------ belt drive (item 8) PC = Vector((0.671, 0.0, 0.242)) # sprocket / motor axis (Y) PH = Vector((0.300, 0.0, 0.2425)) # the hidden pulley in the lower block's pocket R_SP = 0.058 # sprocket body radius R_HP = 0.060 BELT_IN = 0.059 # belt inner radius on the sprocket (1 mm over the body) BELT_T = 0.016 LUG = 0.019 BY0, BY1 = 0.040, 0.100 # belt edges (Y) def _belt_drive(L): # inner bracket plate (Y 0.010..0.028) from the housing's front bottom down round the sprocket axle and the idler plate = [(0.455, 0.352, 0.0), (0.600, 0.352, 0.020), (0.735, 0.300, 0.040), (0.742, 0.200, 0.040), (0.690, 0.070, 0.030), (0.610, 0.060, 0.025), (0.585, 0.140, 0.020), (0.455, 0.300, 0.010)] L.put(xz_slab(plate, 0.010, 0.028, 0.003, 0.003), mat=W, pid='T11', seats=('T03', 'T03p.L')) # outer plate: the motor's flange (Y 0.108..0.120) up to the housing's front face plate2 = [(0.515, 0.352, 0.0), (0.640, 0.352, 0.020), (0.742, 0.300, 0.040), (0.760, 0.236, 0.030), (0.700, 0.172, 0.020), (0.600, 0.196, 0.020), (0.515, 0.300, 0.0)] L.put(xz_slab(plate2, 0.108, 0.120, 0.002, 0.002), mat=W, pid='T11', seats=('T03',)) L.put(xz_slab(rrect(0.220, 0.016, 0.004, 0.630, 0.360), 0.010, 0.120, 0.003, 0.003), mat=W, pid='T11', seats=('T11', 'T03')) for x, z in ((0.535, 0.335), (0.585, 0.340), (0.635, 0.346)): L.put(screw(0.0055), frame((x, 0.120, z), 'Y'), None, 'T11s', seats=('T11',)) # sprocket (dark) with flanges, and its axle through both plates prof = [(0.0, 0.032, 0, G), (0.070, 0.032, 0.001, G), (0.070, 0.036, 0.001, G), (R_SP, 0.036, 0, G), (R_SP, 0.104, 0, G), (0.070, 0.104, 0.001, G), (0.070, 0.108, 0.001, G), (0.0, 0.108, 0, G)] L.put(lathe(prof, 32, n=1), frame(PC, 'Y'), None, 'T12p', seats=('T11',)) L.put(cyl(0.012, 0.114, 12, 0.001, S, z0=0.008), frame(PC, 'Y'), S, 'T12x', seats=('T11', 'T12p', 'T12')) # the J1 motor: white ringed drum outboard of the flange plate, 5 grooves, front face with a white bezel and a # dark lens standing out (ref1 x 655-735, y 1400-1475) prof = [(0.0, 0.120, 0, W), (0.086, 0.120, 0.003, W)] y = 0.124 for k in range(5): prof += [(0.088, y, 0.0, W), (0.088, y + 0.0035, 0.0, W), (0.083, y + 0.0045, 0, W), (0.083, y + 0.0060, 0, W), (0.088, y + 0.0070, 0, W)] y += 0.0070 prof += [(0.088, 0.160, 0.004, W), (0.0, 0.160, 0, W)] L.put(lathe(prof, 40, n=1), frame(PC, 'Y'), None, 'T12', seats=('T11',)) L.put(rings_stack([(0.150, 0.008, 'paint_white'), (0.132, 0.006, 'paint_white'), (0.104, 0.006, 'gunmetal'), (0.086, 0.012, 'glass_dark'), (0.040, 0.004, 'gunmetal')], 40, base=0.002), frame((PC.x, 0.160, PC.z), 'Y'), None, 'T12b', seats=('T12',)) # hidden pulley in the pocket (dark), on an axle into the pocket's walls prof = [(0.0, 0.032, 0, G), (0.070, 0.032, 0.001, G), (0.070, 0.036, 0.001, G), (R_HP, 0.036, 0, G), (R_HP, 0.104, 0, G), (0.070, 0.104, 0.001, G), (0.070, 0.108, 0.001, G), (0.0, 0.108, 0, G)] L.put(lathe(prof, 28, n=1), frame(PH, 'Y'), None, 'T14h', seats=('T02m', 'T02t')) L.put(cyl(0.010, 0.090, 12, 0.001, S, z0=0.025), frame(PH, 'Y'), S, 'T14h', seats=('T02m', 'T02t', 'T14h')) # idler (jockey wheel) below the lower run on the inner plate, with its bolt ic = Vector((0.645, 0.0, 0.098)) L.put(lathe([(0.0, 0.028, 0, S), (0.008, 0.028, 0, S), (0.008, 0.040, 0, G), (0.030, 0.040, 0.002, G), (0.030, 0.100, 0.002, G), (0.0, 0.100, 0, G)], 24), frame(ic, 'Y'), None, 'T14', seats=('T11',)) L.put(rings_stack([(0.024, 0.006, 'steel')], 16, base=0.001), frame((ic.x, 0.100, ic.z), 'Y'), None, 'T14', seats=('T14',)) _belt(L) # T10 clamp over the motor: two halves with a slot and a bolt, sized for the flat cable band for z0, z1 in ((0.368, 0.404), (0.408, 0.446)): L.put(xz_slab(rrect(0.150, z1 - z0, 0.010, 0.690, (z0 + z1) / 2), 0.010, 0.170, 0.004, 0.005), mat=W, pid='T10', seats=('T11', 'T10')) L.put(hexbolt(0.020, 0.008), frame((0.640, 0.170, 0.426), 'Y'), None, 'T10b', seats=('T10',)) L.put(hexbolt(0.020, 0.008), frame((0.740, 0.170, 0.426), 'Y'), None, 'T10b', seats=('T10',)) L.put(xz_slab(rrect(0.018, 0.006, 0.002, 0.690, 0.426), 0.1698, 0.1706, 0.0, 0.0), mat=O, pid='T10t', seats=('T10',), decal=True) def _belt(L): """a closed belt (Y BY0..BY1) round the sprocket PC and the hidden pulley PH, flat inner face, big lugs outside""" def P2(c, r, t): return Vector((c.x + r * math.cos(t), c.y + r * math.sin(t))) r1, r2 = BELT_IN + BELT_T / 2, (R_HP + 0.001) + BELT_T / 2 C1, C2 = Vector((PC.x, PC.z)), Vector((PH.x, PH.z)) d = C2 - C1 ang = math.atan2(d.y, d.x) al = math.acos(max(-1.0, min(1.0, (r1 - r2) / d.length))) up, lo = ang - al, ang + al if math.sin(up) < math.sin(lo): up, lo = lo, up pts = [] a0, a1 = up, lo while a1 > a0: a1 -= TAU for k in range(25): pts.append(P2(C1, r1, a0 + (a1 - a0) * k / 24)) b0, b1 = lo, up while b0 < b1: b0 += TAU for k in range(17): pts.append(P2(C2, r2, b0 + (b1 - b0) * k / 16)) # resample the loop evenly (about 6 mm) loop = [] n = len(pts) for i in range(n): a, b = pts[i], pts[(i + 1) % n] m = max(1, int((b - a).length / 0.006)) for j in range(m): loop.append(a.lerp(b, j / m)) n = len(loop) h = BELT_T / 2 bm = bmesh.new() rings = [] for i in range(n): t = (loop[(i + 1) % n] - loop[i - 1]).normalized() nrm = Vector((-t.y, t.x)) # the loop runs clockwise: this points outward rings.append([bm.verts.new((loop[i].x + nrm.x * dn, yy, loop[i].y + nrm.y * dn)) for (yy, dn) in ((BY0, -h), (BY1, -h), (BY1, h), (BY0, h))]) for i in range(n): A, B = rings[i], rings[(i + 1) % n] cen = Vector(((loop[i].x + loop[(i + 1) % n].x) / 2, (BY0 + BY1) / 2, (loop[i].y + loop[(i + 1) % n].y) / 2)) for k in range(4): k2 = (k + 1) % 4 mid = (A[k].co + A[k2].co + B[k].co + B[k2].co) / 4 face(bm, [A[k], A[k2], B[k2], B[k]], R, out=mid - cen) L.put(bm, None, R, 'T13', seats=('T12p', 'T14h', 'T02p', 'T02m', 'T02t', 'T13t')) # lugs every 0.040 m: rectangular blocks 0.020 x (width - 6 mm) x 0.012 on the outer face seg = [(loop[(i + 1) % n] - loop[i]).length for i in range(n)] total = sum(seg) s = 0.02 while s < total - 0.01: acc = 0.0 for i in range(n): if acc + seg[i] >= s: f = (s - acc) / seg[i] p = loop[i].lerp(loop[(i + 1) % n], f) t = (loop[(i + 1) % n] - loop[i]).normalized() nrm = Vector((-t.y, t.x)) M = Matrix(((t.x, 0, nrm.x), (0, 1, 0), (t.y, 0, nrm.y))).to_4x4() M.translation = Vector((p.x + nrm.x * (h + LUG / 2 - 0.0005), (BY0 + BY1) / 2, p.y + nrm.y * (h + LUG / 2 - 0.0005))) L.put(rbox((0.022, BY1 - BY0 - 0.006, LUG), 0.002, segs=1), M, R, 'T13t', seats=('T13', 'T02p', 'T02m', 'T02t', 'T13t')) break acc += seg[i] s += 0.042 # ------------------------------------------------------------------ cables def _cables(L): # T08 flat gland on the front chamfer (white frame, rubber insert), facing along the chamfer's normal a, b = Vector((0.515, 0.600)), Vector((0.452, 0.700)) t2 = (b - a).normalized() n2 = Vector((t2.y, -t2.x)) # outward (CCW outline) gm = (a + b) / 2 nrm = Vector((n2.x, 0, n2.y)) up = Vector((t2.x, 0, t2.y)) M = basis((gm.x, 0.090, gm.y), nrm, up) # local z = normal, local x along the chamfer L.put(rbox((0.120, 0.215, 0.050), 0.008, rv=0.012, vax=2), M @ Matrix.Translation((0, 0, 0.018)), W, 'T08', seats=('T03', 'T03p.L', 'T03p.R', 'T03l')) L.put(rbox((0.095, 0.190, 0.016), 0.004), M @ Matrix.Translation((0, 0, 0.044)), R, 'T08r', seats=('T08',)) # T09 the flat band: seven cables side by side in the bend plane, white clips round it p0 = Vector((gm.x, 0.090, gm.y)) + nrm * 0.046 path = [p0, p0 + nrm * 0.06, Vector((0.700, 0.090, 0.745)), Vector((0.812, 0.090, 0.640)), Vector((0.820, 0.090, 0.530)), Vector((0.772, 0.090, 0.468)), Vector((0.690, 0.090, 0.452))] P = fillet3d(path, 0.11, 4) # frames: N in the X-Z plane, B = Y; the band's width runs along W = cos(25 deg) B + sin(25 deg) N, so a side view # (ref1) sees about four of the seven cables and a front three-quarter view (ref2) sees the flat band out = [] ca, sa = math.cos(math.radians(25)), math.sin(math.radians(25)) for i in range(len(P)): a_, b_ = P[max(i - 1, 0)], P[min(i + 1, len(P) - 1)] T = (b_ - a_).normalized() Nn = Vector((0, 1, 0)).cross(T).normalized() # in the X-Z plane Wd = (Vector((0, 1, 0)) * ca + Nn * sa).normalized() out.append((T, Wd)) from dra_lib import tube as _tube for k in range(7): off = (k - 3) * 0.0228 pts = [p + Wd * off for p, (T, Wd) in zip(P, out)] L.put(_tube(pts, 0.0105, 8, 0.0, caps=True), None, R, 'T09', seats=('T08', 'T08r', 'T10', 'T09c')) # white clips round the band every 0.13 m lens = [0.0] for i in range(1, len(P)): lens.append(lens[-1] + (P[i] - P[i - 1]).length) tot = lens[-1] for sclip in (0.10, 0.23, 0.36, tot - 0.08): for i in range(1, len(P)): if lens[i] >= sclip: f = (sclip - lens[i - 1]) / max(1e-9, lens[i] - lens[i - 1]) p = P[i - 1].lerp(P[i], f) T, Wd = out[i] Th = T.cross(Wd).normalized() Mc = Matrix((T, Wd, Th)).transposed().to_4x4() Mc.translation = p L.put(rbox((0.022, 0.178, 0.032), 0.004, rv=0.008, vax=0), Mc, W, 'T09c', seats=('T09',)) break def _side_cables(L): """T15: a pair of cables each side from the gland on the housing's lower panel out round and back to the gland at the lower block's rear corner (ref1, ref7)""" from dra_lib import bundle for s in (1, -1): sd = '.L' if s > 0 else '.R' path = [(0.160, s * 0.345, 0.445), (0.160, s * 0.430, 0.410), (0.110, s * 0.535, 0.300), (-0.020, s * 0.575, 0.190), (-0.165, s * 0.520, 0.120), (-0.255, s * 0.420, 0.100), (-0.280, s * 0.345, 0.100)] L.put(bundle(path, 0.0132, [(0.0, 0.028), (0.0, -0.028)], rad=0.085, segs=10), None, R, 'T15' + sd, seats=('T06' + sd, 'T02d' + sd)) for p in ((0.160, s * 0.355, 0.442), (-0.280, s * 0.338, 0.100)): pass # ------------------------------------------------------------------ markings def _markings(L): for s in (1, -1): M = L.on_surface((0.110, s * 0.6, 0.625), (0, -s, 0), up=(0, 0, 1)) if M is None: continue bm = decal_strip([(-0.020, -0.075), (0.020, -0.075), (0.020, 0.075), (-0.020, 0.075)], 0.0026) for k in range(5): y0 = -0.058 + k * 0.026 st = decal_poly([(-0.016, y0 - 0.006), (-0.016, y0 + 0.004), (0.016, y0 + 0.016), (0.016, y0 + 0.006)]) merge(bm, st) st.free() ln = decal_poly([(0.027, -0.075), (0.031, -0.075), (0.031, 0.040), (0.027, 0.040)]) merge(bm, ln) ln.free() if s < 0: xform(bm, Matrix.Scale(-1, 4, Vector((0, 1, 0)))) L.decal(bm, M, 'T07' + ('.L' if s > 0 else '.R')) M = L.on_surface((-0.330, 0.6, 0.205), (0, -1, 0), up=(0, 0, 1)) if M is not None: bm = decal_strip([(-0.030, -0.026), (0.030, -0.026), (0.030, 0.026), (-0.030, 0.026)], 0.0024) for k in range(3): y0 = -0.020 + k * 0.016 st = decal_poly([(-0.025, y0), (-0.025, y0 + 0.006), (0.025, y0 + 0.012), (0.025, y0 + 0.006)]) merge(bm, st) st.free() L.decal(bm, M, 'T07a') M = L.on_surface((0.252, 0.6, 0.095), (0, -1, 0), up=(0, 0, 1)) if M is not None: L.decal(decal_poly([(-0.0017, -0.020), (0.0017, -0.020), (0.0017, 0.020), (-0.0017, 0.020)]), M, 'D10') def build_turret(): L = Link('turret') # T01 turning race: an inner ring inside the fixed race, three stacked rings with two V grooves prof = [(0.0, 0.010, 0, G), (0.246, 0.010, 0.002, G), (0.246, 0.036, 0.001, G), (0.288, 0.038, 0.002, G), (0.288, 0.0425, 0, G), (0.2845, 0.0450, 0, G), (0.288, 0.0475, 0, G), (0.288, 0.0505, 0, G), (0.2845, 0.0530, 0, G), (0.288, 0.0555, 0, G), (0.288, 0.061, 0.001, G), (0.0, 0.061, 0, G)] L.put(lathe(prof, 48), None, None, 'T01') _lower_block(L) _housing(L) _belt_drive(L) _cables(L) _side_cables(L) _markings(L) return L