$fn = 72; include 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]]) screw_post(post[2]); } } 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, wall_height - wall_width]) support([upper_support_length, keyboard_switch_height], support_width); translate([support_x_offset + x, lower_support_y_offset, wall_height - wall_width]) support([lower_support_length, keyboard_switch_height], support_width); } for (y = [0: support_y_interval: keyboard_length + 2 * wall_width]) { translate([right_support_x_offset, support_y_offset + y - wall_width + support_width, wall_height - wall_width]) rotate([0, 0, -90]) support([right_support_length, keyboard_switch_height], support_width); translate([left_support_x_offset, support_y_offset + y - wall_width + support_width, wall_height - wall_width]) rotate([0, 0, -90]) support([left_support_length, 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 - wall_width], false); /* Right */ translate([case_width_bottom - wall_width, 0, 0]) cube([wall_width, case_length_bottom, wall_height - wall_width], false); /* Lower */ cube([case_width_bottom, wall_width, wall_height - wall_width], false); /* Left */ cube([wall_width, case_length_bottom, wall_height - wall_width], false); } 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 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 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, plate_length, 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);