Pip-Boy inspired phone holder built around the PINE64 PinePhone
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

261 righe
6.9 KiB

  1. // dependency: https://github.com/revarbat/BOSL
  2. include <BOSL/constants.scad>
  3. use <BOSL/transforms.scad>
  4. use <BOSL/shapes.scad>
  5. use <BOSL/masks.scad>
  6. // DEBUG:
  7. //validation = 1;
  8. //xray = 1;
  9. // EXPORT:
  10. MODEL_HARNESS_LEFT=1;
  11. MODEL_HARNESS_RIGHT=2;
  12. MODEL_HARNESS_TOP=3;
  13. export=0; // [0:5]
  14. function is_not_export() = is_undef(export) || export == 0;
  15. function is_export() = !is_not_export();
  16. function is_model_strict(m) = is_export() && export == m;
  17. function is_model(m) = is_not_export() || export == m;
  18. function get_phone_size() = [160, 76.7, 10];
  19. shell_wall=3;
  20. shell_rim_wall=3;
  21. rim_edge_thickness=1.2;
  22. rim_edge_tolerance=0.4;
  23. expose_back_camera=false;
  24. screwmount_screw=3;
  25. harness_divider=[30, 0, 1.3];
  26. module phone() {
  27. s=get_phone_size();
  28. color("gray")
  29. cuboid(s, fillet=5);
  30. }
  31. module arm() {
  32. $fn=6;
  33. s=[210, 55, 50];
  34. color("SaddleBrown")
  35. down(s.z/2 + get_phone_size().z/2) cuboid(s, fillet=20);
  36. }
  37. module phone_harness() {
  38. ops=get_phone_size();
  39. ps=[ops.x+0.2, ops.y+0.2, ops.z+0.2];
  40. w=shell_wall;
  41. f=2;
  42. rf=5;
  43. hs=[ps.x+w*2, ps.y+w*2, ps.z+w*2];
  44. module shell() {
  45. $fn = $preview ? 6 : 30;
  46. difference() {
  47. cuboid(hs, fillet=f);
  48. cuboid(ps, fillet=f);
  49. }
  50. shell_rim();
  51. shell_screwmounts();
  52. }
  53. module shell_rim() {
  54. $fn = $preview ? 6 : 30;
  55. w=shell_rim_wall;
  56. s=[hs.x+2*w, hs.y+2*w, 6];
  57. intersection() {
  58. difference() {
  59. cuboid(s, fillet=rf, edges=EDGES_Z_ALL);
  60. cuboid(ps, fillet=f, edges=EDGES_Z_ALL);
  61. }
  62. cuboid(s, fillet=1);
  63. }
  64. }
  65. module shell_rim_edge(thickness, groove, tolerance=rim_edge_tolerance) {
  66. $fn = $preview ? 6 : 30;
  67. w=thickness + (groove ? tolerance : 0);
  68. offset=(groove ? 0 : tolerance/2);
  69. res=[hs.x+2*(w+offset), hs.y+2*(w+offset), 3];
  70. resi=[hs.x+2*offset, hs.y+2*offset, res.z+1];
  71. up(0.0) difference() {
  72. intersection() {
  73. cuboid(res, fillet=rf, edges=EDGES_Z_ALL);
  74. cuboid(res, fillet=(groove?1:1.5), edges=EDGES_BOTTOM);
  75. }
  76. cuboid(resi, fillet=rf, edges=EDGES_Z_ALL);
  77. }
  78. }
  79. module foreach_screwmount() {
  80. for(x = [0:1]) for (y = [0:1]) {
  81. translate([(-0.5+x)*ps.x, (-0.5+y)*ps.y, -hs.z/2])
  82. children();
  83. }
  84. }
  85. module shell_screwmounts() {
  86. $fn = $preview ? 6 : 30;
  87. r=3;
  88. foreach_screwmount() {
  89. cylinder(r=r, h=hs.z);
  90. }
  91. }
  92. module shell_screwmounts_holes() {
  93. $fn = $preview ? 6 : 30;
  94. foreach_screwmount() {
  95. up(w) cylinder(d2=screwmount_screw, d1=screwmount_screw*0.5, h=hs.z+1);
  96. up(hs.z-1) cylinder(d=screwmount_screw+1.5, h=5);
  97. }
  98. }
  99. module screen_cutout() {
  100. s=[138, 69, 100];
  101. up(s.z/2) cuboid(s, fillet=3, edges=EDGES_Z_ALL);
  102. }
  103. top_offset=6.5;
  104. module top_speaker_cutout() {
  105. s=[3, 12, 100];
  106. right(ps.x/2 - top_offset) up(s.z/2 - ps.z/3) cuboid(s, fillet=1);
  107. }
  108. module front_camera_cutout() {
  109. $fn = $preview ? 6 : 30;
  110. d=5;
  111. s=[d, d, 100];
  112. right(ps.x/2 - top_offset) fwd(11) cylinder(d=s.x, h=s.z);
  113. }
  114. module leds_cutout() {
  115. s=[4, 14, 100];
  116. right(ps.x/2 - top_offset) up(s.z/2 - ps.z/3) back(23) cuboid(s, fillet=1);
  117. }
  118. module top_cutout() {
  119. screen_cutout();
  120. top_speaker_cutout();
  121. front_camera_cutout();
  122. leds_cutout();
  123. }
  124. module back_camera_cutout() {
  125. s=[13, 25, expose_back_camera ? 100 : 11];
  126. right(ps.x/2 - 7.5) fwd(ps.y/2 - 23) down(s.z/2 - ps.z/3) cuboid(s, fillet=6, edges=EDGES_Z_ALL);
  127. }
  128. module bottom_speaker_cutout() {
  129. s=[8, 49, 100];
  130. left(ps.x/2 - 13)
  131. difference() {
  132. down(s.z/2 - ps.z/3) cuboid(s, fillet=1);
  133. bars=8;
  134. down(ps.z/2)
  135. for (i = [0:bars-1]) {
  136. bs=[s.x+2, 1, 2];
  137. step=s.y/bars;
  138. fwd(i*step - s.y/2 + step/2) down(w) cube(bs, center=true);
  139. }
  140. }
  141. }
  142. module bottom_cutout() {
  143. back_camera_cutout();
  144. bottom_speaker_cutout();
  145. }
  146. module headphones_cutout() {
  147. $fn = $preview ? 10 : 30;
  148. d=8.8;
  149. p=[ps.x/2, ps.y/2-24, -0.88];
  150. h=100;
  151. translate(p) yrot(90) down(10) cylinder(h=h, d=d);
  152. }
  153. module right_cutout() {
  154. headphones_cutout();
  155. }
  156. module usbc_cutout() {
  157. s=[100, 20, 6];
  158. left(ps.x/2) down(2) cuboid(s, fillet=1);
  159. }
  160. module left_cutout() {
  161. usbc_cutout();
  162. }
  163. module buttons_cutout() {
  164. s=[42, 100, 5];
  165. fwd(ps.y/2) right(ps.x/2 - 44.5) cuboid(s, fillet=1);
  166. }
  167. module front_cutout() {
  168. buttons_cutout();
  169. }
  170. module shell_cutouts() {
  171. top_cutout();
  172. bottom_cutout();
  173. left_cutout();
  174. right_cutout();
  175. front_cutout();
  176. shell_screwmounts_holes();
  177. }
  178. divider=harness_divider;
  179. module model_harness_left() {
  180. intersection() {
  181. intersection() {
  182. translate(divider) downcube([1000, 1000, 1000]);
  183. translate(divider) leftcube([1000, 1000, 1000]);
  184. }
  185. difference() {
  186. shell();
  187. shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
  188. shell_cutouts();
  189. }
  190. }
  191. }
  192. module model_harness_right() {
  193. intersection() {
  194. intersection() {
  195. translate(divider) downcube([1000, 1000, 1000]);
  196. translate(divider) rightcube([1000, 1000, 1000]);
  197. }
  198. difference() {
  199. shell();
  200. shell_rim_edge(rim_edge_thickness, groove=true, tolerance=rim_edge_tolerance);
  201. shell_cutouts();
  202. }
  203. }
  204. }
  205. module model_harness_top() {
  206. intersection() {
  207. translate(divider) upcube([1000, 1000, 1000]);
  208. difference() {
  209. shell();
  210. shell_cutouts();
  211. }
  212. }
  213. difference() {
  214. shell_rim_edge(rim_edge_thickness, groove=false);
  215. shell_cutouts();
  216. }
  217. }
  218. if (is_model(MODEL_HARNESS_LEFT)) model_harness_left();
  219. if (is_model(MODEL_HARNESS_RIGHT)) model_harness_right();
  220. if (is_model(MODEL_HARNESS_TOP)) model_harness_top();
  221. }
  222. module model() {
  223. phone_harness();
  224. }
  225. if (!is_undef(validation)) {
  226. intersection() {
  227. phone();
  228. model();
  229. }
  230. } else {
  231. intersection() {
  232. if (!is_undef(xray)) {
  233. span_cube([0,1000*xray], [0,1000*xray], [-1000,1000]);
  234. }
  235. union() {
  236. if (is_not_export()) {
  237. //phone();
  238. //arm();
  239. }
  240. model();
  241. }
  242. }
  243. }