]> git.armaanb.net Git - atreides.git/blob - case/openscad_3D/atreus_3D.scad
adding files for 3D printing
[atreides.git] / case / openscad_3D / atreus_3D.scad
1 // -*- mode: c -*-
2 /* All distances are in mm. */
3
4 /* set output quality */
5 $fn = 50;
6
7 /* Distance between key centers. */
8 column_spacing   = 19;
9 row_spacing      = column_spacing;
10
11 /* This number should exceed row_spacing and column_spacing. The
12  default gives a 1mm = (20mm - 19mm) gap between keycaps and cuts in
13  the top plate.*/
14 key_hole_size = 20;
15
16 /* rotation angle; the angle between the halves is twice this
17    number */
18 angle = 10;
19
20 /* The radius of screw holes. Holes will be slightly bigger due
21    to the cut width. */
22 screw_hole_radius = 1.5;
23 /* Each screw hole is a hole in a "washer". How big these "washers"
24    should be depends on the material used: this parameter and the
25    `switch_hole_size` determine the spacer wall thickness. */
26 washer_radius     = 4 * screw_hole_radius;
27
28 /* This constant allows tweaking the location of the screw holes near
29    the USB cable. Only useful with small `angle` values. Try the value
30    of 10 with angle=0. */
31 back_screw_hole_offset = 0;
32
33 /* Distance between halves. */
34 hand_separation        = 0;
35
36 /* The approximate size of switch holes. Used to determine how
37    thick walls can be, i.e. how much room around each switch hole to
38    leave. See spacer(). */
39 switch_hole_size = 14;
40
41 /* Sets whether the case should use notched holes. As far as I can
42    tell these notches are not all that useful... */
43 use_notched_holes = true;
44
45 /* Number of rows and columns in the matrix. You need to update
46    staggering_offsets if you change n_cols. */
47 n_rows = 4;
48 n_cols = 5;
49
50 /* Number of thumb keys (per hand), try 1 or 2. */
51 n_thumb_keys = 1;
52
53 /* The width of the USB cable hole in the spacer. */
54 cable_hole_width = 12;
55
56 /* Vertical column staggering offsets. The first element should
57    be zero. */
58 staggering_offsets = [0, 5, 11, 6, 3];
59
60 /* Whether or not to split the spacer into quarters. */
61 quarter_spacer = false;
62
63 /* Where the top/bottom split of a quartered spacer will be. */
64 spacer_quartering_offset = 60;
65
66 module rz(angle, center=undef) {
67   /* Rotate children `angle` degrees around `center`. */
68   translate(center) {
69     rotate(angle) {
70       translate(-center) {
71         for (i=[0:$children-1])
72           children(i);
73       }
74     }
75   }
76 }
77
78 /* Compute coordinates of a point obtained by rotating p angle degrees
79    around center. Used to compute locations of screw holes near the
80    USB cable hole. */
81 function rz_fun(p, angle, center) = [cos(angle) * (p[0] - center[0]) - sin(angle) * (p[1] - center[1]) + center[0],
82                                      sin(angle) * (p[0] - center[0]) + cos(angle) * (p[1] - center[1])+ center[1]];
83
84 module switch_hole(position, notches=use_notched_holes) {
85   /* Cherry MX switch hole with the center at `position`. Sizes come
86      from the ErgoDox design. */
87   hole_size    = 13.97;
88   notch_width  = 3.5001;
89   notch_offset = 4.2545;
90   notch_depth  = 0.8128;
91   translate(position) {
92     union() {
93         translate([0,0,-1])
94       cube([hole_size, hole_size,50], center=true);
95       if (notches == true) {
96         translate([0, notch_offset,-1]) {
97           cube([hole_size+2*notch_depth, notch_width,50], center=true);
98         }
99         translate([0, -notch_offset,-1]) {
100           cube([hole_size+2*notch_depth, notch_width,50], center=true);
101         }
102       }
103     }
104   }
105 };
106
107 module regular_key(position, size) {
108   /* Create a hole for a regular key. */
109   translate(position) {
110     cube([size, size,50], center=true);
111   }
112 }
113
114 module thumb_key(position, size) {
115   /* Create a hole for a 1x1.5 unit thumb key. */
116   translate(position) {
117     scale([1, 1.5]) {
118       translate(-position) {
119         regular_key(position, size);
120       }
121     }
122   }
123 }
124
125 module column (bottom_position, switch_holes, key_size=key_hole_size) {
126   /* Create a column of keys. */
127   translate(bottom_position) {
128     for (i = [0:(n_rows-1)]) {
129       if (switch_holes == true) {
130         switch_hole([0, i*column_spacing,-1]);
131       } else {
132         regular_key([0, i*column_spacing,-1], key_size);
133       }
134     }
135   }
136 }
137
138 module rotate_half() {
139   /* Rotate the right half of the keys around the top left corner of
140      the thumb key. Assumes that the thumb key is a 1x1.5 key and that
141      it is shifted 0.5*column_spacing up relative to the nearest column. */
142   rotation_y_offset = 1.75 * column_spacing;
143   for (i=[0:$children-1]) {
144     rz(angle, [hand_separation, rotation_y_offset]) {
145       children(i);
146     }
147   }
148 }
149
150 module add_hand_separation() {
151   /* Shift everything right to get desired hand separation. */
152   for (i=[0:$children-1]) {
153     translate([0.5*hand_separation, /* we get back the full separation
154                                        because of mirroring */
155                0]) children(i);
156   }
157 }
158
159 module right_half (switch_holes=true, key_size=key_hole_size) {
160   /* Create switch holes or key holes for the right half of the
161      keyboard. Different key_sizes are used in top_plate() and
162      spacer(). */
163   x_offset = 0.5 * row_spacing;
164   y_offset = 0.5 * column_spacing;
165   thumb_key_offset = y_offset + 0.5 * column_spacing;
166   rotate_half() {
167     add_hand_separation() {
168       for (j=[0:(n_thumb_keys-1)]) {
169         if (switch_holes == true) {
170           switch_hole([x_offset + j*row_spacing, thumb_key_offset,-1]);
171         } else {
172           thumb_key([x_offset + j*row_spacing, thumb_key_offset,-1], key_size);
173         }
174       }
175       for (j=[0:(n_cols-1)]) {
176         column([x_offset + (j+n_thumb_keys)*row_spacing, y_offset + staggering_offsets[j]], switch_holes, key_size);
177       }
178     }
179   }
180 }
181
182 module screw_hole(radius, offset_radius, position, direction) {
183   /* Create a screw hole of radius `radius` at a location
184      `offset_radius` from `position`, (diagonally), in the direction
185      `direction`. Oh, what a mess this is. */
186   /* direction is the 2-element vector specifying to which side of
187      position to move to, [-1, -1] for bottom left, etc. */
188
189   /* radius_offset is the offset in the x (or y) direction so that
190      we're offset_radius from position */
191   radius_offset = offset_radius / sqrt(2);
192   /* key_hole_offset if the difference between key spacing and key
193      hole edge */
194   key_hole_offset = 0.5*(row_spacing - key_hole_size);
195   x = position[0] + (radius_offset - key_hole_offset) * direction[0];
196   y = position[1] + (radius_offset - key_hole_offset) * direction[1];
197   translate([x,y,0]) {
198     cylinder(r1=radius,r2=radius,h=3);
199   }
200 }
201
202 module right_screw_holes(hole_radius) {
203   /* coordinates of the back right screw hole before rotation... */
204   back_right = [(n_cols+n_thumb_keys)*row_spacing,
205                staggering_offsets[n_cols-1] + n_rows * column_spacing];
206   /* and after */
207   tmp = rz_fun(back_right, angle, [0, 2.25*column_spacing]);
208
209   nudge = 0.75;
210
211   rotate_half() {
212     add_hand_separation() {
213       screw_hole(hole_radius, washer_radius,
214                  [row_spacing, 0],
215                  [-nudge, -nudge]);
216       screw_hole(hole_radius, washer_radius,
217                  [(n_cols+n_thumb_keys)*row_spacing, staggering_offsets[n_cols-1]],
218                  [nudge, -nudge]);
219       screw_hole(hole_radius, washer_radius,
220                  back_right,
221                  [nudge, nudge]);
222     }
223   }
224
225   /* add the screw hole near the cable hole */
226   translate([washer_radius - tmp[0],
227              back_screw_hole_offset]) {
228     rotate_half() {
229       add_hand_separation() {
230         screw_hole(hole_radius,
231                    washer_radius,
232                    back_right,
233                    [nudge, nudge]);
234       }
235     }
236   }
237 }
238
239 module screw_holes(hole_radius) {
240   /* Create all the screw holes. */
241   right_screw_holes(hole_radius);
242   mirror ([1,0,0]) { right_screw_holes(hole_radius); }
243 }
244
245 module left_half(switch_holes=true, key_size=key_hole_size) {
246   mirror ([1,0,0]) { right_half(switch_holes, key_size); }
247 }
248
249 module bottom_plate() {
250   /* bottom layer of the case */
251   difference() {
252     hull() { screw_holes(washer_radius); }
253     screw_holes(screw_hole_radius);
254   }
255 }
256
257 module top_plate() {
258   /* top layer of the case */
259   difference() {
260     bottom_plate();
261     right_half(false);
262     left_half(false);
263   }
264 }
265
266 module switch_plate() {
267   /* the switch plate */
268   difference() {
269     bottom_plate();
270     right_half();
271     left_half();
272   }
273 }
274
275 module spacer() {
276   /* Create a spacer. */
277   difference() {
278     union() {
279       difference() {
280         bottom_plate();
281         hull() {
282           right_half(switch_holes=false, key_size=switch_hole_size + 3);
283           left_half(switch_holes=false, key_size=switch_hole_size + 3);
284         }
285     /* add the USB cable hole: */
286     translate([-0.5*cable_hole_width, 2*column_spacing,0]) {
287       cube([cable_hole_width, (2*n_rows) * column_spacing,50]);
288     }
289       }
290       screw_holes(washer_radius);
291     }
292     screw_holes(screw_hole_radius);
293   }
294 }
295
296 module spacer_quadrant(spacer_quadrant_number) {
297   /* Cut a quarter of a spacer. */
298   translate([0, spacer_quartering_offset]) {
299     intersection() {
300       translate([0, -spacer_quartering_offset]) { spacer(); }
301       rotate([0, 0, spacer_quadrant_number * 90]) { cube([1000, 1000,3]); }
302     }
303   }
304 }
305
306 module quartered_spacer()
307 {
308   /* Assemble all four quarters of a spacer. */
309   spacer_quadrant(0);
310   spacer_quadrant(1);
311   translate([-5,-10]) spacer_quadrant(2);
312   translate([5,-10]) spacer_quadrant(3);
313 }
314
315 /* Create all four layers. */
316
317 translate([0,0,9]) top_plate();
318 translate([0, 0, 6]) { switch_plate(); }
319 translate([300, 0,0]) { bottom_plate(); }
320 translate([0,0,3]) spacer();
321 translate([0, 0,0]) {
322   if (quarter_spacer == true) {
323     quartered_spacer();
324   }
325   else {
326     spacer();
327   }
328
329 }