Esempio n. 1
0
 def make_pusher_plate(self):
     pusher = CQ().add(self.pusher_plate).toPending().extrude(self.pusher_t)
     pusher = pusher.add(self.plate_mounts).toPending().cutThruAll()
     pusher = pusher.translate(
         (0, 0,
          self.pcb_thickness / 2 + self.slots_t + self.silicone_working_t))
     return pusher
Esempio n. 2
0
    def make_heater_plate(self):
        heater = CQ().add(self.base_plate).toPending().extrude(self.heater_t)
        heater = heater.faces(">Z[-1]").workplane().add(
            self.plate_mounts).translate(
                (0, 0, self.heater_t)).toPending().cutBlind(-self.screw_depth)

        heater = heater.translate((0, 0, -self.heater_t - self.cu_base_t -
                                   self.pcb_thickness / 2 - self.pcb_spacer_h))
        return (heater)
Esempio n. 3
0
def mk_vgroove(cutter_path, entry_point, depth):
    """ for cutting grooves with a 90 degree countersink cutter"""
    half_profile = CQ('XZ').polyline([(0, 0), (depth, 0), (0, -depth)]).close()
    cutter = half_profile.revolve()
    cutter_split = cutter.split(keepTop=True)
    cutter_crosssection = cutter_split.faces('+Y')  #TODO do this more generally
    cutter_crosssection_shift = cutter_crosssection.translate(entry_point)

    to_sweep = cutter_crosssection_shift.wires().toPending()
    sweep_result = to_sweep.sweep(cutter_path, combine=True, transition="round", sweepAlongWires=False, isFrenet=True)
    return sweep_result
Esempio n. 4
0
 def __init__(self):
     self.cu_towers = self.get_wires("cu_towers")
     self.base_plate = self.get_wires("base_plate")
     self.cu_base = self.get_wires("cu_base")
     self.plate_mounts = self.get_wires("plate_mounts")
     self.pusher_plate = self.get_wires("pusher_plate")
     self.slot_plate = self.get_wires("slot_plate")
     self.spacer_pcb = self.get_wires("spacer_pcb")
     self.silicone = self.get_wires("silicone")
     self.glass = self.get_wires("glass")
     self.dowels = self.get_wires("dowels")
     self.cu_nubs = self.get_wires("cu_nubs")
     self.cu_dowel_pf = self.get_wires("cu_dowel_pf")
     self.pcb = CQ().add(
         cadquery.importers.importStep(str(self.pcb_step_filepath)))
     self.vent_screw = CQ().add(
         cadquery.importers.importStep(str(self.vent_screw_filepath)))
Esempio n. 5
0
    def _make_neg(what):
        """makes a negative shape to be cut out of the parent walls"""
        # 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

        # fastener threaded holes
        # TODO: mark these holes as "M3-0.5 threaded" in the engineering drawing
        fhs = CQ().pushPoints(fhps).circle(fix_scr.tap_hole_diameters["Soft"] /
                                           2).extrude(-wall_depth +
                                                      pt_fix_wall_buffer)

        nwp = CQ().add(through_face)
        through = nwp.wires().toPending().extrude(-wall_depth)

        nwp2 = CQ().add(recess_face)
        recess = nwp2.wires().toPending().extrude(-part_thickness)

        neg = recess.union(through).union(fhs)

        return neg.findSolid().moved(base * loc)
Esempio n. 6
0
 def make_reservation(self, do_ventscrews: bool = False):
     if do_ventscrews:
         vss = self.get_ventscrews_a()
     sr = CQ().box(self.reserve_xy,
                   self.reserve_xy,
                   self.reserve_h,
                   centered=(True, True, False))
     sr = sr.translate(
         (0, 0, -self.pcb_thickness - self.pcb_spacer_h - self.cu_base_t))
     wires = CQ().box(self.wire_slot_depth,
                      2.54 * 20,
                      2.54 * 2,
                      centered=(False, True, False)).translate(
                          (-self.reserve_xy / 2, 0,
                           self.wire_slot_z + self.pcb_thickness / 2))
     wiresA = wires.translate((0, self.wire_slot_offset, 0))
     wiresB = wires.translate((0, -self.wire_slot_offset, 0))
     sr = sr.cut(wiresA).cut(wiresB)
     if do_ventscrews:
         sr = sr.add(vss)
     # these next two lines are very expensive (and optional)!
     sr = sr.add(self.get_pcb())
     #sr = CQ().union(sr)
     return sr
Esempio n. 7
0
    def make_tower_plate(self):
        towers = CQ().add(self.cu_base).toPending().extrude(self.cu_base_t)
        towers = towers.faces("<Z[-2]").workplane().add(
            self.cu_towers).translate(
                (0, 0, self.cu_base_t)).toPending().extrude(self.cu_tower_h)
        towers = towers.faces("<Z[-2]").workplane().add(
            self.cu_nubs).translate(
                (0, 0, self.cu_base_t)).toPending().extrude(self.cu_nub_h)
        towers = towers.add(self.plate_mounts).toPending().cutThruAll()
        towers = towers.add(self.cu_dowel_pf).toPending().cutThruAll()

        towers = towers.translate(
            (0, 0,
             -self.cu_base_t - self.pcb_thickness / 2 - self.pcb_spacer_h))
        return (towers)
Esempio n. 8
0
    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)
Esempio n. 9
0
class Badger(object):
    cu_base_t = 3
    pcb_spacer_h = 1.6

    reserve_xy = 200
    reserve_h = 20
    wire_slot_depth = 28  # depth from edge
    wire_slot_offset = 46.5  # offset y
    wire_slot_z = 2.095  # offset z

    heater_t = 20
    pusher_t = 4

    glass_t = 1.1
    silicone_t = 0.508  # uncompressed silicone thickness (0.02 in https://www.mcmaster.com/86915K22/)
    compressed_silicone_fraction = 0.8  # let's say it'll compress to 0.8 of its initial thickness
    silicone_working_t = silicone_t * compressed_silicone_fraction  # working silicone thickness (just sets up where the glass and the pusher end up in the model)
    pcb_thickness = 1.6
    min_min_height = 0.8  # pins are fully depressed on a surface this far from the PCB
    cu_tower_h = pcb_spacer_h + pcb_thickness + min_min_height  # 0.8 here just ensures the 0921 pins can never bottom out
    # thus the thermal pad material can be any thickness 0 through pin working travel (about 1.4mm, but lets say 1.3mm to be safe)
    slots_t = min_min_height + glass_t

    cu_nub_h = pcb_spacer_h + pcb_thickness - 0.3

    dowel_height = 16

    glass_xy = 25

    screw_depth = 7

    # ventscrew coordinates
    screw_spots = [
        (-93, 93),
        (-31, 93),
        (31, 93),
        (93, 93),
        (93, 31),
        (93, -31),
        (93, -93),
        (31, -93),
        (-31, -93),
        (-93, -93),
        (-93, 0),
    ]

    gs = globals()
    ls = locals()
    print(gs)
    print(ls)
    dxf_filepath = Path(__file__).parent / "drawings" / "2d.dxf"
    pcb_step_filepath = Path(__file__).parent / "components" / "pcb.step"
    vent_screw_filepath = Path(
        __file__).parent / "components" / "vent_screw.step"

    def __init__(self):
        self.cu_towers = self.get_wires("cu_towers")
        self.base_plate = self.get_wires("base_plate")
        self.cu_base = self.get_wires("cu_base")
        self.plate_mounts = self.get_wires("plate_mounts")
        self.pusher_plate = self.get_wires("pusher_plate")
        self.slot_plate = self.get_wires("slot_plate")
        self.spacer_pcb = self.get_wires("spacer_pcb")
        self.silicone = self.get_wires("silicone")
        self.glass = self.get_wires("glass")
        self.dowels = self.get_wires("dowels")
        self.cu_nubs = self.get_wires("cu_nubs")
        self.cu_dowel_pf = self.get_wires("cu_dowel_pf")
        self.pcb = CQ().add(
            cadquery.importers.importStep(str(self.pcb_step_filepath)))
        self.vent_screw = CQ().add(
            cadquery.importers.importStep(str(self.vent_screw_filepath)))

    def get_wires(self, layername):
        """returns the wires from the given dxf layer"""
        # list of of all layers in the dxf
        dxf_layernames = [
            "0",
            "base_plate",
            "connector",
            "cu_base",
            "cu_dowel_pf",
            "cu_nubs",
            "cu_towers",
            "Defpoints",
            "dims",
            "dowels",
            "glass",
            "metal_mask",
            "pcb",
            "pin_holes",
            "plate_mounts",
            "pusher_plate",
            "silicone",
            "slot_plate",
            "spacer_pcb",
        ]
        to_exclude = [k for k in dxf_layernames if layername != k]
        dxf_obj = cadquery.importers.importDXF(str(self.dxf_filepath),
                                               exclude=to_exclude)
        return (dxf_obj.wires())

    def make_heater_plate(self):
        heater = CQ().add(self.base_plate).toPending().extrude(self.heater_t)
        heater = heater.faces(">Z[-1]").workplane().add(
            self.plate_mounts).translate(
                (0, 0, self.heater_t)).toPending().cutBlind(-self.screw_depth)

        heater = heater.translate((0, 0, -self.heater_t - self.cu_base_t -
                                   self.pcb_thickness / 2 - self.pcb_spacer_h))
        return (heater)

    def make_tower_plate(self):
        towers = CQ().add(self.cu_base).toPending().extrude(self.cu_base_t)
        towers = towers.faces("<Z[-2]").workplane().add(
            self.cu_towers).translate(
                (0, 0, self.cu_base_t)).toPending().extrude(self.cu_tower_h)
        towers = towers.faces("<Z[-2]").workplane().add(
            self.cu_nubs).translate(
                (0, 0, self.cu_base_t)).toPending().extrude(self.cu_nub_h)
        towers = towers.add(self.plate_mounts).toPending().cutThruAll()
        towers = towers.add(self.cu_dowel_pf).toPending().cutThruAll()

        towers = towers.translate(
            (0, 0,
             -self.cu_base_t - self.pcb_thickness / 2 - self.pcb_spacer_h))
        return (towers)

    def get_ventscrews_a(self):
        ventscrew = self.vent_screw.translate((0, 0, -1.7))
        ventscrews = CQ().pushPoints(self.screw_spots).eachpoint(
            lambda loc: ventscrew.val().moved(loc), True)
        return ventscrews

    def get_ventscrews_b(self):
        ventscrew = self.vent_screw.translate((0, 0, 3.3))
        ventscrews = CQ().pushPoints(self.screw_spots).eachpoint(
            lambda loc: ventscrew.val().moved(loc), True)
        return ventscrews

    def make_reservation(self, do_ventscrews: bool = False):
        if do_ventscrews:
            vss = self.get_ventscrews_a()
        sr = CQ().box(self.reserve_xy,
                      self.reserve_xy,
                      self.reserve_h,
                      centered=(True, True, False))
        sr = sr.translate(
            (0, 0, -self.pcb_thickness - self.pcb_spacer_h - self.cu_base_t))
        wires = CQ().box(self.wire_slot_depth,
                         2.54 * 20,
                         2.54 * 2,
                         centered=(False, True, False)).translate(
                             (-self.reserve_xy / 2, 0,
                              self.wire_slot_z + self.pcb_thickness / 2))
        wiresA = wires.translate((0, self.wire_slot_offset, 0))
        wiresB = wires.translate((0, -self.wire_slot_offset, 0))
        sr = sr.cut(wiresA).cut(wiresB)
        if do_ventscrews:
            sr = sr.add(vss)
        # these next two lines are very expensive (and optional)!
        sr = sr.add(self.get_pcb())
        #sr = CQ().union(sr)
        return sr

    def make_silicone(self):
        silicone = CQ().add(self.silicone).toPending().extrude(self.silicone_t)
        silicone = silicone.translate(
            (0, 0,
             -self.pcb_thickness / 2 - self.pcb_spacer_h + self.cu_tower_h))
        return silicone

    def make_dowels(self):
        dowels = CQ().add(self.dowels).toPending().extrude(self.dowel_height)
        dowels = dowels.translate(
            (0, 0,
             -self.pcb_thickness / 2 - self.pcb_spacer_h - self.cu_base_t))
        return dowels

    def make_glass(self):
        glass = CQ().add(self.glass).toPending().extrude(self.glass_t)
        glass = glass.translate(
            (0, 0, -self.pcb_thickness / 2 - self.pcb_spacer_h +
             self.cu_tower_h + self.silicone_working_t))
        return glass

    def make_spacer_pcb(self):
        spacer = CQ().add(self.spacer_pcb).toPending().extrude(
            self.pcb_spacer_h)
        spacer = spacer.translate(
            (0, 0, -self.pcb_thickness / 2 - self.pcb_spacer_h))
        return (spacer)

    def get_pcb(self):
        return self.pcb

    def make_pusher_plate(self):
        pusher = CQ().add(self.pusher_plate).toPending().extrude(self.pusher_t)
        pusher = pusher.add(self.plate_mounts).toPending().cutThruAll()
        pusher = pusher.translate(
            (0, 0,
             self.pcb_thickness / 2 + self.slots_t + self.silicone_working_t))
        return pusher

    def make_slot_plate(self):
        slots = CQ().add(self.slot_plate).toPending().extrude(self.slots_t)
        slots = slots.add(self.plate_mounts).toPending().cutThruAll()
        slots = slots.translate((0, 0, self.pcb_thickness / 2))
        return (slots)

    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
Esempio n. 10
0
def mk_groove(
    self: cq.Workplane,
    vdepth: float = 0,
    ring_cs: float = 0,
    follow_pending_wires: bool = True,
    ring_id: float = None,
    gland_x: float = None,
    gland_y: float = None,
    compression_ratio: float = 0.25,
    gland_fill_ratio: float = 0.7,
    clean: bool = True,
    hardware: cadquery.Assembly = None,
) -> cq.Workplane:
    """
    for cutting grooves
    set vdepth > 0 to cut a vgroove of that depth
    otherwise
    set ring_cs > 0 to cut an o-ring groove (the diameter of the cross section of the o-ring)
    follow_pending_wires = True, will mean the grooves will be cut according to pending wires/faces
    if that's false, we'll make a groove for a specific o-ring and you must set all off the following:
        ring_id, the innter diameter of the ring to be used (bore diameter)
        gland_x = the spacing in x between the centers of the gland (rounded) rectangle
        gland_y = the spacing in y between the centers of the gland (rounded) rectangle
        the fillets at the gland corners will be determined to ensure the ring fits, they will be equal
    if a hardware assembly is provided, o-oring hardware will be added to it
    """
    def _make_one_groove(wp, _wire, _vdepth, _ring_cs, _compression_ratio,
                         _gland_fill_ratio):
        cp_tangent = _wire.tangentAt(0)  # tangent to cutter_path
        cp_start = _wire.startPoint()
        build_plane = cq.Plane(origin=cp_start,
                               normal=cp_tangent,
                               xDir=wp.plane.zDir)
        if _vdepth > 0:  # we'll cut a vgroove this deep
            half_profile = CQ(build_plane).polyline([(0, 0), (-_vdepth, 0),
                                                     (0, _vdepth)]).close()
        elif ring_cs > 0:  # we'll cut an o-ring groove, ring_cs is the diameter of the cross section of the o-ring
            # according to https://web.archive.org/web/20220512010502/https://www.globaloring.com/o-ring-groove-design/
            gland_height = get_gland_height(_ring_cs, _compression_ratio)
            gland_width = get_gland_width(_ring_cs, _compression_ratio,
                                          _gland_fill_ratio)
            half_profile = CQ(build_plane).polyline([
                (0, 0), (-gland_height, 0), (-gland_height, gland_width / 2),
                (0, gland_width / 2)
            ]).close()
        else:
            raise ValueError("One of vdepth or ring_cs must be larger than 0")
        cutter = half_profile.revolve(axisEnd=(1, 0, 0))
        cutter_split = cutter.split(keepTop=True)
        faces = cutter_split.faces().vals()
        for face in faces:  # find the right face to sweep with
            facenorm = face.normalAt()
            dotval = facenorm.dot(cp_tangent)
            if abs(
                (abs(dotval) - 1)
            ) <= 0.001:  # allow for small errors in orientation calculation
                cutter_crosssection = face
                break
        else:
            raise ValueError("Unable to find a cutter cross-section")

        # make the squished o-ring hardware
        if (ring_cs > 0) and (hardware is not None):
            ring_sweep_wire = CQ(build_plane).center(
                -gland_height / 2,
                0).ellipse(gland_height / 2, ring_cs / 2 *
                           (1 + _compression_ratio)).wires().toPending()
            hardware.add(
                ring_sweep_wire.sweep(_wire,
                                      combine=True,
                                      transition="round",
                                      isFrenet=True).findSolid())

        to_sweep = CQ(cutter_crosssection).wires().toPending()
        return to_sweep.sweep(_wire).findSolid()

    s = self.findSolid()

    if follow_pending_wires:
        faces = self._getFaces()
        for face in faces:
            wire = face.outerWire()
            logger = logging.getLogger(__name__)
            logger.info(
                f"Made an o-ring gland for ring length {wire.Length()}mm and diameter {ring_cs}mm"
            )
            sweep_result = _make_one_groove(
                wp=self,
                _wire=wire,
                _vdepth=vdepth,
                _ring_cs=ring_cs,
                _compression_ratio=compression_ratio,
                _gland_fill_ratio=gland_fill_ratio)
            s = s.cut(sweep_result)

            if clean:
                s = s.clean()
    else:  # we'll need to make our own path wire then, given the user specs
        # ensure the user passed in the right stuff
        assert vdepth == 0
        assert ring_cs > 0
        assert ring_id is not None
        assert gland_x is not None
        assert gland_y is not None
        wire_length = 2 * math.pi * (ring_id / 2 + ring_cs / 2)
        square_length = 2 * gland_x + 2 * gland_y
        if wire_length > square_length:
            raise ValueError(
                "The o-ring circumference is too big for the given x and y gland dims"
            )
        r = (wire_length - 2 * gland_x - 2 * gland_y) / (2 * math.pi - 8)
        if (2 * r > gland_x) or (2 * r > gland_y):
            raise ValueError(
                "The o-ring circumference is too small for the given x and y gland dims"
            )
        logger = logging.getLogger(__name__)
        logger.info(
            f"Using path bend radius {r}mm, that's an uncompressed cord inner radius of {r-ring_cs/2} (and the min is {ring_cs*3})"
        )
        wire = CQ(self.plane).rect(gland_x, gland_y).wires().val()
        wire = wire.fillet2D(r, wire.Vertices())
        sweep_result = _make_one_groove(wp=self,
                                        _wire=wire,
                                        _vdepth=vdepth,
                                        _ring_cs=ring_cs,
                                        _compression_ratio=compression_ratio,
                                        _gland_fill_ratio=gland_fill_ratio)
        s = s.cut(sweep_result)

        if clean:
            s = s.clean()

    return self.newObject([s])
Esempio n. 11
0
 def make_slot_plate(self):
     slots = CQ().add(self.slot_plate).toPending().extrude(self.slots_t)
     slots = slots.add(self.plate_mounts).toPending().cutThruAll()
     slots = slots.translate((0, 0, self.pcb_thickness / 2))
     return (slots)
Esempio n. 12
0
    def _make_one_groove(wp, _wire, _vdepth, _ring_cs, _compression_ratio,
                         _gland_fill_ratio):
        cp_tangent = _wire.tangentAt(0)  # tangent to cutter_path
        cp_start = _wire.startPoint()
        build_plane = cq.Plane(origin=cp_start,
                               normal=cp_tangent,
                               xDir=wp.plane.zDir)
        if _vdepth > 0:  # we'll cut a vgroove this deep
            half_profile = CQ(build_plane).polyline([(0, 0), (-_vdepth, 0),
                                                     (0, _vdepth)]).close()
        elif ring_cs > 0:  # we'll cut an o-ring groove, ring_cs is the diameter of the cross section of the o-ring
            # according to https://web.archive.org/web/20220512010502/https://www.globaloring.com/o-ring-groove-design/
            gland_height = get_gland_height(_ring_cs, _compression_ratio)
            gland_width = get_gland_width(_ring_cs, _compression_ratio,
                                          _gland_fill_ratio)
            half_profile = CQ(build_plane).polyline([
                (0, 0), (-gland_height, 0), (-gland_height, gland_width / 2),
                (0, gland_width / 2)
            ]).close()
        else:
            raise ValueError("One of vdepth or ring_cs must be larger than 0")
        cutter = half_profile.revolve(axisEnd=(1, 0, 0))
        cutter_split = cutter.split(keepTop=True)
        faces = cutter_split.faces().vals()
        for face in faces:  # find the right face to sweep with
            facenorm = face.normalAt()
            dotval = facenorm.dot(cp_tangent)
            if abs(
                (abs(dotval) - 1)
            ) <= 0.001:  # allow for small errors in orientation calculation
                cutter_crosssection = face
                break
        else:
            raise ValueError("Unable to find a cutter cross-section")

        # make the squished o-ring hardware
        if (ring_cs > 0) and (hardware is not None):
            ring_sweep_wire = CQ(build_plane).center(
                -gland_height / 2,
                0).ellipse(gland_height / 2, ring_cs / 2 *
                           (1 + _compression_ratio)).wires().toPending()
            hardware.add(
                ring_sweep_wire.sweep(_wire,
                                      combine=True,
                                      transition="round",
                                      isFrenet=True).findSolid())

        to_sweep = CQ(cutter_crosssection).wires().toPending()
        return to_sweep.sweep(_wire).findSolid()
Esempio n. 13
0
 def make_spacer_pcb(self):
     spacer = CQ().add(self.spacer_pcb).toPending().extrude(
         self.pcb_spacer_h)
     spacer = spacer.translate(
         (0, 0, -self.pcb_thickness / 2 - self.pcb_spacer_h))
     return (spacer)
Esempio n. 14
0
 def make_glass(self):
     glass = CQ().add(self.glass).toPending().extrude(self.glass_t)
     glass = glass.translate(
         (0, 0, -self.pcb_thickness / 2 - self.pcb_spacer_h +
          self.cu_tower_h + self.silicone_working_t))
     return glass
Esempio n. 15
0
 def make_dowels(self):
     dowels = CQ().add(self.dowels).toPending().extrude(self.dowel_height)
     dowels = dowels.translate(
         (0, 0,
          -self.pcb_thickness / 2 - self.pcb_spacer_h - self.cu_base_t))
     return dowels
Esempio n. 16
0
    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 faces we'll need here
        layers = self.get_layers(self.sources, drawing_layers_needed_unique)
        self._layers = layers

        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
                    layer_comp = cadquery.Compound.makeCompound(
                        layers[boundary_layer_name].faces().vals())

                    if "array" in stack_layer:
                        array_points = stack_layer["array"]
                    else:
                        array_points = [(0, 0, 0)]

                    if len(stack_layer["drawing_layer_names"]) == 1:
                        wp = CQ().sketch().push(array_points).face(
                            layer_comp, mode="a", ignore_selection=False)
                    else:
                        wp = CQ().sketch().face(layer_comp,
                                                mode="a",
                                                ignore_selection=False)

                    wp = wp.finalize().extrude(
                        t)  # the workpiece base is now made
                    if len(stack_layer["drawing_layer_names"]) > 1:
                        wp = wp.faces(">Z").workplane(
                            centerOption="ProjectedOrigin").sketch()

                        for drawing_layer_name in stack_layer[
                                "drawing_layer_names"][1:]:
                            layer_comp = cadquery.Compound.makeCompound(
                                layers[drawing_layer_name].faces().vals())
                            wp = wp.push(array_points).face(
                                layer_comp, mode="a", ignore_selection=False)

                        wp = wp.faces()
                        if "edge_case" in stack_layer:
                            edge_layer_name = stack_layer["edge_case"]
                            layer_comp = cadquery.Compound.makeCompound(
                                layers[edge_layer_name].faces().vals())
                            es = CQ().sketch().face(layer_comp)
                            wp = wp.face(es.faces(), mode="i")
                            wp = wp.clean()
                        # wp = wp.finalize().cutThruAll()  # this is a fail, but should work. if it's not a fail is slower than the below line
                        wp = wp.finalize().extrude(-t, combine="cut")

                    # give option to override calculated z_base
                    if "z_base" in stack_layer:
                        z_base = stack_layer["z_base"]

                    new = wp.translate([0, 0, z_base])
                    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
Esempio n. 17
0
    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))
Esempio n. 18
0
def main():
    # define where we'll read shapes from
    sources = [
        Path.cwd().parent / "oxford" / "master.dxf",
        Path.cwd().parent / "oxford" / "derivatives" /
        "5x5_cluster_master.dxf",
    ]

    support_thickness = 0.65
    feature_thickness = 0.2
    shim_thickness = 0.5

    support_color = "GOLDENROD"
    feature_color = "GRAY28"
    shim_color = "DARKGREEN"

    # define how we'll tile things
    spacing5 = 30
    array5 = [(x * spacing5, y * spacing5, 0)
              for x, y in itertools.product(range(-2, 3), range(-2, 3))]

    instructions = []
    instructions.append({
        "name":
        "active_mask_stack",
        "layers": [
            {
                "name":
                "active_support",
                "color":
                support_color,
                "thickness":
                support_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "aggressive_support_active",
                ],
            },
            {
                "name": "active_feature",
                "color": feature_color,
                "thickness": feature_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "active_layer",
                ],
            },
            {
                "name": "spacer_shim",
                "color": shim_color,
                "thickness": shim_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "spacer_shim",
                ],
            },
        ],
    })

    instructions.append({
        "name":
        "active_mask_stack_5x5",
        "layers": [
            {
                "name":
                "active_support",
                "color":
                support_color,
                "thickness":
                support_thickness,
                "drawing_layer_names": [
                    "outline_5x5",
                    "aggressive_support_active",
                ],
                "edge_case":
                "inner_outline_5x5",
                "array":
                array5,
            },
            {
                "name":
                "active_feature",
                "color":
                feature_color,
                "thickness":
                feature_thickness,
                "drawing_layer_names": [
                    "outline_no_alignment_5x5",
                    "active_layer",
                ],
                "edge_case":
                "inner_outline_5x5",
                "array":
                array5,
            },
            {
                "name": "spacer_shim",
                "color": shim_color,
                "thickness": shim_thickness,
                "drawing_layer_names": [
                    "outline_no_alignment_5x5",
                    "spacer_shim",
                ],
                "edge_case": "inner_outline_5x5",
                "array": array5,
            },
        ],
    })

    instructions.append({
        "name":
        "metal_mask_stack",
        "layers": [
            {
                "name":
                "metal_support",
                "color":
                support_color,
                "thickness":
                support_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "aggressive_metal_support_tc_metal",
                    "aggressive_metal_support_small_upper",
                    "aggressive_metal_support_large_lower",
                ],
            },
            {
                "name":
                "metal_feature",
                "color":
                feature_color,
                "thickness":
                feature_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "tc_metal",
                    "pixel_electrodes_small_upper",
                    "pixel_electrodes_large_lower",
                ],
            },
            {
                "name": "spacer_shim_thin",
                "color": shim_color,
                "thickness": shim_thickness,
                "drawing_layer_names": [
                    "glass_extents",
                    "spacer_shim_thin",
                ],
            },
        ],
    })

    instructions.append({
        "name":
        "metal_mask_stack_5x5",
        "layers": [
            {
                "name":
                "metal_support",
                "color":
                support_color,
                "thickness":
                support_thickness,
                "drawing_layer_names": [
                    "outline_5x5",
                    "aggressive_metal_support_tc_metal",
                    "aggressive_metal_support_small_upper",
                    "aggressive_metal_support_large_lower",
                ],
                "edge_case":
                "inner_outline_5x5",
                "array":
                array5,
            },
            {
                "name":
                "metal_feature",
                "color":
                feature_color,
                "thickness":
                feature_thickness,
                "drawing_layer_names": [
                    "outline_no_alignment_5x5",
                    "tc_metal",
                    "pixel_electrodes_small_upper",
                    "pixel_electrodes_large_lower",
                ],
                "edge_case":
                "inner_outline_5x5",
                "array":
                array5,
            },
            {
                "name":
                "spacer_shim_thin",
                "color":
                shim_color,
                "thickness":
                shim_thickness,
                "drawing_layer_names": [
                    "outline_no_alignment_5x5",
                    "spacer_shim_thin",
                ],
                "edge_case":
                "inner_outline_5x5",
                "array":
                array5,
            },
        ],
    })

    ttt = TwoDToThreeD(instructions=instructions, sources=sources)
    to_build = ["active_mask_stack", "metal_mask_stack"]
    # to_build = ["active_mask_stack_5x5"]
    # to_build = [""]  # all of them
    asys = ttt.build(to_build)
    # asy: cadquery.Assembly = list(asys.values())[0]  # TODO:take more than the first value

    for stack_name, asy in asys.items():
        if "show_object" in globals():  # we're in cq-editor
            assembly_mode = True  # at the moment, when true we can't select/deselect subassembly parts
            if assembly_mode:
                show_object(asy)
            else:
                for key, val in asy.traverse():
                    shapes = val.shapes
                    if shapes != []:
                        c = cq.Compound.makeCompound(shapes)
                        odict = {}
                        if val.color is not None:
                            co = val.color.wrapped.GetRGB()
                            rgb = (co.Red(), co.Green(), co.Blue())
                            odict["color"] = rgb
                        show_object(c.locate(val.loc),
                                    name=val.name,
                                    options=odict)
        else:
            # save assembly
            asy.save(
                str(Path(__file__).parent / "output" / f"{stack_name}.step"))
            asy.save(
                str(Path(__file__).parent / "output" / f"{stack_name}.glb"),
                "GLTF")
            # cadquery.exporters.assembly.exportCAF(asy, str(Path(__file__).parent / "output" / f"{stack_name}.std"))
            # cq.Shape.exportBrep(cq.Compound.makeCompound(itertools.chain.from_iterable([x[1].shapes for x in asy.traverse()])), str(Path(__file__).parent / "output" / f"{stack_name}.brep"))

            save_individual_stls = False
            save_individual_steps = False
            save_individual_breps = False
            save_individual_dxfs = True

            # save each shape individually
            for key, val in asy.traverse():
                shapes = val.shapes
                if shapes != []:
                    c = cq.Compound.makeCompound(shapes)
                    if save_individual_stls == True:
                        cadquery.exporters.export(
                            c.locate(val.loc),
                            str(
                                Path(__file__).parent / "output" /
                                f"{stack_name}-{val.name}.stl"))
                    if save_individual_steps == True:
                        cadquery.exporters.export(
                            c.locate(val.loc),
                            str(
                                Path(__file__).parent / "output" /
                                f"{stack_name}-{val.name}.step"))
                    if save_individual_breps == True:
                        cq.Shape.exportBrep(
                            c.locate(val.loc),
                            str(
                                Path(__file__).parent / "output" /
                                f"{stack_name}-{val.name}.brep"))
                    if save_individual_dxfs == True:
                        cl = c.locate(val.loc)
                        bb = cl.BoundingBox()
                        zmid = (bb.zmin + bb.zmax) / 2
                        nwp = CQ("XY", origin=(0, 0, zmid)).add(cl)
                        dxface = nwp.section()
                        cadquery.exporters.export(
                            dxface,
                            str(
                                Path(__file__).parent / "output" /
                                f"{stack_name}-{val.name}.dxf"),
                            cadquery.exporters.ExportTypes.DXF)
Esempio n. 19
0
def lid():
    """Lid for cooling block."""
    lid = cq.Workplane("XY").box(lid_l, lid_w, lid_h)
    lid = lid.translate((0, 0, (block_h + lid_h) / 2))

    # add cut for ground ring
    ground_ring_cut = cq.Workplane("XY").box(ground_ring_lid_cut_l,
                                             ground_ring_lid_cut_w, lid_h)
    ground_ring_cut = ground_ring_cut.translate((
        -(lid_l - ground_ring_lid_cut_l) / 2,
        -(lid_w - ground_ring_lid_cut_w) / 2,
        (block_h + lid_h) / 2,
    ))
    ground_ring_cut = ground_ring_cut.edges(">X and >Y and |Z").fillet(
        ground_screw_lid_cut_r)
    lid = lid.cut(ground_ring_cut)

    # add holes for lid fasteners
    lid = lid.faces(">Z").workplane(centerOption="CenterOfBoundBox")
    lid = lid.pushPoints(cs_holes)
    lid = lid.cskHole(2 * cs_screw_clearance_r, 2 * cs_screw_cap_r,
                      cs_screw_angle, cs_screw_tread_h)

    # add holes for extrusion screws
    lid = lid.faces(">Z").workplane(centerOption="CenterOfBoundBox")
    lid = lid.pushPoints(extrusion_holes)
    lid = lid.hole(2 * extrusion_screw_clearance_r)

    # add holes for wire passthroughs
    lid = lid.faces(">Z").workplane(centerOption="CenterOfBoundBox")
    lid = lid.pushPoints(pt_hole_centers)
    lid = lid.hole(2 * pt_hole_clearance_r)

    # add cuts to turn wire passthroughs into U-shapes
    u_cut = cq.Workplane("XY").box(pt_u_x, pt_u_y, lid_h)
    for x, y in pt_u_centers:
        _u_cut = u_cut
        _u_cut = _u_cut.translate((x, y, (block_h + lid_h) / 2))
        lid = lid.cut(_u_cut)

    # for making ure the chamfer cutting tool can get down to where it needs to be
    chamfer_allowance = (CQ().copyWorkplane(
        lid.faces(">Z").workplane(
            centerOption="CenterOfBoundBox")).pushPoints(cs_holes).circle(
                lid_chamfer_clearance).extrude(lid_water_thread_length -
                                               lid_h))

    # for a pocket in the middle to reduce weight
    recess = (CQ().copyWorkplane(
        lid.faces(">Z").workplane(centerOption="CenterOfBoundBox",
                                  invert=True)).box(lid_recess_xy,
                                                    lid_recess_xy,
                                                    lid_recess_depth,
                                                    centered=(True, True,
                                                              False)))

    # for a block around the hose connections to add more connector thread purchase
    thread_block = (CQ().copyWorkplane(
        lid.faces("<Z").workplane(
            centerOption="CenterOfBoundBox",
            invert=True)).center(0, water_port_hole_centers[0][1]).box(
                lid_threadblock_xy[0],
                lid_threadblock_xy[1],
                lid_water_thread_length,
                centered=(True, True, False)).cut(chamfer_allowance).edges(
                    '|Z').fillet(lid_fillet_r))

    # cut the thread block from the recess negative and then fillet that
    # this allows the result to have fillets that are manufacturable
    recess = recess.cut(thread_block).edges('|Z').fillet(lid_fillet_r)

    # cut out the recess then add the thread block
    lid = lid.cut(recess).union(thread_block)

    # add holes for water ports (drill holes up form bottom)
    lid = lid.faces("<Z").workplane(centerOption="CenterOfBoundBox",
                                    invert=True)
    lid = lid.pushPoints(water_port_hole_centers)
    lid = lid.circle(water_port_thread_tap_r).cutThruAll()

    return lid
Esempio n. 20
0
def make_oringer(
    self: cq.Workplane,
    board_width: float = 84.12,
    board_inner_depth: float = 9.271,
    board_outer_depth: float = 9.271,
    part_thickness: float = 0,
    wall_depth: float = 0,
    screw="M3-0.5",
    pt_asy: cadquery.Assembly = None,
    pcb_asy: cadquery.Assembly = None,
    hw_asy: cadquery.Assembly = None,
) -> cq.Workplane:
    logger = logging.getLogger(__name__)
    if wall_depth == 0:  # if depth is not given do our best to find it
        wall_depth = u.find_length(self, along="normal", bb_method=False)
    if part_thickness == 0:  # if thickness is not given, use half the wall thickness
        part_thickness = wall_depth / 2

    pcbt = 1.6  # pcb thickness
    washert = 0.5  # washer thickness

    screw_nominal_d = 3
    screw_head_nominal_d = 6

    # header specific for making the pin0 holes, probably doesn't belong here, but it's too convenient...
    non_notch_side_chunk_width = 0.381  # is 0.15 in
    non_chunk_con_width = 8.89  # is 0.35 in
    pin0_offsetx = non_chunk_con_width / 2 + non_notch_side_chunk_width + 2.54 / 2
    pin0_offsety_25 = 2.54 * (25 - 1) / 2
    pin0_offsety_20 = 2.54 * (20 - 1) / 2
    pin0_holed = 1

    p0pts = [
    ]  # the pin pin 1 points for the two connectors (for checking the correctness of the PCB designs)
    p0pts.append((pin0_offsety_25, pin0_offsetx))
    p0pts.append((-pin0_offsety_20 + 2.5 * 2.54, -(wall_depth + pin0_offsetx)))

    block_width = 7
    block_height_nominal = 6
    support_block = (block_width, block_height_nominal - washert
                     )  # actual support block (leaves room for washer)

    pcb_corner = 2
    pt_pcb_mount_hole_offset = (4.445, block_width / 2)  # from corners

    pcb_scr_len = 12  # SHP-M3-12-V2-A2, round(block_height_nominal + pcbt + 4)
    pt_fix_scr_len = 10  # SHK-M3-10-V2-A2, round(wall_depth * 0.8)
    pt_fix_wall_buffer = 1  # amount of wall to leave behind the threaded screw hole
    fix_scr = CounterSunkScrew(size=screw,
                               fastener_type="iso14581",
                               length=pt_fix_scr_len)
    pcb_scr = PanHeadScrew(size=screw,
                           fastener_type="iso14583",
                           length=pcb_scr_len)
    # washer = CheeseHeadWasher(size=screw, fastener_type="iso7092")
    # nylock nut = HNN-M3-A2

    oring_cs = 1  # oring thickness

    min_radius = oring_cs * 3  # min inner bend radius
    min_wall = 0.8  # walls should not be mfg'd thinner than this

    min_gap = 0.25  # cutting tolerances prevent smaller gaps between things

    gland_width = groovy.get_gland_width(oring_cs)
    # effective_gland_width = (round(gland_width * 100) + 1) / 100  # rounded up to the nearest 0.01mm
    # logger.info(f"Using {effective_gland_width=}")

    # some important radii for construction to ensure we don't overbend the o-ring
    minr1 = min_radius - min_wall
    minr2 = min_radius + min_wall + gland_width

    # actual support block centers
    sbpts = []
    sbx = board_width / 2 - block_width / 2
    sby = ((-pcbt / 2 - washert) + (-pcbt / 2 - block_height_nominal)) / 2
    sbpts.append((sbx, sby))
    sbpts.append((-sbx, sby))

    in_off = minr1 * 2**-0.5 - min_gap * 2**0.5 / 2  # exact inward offset to get min_gap spacing with minr1 fillets

    ffo = minr1 * (1 - 2**-0.5) + min_gap * (2**0.5 / 2)
    co_tw = minr1 * 2 + min_gap  # width of the thin part of the cutout (so that the cutting tool can easily fit)
    max_slot_y = ffo + pcbt + block_height_nominal + ffo  # width at the slot at its max
    if co_tw > max_slot_y:
        co_tw = max_slot_y

    scy = -pcbt / 2 - block_height_nominal + in_off  # y coordinate for the inner, small radius circle
    scx = board_width / 2 - block_width + in_off  # small, inner circle x value

    tcy = pcbt / 2 - in_off  # top circles center y value
    tcx = board_width / 2 - in_off  # top circles center c values
    tcpts = []  # top circle points
    tcpts.append((tcx, tcy))
    tcpts.append((-tcx, tcy))

    ocpts1 = []  # outer circle points for positive x
    ocpts1.append((tcx, tcy))
    ocpts1.append((tcx, scy))

    ocpts2 = []  # outer circle points for negative x
    ocpts2.append((-tcx, tcy))
    ocpts2.append((-tcx, scy))

    bcpts1 = []  # bottom circle points for positive x
    bcpts1.append((tcx, scy))
    bcpts1.append((scx, scy))

    bcpts2 = []  # bottom circle points for negative x
    bcpts2.append((-tcx, scy))
    bcpts2.append((-scx, scy))

    icpts1 = []  # inner circle points for positive x
    icpts1.append((scx, scy))
    icpts1.append((scx, tcy))

    icpts2 = []  # inner circle points for negative x
    icpts2.append((-scx, scy))
    icpts2.append((-scx, tcy))

    swp = CQ().sketch()

    # need support block shapes to fill in gaps
    swp.push(sbpts).rect(*support_block)

    # the fillets at the bottom collide and should be unified with a circle, but the ones at the sides don't
    if (2 * minr1 > 2 * ffo + block_width) and (2 * minr1 < max_slot_y):
        scx = board_width / 2 - block_width / 2  # new center point for circles
        tcpts = []  # top circle points
        tcpts.append((scx, tcy))
        tcpts.append((-scx, tcy))

        ocpts1 = []  # outer circle points for positive x
        ocpts1.append((scx, tcy))
        ocpts1.append((scx, scy))

        ocpts2 = []  # outer circle points for negative x
        ocpts2.append((-scx, tcy))
        ocpts2.append((-scx, scy))

        # make the right circle hull
        swp.push(ocpts1).circle(
            minr1, mode="c",
            tag="c").reset().edges(tag="c").hull().clean().reset()

        # make the left circle hull
        swp.push(ocpts2).circle(
            minr1, mode="c",
            tag="d").reset().edges(tag="d").hull().clean().reset()

    # the fillets at the side collide and should be unified with a circle
    elif 2 * minr1 >= max_slot_y:
        cpts = []  # center points for new circles
        scy = (pcbt / 2 + (-pcbt / 2 - block_height_nominal)) / 2
        tcpts = []  # top circle points
        tcpts.append((tcx, scy))
        tcpts.append((-tcx, scy))

    # normal case, no fillets collide
    else:
        # make the right outer circle hull
        swp.push(ocpts1).circle(
            minr1, mode="c",
            tag="c").reset().edges(tag="c").hull().clean().reset()

        # make the left outer circle hull
        swp.push(ocpts2).circle(
            minr1, mode="c",
            tag="d").reset().edges(tag="d").hull().clean().reset()

        # make the right bottom circle hull
        swp.push(bcpts1).circle(
            minr1, mode="c",
            tag="e").reset().edges(tag="e").hull().clean().reset()

        # make the left bottom circle hull
        swp.push(bcpts2).circle(
            minr1, mode="c",
            tag="f").reset().edges(tag="f").hull().clean().reset()

    bcy = pcbt / 2 + ffo - (co_tw + minr2
                            )  # y coordinate for the large radius circle

    # make the top circle hull
    swp.push(tcpts).circle(
        minr1, mode="c",
        tag="g").reset().edges(tag="g").hull().clean().reset()

    # do all the big circle stuff only if the outer fillets haven't merged
    if not (2 * minr1 > max_slot_y):
        o = scy - bcy  # opposite triangle side length (along y)
        h = minr2 + minr1  # hypotenuse
        if o < 0:  # the circles have moved apart: big one above small one (and the trig breaks)
            a = h
        elif o > h:  # the circles have moved apart (and the trig breaks)
            a = h  # adjacent (along x)
        else:
            a = h * math.cos(math.asin(o / h))
            # a = o/math.tan(math.asin(o/h))  # adjacent (along x)
        bcx = scx - a  # big circle x
        # bcy = pcbt/2+ffo-(co_tw+minr2)
        bcpts = []
        bcpts.append((-bcx, bcy))
        bcpts.append((bcx, bcy))

        swp.push([(-scx, scy), (scx, scy)]).circle(minr1).clean().reset()

        if o < 0:  # the circles have moved apart: big one above small one
            scy = bcy
            if 2 * minr1 < 2 * ffo + block_width:  # the bottom fillets haven't merged
                # make the left inner circle hull
                swp.push(icpts1).circle(
                    minr1, mode="c",
                    tag="h").reset().edges(tag="h").hull().clean().reset()
                # make the right inner circle hull
                swp.push(icpts2).circle(
                    minr1, mode="c",
                    tag="i").reset().edges(tag="i").hull().clean().reset()

        swp.polygon([(-bcx, bcy), (bcx, bcy), (scx, scy), (scx, 0), (-scx, 0),
                     (-scx, scy), (-bcx, bcy)]).clean().reset()

        swp.push(bcpts).circle(
            minr2, mode="s").clean().reset()  # cut away the large circles

        swp.push([(0, bcy)]).rect(
            2 * bcx, minr2 * 2,
            mode="s").clean().reset()  # cut away the space between the circles

    through_face = swp.finalize().extrude(-1).faces(
        ">>Z").val()  # get just the face for the through cut

    swp = swp.wires().offset(min_wall + gland_width /
                             2).clean().reset()  # inner edge of ogland
    o_face = swp.finalize().extrude(-1).faces(
        ">>Z").val()  # get just the face for the oring path wire

    # passthrough face
    pfw = min_wall + gland_width + min_wall + ffo + board_width + ffo + min_wall + gland_width + min_wall  # passthrough face width
    pfha = min_wall + gland_width + min_wall + screw_nominal_d + (
        screw_head_nominal_d / 2 - screw_nominal_d /
        2) + min_wall  # passthrough face height above cutout top edge
    pfhb1 = co_tw + min_wall + gland_width + min_wall + screw_nominal_d + (
        screw_head_nominal_d / 2 - screw_nominal_d /
        2) + min_wall  # passthrough face height below cutout top edge
    pfhb2 = ffo + pcbt + block_height_nominal + ffo + min_wall + gland_width + min_wall  # passthrough face height below cutout top edge if limited by support block clearance
    if pfhb2 > pfhb1:  # if the part below the support blocks would be lower, use that to determine the face height
        pfhb = pfhb2
    else:
        pfhb = pfhb1
    pfha_pcb = pfha + pcbt / 2 + ffo  # passthrough face height above PCB middle
    pfh = pfha + pfhb  # passthrough face height
    pfx = 0
    pfy = -pfh / 2 + pfha_pcb
    pf_ctr = (pfx, pfy)  # passthrough face center
    pfdim = (pfw, pfh)  # passthrough face dims
    pf_fillets = 5  # fillets to corners of passthrough face
    pfwp = CQ().sketch()  # make passthrough face sketch workplane
    pfwp = pfwp.push([pf_ctr]).rect(*pfdim).reset()
    pfwp = pfwp.vertices().fillet(pf_fillets).clean().reset()
    # swp = swp.wires().offset(gland_width / 2 + min_wall).clean().reset()  # edge of passthrough part
    # + screw_nominal_d + (screw_head_nominal_d / 2 - screw_nominal_d / 2) + min_wall
    passthrough_face = pfwp.finalize().extrude(-1).faces(
        ">>Z").val()  # get just the face for the passthrough part

    pfwp = pfwp.wires().offset(min_gap).clean().reset()  # edge of recess_cut
    recess_face = pfwp.finalize().extrude(-1).faces(
        ">>Z").val()  # get just the face for the recess

    # fastening screw hole points
    fhps = []
    fhps.append(((board_width - 2 * block_width / 2) / 2,
                 pcbt / 2 + ffo + min_wall + gland_width + min_wall +
                 fix_scr.clearance_hole_diameters["Close"] / 2))
    fhps.append((-(board_width - 2 * block_width / 2) / 2,
                 pcbt / 2 + ffo + min_wall + gland_width + min_wall +
                 fix_scr.clearance_hole_diameters["Close"] / 2))
    fhps.append((bcx, pcbt / 2 + ffo - co_tw - min_wall - gland_width -
                 min_wall - fix_scr.clearance_hole_diameters["Close"] / 2))
    fhps.append((-bcx, pcbt / 2 + ffo - co_tw - min_wall - gland_width -
                 min_wall - fix_scr.clearance_hole_diameters["Close"] / 2))

    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 _make_pt(what):
        """build a passthrough component"""
        # 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

        hardware = cadquery.Assembly()
        passthrough = CQ().add(passthrough_face)
        passthrough = passthrough.wires().toPending().extrude(
            -part_thickness)  # extrude the bulk
        slotd = pcbt + 2 * min_gap
        passthrough = passthrough.workplane(
            centerOption="ProjectedOrigin").slot2D(
                length=board_width + slotd / 2, diameter=slotd,
                angle=0).cutThruAll()  # cut the pcb slot
        # TODO: retool some geometry because this cutout could possibly interfere with the oring gland for thick PCBs

        # cut the oring groove
        cq.Workplane.mk_groove = groovy.mk_groove
        oring_path = o_face.outerWire().translate((0, 0, -part_thickness))
        passthrough = passthrough.faces("<<Z").workplane(
            **u.copo).add(oring_path).toPending().mk_groove(ring_cs=oring_cs,
                                                            hardware=hardware)

        # cut the fastening screw holes
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo,
            origin=(0, 0,
                    0)).pushPoints(fhps).clearanceHole(fix_scr,
                                                       fit="Close",
                                                       baseAssembly=hardware)

        # add the support towers
        in_post_length = wall_depth + board_inner_depth
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo, origin=(0, 0, 0)).sketch().push(sbpts).rect(
                *support_block).finalize().extrude(-in_post_length)
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo, origin=(0, 0, 0)).sketch().push(sbpts).rect(
                *support_block).finalize().extrude(board_outer_depth)
        # mount holes
        pcb_center_z = ((board_outer_depth) -
                        (wall_depth + board_inner_depth)) / 2
        passthrough = passthrough.faces("+Y").faces(">>Z").workplane(
            **u.copo, origin=(0, 0, pcb_center_z)).rarray(
                board_width - 2 * pt_pcb_mount_hole_offset[1],
                board_inner_depth + board_outer_depth + wall_depth -
                2 * pt_pcb_mount_hole_offset[0], 2,
                2).clearanceHole(pcb_scr, fit="Close", counterSunk=False)
        passthrough = passthrough.edges("<<Z or >>Z").edges("|Y").fillet(
            pcb_corner)
        passthrough = passthrough.edges(
            "<<Z[-1] or <<Z[-2] or <<Z[-3] or >>Z[-1] or >>Z[-2] or >>Z[-3]"
        ).chamfer(0.5)

        if hw_asy is not None:
            hw_asy.add(hardware, loc=base * loc)

        return passthrough.findSolid().moved(base * loc)

    def _make_neg(what):
        """makes a negative shape to be cut out of the parent walls"""
        # 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

        # fastener threaded holes
        # TODO: mark these holes as "M3-0.5 threaded" in the engineering drawing
        fhs = CQ().pushPoints(fhps).circle(fix_scr.tap_hole_diameters["Soft"] /
                                           2).extrude(-wall_depth +
                                                      pt_fix_wall_buffer)

        nwp = CQ().add(through_face)
        through = nwp.wires().toPending().extrude(-wall_depth)

        nwp2 = CQ().add(recess_face)
        recess = nwp2.wires().toPending().extrude(-part_thickness)

        neg = recess.union(through).union(fhs)

        return neg.findSolid().moved(base * loc)

    rslt = self.each(_make_neg,
                     useLocalCoordinates=False,
                     combine="cut",
                     clean=True)

    # pass out the passthrough geometry
    if pt_asy is not None:
        passthroughs = self.each(_make_pt,
                                 useLocalCoordinates=False,
                                 combine=False).vals()
        for i, passthrough in enumerate(passthroughs):
            pt_asy.add(passthrough.Solids()[0], name=f"passthrough {i}")

    # pass out the pcb geometry
    if pcb_asy is not None:
        # pcbs = self.eachpoint(lambda loc: _make_pcb().moved(loc), useLocalCoordinates=True, combine=False).vals()
        pcbs = self.each(_make_pcb, useLocalCoordinates=False,
                         combine=False).vals()
        for i, pcb in enumerate(pcbs):
            pcb_asy.add(pcb.Solids()[0], name=f"pcb {i}")

    return rslt
Esempio n. 21
0
    def _makeNegative(center):
        """
        Generates the pocket shape we'll be cutting out
        """

        # the connector pocket's dimensions
        pocket_w = connector_width + con_clearance * 2
        pocket_l = con_len + con_clearance * 2
        pocket_d = connector_height + con_clearance

        # find the source thing's thickness at the cut point
        swiss = CQ(self.plane).add(self.findSolid())
        cheese = CQ(self.plane).add(self.findSolid()).pushPoints(
            [center]).circle(0.5).cutThruAll()
        core = swiss.cut(cheese)
        this_thikness = u.find_length(core, along="normal", bb_method=False)

        min_thickness = pocket_d + min_gp_connector_pocket_spacing + gp_depth

        # check that it's thick enough here
        if this_thikness < min_thickness:
            raise (ValueError(
                f"The part is too thin (thickness = {this_thikness}) at {center} to cut the PCB pocket"
            ))

        # make a box to subtract from
        start_box = CQ("XY").box(100,
                                 100,
                                 this_thikness,
                                 centered=(True, True, False))

        # make a simple pocket that we'll use for the chamfer operation
        result = start_box.faces("<Z").rect(pocket_w,
                                            pocket_l).cutBlind(pocket_d)

        # chamfer the connector edge
        result = result.faces("<Z").edges("not(<X or >X or <Y or >Y)").chamfer(
            chamfer_length)

        # now make the undercut pocket
        CQ.undercutRelief2D = u.undercutRelief2D
        result = result.faces("<Z").workplane().undercutRelief2D(
            pocket_l, pocket_w, diameter=r * 2, angle=90,
            kind=kind).cutBlind(pocket_d)

        # cut out the glue pocket
        slot_width = c.pcb_thickness + 2 * gp_buffer
        slot_len = pcb_len + slot_width
        result = result.faces(">Z").workplane().slot2D(
            slot_len, slot_width, angle=90).cutBlind(-gp_depth)

        # cut out the pcb passthrough slot
        slot_width = c.pcb_thickness + 2 * pcb_clearance
        slot_len = pcb_len + slot_width
        result = result.faces(">Z").workplane().slot2D(slot_len,
                                                       slot_width,
                                                       angle=90).cutThruAll()

        # invert the geometry and rotate the negative
        negative = start_box.cut(result)
        negative = negative.rotate((0, 0, 0), (0, 0, 1), angle)
        to_cut = negative.findSolid().locate(center)
        to_cut = to_cut.mirror("XY")
        return to_cut
Esempio n. 22
0
    def _make_pt(what):
        """build a passthrough component"""
        # 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

        hardware = cadquery.Assembly()
        passthrough = CQ().add(passthrough_face)
        passthrough = passthrough.wires().toPending().extrude(
            -part_thickness)  # extrude the bulk
        slotd = pcbt + 2 * min_gap
        passthrough = passthrough.workplane(
            centerOption="ProjectedOrigin").slot2D(
                length=board_width + slotd / 2, diameter=slotd,
                angle=0).cutThruAll()  # cut the pcb slot
        # TODO: retool some geometry because this cutout could possibly interfere with the oring gland for thick PCBs

        # cut the oring groove
        cq.Workplane.mk_groove = groovy.mk_groove
        oring_path = o_face.outerWire().translate((0, 0, -part_thickness))
        passthrough = passthrough.faces("<<Z").workplane(
            **u.copo).add(oring_path).toPending().mk_groove(ring_cs=oring_cs,
                                                            hardware=hardware)

        # cut the fastening screw holes
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo,
            origin=(0, 0,
                    0)).pushPoints(fhps).clearanceHole(fix_scr,
                                                       fit="Close",
                                                       baseAssembly=hardware)

        # add the support towers
        in_post_length = wall_depth + board_inner_depth
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo, origin=(0, 0, 0)).sketch().push(sbpts).rect(
                *support_block).finalize().extrude(-in_post_length)
        passthrough = passthrough.faces(">Z").workplane(
            **u.copo, origin=(0, 0, 0)).sketch().push(sbpts).rect(
                *support_block).finalize().extrude(board_outer_depth)
        # mount holes
        pcb_center_z = ((board_outer_depth) -
                        (wall_depth + board_inner_depth)) / 2
        passthrough = passthrough.faces("+Y").faces(">>Z").workplane(
            **u.copo, origin=(0, 0, pcb_center_z)).rarray(
                board_width - 2 * pt_pcb_mount_hole_offset[1],
                board_inner_depth + board_outer_depth + wall_depth -
                2 * pt_pcb_mount_hole_offset[0], 2,
                2).clearanceHole(pcb_scr, fit="Close", counterSunk=False)
        passthrough = passthrough.edges("<<Z or >>Z").edges("|Y").fillet(
            pcb_corner)
        passthrough = passthrough.edges(
            "<<Z[-1] or <<Z[-2] or <<Z[-3] or >>Z[-1] or >>Z[-2] or >>Z[-3]"
        ).chamfer(0.5)

        if hw_asy is not None:
            hw_asy.add(hardware, loc=base * loc)

        return passthrough.findSolid().moved(base * loc)
Esempio n. 23
0
    def make_thing(self, nx=5, ny=5):
        s = self
        co = "CenterOfBoundBox"
        fudge = 1

        unit_x = s.x_nom + s.xy_extra + s.x_spacing
        unit_y = s.y_nom + s.xy_extra + s.y_spacing

        x_len = nx * unit_x
        y_len = ny * unit_y
        z_len = s.shelf_height + s.wall_height

        one_void = CQ().box(s.x_nom + s.xy_extra,
                            s.y_nom + s.xy_extra,
                            s.shelf_height,
                            centered=(True, True, False)).edges("|Z").fillet(
                                s.cut_tool_diameter / 2)
        tweezer_void = CQ().box(unit_x + fudge,
                                s.tweezer_allowance_width,
                                s.wall_height + s.tweezer_allowance_depth,
                                centered=(True, True, False))

        CQ.undercutRelief2D = tbutil.undercutRelief2D
        h00 = CQ().box(x_len, y_len, z_len,
                       centered=(True, True, False))  # limits box
        #h01 = h00.faces('>Z').workplane().rarray(x_len/nx, y_len/ny, nx, ny, center=True).rect(unit_x+fudge, s.tweezer_allowance_width).cutBlind(-s.wall_height-s.tweezer_allowance_depth)  # x tweezer cuts
        #h02 = h01.faces('>Z').workplane().rarray(x_len/nx, y_len/ny, nx, ny, center=True).rect(s.tweezer_allowance_width, unit_y+fudge).cutBlind(-s.wall_height-s.tweezer_allowance_depth)  # y tweezer cuts
        h01 = h00.faces('>Z').workplane().rarray(
            x_len / nx, y_len / ny, nx, ny, center=True).undercutRelief2D(
                s.y_nom + s.xy_extra,
                s.y_nom + s.xy_extra,
                diameter=s.cut_tool_diameter).cutBlind(
                    -s.wall_height)  # substrate pockets

        all_voids = h00.faces('<Z').workplane(invert=True).rarray(
            x_len / nx, y_len / ny, nx, ny, center=True).eachpoint(
                lambda l: one_void.val().located(l))  # voids under
        h02 = h01.cut(all_voids)

        tweezer_voids = h00.faces('>Z').workplane(invert=True).rarray(
            x_len / nx, y_len / ny, nx, ny, center=True).eachpoint(
                lambda l: tweezer_void.val().located(l))  # tweezer voids
        h03 = h02.cut(tweezer_voids)

        tweezer_voids2 = h00.faces('>Z').workplane(invert=True).rarray(
            x_len / nx, y_len / ny, nx, ny,
            center=True).eachpoint(lambda l: tweezer_void.rotate(
                (0, 0, 0), (0, 0, 1), 90).val().located(l))  # tweezer voids
        h04 = h03.cut(tweezer_voids2)

        return h04
Esempio n. 24
0
 def get_ventscrews_b(self):
     ventscrew = self.vent_screw.translate((0, 0, 3.3))
     ventscrews = CQ().pushPoints(self.screw_spots).eachpoint(
         lambda loc: ventscrew.val().moved(loc), True)
     return ventscrews
Esempio n. 25
0
    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
Esempio n. 26
0
 def make_silicone(self):
     silicone = CQ().add(self.silicone).toPending().extrude(self.silicone_t)
     silicone = silicone.translate(
         (0, 0,
          -self.pcb_thickness / 2 - self.pcb_spacer_h + self.cu_tower_h))
     return silicone
Esempio n. 27
0
    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
Esempio n. 28
0
    def outputter(cls,
                  asys,
                  wrk_dir,
                  save_dxfs=False,
                  save_stls=False,
                  save_steps=False,
                  save_breps=False,
                  save_vrmls=False):
        """do output tasks on a dictionary of assemblies"""
        for stack_name, asy in asys.items():
            if "show_object" in globals():  # we're in cq-editor
                assembly_mode = True  # at the moment, when true we can't select/deselect subassembly parts
                if assembly_mode:
                    show_object(asy)
                else:
                    for key, val in asy.traverse():
                        shapes = val.shapes
                        if shapes != []:
                            c = cq.Compound.makeCompound(shapes)
                            odict = {}
                            if val.color is not None:
                                co = val.color.wrapped.GetRGB()
                                rgb = (co.Red(), co.Green(), co.Blue())
                                odict["color"] = rgb
                            show_object(c.locate(val.loc),
                                        name=val.name,
                                        options=odict)
            else:
                Path.mkdir(wrk_dir / "output", exist_ok=True)

                # save assembly
                asy.save(str(wrk_dir / "output" / f"{stack_name}.step"))
                # asy.save(str(wrk_dir / "output" / f"{stack_name}.brep"))
                asy.save(str(wrk_dir / "output" / f"{stack_name}.xml"), "XML")
                # asy.save(str(wrk_dir / "output" / f"{stack_name}.vtkjs"), "VTKJS")

                # stupid workaround for gltf export bug: https://github.com/CadQuery/cadquery/issues/993
                asy2 = None
                # for path, child in asy._flatten().items():
                for child in asy.children:
                    # if "/" in path:
                    if asy2 is None:
                        asy2 = cadquery.Assembly(child.obj,
                                                 name=child.name,
                                                 color=child.color)
                    else:
                        asy2.add(child.obj, name=child.name, color=child.color)
                asy2.save(str(wrk_dir / "output" / f"{stack_name}.glb"),
                          "GLTF")

                # cadquery.exporters.assembly.exportCAF(asy, str(wrk_dir / "output" / f"{stack_name}.std"))
                # cq.Shape.exportBrep(cq.Compound.makeCompound(itertools.chain.from_iterable([x[1].shapes for x in asy.traverse()])), str(wrk_dir / "output" / f"{stack_name}.brep"))

                # save each shape individually
                for key, val in asy.traverse():
                    shapes = val.shapes
                    if shapes != []:
                        c = cq.Compound.makeCompound(shapes)
                        if save_stls == True:
                            cadquery.exporters.export(
                                c.locate(val.loc),
                                str(wrk_dir / "output" /
                                    f"{stack_name}-{val.name}.stl"),
                                cadquery.exporters.ExportTypes.STL)
                        if save_steps == True:
                            cadquery.exporters.export(
                                c.locate(val.loc),
                                str(wrk_dir / "output" /
                                    f"{stack_name}-{val.name}.step"),
                                cadquery.exporters.ExportTypes.STEP)
                        if save_breps == True:
                            cq.Shape.exportBrep(
                                c.locate(val.loc),
                                str(wrk_dir / "output" /
                                    f"{stack_name}-{val.name}.brep"))
                        if save_vrmls == True:
                            cadquery.exporters.export(
                                c.locate(val.loc),
                                str(wrk_dir / "output" /
                                    f"{stack_name}-{val.name}.wrl"),
                                cadquery.exporters.ExportTypes.VRML)
                        if save_dxfs == True:
                            cl = c.locate(val.loc)
                            bb = cl.BoundingBox()
                            zmid = (bb.zmin + bb.zmax) / 2
                            nwp = CQ("XY", origin=(0, 0, zmid)).add(cl)
                            dxface = nwp.section()
                            cadquery.exporters.export(
                                dxface,
                                str(wrk_dir / "output" /
                                    f"{stack_name}-{val.name}.dxf"),
                                cadquery.exporters.ExportTypes.DXF)