def nested_assy(): b1 = cq.Workplane().box(1, 1, 1) b2 = cq.Workplane().box(1, 1, 1) b3 = cq.Workplane().pushPoints([(-2, 0), (2, 0)]).box(1, 1, 0.5) assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(0, 0, 0)), name="TOP") assy2 = cq.Assembly(b2, loc=cq.Location(cq.Vector(0, 4, 0)), name="SECOND") assy2.add(b3, loc=cq.Location(cq.Vector(0, 4, 0)), name="BOTTOM") assy.add(assy2, color=cq.Color("green")) return assy
def nested_assy_sphere(): b1 = cq.Workplane().box(1, 1, 1).faces("<Z").tag("top_face").end() b2 = cq.Workplane().box(1, 1, 1).faces("<Z").tag("bottom_face").end() b3 = cq.Workplane().pushPoints([(-2, 0), (2, 0)]).tag("pts").sphere(1).tag("boxes") assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(0, 0, 0)), name="TOP") assy2 = cq.Assembly(b2, loc=cq.Location(cq.Vector(0, 4, 0)), name="SECOND") assy2.add(b3, loc=cq.Location(cq.Vector(0, 4, 0)), name="BOTTOM") assy.add(assy2, color=cq.Color("green")) return assy
def faceputter(cls, wrk_dir): """ouputs faces that were read from dxfs during build""" Path.mkdir(wrk_dir / "output" / "faces", exist_ok=True) all_faces = cadquery.Assembly() for layer_name, layer_wp in cls._layers.items(): faces = layer_wp.faces().vals() for i, face in enumerate(faces): all_faces.add(face) cadquery.exporters.export( face, str(wrk_dir / "output" / "faces" / f"{layer_name}-{i}.stl"), cadquery.exporters.ExportTypes.STL) cadquery.exporters.export( face, str(wrk_dir / "output" / "faces" / f"{layer_name}-{i}.amf"), cadquery.exporters.ExportTypes.AMF) cadquery.exporters.export( face, str(wrk_dir / "output" / "faces" / f"{layer_name}-{i}.wrl"), cadquery.exporters.ExportTypes.VRML) cadquery.exporters.export( face, str(wrk_dir / "output" / "faces" / f"{layer_name}-{i}.step"), cadquery.exporters.ExportTypes.STEP) all_faces.save(str(wrk_dir / "output" / "faces" / f"all_faces.step"))
def metadata_assy(): b1 = cq.Solid.makeBox(1, 1, 1) b2 = cq.Workplane().box(1, 1, 2) assy = cq.Assembly( b1, loc=cq.Location(cq.Vector(2, -5, 0)), name="base", metadata={"b1": "base-data"}, ) sub_assy = cq.Assembly( b2, loc=cq.Location(cq.Vector(1, 1, 1)), name="sub", metadata={"b2": "sub-data"} ) assy.add(sub_assy) return assy
def build(self, print3d=True): s = self asy = cadquery.Assembly() # global calcs x = s.glass_dim + s.extra_xy y = s.glass_dim + s.extra_xy # make the bottom piece bottom = self.make_bottom(x, y, print3d=print3d) asy.add(bottom, name="bottom", color=cadquery.Color("red")) # make the top piece top = self.make_top(x, y, print3d=print3d) asy.add(top.translate((0, 0, s.pedestal_z)), name="top", color=cadquery.Color("gray")) # constrain assembly #asy.constrain("bottom?bottom_mate", "top?top_mate", "Point") # solve constraints #asy.solve() return asy
def box_and_vertex(): box_wp = cq.Workplane().box(1, 2, 3) assy = cq.Assembly(box_wp, name="box") vertex_wp = cq.Workplane().newObject([cq.Vertex.makeVertex(0, 0, 0)]) assy.add(vertex_wp, name="vertex") return assy
def empty_top_assy(): b1 = cq.Workplane().box(1, 1, 1) assy = cq.Assembly() assy.add(b1, color=cq.Color("green")) return assy
def test_infinite_face_constraint_Plane(kind): assy = cq.Assembly(cq.Workplane().sphere(1), name="part0") assy.add(cq.Workplane().sphere(1), name="part1") assy.constrain( "part0", cq.Face.makePlane(), "part1", cq.Face.makePlane(), kind, ) assy.solve() assert solve_result_check(assy._solve_result)
def simple_assy2(): b1 = cq.Workplane().box(1, 1, 1) b2 = cq.Workplane().box(2, 1, 1) assy = cq.Assembly() assy.add(b1, name="b1") assy.add(b2, loc=cq.Location(cq.Vector(0, 0, 4)), name="b2") return assy
def build(self, nx=5, ny=5): asy = cadquery.Assembly() # make the bottom piece thing = self.make_thing(nx=nx, ny=ny) bb = thing.findSolid().BoundingBox() self.lg.debug(f"extents = ({bb.xlen},{bb.ylen},{bb.zlen})") asy.add(thing, name="tray", color=cadquery.Color("gray")) return asy
def simple_assy(): b1 = cq.Solid.makeBox(1, 1, 1) b2 = cq.Workplane().box(1, 1, 2) b3 = cq.Workplane().pushPoints([(0, 0), (-2, -5)]).box(1, 1, 3) assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(2, -5, 0))) assy.add(b2, loc=cq.Location(cq.Vector(1, 1, 0))) assy.add(b3, loc=cq.Location(cq.Vector(2, 3, 0))) return assy
def test_groove(self): # path should be a wire in XY plane at Z=0 # the path the cutting tool will follow cq.Workplane.mk_groove = groovy.mk_groove # add our vgroove function to the Workplane class cutter_path = cq.Workplane("XY").rect(150, 150, centered=True).extrude( 1).edges("|Z").fillet(10).faces("-Z").wires().val() demo_block = cq.Workplane("XY").rect( 200, 200, centered=True).extrude(-200).edges("|Z").fillet(3) asy = cadquery.Assembly() depth = 4 # vslot ring_cs = 1 # o-ring cross-section diameter co = {"centerOption": "CenterOfBoundBox"} demo_block = demo_block.faces(">Z").workplane( **co).add(cutter_path).wires().toPending().mk_groove(vdepth=depth) demo_block = demo_block.faces("<Z").workplane(**co).sketch().rect( 50, 50).vertices().fillet(10).finalize().mk_groove(vdepth=depth) demo_block = demo_block.faces("<X").workplane(**co).sketch().rarray( 75, 75, 2, 2).circle(25).finalize().mk_groove(vdepth=depth) min_inner_rad = 3 * ring_cs gland_width = groovy.get_gland_width(ring_cs=ring_cs) mid_rad = min_inner_rad + gland_width / 2 demo_block = demo_block.faces(">X").workplane(**co).sketch() demo_block = demo_block.push([(75 / 2, 75 / 2) ]).rect(50, 50, angle=31).reset() demo_block = demo_block.push([(-75 / 2, -75 / 2) ]).rect(50, 50, angle=7).reset() demo_block = demo_block.push([(75 / 2, -75 / 2) ]).rect(50, 50, angle=23).reset() demo_block = demo_block.push([(-75 / 2, 75 / 2) ]).rect(50, 50, angle=-17).reset() demo_block = demo_block.vertices().fillet( mid_rad).finalize().mk_groove(ring_cs=ring_cs, hardware=asy) demo_block = demo_block.faces("<Y").workplane(**co).mk_groove( ring_cs=ring_cs, follow_pending_wires=False, ring_id=90, gland_x=70, gland_y=100, hardware=asy) demo_block = demo_block.faces(">Y").workplane(**co).mk_groove( ring_cs=ring_cs, follow_pending_wires=False, ring_id=111, gland_x=80, gland_y=100, hardware=asy) tmpdirname = tempfile.mkdtemp() outfile = pathlib.Path(tmpdirname) / "groove.step" asy.add(demo_block) asy.save(str(outfile)) # save step
def test_oringer(self): """testing for an o-ring based pcb passthrough""" cq.Workplane.make_oringer = passthrough.make_oringer wall_thickness = 12 pcb_scr_head_d_safe = 6 n_header_pins = 50 header_length = n_header_pins / 2 * 2.54 + 7.62 # n*0.1 + 0.3 inches support_block_width = 7 pt_pcb_width = 2 * (support_block_width / 2 + pcb_scr_head_d_safe / 2) + header_length outer_depth = 8.89 + 0.381 # 0.35 + 0.15 inches inner_depth = 8.89 + 0.381 # 0.35 + 0.15 inches mwp = cq.Workplane("ZX").circle(80.0).extrude(wall_thickness) mwp = mwp.translate((99, 99, 99)) mwp = mwp.faces("<Y").workplane(centerOption="CenterOfBoundBox") hardware = cadquery.Assembly(name="passthrough hardware") pcb = cadquery.Assembly(name="passthrough pcbs") oringer = cadquery.Assembly(name="passthroughs") mwp = mwp.rarray(1, 40, 1, 3).make_oringer(board_width=pt_pcb_width, board_inner_depth=inner_depth, board_outer_depth=outer_depth, pt_asy=oringer, pcb_asy=pcb, hw_asy=hardware) final = cadquery.Assembly(name="passthrough testing") final.add(mwp, name="base part") final.add(hardware) final.add(pcb) final.add(oringer) tmpdirname = tempfile.mkdtemp() outfile = pathlib.Path(tmpdirname) / "passthrough.step" final.save(str(outfile))
def test_toCompound(simple_assy, nested_assy): c0 = simple_assy.toCompound() assert isinstance(c0, cq.Compound) assert len(c0.Solids()) == 4 c1 = nested_assy.toCompound() assert isinstance(c1, cq.Compound) assert len(c1.Solids()) == 4 # check nested assy location appears in compound # create four boxes, stack them on top of each other, check highest face is in final compound box0 = cq.Workplane().box(1, 1, 3, centered=(True, True, False)) box1 = cq.Workplane().box(1, 1, 4) box2 = cq.Workplane().box(1, 1, 5) box3 = cq.Workplane().box(1, 1, 6) # top level assy assy0 = cq.Assembly(box0, name="box0") assy0.add(box1, name="box1") assy0.constrain("box0@faces@>Z", "box1@faces@<Z", "Plane") # subassy assy1 = cq.Assembly() assy1.add(box2, name="box2") assy1.add(box3, name="box3") assy1.constrain("box2@faces@>Z", "box3@faces@<Z", "Plane") assy1.solve() assy0.add(assy1, name="assy1") assy0.constrain("box1@faces@>Z", "assy1/box2@faces@<Z", "Plane") # before solving there should be no face with Center = (0, 0, 18) c2 = assy0.toCompound() assert not cq.Vector(0, 0, 18) in [x.Center() for x in c2.Faces()] # after solving there should be a face with Center = (0, 0, 18) assy0.solve() c3 = assy0.toCompound() assert cq.Vector(0, 0, 18) in [x.Center() for x in c3.Faces()] # also check with bounding box assert c3.BoundingBox().zlen == pytest.approx(18)
def build(self, do_ventscrews: bool = False): s = self asy = cadquery.Assembly() # the spacer PCB spacer = s.make_spacer_pcb() asy.add(spacer, name="spacer", color=cadquery.Color("DARKGREEN")) # the towerplate tp = self.make_tower_plate() asy.add(tp, name="towers", color=cadquery.Color("GOLDENROD")) # dowels dwl = self.make_dowels() asy.add(dwl, name="dowels", color=cadquery.Color("BLACK")) # silicone sil = self.make_silicone() asy.add(sil, name="silicone", color=cadquery.Color("WHITE")) # glass glass = self.make_glass() asy.add(glass, name="glass", color=cadquery.Color("SKYBLUE")) # the heater base plate heater = s.make_heater_plate() asy.add(heater, name="heater", color=cadquery.Color("MATRAGRAY")) # the spring pin PCB pcb = self.get_pcb() asy.add(pcb, name="pcb", color=cadquery.Color("brown")) if do_ventscrews: # the vent screws vss_a = self.get_ventscrews_a() vss_b = self.get_ventscrews_b() asy.add(vss_a.add(vss_b), name="ventscrew") # the alignment slot plate slots = self.make_slot_plate() asy.add(slots, name="sample_slots", color=cadquery.Color("GRAY45")) pusher = self.make_pusher_plate() asy.add(pusher, name="pusher", color=cadquery.Color("GRAY28")) reserve = self.make_reservation(do_ventscrews=do_ventscrews) asy.add(reserve, name="space_reservation") return asy
def test_repr_javascript(self): cube = cq.Workplane("XY").box(1, 1, 1) assy = cq.Assembly().add(cube) shape = cube.val() self.assertIsInstance(shape, cq.occ_impl.shapes.Solid) # Test no exception on rendering to js js1 = shape._repr_javascript_() js2 = cube._repr_javascript_() js3 = assy._repr_javascript_() assert "function render" in js1 assert "function render" in js2 assert "function render" in js3
def __init__(self, *, vslot_dxf_profile_location: str): self.dimensions: MappingProxyType = MappingProxyType({}) back = VSlot( outer_x=80, outer_y=40, base_depth=20, slot_length=250, c_beam_dxf_profile_loc=vslot_dxf_profile_location, ) clamp = Clamp() bracket = Bracket(clamp=clamp) spindle = Spindle() bottom_of_vslot_to_bottom_of_bracket = ( -6 + spindle.dimensions["nut_length"] + spindle.dimensions["shaft_length"] + spindle.dimensions["bearing_cap_height"] + spindle.dimensions["body_clamp_end_offset"] + clamp.dimensions["z"] / 2 - bracket.dimensions["height"] / 2) backpoint = (back.geometry.faces( "<Z", tag="unslotted").edges("<Y").translate( (0, 0, bottom_of_vslot_to_bottom_of_bracket)).val()) bracketpoint = bracket.geometry.faces("<Z").edges(">Y").val() self.geometry = (cq.Assembly(name="SpindleAssembly").add( back.geometry, name="back", color=cq.Color(0.8, 0.8, 0.8), ).add(bracket.geometry, name="bracket", color=cq.Color(0.9, 0.9, 0.95)).constrain( "back", backpoint, "bracket", bracketpoint, "Point").constrain( "back", back.geometry.faces("<Y", tag="unslotted").val(), "bracket", bracket.geometry.faces(">Y").val(), "Axis", ).constrain( "back", back.geometry.faces("<Z", tag="unslotted").val(), "bracket", bracket.geometry.faces(">Z").val(), "Axis", ).solve())
def build(include_hardware=True, save_step=False): """Generate the lid/support assembly.""" hwith = "with" if include_hardware else "without" ssave = "" if save_step else "not " logger.info(f"Building chamber {hwith} hardware and {ssave}saving step file...") # container for parts of the assembly assembly = cq.Assembly(None) # build parts lid(assembly, include_hardware) window_support(assembly, include_hardware) # shift output geometry to match that of the base assembly.loc = cq.Location(cq.Vector(-4.5, 0, 15.1)) # output TwoDToThreeD.outputter({"lid": assembly}, wrk_dir)
def button(position: cq.Vector, rotation: int): switch = kailh_switch().rotate(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), rotation) switch = switch.translate(position) socket = kailh_socket().rotate(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), rotation) socket = socket.translate(position) keycap = kailh_keycap().rotate(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), rotation) keycap = keycap.translate(position) a = cq.Assembly() a.add(switch, color=cq.Color(1, 1, 1, 1)) a.add(keycap, color=cq.Color(.5, .5, .5, 1)) a.add(socket, color=cq.Color(0, 0, 0, 1)) return a
def show_mates(assembly, show_object, length=10): radius = length / 10 for name, mate in assembly.mates.items(): coord = cq.Assembly(name=name) coord.add(cq.Workplane("YZ").circle(radius).extrude(length), color=cq.Color(1, 0, 0)) coord.add(cq.Workplane("ZX").circle(radius).extrude(length), color=cq.Color(0, 0.5, 0)) coord.add(cq.Workplane("XY").circle(radius).extrude(length), color=cq.Color(0, 0, 1)) mloc = mate.mate.loc a = mate.assembly aloc = a.loc while a.parent is not None: aloc = a.parent.loc * aloc a = a.parent coord.loc = aloc * mloc show_object(coord, name=f"mate:{name}")
def build(self, print3d=True): s = self asy = cadquery.Assembly() # global calcs x = s.glass_dim + s.extra_xy y = s.glass_dim + s.extra_xy # make the bottom piece bottom = self.make_bottom(x, y, print3d=print3d) asy.add(bottom, name="bottom", color=cadquery.Color("red")) # make the top pieces top1 = self.make_top(x, y, print3d=print3d, center_slot_width=s.center_slot_width_3, outer_slot_spacing=s.outer_slot_spacing_3, outer_slot_widths=s.outer_slot_width_3, slots_rotated=False) top2 = self.make_top(x, y, print3d=print3d, center_slot_width=s.center_slot_width_2, outer_slot_spacing=s.outer_slot_spacing_2, outer_slot_widths=s.outer_slot_width_2, slots_rotated=True) asy.add(top1.translate((0, 0, s.pedestal_z)), name="top1", color=cadquery.Color("gray")) asy.add(top2.translate((0, 0, s.pedestal_z + 20)), name="top2", color=cadquery.Color("gray")) # constrain assembly # asy.constrain("bottom?bottom_mate", "top?top_mate", "Point") # solve constraints # asy.solve() return asy
def walk(objs): a = cq.Assembly() names = {} for obj in objs: name = obj["name"] # Create a unique name by postfixing the enumerator index if needed if names.get(name) is None: names[name] = 1 else: names[name] += 1 name = f"{obj['name']}_{names[name]}" a.add( walk(obj["shapes"]) if len(obj["shapes"]) > 0 else to_workplane(obj["shape"]), name=name, color=to_color(obj["color"]), loc=to_location(obj.get("loc")), ) return a
def _make_pcb(what): """build the actual passthrough PCB""" # this copies some logic in the eachpoint() function so that we can use each() which is safer base_plane = self.plane base = base_plane.location if isinstance(what, (cq.Vector, cq.Shape)): loc = base.inverse * cq.Location(base_plane, what.Center()) elif isinstance(what, cq.Sketch): loc = base.inverse * cq.Location(base_plane, what._faces.Center()) else: loc = what pcb = CQ().workplane(offset=-wall_depth - board_inner_depth) pcb = pcb.rect(board_width, pcbt).extrude(until=board_inner_depth + wall_depth + board_outer_depth) pcb = pcb.edges("|Y").fillet(pcb_corner) # put in screws with holes hardware = cadquery.Assembly() pcb = pcb.faces(">Y").workplane(**u.cobb).rarray( board_width - 2 * block_width / 2, board_inner_depth + board_outer_depth + wall_depth - 2 * pt_pcb_mount_hole_offset[0], 2, 2).clearanceHole(pcb_scr, fit="Close", counterSunk=False, baseAssembly=hardware) if hw_asy is not None: hw_asy.add(hardware, loc=base * loc) # put in pin0 holes pcb = pcb.faces(">Y").workplane(**u.copo, origin=(0, 0, 0)).pushPoints(p0pts).circle( pin0_holed / 2).cutThruAll() return pcb.findSolid().moved(base * loc)
def window_support(assembly, include_hardware=False): """Create window support.""" hardware = cq.Assembly(None) # create window support plate window_support = cq.Workplane("XY").box(chamber_l, chamber_w, support_h) # chamfer upper side edges window_support = window_support.edges("|X and >Z").chamfer(chamber_chamfer).edges("|Y and >Z").chamfer(chamber_chamfer) # cut corners for lid nut clearance edges = [ "|Z and <X and <Y", "|Z and >X and <Y", "|Z and <X and >Y", "|Z and >X and >Y", ] for (x, y), e in zip(chamber_bolt_xys, edges): corner = cq.Workplane("XY").box(m5_socket_clearance, m5_socket_clearance, support_h).edges(e).fillet(m5_socket_clearance / 2).translate((x, y, 0)) window_support = window_support.cut(corner) # fillet side edges window_support = window_support.edges("|Z").fillet(chamber_fillet) # cut window aperture window_ap = cq.Workplane("XY").box(window_ap_l, window_ap_w, support_h).edges("|Z").fillet(window_ap_r).translate((window_ap_x_offset, 0, 0)) window_support = window_support.cut(window_ap) # move up to sit above lid window_support = window_support.translate((0, 0, lid_h / 2 + support_h / 2)) # cut countersink holes for support bolts window_support = window_support.faces(">Z").workplane(centerOption="CenterOfBoundBox").pushPoints(support_bolt_xys).clearanceHole(fastener=support_bolt, baseAssembly=hardware) assembly.add(window_support, name="window_support") if include_hardware is True: assembly.add(hardware.toCompound(), name="support_bolts")
def build(self): s = self asy = cq.Assembly() # global calcs x = s.glass_dim + s.extra_xy y = s.glass_dim + s.extra_xy # make the bottom piece bottom = self.make_bottom(x, y) asy.add(bottom, name="bottom", color=cq.Color("red")) # make the top piece top = self.make_top(x, y) asy.add(top, name="top") # constrain assembly asy.constrain("bottom?bottom_mate", "top?top_mate", "Point") # solve constraints asy.solve() return asy
def mkwalls( aso: cadquery.Assembly, height: float, cshift, extents, hps, zbase: float, ): """the chamber walls""" name = "walls" color = cadquery.Color("GRAY55") thickness = 12 inner = (extents[0] - 2 * thickness, extents[1] - 2 * thickness) inner_shift = cshift outer_fillet = 2 inner_fillet = 6 chamfer = 0.75 nut = HexNut(size="M5-0.8", fastener_type="iso4033") # HNN-M5-A2 flat_to_flat = math.sin(60 * math.pi / 180) * nut.nut_diameter + 0.25 gas_fitting_hole_diameter = 20.6375 # 13/16" gas_fitting_recess = 6.35 gas_fitting_flat_to_flat = 22.22 + 0.28 gas_fitting_diameter = 25.66 + 0.34 back_holes_shift = 45 back_holes_spacing = 27 front_holes_spacing = 75 fitting_step_xy = ( 3, 15) # dims of the little step for the vac fitting alignment fitting_step_center = (-fitting_step_xy[0] / 2 + inner[0] / 2 + cshift[0], extents[1] / 2 - fitting_step_xy[1] / 2 - thickness) wp = CQ().workplane(offset=zbase).sketch() wp = wp.push([cshift ]).rect(extents[0], extents[1], mode="a").reset().vertices().fillet(outer_fillet) wp = wp.push([inner_shift]).rect(inner[0], inner[1], mode="s").reset() dummy_xy = (fitting_step_xy[0], inner[1]) dummy_center = (fitting_step_center[0], 0) wp = wp.push([dummy_center]).rect( *dummy_xy, mode="a") # add on a dummy bit that we'll mostly subtract away wp = wp.finalize().extrude(height).edges("|Z").fillet(inner_fillet) sub_xy = (40, inner[1] - fitting_step_xy[1]) sub_center = (-sub_xy[0] / 2 + inner[0] / 2 + cshift[0], -fitting_step_xy[1] / 2) wp2 = CQ().workplane(offset=zbase).sketch().push([sub_center ]).rect(*sub_xy, mode="a") wp2 = wp2.finalize().extrude(height).edges("|Z").fillet(inner_fillet) wp = wp.cut(wp2) # wp = CQ().workplane(offset=zbase).sketch() # wp = wp.push([cshift]).rect(extents[0], extents[1], mode="a").reset().vertices().fillet(outer_fillet) # wp = wp.push([inner_shift]).rect(inner[0], inner[1], mode="s") # .reset().vertices().fillet(inner_fillet) # wp = wp.finalize().extrude(height) wp: cadquery.Workplane # shouldn't have to do this (needed for type hints) wall_hardware = cq.Assembly(None, name="wall_hardware") # corner holes (with nuts and nut pockets) wp = wp.faces(">Z").workplane( **u.copo, offset=-nut.nut_thickness).pushPoints(hps).clearanceHole( fastener=nut, fit="Close", counterSunk=False, baseAssembly=wall_hardware) wp = wp.faces(">Z").workplane(**u.copo).sketch().push(hps[0:4:3]).rect( flat_to_flat, nut.nut_diameter, angle=45).reset().push( hps[1:3]).rect(flat_to_flat, nut.nut_diameter, angle=-45).reset().vertices().fillet( nut.nut_diameter / 4).finalize().cutBlind(-nut.nut_thickness) # chamfers wp = wp.faces(">Z").edges(">>X").chamfer(chamfer) # gas holes with recesses wp = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift, 0).rarray(back_holes_spacing, 1, 2, 1).hole(diameter=gas_fitting_hole_diameter, depth=thickness) # wp = wp.faces("<X").workplane(**u.cobb).center(back_holes_shift, 0).sketch().rarray(back_holes_spacing, 1, 2, 1).rect(gas_fitting_diameter, gas_fitting_flat_to_flat).reset().vertices().fillet(gas_fitting_diameter / 4).finalize().cutBlind(-gas_fitting_recess) wp = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift, 0).sketch().rect( 2 * gas_fitting_diameter / 2 + back_holes_spacing, gas_fitting_flat_to_flat).reset().vertices().fillet( gas_fitting_diameter / 4).finalize().cutBlind( -gas_fitting_recess) # unify the back holes wp = wp.faces(">X").workplane(**u.cobb).rarray( front_holes_spacing, 1, 2, 1).hole(diameter=gas_fitting_hole_diameter, depth=thickness) wp = wp.faces(">X").workplane(**u.cobb).sketch().rarray( front_holes_spacing, 1, 2, 1).rect(gas_fitting_diameter, gas_fitting_flat_to_flat).reset().vertices().fillet( gas_fitting_diameter / 4).finalize().cutBlind(-gas_fitting_recess) # that's part number polymax 230X2N70 o_ring_thickness = 2 o_ring_inner_diameter = 230 ooffset = 17 # two times the o-ring path's center offset from the outer edge of the walls # cut the lid o-ring groove wp = wp.faces(">Z").workplane(**u.cobb).mk_groove( ring_cs=o_ring_thickness, follow_pending_wires=False, ring_id=o_ring_inner_diameter, gland_x=extents[0] - ooffset, gland_y=extents[1] - ooffset, hardware=wall_hardware) # cut the base o-ring groove wp = wp.faces("<Z").workplane(**u.cobb).mk_groove( ring_cs=o_ring_thickness, follow_pending_wires=False, ring_id=o_ring_inner_diameter, gland_x=extents[0] - ooffset, gland_y=extents[1] - ooffset, hardware=wall_hardware) # get pipe fitting geometry a_pipe_fitting = u.import_step( wrk_dir.joinpath( "components", "5483T93_Miniature Nickel-Plated Brass Pipe Fitting.step")) a_pipe_fitting = a_pipe_fitting.translate( (0, 0, -6.35 - gas_fitting_recess)) pipe_fitting_asy = cadquery.Assembly(a_pipe_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=30), name="one_pipe_fitting") # move the pipe fittings to their wall holes wppf = wp.faces(">X").workplane(**u.cobb).center( front_holes_spacing / 2, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="front_right_gas_fitting") wppf = wppf.center(-front_holes_spacing, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="front_left_gas_fitting") wppf = wp.faces("<X").workplane(**u.cobb).center( back_holes_shift + back_holes_spacing / 2, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="rear_left_gas_fitting") wppf = wppf.center(-back_holes_spacing, 0) pipe_fitting_asy.loc = wppf.plane.location wall_hardware.add(pipe_fitting_asy, name="rear_right_gas_fitting") # get bonded washer geometry, part 229-6277 bonded_washer = u.import_step( wrk_dir.joinpath("components", "hutchinson_ljf_207242.stp")) bonded_washer = bonded_washer.rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=90).translate( (0, 0, 1.25)) bonded_washer_asy = cadquery.Assembly(bonded_washer, name="one_bonded_washer") # move bonded washers to their wall holes washer_thickness = 2.5 wpbw = wp.faces(">X").workplane(**u.cobb, offset=-thickness - washer_thickness).center( -front_holes_spacing / 2, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="front_right_bonded_washer") wpbw = wpbw.center(front_holes_spacing, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="front_left_bonded_washer") wpbw = wp.faces("<X[-5]").workplane(**u.cobb).center( -back_holes_shift - back_holes_spacing / 2, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="rear_right_bonded_washer") wpbw = wpbw.center(back_holes_spacing, 0) bonded_washer_asy.loc = wpbw.plane.location wall_hardware.add(bonded_washer_asy, name="rear_left_bonded_washer") aso.add(wall_hardware.toCompound(), name="wall_hardware", color=cadquery.Color(hardware_color)) # passthrough details pcb_scr_head_d_safe = 6 n_header_pins = 50 header_length = n_header_pins / 2 * 2.54 + 7.62 # n*0.1 + 0.3 inches support_block_width = 7 pt_pcb_width = 2 * (support_block_width / 2 + pcb_scr_head_d_safe / 2) + header_length pt_pcb_outer_depth = 8.89 + 0.381 # 0.35 + 0.15 inches pt_pcb_inner_depth = 8.89 + 0.381 # 0.35 + 0.15 inches pt_center_offset = 28.65 # so that the internal passthrough connector aligns with the one in the chamber # make the electrical passthrough pt_asy = cadquery.Assembly( ) # this will hold the passthrough part that gets created # pcb_asy = cadquery.Assembly() # this will hold the pcb part that gets created pcb_asy = None # dont generate the base PCB (will probably later import the detailed board model) hw_asy = cadquery.Assembly( ) # this will hold the pcb part that gets created ptt = 5.5 # passthrough thickness, reduce a bit from default (which was half wall thickness) to prevent some thin walls close to an o-ring gland wp = wp.faces("<X").workplane(**u.cobb).center( -pt_center_offset, 0).make_oringer(board_width=pt_pcb_width, board_inner_depth=pt_pcb_inner_depth, board_outer_depth=pt_pcb_outer_depth, wall_depth=thickness, part_thickness=ptt, pt_asy=pt_asy, pcb_asy=pcb_asy, hw_asy=hw_asy) # insert passthrough into assembly for asyo in pt_asy.traverse(): part = asyo[1] if isinstance(part.obj, cadquery.occ_impl.shapes.Solid): aso.add(part.obj, name=asyo[0], color=color) if pcb_asy is not None: # insert pcb into assembly for asyo in pcb_asy.traverse(): # insert only one solid object part = asyo[1] if isinstance(part.obj, cadquery.occ_impl.shapes.Solid): aso.add(part.obj, name=asyo[0], color=cadquery.Color("DARKGREEN")) # insert hardware into assembly aso.add(hw_asy.toCompound(), name="passthrough hardware") # add in little detailed PCB a_little_pcb = u.import_step( wrk_dir.joinpath("components", "pt_pcb.step")).translate( (0, 0, -pcb_thickness / 2)) # shift pcb to be z-centered little_pcb = cadquery.Assembly(a_little_pcb.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=90).rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=90), name="small detailed pcb") asys["squirrel"].add(little_pcb, loc=wp.plane.location, name="little pcb") # for the vac chuck fittings rotation_angle = -155 # degrees vac_fitting_wall_offset = extents[ 1] / 2 - thickness - inner_fillet - 4 # mounting location offset from center wp = wp.faces(">X").workplane(**u.cobb).center( vac_fitting_wall_offset, 0).tapHole(vac_fitting_screw, depth=thickness + fitting_step_xy[0]) vac_chuck_fitting = cadquery.Assembly(a_vac_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=rotation_angle), name="outer_wall_vac_fitting") aso.add(vac_chuck_fitting, loc=wp.plane.location, name="vac chuck fitting (wall outer)") nwp = wp.faces(">X").workplane(**u.cobb, invert=True, offset=thickness + fitting_step_xy[0]).center( vac_fitting_wall_offset, 0) vac_chuck_fitting = cadquery.Assembly(a_vac_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=-rotation_angle), name="inner_wall_vac_fitting") aso.add(vac_chuck_fitting, loc=nwp.plane.location, name="vac chuck fitting (wall inner)") aso.add(wp, name=name, color=color) # add the walls bulk
def mkbase( aso: cadquery.Assembly, thickness: float, cshift, extents, hps, screw: SocketHeadCapScrew, pedistal_height: float, zbase: float, subs_boost: float, ): """the thermal base""" plate_name = "thermal_plate" vac_name = "vacuum_chuck" color = cadquery.Color("GOLD") fillet_outer = 2 fillet_inner = 10 chamfer = 1 corner_screw_depth = 4.5 pedistal_xy = (161, 152) pedistal_fillet = 10 dowelpts = [(-73, -66), (73, 66)] dowel_nominal_d = 3 # marked on drawing for pressfit with ⌀3K7 # vac chuck clamp screws vacscrew_length = 20 vacscrew = CounterSunkScrew(size="M6-1", fastener_type="iso14581", length=vacscrew_length, simple=no_threads) # SHK-M6-20-V2-A4 vacclamppts = [(-73, -54.75), (-73, 54.75), (73, -54.75), (73, 54.75)] # slot plate clamp screws spscrew_length = 8 spscrew = CounterSunkScrew(size="M3-0.5", fastener_type="iso14581", length=spscrew_length, simple=no_threads) # SHK-M3-8-V2-A4 # setscrew clamping stuff setscrew_len = 30 screw_well_depth = 3 setscrew_recess = pedistal_height + screw_well_depth setscrew = SetScrew(size="M6-1", fastener_type="iso4026", length=setscrew_len, simple=no_threads) # SSU-M6-30-A2 setscrewpts = [(-73, -43.5), (73, 43.5)] # waterblock nuts and holes wb_w = 177.8 wb_mount_offset_from_edge = 7.25 wb_mount_offset = wb_w / 2 - wb_mount_offset_from_edge waterblock_mount_nut = HexNutWithFlange( size="M6-1", fastener_type="din1665", simple=no_threads) # HFFN-M6-A2 wb_mount_points = [ (120, wb_mount_offset), (120, -wb_mount_offset), (-129, wb_mount_offset), (-129, -wb_mount_offset), ] # make the base chunk wp = CQ().workplane(**u.copo, offset=zbase).sketch() wp = wp.push([cshift]).rect(extents[0], extents[1], mode="a") wp = wp.finalize().extrude(thickness) wp: cadquery.Workplane # shouldn't have to do this (needed for type hints) # cut for waterblock mnt ears ear_square = 2 * wb_mount_offset wp = wp.faces("<X").workplane(**u.cobb).rect( xLen=extents[1] - 2 * ear_square, yLen=thickness, centered=True).cutBlind(-(extents[0] - wall_outer[0]) / 2) wp = wp.faces(">X").workplane(**u.cobb).rect( xLen=extents[1] - 2 * ear_square, yLen=thickness, centered=True).cutBlind(-(extents[0] - wall_outer[0]) / 2) wp = wp.edges("|Z exc (<<X or >>X)").fillet(fillet_inner) wp = wp.edges("|Z and (<<X or >>X)").fillet(fillet_outer) # pedistal wp = wp.faces(">Z").workplane(**u.copo, origin=( 0, 0, 0)).sketch().rect( *pedistal_xy).reset().vertices().fillet(pedistal_fillet) wp = wp.finalize().extrude(pedistal_height) hardware = cq.Assembly(None) # a place to keep the harware # corner screws wp = wp.faces("<Z").workplane(**u.copo, offset=-corner_screw_depth).pushPoints( hps).clearanceHole( fastener=screw, fit="Close", baseAssembly=hardware) wp = wp.faces("<Z[-2]").wires().toPending().extrude( corner_screw_depth, combine="cut") # make sure the recessed screw is not buried # dowel holes wp = wp.faces(">Z").workplane(**u.copo).pushPoints(dowelpts).hole( dowel_nominal_d + dowel3_delta_press, depth=pedistal_height) # waterblock mounting wp = wp.faces(">Z[-2]").workplane( **u.copo).pushPoints(wb_mount_points).clearanceHole( fastener=waterblock_mount_nut, counterSunk=False, fit="Loose", baseAssembly=hardware) # vac chuck stuff # split wp = wp.faces(">Z[-2]").workplane(**u.copo).split( keepTop=True, keepBottom=True).clean() btm_piece = wp.solids("<Z").first().edges("not %CIRCLE").chamfer( chamfer) top_piece = wp.solids(">Z").first().edges("not %CIRCLE").chamfer( chamfer) # hole array n_array_x = 4 n_array_y = 5 x_spacing = 35 y_spacing = 29 x_start = (n_array_x - 1) / 2 y_start = (n_array_y - 1) / 2 n_sub_array_x = 8 n_sub_array_y = 2 x_spacing_sub = 3 y_spacing_sub = 10 x_start_sub = (n_sub_array_x - 1) / 2 y_start_sub = (n_sub_array_y - 1) / 2 hole_d = 1 hole_cskd = 1.1 csk_ang = 45 # compute all the vac chuck vent hole points vac_hole_pts = [] # where the vac holes are drilled street_centers = [] # the distribution street y values for i in range(n_array_x): for j in range(n_array_y): for k in range(n_sub_array_x): for l in range(n_sub_array_y): ctrx = (i - x_start) * x_spacing ctry = (j - y_start) * y_spacing offx = (k - x_start_sub) * x_spacing_sub offy = (l - y_start_sub) * y_spacing_sub vac_hole_pts.append((ctrx + offx, ctry + offy)) street_centers.append((0, ctry + offy)) street_centers = list(set(street_centers)) # prune duplicates # boost substrates up so they can't slip under raise_square = (25, 25) raise_fillet = 1 top_piece = CQ(top_piece.findSolid()).faces(">Z").workplane( **u.copo).sketch().rarray( x_spacing, y_spacing, n_array_x, n_array_y).rect(*raise_square).reset().vertices().fillet( raise_fillet).finalize().extrude(subs_boost) # drill all the vac holes top_piece = top_piece.faces(">Z").workplane( **u.copo).pushPoints(vac_hole_pts).cskHole(diameter=hole_d, cskDiameter=hole_cskd, cskAngle=csk_ang) # clamping setscrew threaded holes top_piece = top_piece.faces(">Z").workplane().pushPoints( setscrewpts).tapHole( setscrew, depth=setscrew_recess, baseAssembly=hardware ) # bug prevents this from working correctly, workaround below # clamping setscrew downbumps in the thermal plate btm_piece = CQ(btm_piece.findSolid()).faces(">Z").workplane( **u.copo).pushPoints(setscrewpts).circle( vacscrew.clearance_hole_diameters["Close"] / 2).cutBlind(-screw_well_depth) # vac chuck clamping screws top_piece = top_piece.faces(">Z[-2]").workplane( **u.copo, origin=(0, 0, 0)).pushPoints(vacclamppts).clearanceHole( vacscrew, fit="Close", baseAssembly=hardware) # next line is a hack to make absolutely sure the screws are recessed top_piece = top_piece.faces(">Z[-2]").workplane( **u.copo, origin=(0, 0, 0)).pushPoints(vacclamppts).cskHole( vacscrew.clearance_hole_diameters["Close"], cskDiameter=vacscrew.head_diameter + 1, cskAngle=vacscrew.screw_data["a"]) btm_piece = btm_piece.faces(">Z").workplane(**u.copo, origin=( 0, 0, 0)).pushPoints(vacclamppts).tapHole( setscrew, depth=vacscrew_length - pedistal_height + 1) # threaded holes to attach to # mod the slot plate to include csk screws for clamping for name, part in asys["squirrel"].traverse(): if name == "slot_plate": sp_clamp_pts = [(p[0], p[1] + 5) for p in vacclamppts] sp = part.obj vch_shift_y = -37 vch_shift_x = 3 sp = sp.faces(">Z").workplane(**u.copo, origin=( 0, 0, 0)).rarray(vacclamppts[3][0] * 2 + vch_shift_x, vacclamppts[3][1] * 2 + vch_shift_y, 2, 2).clearanceHole(spscrew, fit="Close", baseAssembly=hardware) # next line is a hack to make absolutely sure the screws are recessed sp = sp.faces(">Z").workplane(**u.copo, origin=( 0, 0, 0)).rarray( vacclamppts[3][0] * 2 + vch_shift_x, vacclamppts[3][1] * 2 + vch_shift_y, 2, 2).cskHole(spscrew.clearance_hole_diameters["Close"], cskDiameter=spscrew.head_diameter + 1, cskAngle=spscrew.screw_data["a"]) part.obj = sp # make threaded holes to attach to, TODO: mark these as M3x0.5 threaded holes in engineering drawing top_piece = top_piece.faces(">Z[-2]").workplane( **u.copo, origin=(0, 0, 0)).rarray(vacclamppts[3][0] * 2 + vch_shift_x, vacclamppts[3][1] * 2 + vch_shift_y, 2, 2).tapHole(spscrew, depth=spscrew_length - 1, counterSunk=False) # compute the hole array extents for o-ring path finding sub_x_length = (n_sub_array_x - 1) * x_spacing_sub + hole_d array_x_length = (n_array_x - 1) * x_spacing + sub_x_length sub_y_length = (n_sub_array_y - 1) * y_spacing_sub + hole_d array_y_length = (n_array_y - 1) * y_spacing + sub_y_length # for the vac chuck fitting vac_fitting_chuck_offset = -0.5 * y_spacing fitting_tap_depth = 20 top_piece = top_piece.faces(">X").workplane(**u.cobb).center( vac_fitting_chuck_offset, 0).tapHole(vac_fitting_screw, depth=fitting_tap_depth) vac_chuck_fitting = cadquery.Assembly(a_vac_fitting.rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=-5), name="chuck_vac_fitting") hardware.add(vac_chuck_fitting, loc=top_piece.plane.location, name="vac chuck fitting") # handle the valve, part number 435-8101 a_valve = u.import_step( wrk_dir.joinpath("components", "VHK2-04F-04F.step")) # a_valve = a_valve.rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=90).translate((0, 7.5, 9)) a_valve = a_valve.translate((0, 7.5, 9)) valve_mnt_spacing = 16.5 valve_mnt_screw_length = 30 valve_body_width = 18 valve_mnt_hole_depth = 15 valve_mnt_screw = PanHeadScrew( size="M4-0.7", fastener_type="iso14583", length=valve_mnt_screw_length) # SHP-M4-30-V2-A4 btm_piece = btm_piece.faces(">X[-2]").workplane(**u.cobb).rarray( valve_mnt_spacing, 1, 2, 1).tapHole(valve_mnt_screw, depth=valve_mnt_hole_depth, counterSunk=False) # cut threaded holes btm_piece = btm_piece.faces(">X[-2]").workplane(**u.cobb).rarray( valve_mnt_spacing, 1, 2, 1).tapHole(valve_mnt_screw, depth=valve_mnt_screw_length - valve_body_width, counterSunk=False, baseAssembly=aso) # add screws aso.add(a_valve, loc=btm_piece.plane.location, name="valve") # handle the elbow, part number 306-5993 an_elbow = u.import_step( wrk_dir.joinpath("components", "3182_04_00.step")) an_elbow = an_elbow.rotate(axisStartPoint=(0, 0, 0), axisEndPoint=(0, 1, 0), angleDegrees=-90).rotate( axisStartPoint=(0, 0, 0), axisEndPoint=(0, 0, 1), angleDegrees=90) # rotate the elbow btm_pln = btm_piece.faces(">X[-2]").workplane( **u.cobb, offset=valve_body_width / 2).center(-26.65, 7.5) # position the elbow aso.add(an_elbow, loc=btm_pln.plane.location, name="elbow") # vac distribution network zdrill_loc = (pedistal_xy[0] / 2 - fitting_tap_depth, 0.5 * y_spacing) zdrill_r = 3 zdrill_depth = -pedistal_height / 2 - 2.5 top_piece = top_piece.faces("<Z").workplane(**u.cobb).pushPoints( [zdrill_loc]).circle(zdrill_r).cutBlind(zdrill_depth) highway_depth = 3 highway_width = 6 street_depth = 2 street_width = 1 top_piece = top_piece.faces("<Z").workplane(**u.cobb).sketch().push([ (zdrill_loc[0] / 2, zdrill_loc[1]) ]).slot(w=zdrill_loc[0], h=highway_width).finalize().cutBlind(-highway_depth) top_piece = top_piece.faces("<Z").workplane(**u.cobb).sketch().slot( w=pedistal_xy[0] - 2 * fitting_tap_depth, h=highway_width, angle=90).finalize().cutBlind(-highway_depth) # cut center highway top_piece = top_piece.faces("<Z").workplane( **u.cobb).sketch().push(street_centers).slot( w=array_x_length - hole_d, h=street_width).finalize().cutBlind( -street_depth) # cut streets # padding to keep the oring groove from bothering the vac holes groove_x_pad = 8 groove_y_pad = 16 # that's part number 196-4941 o_ring_thickness = 2 o_ring_inner_diameter = 170 # cut the o-ring groove top_piece = top_piece.faces("<Z").workplane(**u.cobb).mk_groove( ring_cs=o_ring_thickness, follow_pending_wires=False, ring_id=o_ring_inner_diameter, gland_x=array_x_length + groove_x_pad, gland_y=array_y_length + groove_y_pad, hardware=hardware) # cut the electrical contact screw mount holes vc_e_screw_spacing = 15 vc_e_screw_center_offset = 10 vc_e_screw_hole_depth = 12 vc_e_screw_screw_length = 8 vc_e_srew_type = "M3-0.5" e_dummy = SetScrew(vc_e_srew_type, fastener_type="iso4026", length=vc_e_screw_screw_length, simple=no_threads) # mark these chuck electrical connection screw holes in engineering drawing as M3x0.5 top_piece = top_piece.faces("<X").workplane(**u.cobb).center( vc_e_screw_center_offset, 0).rarray(vc_e_screw_spacing, 1, 2, 1).tapHole(e_dummy, depth=vc_e_screw_hole_depth) aso.add(btm_piece, name=plate_name, color=color) aso.add(top_piece, name=vac_name, color=color) aso.add(hardware.toCompound(), name="hardware", color=cadquery.Color(hardware_color))
import dims import importlib importlib.reload(dims) importlib.reload(clamp_module) importlib.reload(bracket_module) importlib.reload(spindle_module) importlib.reload(vac_brack_module) importlib.reload(vac_module) importlib.reload(chimney_module) importlib.reload(brace_module) # Looks like I'm asking too much from the solver to assemble all these # components in a top level assembly. I should try breaking these parts into # subassemblies to simplify the process. assy = cq.Assembly() back = vslot.cbeam_dxf(250) assy.add(back, name="back", color=cq.Color(0.8, 0.8, 0.8)) assy.add(bracket_module.bracket, name="bracket", color=cq.Color(0.9, 0.9, 0.95)) # Make the constraint between the centre of the bottom back edge of the bracket # and the centre of the bottom front edge of the back aluminium profile plus an # offset backpoint = (back.faces("<Z", tag="unslotted").edges("<Y").translate( (0, 0, dims.bottom_of_vslot_to_bottom_of_bracket)).val()) bracketpoint = bracket_module.bracket.faces("<Z").edges(">Y").val() assy.constrain("back", backpoint, "bracket", bracketpoint, "Point") assy.constrain( "back",
def build(self, stacks_to_build: List[str] = [""]): if stacks_to_build == [""]: # build them all by default stacks_to_build = [x["name"] for x in self.stacks] drawing_layers_needed = [] for stack_instructions in self.stacks: if stack_instructions["name"] in stacks_to_build: for stack_layer in stack_instructions["layers"]: drawing_layers_needed += stack_layer["drawing_layer_names"] if "edge_case" in stack_layer: drawing_layers_needed.append(stack_layer["edge_case"]) drawing_layers_needed_unique = list(set(drawing_layers_needed)) # all the wires we'll need here wires = self.get_wires(self.sources, drawing_layers_needed_unique) stacks = {} for stack_instructions in self.stacks: # asy = cadquery.Assembly() asy = None if stack_instructions["name"] in stacks_to_build: # asy.name = stack_instructions["name"] z_base = 0 for stack_layer in stack_instructions["layers"]: t = stack_layer["thickness"] boundary_layer_name = stack_layer["drawing_layer_names"][ 0] # boundary layer must always be the first one listed w0 = wires[boundary_layer_name][0] wp = CQ().sketch().face(w0) for w in wires[boundary_layer_name][1::]: wp = wp.face(w, mode="s") wp = wp.finalize().extrude(t) # the workpiece is now made wp = wp.faces(">Z").sketch() if "array" in stack_layer: array_points = stack_layer["array"] else: array_points = [(0, 0, 0)] for drawing_layer_name in stack_layer[ "drawing_layer_names"][1:]: some_wires = wires[drawing_layer_name] for awire in some_wires: wp = wp.push(array_points).face( awire, mode="a", ignore_selection=False) wp = wp.faces() if "edge_case" in stack_layer: edge_wire = wires[stack_layer["edge_case"]][0] wp = wp.face(edge_wire, mode="i") wp = wp.clean() # wp = wp.finalize().cutThruAll() # this is a fail, but should work wp = wp.finalize().extrude(-t, combine="cut") new = wp.translate([0, 0, z_base]) if asy is None: # some silly hack needed to work around https://github.com/CadQuery/cadquery/issues/993 asy = cadquery.Assembly(new, name=stack_layer["name"], color=cadquery.Color( stack_layer["color"])) # asy.name = stack_instructions["name"] else: asy.add(new, name=stack_layer["name"], color=cadquery.Color(stack_layer["color"])) z_base = z_base + t stacks[stack_instructions["name"]] = asy return stacks
# define the elements door = (cq.Assembly().add(make_vslot(H), name="left").add( make_vslot(H), name="right").add(make_vslot(W), name="top").add( make_vslot(W), name="bottom").add(make_connector(), name="con_tl", color=cq.Color("black")).add( make_connector(), name="con_tr", color=cq.Color("black")).add( make_connector(), name="con_bl", color=cq.Color("black")).add( make_connector(), name="con_br", color=cq.Color("black")).add( make_panel(W + 2 * SLOT_D, H + 2 * SLOT_D, PANEL_T, SLOT_D), name="panel", color=cq.Color(0, 0, 1, 0.2), ).add( make_handle(HANDLE_D, HANDLE_L, HANDLE_W), name="handle", color=cq.Color("yellow"), )) # define the constraints (