344 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			OpenSCAD
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			OpenSCAD
		
	
	
	
	
	
| $fn = 72;
 | |
| 
 | |
| include <keyboard.scad>
 | |
| 
 | |
| module top_case(key_switch_sizes, pcb_screw_holes) {
 | |
|     case_width_top     = 317.5000;
 | |
|     case_width_bottom  = 320.0000;
 | |
|     case_length_top    = 150.0000;
 | |
|     case_length_bottom = 151.5000;
 | |
| 
 | |
|     wall_width  =  2.5000;
 | |
|     wall_height = 17.2500;
 | |
| 
 | |
|     keyboard_width    = keyboard_switch_width  * 13.5;
 | |
|     keyboard_length   = keyboard_switch_length *  5.0;
 | |
|     keyboard_x_offset = 12.2500;
 | |
|     keyboard_y_offset = 12.2500;
 | |
| 
 | |
|     keyboard_deck_z_offset = wall_height - wall_width - keyboard_switch_height;
 | |
| 
 | |
|     accent_width    =  1.0000;
 | |
|     accent_depth    = 0.5;
 | |
|     accent_y_stride = (keyboard_length - accent_width) / 5.0;
 | |
|     accent_y_bottom = keyboard_y_offset;
 | |
| 
 | |
|     vent_width    =  2.0000;
 | |
|     vent_length   = wall_width;
 | |
|     vent_height   = 12.0000;
 | |
|     vent_count    = 32;
 | |
|     vent_x_first  = keyboard_x_offset + keyboard_width - vent_count * (vent_width + vent_width);
 | |
|     vent_y_offset = case_length_bottom - vent_length;
 | |
| 
 | |
|     support_width = 1.2500;
 | |
| 
 | |
|     screw_post_diameter_inner  =  3.00;
 | |
|     screw_post_diameter_outer  =  6.25;
 | |
|     screw_post_corner_height   = 12.00;
 | |
|     screw_post_middle_height   = 29.30;
 | |
|     screw_post_upper_y_offset  = case_length_bottom - wall_width - 15.00;
 | |
|     screw_post_middle_y_offset = 72.50;
 | |
|     screw_post_lower_y_offset  =  6.50;
 | |
|     screw_post_x_offset        = (keyboard_x_offset - 2 * wall_width) / 2 + wall_width;
 | |
| 
 | |
|     eps = 0.01;
 | |
| 
 | |
|     module fascia() {
 | |
|         difference() {
 | |
|             cube([case_width_bottom, case_length_bottom, wall_width], false);
 | |
| 
 | |
|             translate([keyboard_x_offset, keyboard_y_offset, -eps])
 | |
|             cube([keyboard_width, keyboard_length, wall_width + 2*eps], false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module vents() {
 | |
|         for (i = [0:vent_count]) {
 | |
|             x = vent_x_first + (i * (vent_width + vent_width));
 | |
| 
 | |
|             translate([x, vent_y_offset-eps, wall_height - vent_height])
 | |
|             cube([vent_width, vent_length+2*eps, vent_height+eps], false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module accents() {
 | |
|         for (y = [accent_y_bottom: accent_y_stride: case_length_bottom]) {
 | |
|             /* Top */
 | |
|             translate([-eps, y, wall_height - accent_depth])
 | |
|             cube([case_width_bottom+2*eps, accent_width, accent_depth+eps], false);
 | |
| 
 | |
|             /* Right */
 | |
|             translate([case_width_bottom - accent_depth, y, -eps])
 | |
|             cube([accent_depth+eps, accent_width+eps, wall_height+2*eps], false);
 | |
| 
 | |
|             /* Left */
 | |
|             translate([-eps, y, -eps])
 | |
|             cube([accent_depth+eps, accent_width, wall_height+2*eps], false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module screw_post(h) {
 | |
|         diameter_inner = 3.00;
 | |
|         diameter_outer = 6.25;
 | |
| 
 | |
|         difference() {
 | |
|             cylinder(h, d=diameter_outer);
 | |
| 
 | |
|             translate([0, 0, -eps])
 | |
|             cylinder(h + 2*eps, d=diameter_inner);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module screw_posts() {
 | |
|         posts = [
 | |
|             /* Upper row */
 | |
|             [screw_post_x_offset,   screw_post_upper_y_offset, screw_post_corner_height],
 | |
|             [case_width_bottom / 2, screw_post_upper_y_offset, screw_post_middle_height],
 | |
|             [case_width_bottom - screw_post_x_offset, screw_post_upper_y_offset, screw_post_corner_height],
 | |
| 
 | |
|             /* Middle row */
 | |
|             [screw_post_x_offset, screw_post_middle_y_offset, screw_post_corner_height],
 | |
|             [case_width_bottom - screw_post_x_offset, screw_post_middle_y_offset, screw_post_corner_height],
 | |
| 
 | |
|             /* Bottom row */
 | |
|             [screw_post_x_offset, screw_post_lower_y_offset, screw_post_corner_height],
 | |
|             [case_width_bottom / 2, screw_post_lower_y_offset, screw_post_corner_height],
 | |
|             [case_width_bottom - screw_post_x_offset, screw_post_lower_y_offset, screw_post_corner_height]
 | |
|         ];
 | |
| 
 | |
|         for (post = posts) {
 | |
|             translate([post[0], post[1], wall_height - wall_width - post[2] - eps])
 | |
|             screw_post(post[2] + eps);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module support(dimensions, width) {
 | |
|         length = dimensions[0];
 | |
|         height = dimensions[1];
 | |
| 
 | |
|         module right_triangle(base) {
 | |
|             hypot = sqrt(2*(base^2));
 | |
| 
 | |
|             intersection() {
 | |
|                 square([base, base]);
 | |
| 
 | |
|                 translate([-base, 0, 0])
 | |
|                 rotate([0, 0, -45])
 | |
|                 square([hypot, hypot]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         module shape() {
 | |
|             /* Height ratio of lower aspect to upper aspect */
 | |
|             aspect_ratio = 3.75 / 12.0;
 | |
| 
 | |
|             aspect_upper_height = height;
 | |
|             aspect_lower_height = aspect_ratio * height;
 | |
| 
 | |
|             /* The length of each individual support aspect */
 | |
|             aspect_length = 1/3 * length;
 | |
| 
 | |
|             hypotenuse     = sqrt(2*(aspect_length^2));
 | |
|             lower_x_offset = aspect_length - (hypotenuse - aspect_length);
 | |
| 
 | |
|             right_triangle(height);
 | |
| 
 | |
|             square([length, aspect_lower_height], false);
 | |
| 
 | |
|             translate([3 * aspect_length, 0, 0])
 | |
|             mirror([1, 0, 0])
 | |
|             right_triangle(height);
 | |
|         }
 | |
| 
 | |
|         translate([0, length, 0])
 | |
|         rotate([-90, 0, -90])
 | |
|         linear_extrude(width)
 | |
|         intersection() {
 | |
|             shape();
 | |
|             square([length, height], false);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module supports() {
 | |
|         support_x_interval = (keyboard_width + 2 * wall_width - support_width) / 6;
 | |
|         support_x_offset   =  keyboard_x_offset - wall_width;
 | |
| 
 | |
|         support_y_interval = (keyboard_length + 2 * wall_width - support_width) / 4;
 | |
|         support_y_offset   =  keyboard_y_offset;
 | |
| 
 | |
|         /* Upper vertical supports */
 | |
|         upper_support_length = case_length_bottom
 | |
|                              - keyboard_length
 | |
|                              - keyboard_y_offset
 | |
|                              - 2 * wall_width;
 | |
| 
 | |
|         upper_support_y_offset = keyboard_y_offset
 | |
|                                + keyboard_length
 | |
|                                + wall_width;
 | |
| 
 | |
|         /* Lower vertical supports */
 | |
|         lower_support_length   = keyboard_y_offset - 2 * wall_width;
 | |
|         lower_support_y_offset = wall_width;
 | |
| 
 | |
|         /* Left horizontal supports */
 | |
|         left_support_length   = keyboard_x_offset - 2 * wall_width;
 | |
|         left_support_x_offset = wall_width;
 | |
| 
 | |
|         /* Right horizontal supports */
 | |
|         right_support_length = case_width_bottom
 | |
|                              - keyboard_width
 | |
|                              - keyboard_x_offset
 | |
|                              - 2 * wall_width;
 | |
| 
 | |
|         right_support_x_offset = keyboard_x_offset
 | |
|                                + keyboard_width
 | |
|                                + wall_width;
 | |
| 
 | |
|         for (x = [0: support_x_interval: keyboard_width + 2 * wall_width]) {
 | |
|             translate([support_x_offset + x,
 | |
|                        upper_support_y_offset - eps,
 | |
|                        wall_height - wall_width])
 | |
|             support([upper_support_length + 2*eps, keyboard_switch_height], support_width);
 | |
| 
 | |
|             translate([support_x_offset + x,
 | |
|                        lower_support_y_offset - eps,
 | |
|                        wall_height - wall_width])
 | |
|             support([lower_support_length + 2*eps, keyboard_switch_height], support_width);
 | |
|         }
 | |
| 
 | |
|         for (y = [0: support_y_interval: keyboard_length + 2 * wall_width]) {
 | |
|             translate([right_support_x_offset - eps,
 | |
|                        support_y_offset + y - wall_width + support_width,
 | |
|                        wall_height - wall_width])
 | |
|             rotate([0, 0, -90])
 | |
|             support([right_support_length + 2*eps, keyboard_switch_height], support_width);
 | |
| 
 | |
|             translate([left_support_x_offset - eps,
 | |
|                        support_y_offset + y - wall_width + support_width,
 | |
|                        wall_height - wall_width])
 | |
|             rotate([0, 0, -90])
 | |
|             support([left_support_length + 2*eps, keyboard_switch_height], support_width);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     module body() {
 | |
|         translate([0, 0, wall_height - wall_width])
 | |
|         fascia();
 | |
| 
 | |
|         /* Upper */
 | |
|         translate([0, case_length_bottom - wall_width, 0])
 | |
|         cube([case_width_bottom, wall_width, wall_height], false);
 | |
| 
 | |
|         /* Right */
 | |
|         translate([case_width_bottom - wall_width, 0, 0])
 | |
|         cube([wall_width, case_length_bottom, wall_height], false);
 | |
| 
 | |
|         /* Lower */
 | |
|         cube([case_width_bottom, wall_width, wall_height], false);
 | |
| 
 | |
|         /* Left */
 | |
|         cube([wall_width, case_length_bottom, wall_height], false);
 | |
|     }
 | |
| 
 | |
|     module keyboard_deck() {
 | |
|         key_switch_footprint = [15.25, 15.25];
 | |
| 
 | |
|         function add(v)            = [for(p=v) 1]*v;
 | |
|         function slice(v, x, y)    = [for (i=[x:y]) v[i]];
 | |
|         function addrange(v, x, y) = add(slice(v, x, y));
 | |
| 
 | |
|         module screw_holes() {
 | |
|             pcb_screw_diameter = 2.5;
 | |
| 
 | |
|             for (screw_hole = pcb_screw_holes) {
 | |
|                 translate([screw_hole[0], screw_hole[1], -eps])
 | |
|                 cylinder(h=wall_width+2*eps, d=pcb_screw_diameter);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         module key_switch_plate(key_switch_size) {
 | |
|             plate_width  = keyboard_switch_width * key_switch_size;
 | |
|             plate_length = keyboard_switch_length;
 | |
| 
 | |
|             if (key_switch_size <= 0.5) {
 | |
|                 cube([keyboard_switch_width  * key_switch_size,
 | |
|                       keyboard_switch_length,
 | |
|                       wall_width], false);
 | |
|             } else {
 | |
|                 hole_width  = key_switch_footprint[0];
 | |
|                 hole_length = key_switch_footprint[1];
 | |
| 
 | |
|                 hole_x = plate_width  / 2 - hole_width  / 2;
 | |
|                 hole_y = plate_length / 2 - hole_length / 2;
 | |
| 
 | |
|                 difference() {
 | |
|                     cube([plate_width + eps, plate_length + eps, wall_width], false);
 | |
| 
 | |
|                     translate([hole_x, hole_y, -eps])
 | |
|                     cube([hole_width, hole_length, wall_width + 2*eps], false);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         module walls() {
 | |
|             /* Upper */
 | |
|             translate([-wall_width, keyboard_length, 0])
 | |
|             cube([keyboard_width + 2 * wall_width, wall_width, keyboard_switch_height], false);
 | |
| 
 | |
|             /* Right */
 | |
|             translate([keyboard_width, -wall_width, 0])
 | |
|             cube([wall_width, keyboard_length + 2 * wall_width, keyboard_switch_height], false);
 | |
| 
 | |
|             /* Lower */
 | |
|             translate([-wall_width, -wall_width, 0])
 | |
|             cube([keyboard_width + 2 * wall_width, wall_width, keyboard_switch_height], false);
 | |
| 
 | |
|             /* Left */
 | |
|             translate([-wall_width, -wall_width, 0])
 | |
|             cube([wall_width, keyboard_length + 2 * wall_width, keyboard_switch_height], false);
 | |
|         }
 | |
| 
 | |
|         module body() {
 | |
|             rows = len(key_switch_sizes);
 | |
| 
 | |
|             for (i = [0: rows-1]) {
 | |
|                 y = keyboard_switch_length * (rows - 1 - i);
 | |
| 
 | |
|                 key_switch_row = key_switch_sizes[i];
 | |
|                 cols           = len(key_switch_row);
 | |
| 
 | |
|                 for (j = [0: cols-1]) {
 | |
|                     x = keyboard_switch_width * ((j == 0)?
 | |
|                         0:
 | |
|                         addrange(key_switch_row, 0, j-1));
 | |
| 
 | |
|                     key_switch_size = key_switch_row[j];
 | |
| 
 | |
|                     translate([x, y, 0])
 | |
|                     key_switch_plate(key_switch_size);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         difference() {
 | |
|             body();
 | |
|             screw_holes();
 | |
|         }
 | |
| 
 | |
|         walls();
 | |
|     }
 | |
| 
 | |
|     difference() {
 | |
|         body();
 | |
|         accents();
 | |
|         vents();
 | |
|     }
 | |
| 
 | |
|     supports();
 | |
|     screw_posts();
 | |
| 
 | |
|     translate([keyboard_x_offset, keyboard_y_offset, keyboard_deck_z_offset])
 | |
|     keyboard_deck();
 | |
| }
 | |
| 
 | |
| top_case(keyboard_switch_sizes, keyboard_pcb_screw_holes);
 |