Created
February 10, 2024 22:01
-
-
Save dov/f840e12f24804501540dac1794331cb9 to your computer and use it in GitHub Desktop.
A shampoo holder created with CadQuery
This file contains 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
#!/usr/bin/env python | |
###################################################################### | |
# A cup holder | |
# 2024-02-10 Sat | |
# Dov Grobgeld <dov.grobgeld@gmail.com> | |
# | |
# This code is in the public domain. | |
# | |
# The shower pole shampoo holder is built as follows | |
# | |
# - The cyl part for attachements to the shower 25 mm diam pole) | |
# - The cup part (for holding the soap) | |
# | |
# The cup is built as follows: | |
# - Make a general cup by extruction and cut | |
# - Remove a hole at the bottom of the cup for inserting the bottom | |
# part | |
# - The bottom part is a cylinder with a hexagonal grid of holes | |
# - The bottom part is unioned into the cup | |
# | |
###################################################################### | |
import cadquery as cq | |
from cadquery import exporters | |
import math | |
def make_cup(inner_radius, | |
inner_height, | |
thickness, | |
bottom_fillet_radius, | |
rim_fillet_radius, | |
): | |
outer_radius = inner_radius + thickness | |
outer_height = inner_height +thickness | |
return (cq | |
.Workplane("XY") | |
.circle(outer_radius) | |
.extrude(outer_height) | |
.faces(">Z") | |
.workplane() | |
.circle(inner_radius) | |
# To do a pocket need cut | |
.extrude(until=-inner_height, | |
combine='cut') | |
.faces("<Z[-1] or <Z[-2]").fillet(bottom_fillet_radius) # Smooth inner and outer cup bottom | |
.faces(">Z").fillet(rim_fillet_radius) # Smooth the rim | |
) | |
def make_hollow_cylinder(inner_radius, | |
height, | |
thickness, | |
rim_fillet_radius): | |
outer_radius = inner_radius + thickness | |
return (cq | |
.Workplane("XY") | |
.circle(outer_radius) | |
.circle(inner_radius) | |
.extrude(until=height) | |
.faces(">Z or <Z").fillet(rim_fillet_radius) # Smooth the rims | |
) | |
# Generate all the points lying on a hexagonal (honycomb) grid | |
# inside a circle. | |
def make_hex_points_in_circle(big_circle_radius, | |
hex_grid_step): | |
dy = hex_grid_step * math.sin(math.radians(60)) | |
num_rows = math.floor(big_circle_radius / dy) | |
num_x = math.floor(big_circle_radius/ hex_grid_step) | |
for y_idx in range(num_rows*2+1): | |
centered_y = y_idx-num_rows | |
y = centered_y * dy | |
for x_idx in range(num_x*2+2): | |
x_offset = 0 if centered_y%2==0 else -hex_grid_step/2 | |
x = x_offset + (x_idx-num_x) * hex_grid_step | |
if x**2 + y**2 < big_circle_radius**2: | |
yield (x,y) | |
# Parameters | |
thickness=3 | |
cup_inner_radius = 40 | |
cup_height = 35 | |
bottom_fillet_radius=2 | |
rim_fillet_radius = 1 | |
hole_radius = 3 | |
cyl_inner_radius = 12.6 | |
cyl_height = 25 | |
holes_grid_spacing = 13 | |
hole_fillet_radius = 0.5 | |
cup = make_cup(inner_radius = cup_inner_radius, | |
inner_height = cup_height-thickness, | |
thickness = thickness, | |
bottom_fillet_radius = bottom_fillet_radius, | |
rim_fillet_radius = rim_fillet_radius) | |
# remove a cylinder from the cup to make space for the bottom | |
bottom_radius = cup_inner_radius - bottom_fillet_radius*2 | |
bottom_mask = (cq.Workplane('XY') | |
.circle(bottom_radius) | |
.extrude(thickness)) | |
cup = cup - bottom_mask | |
# Create the bottom by a cylinder with holes | |
hole_points = make_hex_points_in_circle(cup_inner_radius-thickness-hole_radius*2, | |
holes_grid_spacing) | |
#print(f'{hole_points=}') | |
bottom = (cq.Workplane('XY') | |
.circle(bottom_radius+bottom_fillet_radius) # Make this bigger to fix fillet at edges | |
.pushPoints(hole_points) | |
.circle(hole_radius) | |
.extrude(thickness) | |
.edges('>Z or <Z').fillet(hole_fillet_radius) | |
).intersect(bottom_mask) | |
cup += bottom | |
# The pole connector cylinder | |
cyl = make_hollow_cylinder(inner_radius = cyl_inner_radius, | |
height = cyl_height, | |
thickness = thickness, | |
rim_fillet_radius = rim_fillet_radius) | |
result = cyl + cup.translate(cq.Vector(cup_inner_radius+cyl_inner_radius+thickness,0,0)) | |
exporters.export(result, 'shampoo-holder.stl') | |
print('ok') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment