Last active
December 21, 2025 15:00
-
-
Save yschimke/d096598118d8d3a784f732f51e5e97fd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import cadquery as cq | |
| from ocp_vscode import show_object | |
| box_length = 180.0 | |
| box_width = 120.0 | |
| box_height = 60.0 | |
| bottom_thickness = 5.0 | |
| side_wall_thickness = 10.0 # Double the bottom thickness | |
| fillet_size = 5.0 | |
| # Create the outer solid box, centered at the origin | |
| outer_box = cq.Workplane("XY").box(box_length, box_width, box_height) | |
| # Apply fillet to all vertical edges | |
| outer_box = outer_box.edges("|Z").fillet(fillet_size) | |
| # Dimensions for the inner box to be subtracted | |
| inner_length = box_length - (2 * side_wall_thickness) | |
| inner_width = box_width - (2 * side_wall_thickness) | |
| inner_height = box_height - bottom_thickness | |
| # The inner box needs to be shifted upwards so that it doesn't cut through the bottom. | |
| # The top of the inner box should align with the top of the outer box. | |
| z_shift = bottom_thickness / 2 | |
| # Create the inner box, shifted up | |
| inner_box = ( | |
| cq.Workplane("XY") | |
| .workplane(offset=z_shift) | |
| .box(inner_length, inner_width, inner_height) | |
| .edges("|Z") | |
| .fillet(fillet_size) | |
| .faces("<Z") | |
| .edges() | |
| .fillet(fillet_size) | |
| ) | |
| open_box = outer_box.cut(inner_box) | |
| # Add cutouts for the knock box bar | |
| bar_diameter = 25.0 | |
| bar_radius = bar_diameter / 2 | |
| # Position from the front edge of the box | |
| bar_offset_from_front = 60.0 | |
| cutter_x = (box_length / 2) - bar_offset_from_front | |
| # To have the top of the bar flush with the top of the box, | |
| # the center of the bar must be lowered by its radius from the top edge. | |
| cutter_z = (box_height / 2) - bar_radius | |
| # Create a cylinder for the round part of the cut, centered at the origin | |
| cutter_cyl = cq.Workplane("XZ").circle(bar_radius).extrude(box_width + 40, both=True) | |
| # Create a rectangular box to clear the material above the cylinder, | |
| # making it a U-shaped slot. | |
| clearance_box = cq.Workplane("XY").box(bar_diameter, box_width + 40, bar_radius) | |
| # Combine them into a single cutter shape. | |
| # The clearance box is positioned so its bottom is at the cylinder's centerline. | |
| cutter = cutter_cyl.union(clearance_box.translate((0, 0, bar_radius / 2))) | |
| # Translate the combined cutter to the final position | |
| cutter = cutter.translate((cutter_x, 0, cutter_z)) | |
| # Subtract the cutter from the box | |
| final_box = open_box.cut(cutter) | |
| # Add a swoop down on the front face for hand clearance | |
| swoop_width = 90.0 | |
| flat_width = 40.0 | |
| swoop_depth = 20.0 | |
| h = box_height / 2 | |
| final_box = ( | |
| final_box.faces(">X") | |
| .workplane() | |
| .moveTo(-swoop_width / 2, h) | |
| .spline( | |
| [ | |
| (-flat_width / 2, h - swoop_depth), | |
| (flat_width / 2, h - swoop_depth), | |
| (swoop_width / 2, h), | |
| ], | |
| tangents=[(1, 0), (1, 0), (1, 0), (1, 0)], | |
| includeCurrent=True, | |
| ) | |
| .lineTo(swoop_width / 2, h + 1) | |
| .lineTo(-swoop_width / 2, h + 1) | |
| .close() | |
| .cutBlind(-side_wall_thickness) | |
| ) | |
| # Fillet top edges (rim and swoop) but exclude the knock bar cutouts | |
| final_box = final_box.edges( | |
| cq.selectors.BoxSelector( | |
| ( | |
| cutter_x + bar_radius + 0.1, | |
| -box_width / 2 - 1, | |
| box_height / 2 - swoop_depth - 1, | |
| ), | |
| (box_length / 2 + 1, box_width / 2 + 1, box_height / 2 + 1), | |
| ) | |
| + cq.selectors.BoxSelector( | |
| (-box_length / 2 - 1, -box_width / 2 - 1, box_height / 2 - swoop_depth - 1), | |
| (cutter_x - bar_radius - 0.1, box_width / 2 + 1, box_height / 2 + 1), | |
| ) | |
| ).fillet(2.0) | |
| # Add embossed text "Baulsupp Design" on the back external face. | |
| final_box = ( | |
| final_box.faces("<X") | |
| .workplane(centerOption="CenterOfBoundBox") | |
| .text("Baülsupp Design", 12, -1.0, fontPath="AlbertSans.ttf") | |
| ) | |
| show_object(final_box) | |
| cq.exporters.export(final_box, "coffee_box.stl") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment