commit 85e695ff8d1b3f90c3ed6e114c98decc21d4dfaa Author: wes Date: Mon Apr 22 14:45:06 2024 -0400 initial commit diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/coaster.py b/coaster.py new file mode 100755 index 0000000..1fef543 --- /dev/null +++ b/coaster.py @@ -0,0 +1,59 @@ +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +import cadquery as cq + +coaster_radius = 75 +xmas_tree_offset = -35 +xmas_tree_height = 12 +xmas_tree_width = 12 + +def makeTriangle(self, width, height, x_offset=0, y_offset=0): + return (self.moveTo(x_offset-(width), y_offset).makePolygon( + [ + (0,0,0),(width,height,0), (width*2,0,0), + ] + ) + .cutBlind(30) + .clean()) + +def makeXmasTree(self): + return (self.center(0,0) + .triangle(xmas_tree_width, xmas_tree_height, y_offset=-(xmas_tree_offset)) + .triangle(xmas_tree_width+3, xmas_tree_height+3, y_offset=-(xmas_tree_offset+8)) + .triangle(xmas_tree_width+1, xmas_tree_height+13, y_offset=-(xmas_tree_offset+15)) + .triangle(xmas_tree_width-2, xmas_tree_height+16, y_offset=-(xmas_tree_offset+20)) + .moveTo(0, -(xmas_tree_offset+22)) + .rect(5,8) + .cutBlind(30)) + +Workplane.triangle = makeTriangle +Workplane.xmasTree = makeXmasTree + + +polygon = (Workplane() + .makePolygon( + regularPolygon( + nSides = 16, + radius = coaster_radius, + thetaStart = 0, + thetaEnd = 360 + ) + ) + .extrude(10) + .xmasTree() + .workplane() + ) + +text_solid = (Workplane() + .text("David Kerfoot", + 25, 25, + clean=False, + combine=False, + fontPath="/home/wes/cad_files/StackyardPersonalUse-16Dj.ttf") + ) + + +result = polygon.cut(text_solid) + +cq.exporters.export(result, "/home/wes/cad_files/coaster.step") diff --git a/dice.py b/dice.py new file mode 100644 index 0000000..adbd68e --- /dev/null +++ b/dice.py @@ -0,0 +1,50 @@ +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import cadquery as cq +import functools as fnc +import itertools as it +from cad_utilities.shapes import makeDice +from typing import cast +from cadquery import Face +from cqmore import Workplane +from cqmore.polyhedron import tetrahedron, hexahedron, octahedron, dodecahedron, icosahedron + +radius = 20 +font_name = 'Arial Black' +font_distance = 2 +detail = 0 + +dice = (Workplane() + .polyhedron( + *icosahedron(radius, detail) + ) + ) + +faces = dice.faces().vals() +nums = len(faces) +texts = Workplane() +for i in range(nums): + print(i) + if i == 0: + text_to_write = "20" + font_size = 8.5 + else: + text_to_write = str(nums-i) + font_size = 8.5 + texts.add( + Workplane(faces[i]) + .workplane(origin = cast(Face, faces[i]).Center()) + .text( + text_to_write, + font_size, + -font_distance, + fontPath="/home/deck/cad_files/SEVESBRG.TTF" + ) + ) + +dice = dice.cut(texts) + +cq.exporters.export(dice, "/home/deck/cad_files/dice.step") + diff --git a/enclosure.py b/enclosure.py new file mode 100755 index 0000000..7e3c589 --- /dev/null +++ b/enclosure.py @@ -0,0 +1,159 @@ +import cadquery as cq + +socket_distance_x = 10.8 +socket_distance_y = 36.55 +socket_width = 28 + +# the width of the bezel on the side of the inner relay +side_bezel_width = 3.14 + +# how far the plug in the middle is from the side +# where the socket that powers the relay coil is +distance_from_socket_to_end = 46 + +relay_x_size = 120.2 +relay_y_size = 168 + +# dimensions of the socket for coil power on the side +end_socket_width = 30.4 +end_socket_height = 22.6 + +# the distance from the side of the socket to the edge of the box +# for the socket that powers the relay coil +end_socket_distance_from_side = 3.47 + 3 # add 3mm for tape + +reset_button_dist_from_socket = 5.27 +reset_width = 18.7 +reset_height = 35.04 +reset_lip_height = 3.37 # probably not needed + +# parameter definitions +p_outerWidth = relay_x_size + 15 # Outer width of box enclosure +p_outerLength = relay_y_size # Outer length of box enclosure +p_outerHeight = 33.6 + 30 # Outer height of box enclosure + +p_thickness = 3.0 # Thickness of the box walls +p_sideRadius = 10.0 # Radius for the curves around the sides of the box +p_topAndBottomRadius = ( + 2.0 # Radius for the curves on the top and bottom edges of the box +) + +p_screwpostInset = 12.0 # How far in from the edges the screw posts should be place. +p_screwpostID = 4.0 # Inner Diameter of the screw post holes, should be roughly screw diameter not including threads +p_screwpostOD = 10.0 # Outer Diameter of the screw posts.\nDetermines overall thickness of the posts + +p_boreDiameter = 8.0 # Diameter of the counterbore hole, if any +p_boreDepth = 1.0 # Depth of the counterbore hole, if +p_countersinkDiameter = 0.0 # Outer diameter of countersink. Should roughly match the outer diameter of the screw head +p_countersinkAngle = 90.0 # Countersink angle (complete angle between opposite sides, not from center to one side) +p_flipLid = True # Whether to place the lid with the top facing down or not. +p_lipHeight = 1.0 # Height of lip on the underside of the lid.\nSits inside the box body for a snug fit. + +# outer shell +oshell = ( + cq.Workplane("XY") + .rect(p_outerWidth, p_outerLength) + .extrude(p_outerHeight + p_lipHeight) +) + +# weird geometry happens if we make the fillets in the wrong order +if p_sideRadius > p_topAndBottomRadius: + oshell = oshell.edges("|Z").fillet(p_sideRadius) + oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius) +else: + oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius) + oshell = oshell.edges("|Z").fillet(p_sideRadius) + +# inner shell +ishell = ( + oshell.faces("Z") + .workplane(-p_thickness) + .rect(POSTWIDTH, POSTLENGTH, forConstruction=True) + .vertices() + .circle(p_screwpostOD / 2.0) + .circle(p_screwpostID / 2.0) + .extrude(-1.0 * (p_outerHeight + p_lipHeight - p_thickness), True) +) + +# split lid into top and bottom parts +(lid, bottom) = ( + box.faces(">Z") + .workplane(-p_thickness - p_lipHeight) + .split(keepTop=True, keepBottom=True) + .all() +) # splits into two solids + +lid = (lid.workplane() + .rect(socket_width+socket_distance_x, socket_distance_y+(socket_width), + forConstruction=True) + .tag("sockets") + .vertices() + .rect(socket_width, socket_width) + .cutThruAll()) + +bottom = (bottom + .faces(">Y") + .workplane() + .center(0, -end_socket_height+8) + .rect(end_socket_width, end_socket_height) + .cutBlind("next")) + + +#lid = (lid.center(socket_width-8, socket_distance_y+(socket_width)-3) +# .rect(reset_height, reset_width) +# .cutThruAll()) + +# translate the lid, and subtract the bottom from it to produce the lid inset +lowerLid = lid.translate((0, 0, -p_lipHeight)) +cutlip = lowerLid.cut(bottom).translate( + (p_outerWidth + p_thickness, 0, p_thickness - p_outerHeight + p_lipHeight) +) + +# compute centers for screw holes +topOfLidCenters = ( + cutlip.faces(">Z") + .workplane(centerOption="CenterOfMass") + .rect(POSTWIDTH, POSTLENGTH, forConstruction=True) + .vertices() +) + +# add holes of the desired type +if p_boreDiameter > 0 and p_boreDepth > 0: + print("first") + topOfLid = topOfLidCenters.cboreHole( + p_screwpostID, p_boreDiameter, p_boreDepth, 2.0 * p_thickness + ) +elif p_countersinkDiameter > 0 and p_countersinkAngle > 0: + print("second") + topOfLid = topOfLidCenters.cskHole( + p_screwpostID, p_countersinkDiameter, p_countersinkAngle, 2.0 * p_thickness + ) +else: + print("third") + topOfLid = topOfLidCenters.hole(p_screwpostID, 2.0 * p_thickness) + +# flip lid upside down if desired +if p_flipLid: + topOfLid = topOfLid.rotateAboutCenter((1, 0, 0), 180) + +# return the combined result +result = topOfLid.union(bottom) + +cq.exporters.export(result, "/home/wes/cad_files/enclosure.step") \ No newline at end of file diff --git a/light_holder.py b/light_holder.py new file mode 100644 index 0000000..082859b --- /dev/null +++ b/light_holder.py @@ -0,0 +1,53 @@ +import cadquery as cq +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import functools as fnc +import itertools as it + + +inner_len = 100 +inner_width = 68.8 +inner_height = 49.7 + +outer_len = 131.9 +outer_thickness = 5.26 +outer_width = inner_width + +hole_diameter = 6 + +hole_dist_from_long = 10.2 +hole_dist_from_short = 5.37 + +recess_height = 61.9 +recess_width = 11.9 + +clip_thickness = 15 +clip_length = 65 +clip_width = 60 + +clip_distance_from_sensor = 90 # how far it is from the enclosure + +result = (Workplane(). + box(outer_len, outer_width, outer_thickness) + .edges("|Z").fillet(0.9)) + + +result = result.moveTo(outer_width-recess_width, 0).rect(recess_width, recess_height).extrude(5) +result = result.moveTo(-outer_width+recess_width, 0).rect(recess_width, recess_height).extrude(5) +result = result.workplane(offset=-(outer_thickness/2)-0.33).moveTo(-outer_len/2, 0).rect(clip_length/2, clip_width).extrude(outer_thickness) +result = result.workplane(offset=-0.33).moveTo(inner_height+(clip_length/2.0)-1, 0).box(clip_width/1.8, clip_width/2.5, outer_thickness).moveTo(outer_len/2+26, 0).cylinder(10, 5/2, combine="cut") +result = result.moveTo(outer_len/2.4+30, 0).cylinder(10, 12/2, combine="cut") +result = result.faces(">Z[0]").moveTo(-70, 0).rect(10, clip_width).extrude(clip_length) + +result = (result.faces(">Z[1]").moveTo(0,0) + .rect(outer_len-hole_dist_from_short-hole_diameter*2, + outer_width-hole_dist_from_long-hole_diameter*3, + forConstruction=True) + .vertices().cylinder(outer_thickness*3, hole_diameter/2, combine="cut")) + + + + +cq.exporters.export(result, "/home/deck/cad_files/light_holder.step") diff --git a/oil_cap.py b/oil_cap.py new file mode 100644 index 0000000..1d60778 --- /dev/null +++ b/oil_cap.py @@ -0,0 +1,15 @@ +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import cadquery as cq +import functools as fnc +import itertools as it +from cad_utilities.shapes import makeTriangle + + +cone = cq.Solid.makeCone(8/2, 1, 28) + +result = Workplane().circle(8.3/2).extrude(30).cut(cone) + +cq.exporters.export(result, "/home/deck/cad_files/oil_cap.step") \ No newline at end of file diff --git a/picture_frame.py b/picture_frame.py new file mode 100644 index 0000000..ca640d3 --- /dev/null +++ b/picture_frame.py @@ -0,0 +1,53 @@ +import cadquery as cq +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import functools as fnc +import itertools as it + +picture_height = 178.3 +length = picture_height+5 +picture_length = 4.2 +width = picture_length + 10 +picture_width = 127 +height = picture_width + 10 + +triangle_size = 25 +triangle_width = width+15 + + +def makeTriangle(self, width, height, x_offset=0, y_offset=0): + return (self.moveTo(x_offset-(width), y_offset).makePolygon( + [ + (width, height, 0), (width*2, 0, 0), (width*2, width*2, 0), + ] + )) + +def add_triangle(plane, width, height, offset): + return plane.triangle(width, height, y_offset=offset) + +Workplane.triangle = makeTriangle + +result = Workplane("front").box(length, width, height) + +result = result.workplane().box(length-20, width, height-15, True, "cut") + +result = result.workplane().box(length-2, picture_length, picture_width+2, True, "cut") + +result = result.faces("X[3]").workplane().moveTo(-25,-5).sphere(socket_radius, combine="cut") +result = result.faces(">X[1]").box(12.5,5.5,7.5, combine="cut") + +result = result.faces(">X[0]").center(15, -10).text("Danger!", 8.5, -1.6, fontPath="/home/wes/cad_files/StackyardPersonalUse-16Dj.ttf") + +cq.exporters.export(result, "/home/deck/cad_files/solder_stand.step") diff --git a/tape_holder.py b/tape_holder.py new file mode 100644 index 0000000..0713f49 --- /dev/null +++ b/tape_holder.py @@ -0,0 +1,57 @@ +import cadquery as cq +from cq_warehouse.fastener import SocketHeadCapScrew +from cq_warehouse.bearing import SingleRowDeepGrooveBallBearing +import cq_warehouse.extensions +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import functools as fnc +import itertools as it + + +def makeTriangle(self, width, height, x_offset=0, y_offset=0): + return (self.move(x_offset, y_offset).makePolygon( + [ + (height/2, width*20, -width), (0, width, 0), (width, height, 0) + ] + )) + +def add_triangle(plane, width, height, offset): + return plane.triangle(width, height, y_offset=offset) + +Workplane.triangle = makeTriangle + +# must be 17 mm wide +# gap must be at least 4 mm + +holder_dim = (18, 30, 30) +holder_slot_dim = (holder_dim[0] + holder_dim[0]*0.65, + holder_dim[1]-holder_dim[1]*0.2, + holder_dim[1]-holder_dim[1]*0.865) # should be around 4mm + +pole_dim = (18, 10) +lip_dim = (pole_dim[0], 15) +pole_length = 230 + +print(holder_slot_dim) + +result = Workplane().box(*holder_dim) +result = result.workplane().moveTo(0, -5).box(*holder_slot_dim, True, "cut") +result = (result.faces(">Z").workplane() + .moveTo(0, (holder_dim[0]) - 8) + .rect(*pole_dim).extrude(pole_length)) + +support_width = 10 + +result = result.faces(">Y[1]").workplane().triangle(support_width, + support_width, + -support_width/2, + -holder_dim[0]).extrude(15) + +result = (result.faces(">Z[3]").center(0, pole_length-lip_dim[0]/4).workplane() + .moveTo(0, lip_dim[1]) + .rect(*lip_dim).extrude(pole_dim[0]/4)) + +cq.exporters.export(result, "/home/deck/cad_files/tape_holder.step") + diff --git a/threaded_tool_holder.py b/threaded_tool_holder.py new file mode 100644 index 0000000..8c2e874 --- /dev/null +++ b/threaded_tool_holder.py @@ -0,0 +1,29 @@ +import cadquery as cq +from cq_warehouse.fastener import SocketHeadCapScrew +from cq_warehouse.bearing import SingleRowDeepGrooveBallBearing +from cq_warehouse.thread import * +from cq_warehouse.fastener import * +from cq_warehouse.extensions import Workplane +from random import randint, choice +import functools as fnc +import itertools as it + +# must be 17 mm wide +# gap must be at least 4 mm + +pole_length = 50*MM + +plate = ( + cq.Workplane() + .circle(8) + .extrude(pole_length) +) + +simple = False +screw = HexHeadScrew("M8-1.25", length=pole_length/2, fastener_type="din931", simple=simple) +threaded_hole = plate.faces(">Z[1]").threadedHole(screw, pole_length/2, simple=simple, fit="Loose") +show_object(threaded_hole) + +cq.exporters.export(threaded_hole, "/home/deck/cad_files/threaded_tool_holder.step") +cq.exporters.export(screw, "/home/deck/cad_files/threaded_tool_holder_screw.step") + diff --git a/tool_holder.py b/tool_holder.py new file mode 100644 index 0000000..e5fa994 --- /dev/null +++ b/tool_holder.py @@ -0,0 +1,38 @@ +import cadquery as cq +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import functools as fnc +import itertools as it + + +top_rect_len = 6.28 +bottom_rect_len = 21.5 +sides_width = 4 +base_thickness = 7 + +height = 2.5 + + +result = (cq.Workplane().moveTo(-top_rect_len+2, 0) + .box(sides_width, bottom_rect_len, height) + .edges("|Z").fillet(1.25)) + + +result = (result.faces(">Z[0]").circle(1.5) + .workplane() + .circle(sides_width-1) + .loft() + .clean()) + +result = result.faces(">Z[0]").box(bottom_rect_len*6, bottom_rect_len*2, base_thickness) +result = (result + .faces(">Z").workplane() + .rect(bottom_rect_len*5, bottom_rect_len*1, forConstruction=True) + .vertices() + .cboreHole(4,8,7, depth=None)) + + + +cq.exporters.export(result, "/home/deck/cad_files/power_bar_holder.step") diff --git a/tool_holder_final.py b/tool_holder_final.py new file mode 100644 index 0000000..2317c4b --- /dev/null +++ b/tool_holder_final.py @@ -0,0 +1,55 @@ +import cadquery as cq +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import functools as fnc +import itertools as it + +wall_width = 12 +length = 90 +width = 150 +height = 100 +magnet_height = 27 +magnet_width = 27 +magnet_thickness = 5 +bottom_thickness = 12 + +first_magnet_position = 35 +second_magnet_position = -35 + +magnet_slot_offset = 10 +second_slot_offset = -25 + +result = Workplane("front").box(length, width, height) +result = result.workplane().center(0, -bottom_thickness).workplane().box(length-wall_width, + width-wall_width, + height-wall_width, + True, + "cut") + +result = (result.faces(">Z").workplane(0, True) + .moveTo(0, first_magnet_position).rect(magnet_width, + magnet_height).cutBlind(magnet_thickness)) + +result = (result.faces(">Z").workplane(0, True) + .moveTo(0, magnet_slot_offset).rect(magnet_width, + magnet_height).cutBlind(magnet_thickness) + .faces(">Z") + .moveTo(0, magnet_slot_offset) + .rect(magnet_width, magnet_height).extrude(2)) + +result = (result.faces(">Z").workplane(0, True) + .moveTo(0, second_magnet_position).rect(magnet_width, + magnet_height).cutBlind(magnet_thickness)) + +result = (result.faces(">Z").workplane(0, True) + .moveTo(0, second_magnet_position+second_slot_offset).rect(magnet_width, + magnet_height).cutBlind(magnet_thickness) + .faces(">Z") + .moveTo(0, second_magnet_position+second_slot_offset) + .rect(magnet_width, magnet_height).extrude(2)) + + + +cq.exporters.export(result, "/home/deck/cad_files/tool_holder.step") diff --git a/utilities.py b/utilities.py new file mode 100644 index 0000000..fed104b --- /dev/null +++ b/utilities.py @@ -0,0 +1,16 @@ +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import cadquery as cq +import functools as fnc +import itertools as it + +def makeTriangle(self, width, height, x_offset=0, y_offset=0): + return (self.moveTo(x_offset-(width), y_offset).makePolygon( + [ + (0,0,0),(width,height,0), (width*2,0,0), + ] + ) + .cutBlind(30) + .clean()) diff --git a/xmas_coaster.py b/xmas_coaster.py new file mode 100755 index 0000000..01e0964 --- /dev/null +++ b/xmas_coaster.py @@ -0,0 +1,93 @@ +from cqmore import Workplane +from cqmore.curve import archimedeanSpiral, circle +from cqmore.polygon import regularPolygon, star +from random import randint, choice +import cadquery as cq +import functools as fnc +import itertools as it +from cad_utilities.shapes import makeTriangle + +coaster_radius = 50 + +def add_triangle(plane, width, height, offset): + return plane.triangle(width, height, y_offset=offset) + +def addXmas(self, offsets): + xmas_tree_offset = -25 + xmas_tree_height = 8 + xmas_tree_width = 6 + w_off, h_off, y_off = offsets + return self.triangle(xmas_tree_width+(choice([-1,1])*w_off), + xmas_tree_height+(choice([-1,1])*h_off), + y_offset=-(xmas_tree_offset+(y_off))) + + +def makeXmasTree(self): + xmas_tree_offset = -25 + xmas_tree_height = 8 + xmas_tree_width = 6 + + offsets = [(0,0,0)] + [tuple(randint(1, 5) for _ in range(4)) for _ in range(3)] + print(offsets) + + offsets_added = list(it.accumulate(offsets, lambda t1, t2: list(a+b for a,b in zip(t1, t2)))) + + last_y = offsets_added[-1][2] + + #offsets = [(0,0,0), (3,2,6), (4,11,13), (4,13,16)] + + tree = fnc.reduce(addXmas, offsets_added, self.center(0,0)) + + return (tree + .moveTo(0, -(xmas_tree_offset+last_y)) + .rect(2,5) + .cutThruAll()) + +Workplane.triangle = makeTriangle +Workplane.xmasTree = makeXmasTree + + +polygon = (Workplane() + .makePolygon( + regularPolygon( + nSides = 16, + radius = coaster_radius, + thetaStart = 0, + thetaEnd = 360 + ) + ) + .extrude(7, clean=True, combine=True, taper=15) + .xmasTree() + ) + +result = (polygon.workplane() + .text("Wes", + 10, 40, + clean=True, + combine="cut", + fontPath="/home/wes/TiltNeon-Regular-VariableFont_XROT,YROT.ttf") + ) + + +result = (result.faces("Z").workplane() + .makePolygon( + regularPolygon( + nSides = 10, + radius = coaster_radius-5, + thetaStart = 0, + thetaEnd = 360 + ), + forConstruction=True + ) + .vertices() + .circle(2) + .extrude(5)) + +cq.exporters.export(result, "/home/deck/cad_files/coaster.step") +