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