Advertisement
Guest User

ShowerPhoneHolder.py

a guest
May 7th, 2025
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.99 KB | Source Code | 0 0
  1. from dataclasses import dataclass
  2. from build123d import *
  3.  
  4. @dataclass(frozen = True)
  5. class PhoneHolderParams():
  6. phone_length: float # Or rather "how much length of the phone to hold"
  7. phone_width: float
  8. phone_thickness: float
  9. glass_thickness: float
  10. holder_lip: float = 3 *MM
  11. clip_length: float = 50 *MM
  12. clip_thickness: float = 4 *MM
  13. wall_thickness: float = 3 *MM
  14. phone_gap: float = 0.5 *MM # Space around phone
  15. glass_gap: float = 0.3 *MM # Space around glass
  16. bottom_fillet_radius = 12 *MM
  17. overall_chamfer: float = 1 *MM
  18. hole_chamfer: float = 0.6 *MM
  19.  
  20. def build_phone_holder(params: PhoneHolderParams):
  21. # Convenience variables to help keep track of the different distances
  22. outer_width = params.wall_thickness + params.phone_width + params.phone_gap + params.wall_thickness
  23. outer_holder_x = params.wall_thickness + params.phone_thickness + params.phone_gap + params.wall_thickness
  24. outer_holder_y = params.phone_length + params.wall_thickness
  25. outer_clip_x = outer_holder_x + params.glass_thickness + params.glass_gap + params.clip_thickness
  26. cutout_thickness = params.phone_thickness + params.phone_gap
  27.  
  28. with BuildPart() as holder_part:
  29. # Main holder piece with clip
  30. with BuildSketch():
  31. with BuildLine():
  32. Polyline([
  33. (0, 0),
  34. (outer_clip_x, 0), # Across to clip
  35. (outer_clip_x - params.glass_gap * 2, params.clip_length), # Up to top of clip. Slight tilt so the clip flexes slightly and grips the glass
  36. (outer_clip_x - params.glass_gap * 2 - params.clip_thickness, params.clip_length), # Across top of clip
  37. (outer_clip_x - params.clip_thickness, params.clip_thickness), # Down to glass gap
  38. (outer_holder_x, params.clip_thickness), # Across glass gap
  39. (outer_holder_x, outer_holder_y), # Up to top of holder
  40. (0, outer_holder_y), # Across top of holder
  41. ], close = True)
  42. make_face()
  43. extrude(amount = outer_width)
  44.  
  45. # Round the bottom to match the look of a curved phone
  46. fillet(holder_part.edges().filter_by(Plane.XZ).filter_by(Plane.XY).sort_by(Axis.Y)[-2:], radius = params.bottom_fillet_radius)
  47.  
  48. # Cutout where the phone slides in
  49. offset_top = Plane(holder_part.faces().sort_by(Axis.X)[0]).offset(-params.wall_thickness)
  50. with BuildSketch(offset_top):
  51. RectangleRounded(params.phone_length, params.phone_width + params.phone_gap, params.bottom_fillet_radius - params.wall_thickness)
  52. extrude(amount=-cutout_thickness, mode=Mode.SUBTRACT)
  53.  
  54. # Cut out the front so you can see the phone screen
  55. offset_side = Plane(holder_part.faces().sort_by(Axis.X)[0])
  56. offset_side = offset_side.shift_origin(offset_side.origin + (0, -params.holder_lip, 0))
  57. with BuildSketch(offset_side):
  58. RectangleRounded(params.phone_length - params.holder_lip, params.phone_width - (params.holder_lip * 2), params.bottom_fillet_radius - params.holder_lip)
  59. extrude(amount = -params.wall_thickness, mode = Mode.SUBTRACT)
  60.  
  61. # Cut out the sides so that you can access buttons and more easily slide the phone out
  62. offset_side = Plane(holder_part.faces().sort_by(Axis.Z)[0]).shift_origin((0, 0, 0))
  63. with BuildSketch(offset_side):
  64. Rectangle((cutout_thickness + params.wall_thickness) * 2, 5)
  65. with Locations((0, -params.phone_length * 0.4)):
  66. Circle(cutout_thickness + params.wall_thickness)
  67. make_hull()
  68. extrude(amount = -outer_width, mode = Mode.SUBTRACT)
  69.  
  70. # Make it easy to handle in the hand. Arguably should exclude the edges inside of the cutouts, but that's a pain
  71. chamfer(holder_part.edges().filter_by(GeomType.LINE), length = params.overall_chamfer)
  72.  
  73. # Drainage/speaker hole in the bottom
  74. with BuildSketch(holder_part.faces().sort_by(Axis.Y)[-1]):
  75. with Locations((0, params.phone_width / 2 - params.phone_thickness * 0.8), (0, -(params.phone_width / 2 - params.phone_thickness * 0.8))):
  76. RegularPolygon(radius = params.phone_thickness * 0.4, side_count = 6, rotation = 30)
  77. make_hull()
  78. extrude(amount = -params.wall_thickness * 2, mode = Mode.SUBTRACT)
  79. chamfer(holder_part.edges(Select.LAST).filter_by(lambda e: e.edge().length > params.wall_thickness), length = params.hole_chamfer)
  80.  
  81. return holder_part.part
  82.  
  83. # %%
  84.  
  85. import importlib
  86. import ShowerPhoneHolder
  87. importlib.reload(ShowerPhoneHolder)
  88.  
  89. from ShowerPhoneHolder import *
  90. from ocp_vscode import *
  91. set_port(3939)
  92.  
  93. phone_holder_params = PhoneHolderParams(
  94. phone_length = 140 *MM,
  95. phone_width = 79 *MM,
  96. phone_thickness = 10.0 *MM,
  97. glass_thickness = 4.7 *MM,
  98. )
  99.  
  100. phone_holder = build_phone_holder(phone_holder_params)
  101.  
  102. export_stl(phone_holder, "ShowerPhoneHolder.stl")
  103.  
  104. show_all()
  105. # %%
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement