a whole bunch of work

This commit is contained in:
Bob - Home - Windows 2018-02-04 14:33:12 -05:00
parent a537407cca
commit 2368961370
12 changed files with 365 additions and 321 deletions

View File

@ -22,7 +22,7 @@ cherry() key();
which is a bog-standard DCS row 5 keycap. To change key profile or make varying width keys, you can use the row and unit length functions, like so:
```
sa_row(2) u(2) cherry() key();
sa_row(2) 2u() cherry() key();
```
![a 2 unit SA row 2 cherry key](assets/example2.JPG)
@ -36,7 +36,7 @@ If you wanted to generate some 2u stabilized keycaps for an Ergodox for instance
```
legends = ["Enter", "Escape", "Tab", "Shift"];
for(y=[0:3]) {
translate_u(0,y) 2u() dsa_row() stabilized() legend(legends[y], inset=true) cherry() key();
translate_u(0,y) 2u() dsa_row() stabilized() cherry() key(legends[y], inset=true);
}
```
@ -52,19 +52,27 @@ cherry() key() {
![an artisan key with no-face on it](assets/example4.JPG)
(no face courtesy of [this thing](https://www.thingiverse.com/thing:519727/))
Artisan support also supports _subtracting_ children by doing `key(inset=true) { ... }`, which is super helpful if you want to make keycaps with legends that are not text. The children will be placed just above the middle of the dish as per usual; you will need to translate them downwards (`ex translate([0,0,-1])`) to get them to 'dig in' to the top of the key.
## What if I want to get _really_ technical?
If you're not afraid to write some code yourself, at the base level this library _should_ function well as a key profile design library. by loading up `src/key.scad` (notice no s) you can tweak variables in `src/settings.scad` to prototype your own profiles. You can design your own keyset with custom width height and depth, dish tilt, top skew, fonts, wall thickness, etc.
At the base level this library should function well as a key profile design library. by loading up `src/key.scad` (notice no s) you can tweak variables in `src/settings.scad` to prototype your own profiles. There are currently 44 different settings to tweak in `src/settings.scad` including width height and depth of the keycap, dish tilt, top skew, fonts, wall thickness, etc.
In addition, the library should be abstract enough to handle new dish types, keystems, and key shapes, in case you want to design your own DataMancer keycaps, support buckling spring keyboards (maybe) or design some kind of triangular dished profile. `src/shapes.scad` `src/stems.scad` and `src/dishes.scad` all have a 'selector' module at the top that should allow you to implement your own creations alongside what already exists.
### What if I want to get even more technical than that?
Now we're talkin!
This library should be abstract enough to handle new dish types, keystems, and key shapes, in case you want to design your own Typewriter-style keycaps, support buckling spring keyboards or design some kind of triangular dished profile. `src/shapes.scad` `src/stems.scad` and `src/dishes.scad` all have a 'selector' module at the top that should allow you to implement your own creations alongside what already exists.
Here's an example of tweaking the settings and code to make a 'stop sign' key profile:
In `key_shape()` in `shapes.scad`:
```
else if ($key_shape_type == "circle") {
rotate([0,0,22.5]) circle(d=width - width_difference, $fn=8);
else if ($key_shape_type == "stop_sign") {
rotate([0,0,22.5]) circle(d=size[0] - delta[0], $fn=8);
}
```
@ -72,17 +80,20 @@ In `keys.scad`:
```
union() {
// make the font smaller
$font_size = 3;
// top of keycap is the same size as the bottom
$width_difference = 0;
$height_difference = 0;
$key_shape_type="circle";
$key_shape_type="stop_sign";
$dish_type = "cylindrical";
// some keycap tops are slid backwards a little, and we don't want that
$top_skew = 0;
legends = ["Stop..", "Hammer", "time!"];
for(x=[0:len(legends)-1]) {
translate_u(x) legend(legends[x]) cherry() key();
translate_u(x) cherry() key(legends[x]);
}
}
```
@ -93,9 +104,9 @@ union() {
Prints from this library are still challenging, despite all efforts to the contrary. Resin printers can create great looking keycaps; FDM printers can create usable keys that look alright, but may require tweaking to get prints acceptable. There are a few quick things that you can do:
1. If your switch isn't fitting in the keycap, try upping the slop factor, accessed by giving your keystem function a numeric value (eg `cherry(0.5) key()`). This will lengthen the cross and decrease the overall size of the keystem. The default value is 0.3, and represents millimeters. Note that even if you have a resin printer, you should probably keep the default value; keys printed with 0 slop will barely fit on the stem.
1. If your stem isn't fitting in the switch, try upping the slop factor, accessed by giving your keystem function a numeric value (eg `cherry(0.5) key()`). This will lengthen the cross and decrease the overall size of the keystem. The default value is 0.3, and represents millimeters. Note that even if you have a resin printer, you should probably keep the default value; keys printed with 0 slop will barely fit on the stem.
2. If your keystem breaks off mid-print, you can enable a brim by adding the `brimmed()` modifier. This will give a solid base for the keystem to anchor into.
2. If your keystem breaks off the bed mid-print, you can enable a brim by adding the `brimmed()` modifier. This will give a solid base for the keystem to anchor into.
3. If you are unsatisfied with the quality of the top surface, you can try printing the keycap on a different surface than the bottom, though it may impact the quality of the stem.

View File

@ -9,7 +9,6 @@ module 1u() {
u(1) children();
}
module 1_25u() {
u(1.25) children();
}

View File

@ -51,39 +51,33 @@ module inset(val=1) {
}
module filled() {
$stem_profile = "filled";
$stem_type = "filled";
children();
}
module blank() {
$stem_profile = "blank";
$stem_type = "blank";
children();
}
module cherry(slop = 0.3) {
$slop = slop;
$stem_profile = "cherry";
$stem_slop = slop;
$stem_type = "cherry";
children();
}
module alps(slop = 0.3) {
$slop = slop;
$stem_profile = "alps";
$stem_slop = slop;
$stem_type = "alps";
children();
}
module rounded_cherry(slop = 0.3) {
$slop = slop;
$stem_profile = "cherry_rounded";
$stem_slop = slop;
$stem_type = "cherry_rounded";
children();
}
module legend(text, inset=false) {
$text=text;
$inset_text = inset;
children();
}
module flared_support() {
$support_type = "flared";
children();

View File

@ -1,11 +1,7 @@
module spacebar() {
$inverted_dish = true;
if ($dish_type == "cylindrical") {
$dish_type = "sideways cylindrical";
6_25u() stabilized(mm=50) children();
} else {
6_25u() stabilized(mm=50) children();
}
$dish_type = "sideways cylindrical";
6_25u() stabilized(mm=50) children();
}
module lshift() {

View File

@ -20,13 +20,22 @@ module translate_u(x=0, y=0, z=0){
translate([x * unit, y*unit, z*unit]) children();
}
dcs_row(2) u(2) dishless() cherry() {
/* $inverted_dish = true; */
$key_shape_type = "obloid";
// basic
cherry() key();
translate_u(1) sa_row(2) cherry() key("q");
translate_u(2) oem_row(2) alps() key("q", inset=true);
translate_u(3) dsa_row() rounded_cherry() key();
translate_u(1, 1) sa_row(3) lshift() cherry() key(inset=true) {
sphere(1);
};
translate_u(3, 2) sa_row(3) bar_support() spacebar() cherry() key("space bar");
translate_u(3,1) sa_row(3) 2u() cherry() {
$key_shape_type = "spherical";
$support_type = false;
$inverted_dish = true;
key();
}
translate_u(3) u(2) dcs_row(3) dishless() cherry() {
$key_shape_type = "obloid";
key();
}

View File

@ -22,7 +22,7 @@ for (row = [0:len(60_percent)-1]){
translate_u(columnDist - (a/2), -row) dishless() dcs_row((row+4) % 5 + 1) u(a) cherry() {
$width_difference = 0;
$height_difference = 0;
$key_shape_type = "obloid";
$key_shape_type = "spherical";
if (a != 6.25) {
key();
} else {

View File

@ -4,23 +4,26 @@ include <shapes.scad>
geodesic=false;
//dish selector
module dish(width, height, depth, inverted, tilt) {
module dish(width, height, depth, inverted) {
if($dish_type == "cylindrical"){
cylindrical_dish(width, height, depth, inverted, tilt);
cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "spherical") {
spherical_dish(width, height, depth, inverted, tilt);
spherical_dish(width, height, depth, inverted);
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted, tilt);
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
old_spherical_dish(width, height, depth, inverted, tilt);
old_spherical_dish(width, height, depth, inverted);
} else {
// else no dish, "no dish" is the value
// switchted to actually diffing a cube here due to (hopeful) changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
// else no dish, "no dish" is the value
}
module cylindrical_dish(width, height, depth, inverted, tilt){
module cylindrical_dish(width, height, depth, inverted){
// .5 has problems starting around 3u
$fa=.25;
/* we do some funky math here
@ -35,28 +38,25 @@ module cylindrical_dish(width, height, depth, inverted, tilt){
rad = (pow(width, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
rotate([90-tilt,0,0]){
translate([0,chord_length * direction,0]){
cylinder(h=height + 20, r=rad, center=true);
}
translate([0,0, chord_length * direction]){
rotate([90, 0, 0]) cylinder(h=height + 20, r=rad, center=true);
}
}
module sideways_cylindrical_dish(width, height, depth, inverted, tilt){
module sideways_cylindrical_dish(width, height, depth, inverted){
$fa=1;
chord_length = (pow(height, 2) - 4 * pow(depth, 2)) / (8 * depth);
rad = (pow(height, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
rotate([90,tilt,90]){
translate([0,chord_length * direction,0]){
cylinder(h = width + 20,r=rad, center=true); // +20 for fudge factor
}
translate([0,0, chord_length * direction]){
// cylinder is rendered facing up, so we rotate it on the y axis first
rotate([0,90,0]) cylinder(h = width + 20,r=rad, center=true); // +20 for fudge factor
}
}
module spherical_dish(width, height, depth, inverted, tilt, txt=""){
module spherical_dish(width, height, depth, inverted){
//same thing as the cylindrical dish here, but we need the corners to just touch - so we have to find the hypotenuse of the top
chord = pow((pow(width,2) + pow(height, 2)),0.5); //getting diagonal of the top
@ -67,29 +67,26 @@ module spherical_dish(width, height, depth, inverted, tilt, txt=""){
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
/*intersection(){*/
rotate([-tilt,0,0]){
translate([0,0,0 * direction]){
if (geodesic){
$fa=20;
scale([chord/2/depth, chord/2/depth]) {
geodesic_sphere(r=depth);
}
} else {
$fa=7;
// rotate 1 because the bottom of the sphere looks like trash.
scale([chord/2/depth, chord/2/depth]) {
geodesic_sphere(r=depth);
}
}
}
translate([0,0,0 * direction]){
if (geodesic){
$fa=20;
scale([chord/2/depth, chord/2/depth]) {
geodesic_sphere(r=depth);
}
} else {
$fa=7;
// rotate 1 because the bottom of the sphere looks like trash.
scale([chord/2/depth, chord/2/depth]) {
geodesic_sphere(r=depth);
}
}
}
}
//the older, 'more accurate', and MUCH slower spherical dish.
// generates the largest sphere possible that still contains the chord we are looking for
// much more graduated curvature at an immense cost
module old_spherical_dish(width, height, depth, inverted, tilt, txt=""){
module old_spherical_dish(width, height, depth, inverted){
//same thing as the cylindrical dish here, but we need the corners to just touch - so we have to find the hypotenuse of the top
chord = pow((pow(width,2) + pow(height, 2)),0.5); //getting diagonal of the top
@ -100,17 +97,14 @@ module old_spherical_dish(width, height, depth, inverted, tilt, txt=""){
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
/*intersection(){*/
rotate([-tilt,0,0]){
translate([0,0,chord_length * direction]){
if (geodesic){
$fa=7;
geodesic_sphere(r=rad);
} else {
$fa=1;
// rotate 1 because the bottom of the sphere looks like trash
sphere(r=rad);
}
}
translate([0,0,chord_length * direction]){
if (geodesic){
$fa=7;
geodesic_sphere(r=rad);
} else {
$fa=1;
// rotate 1 because the bottom of the sphere looks like trash
sphere(r=rad);
}
}
}

View File

@ -2,28 +2,18 @@
include <shapes.scad>
include <stems.scad>
include <dishes.scad>
include <supports.scad>
include <libraries/geodesic_sphere.scad>
/* [Fancy Bowed Sides] */
// if you're doing fancy bowed keycap sides, this controls how many slices you take
// default of 1 for no sampling, just top/bottom
height_slices = 1;
enable_side_sculpting = false;
/* [Hidden] */
$fs = .1;
//beginning to use unit instead of baked in 19.05
unit = 19.05;
//minkowski radius. radius of sphere used in minkowski sum for minkowski_key function. 1.75 default for faux G20
$minkowski_radius = .33;
color1 = [.2667,.5882,1];
color2 = [.5412, .4784, 1];
color3 = [.4078, .3569, .749];
color4 = [1, .6941, .2];
transparent_red = [1,0,0, 0.5];
// derived values. can't be variables if we want them to change when the special variables do
@ -36,34 +26,30 @@ function top_total_key_width() = $bottom_key_width + (unit * ($key_length - 1))
function top_total_key_height() = $bottom_key_height + (unit * ($key_height - 1)) - $height_difference;
// key shape including dish. used as the ouside and inside shape in key()
// key shape including dish. used as the ouside and inside shape in keytop(). allows for itself to be shrunk in depth and width / height
module shape(thickness_difference, depth_difference){
intersection(){
dished(depth_difference, $inverted_dish) {
color([.2667,.5882,1]) shape_hull(thickness_difference, depth_difference);
}
if ($inverted_dish) {
// larger shape_hull to clip off bits of the inverted dish
color([.5412, .4784, 1]) shape_hull(thickness_difference, 0, 2);
}
dished(depth_difference, $inverted_dish) {
color(color1) shape_hull(thickness_difference, depth_difference, 1);
}
}
// shape of the key but with soft, rounded edges. much more realistic, MUCH more complex. orders of magnitude more complex
module rounded_shape() {
render(){
minkowski(){
color(color1) minkowski(){
// half minkowski. that means the shape is neither circumscribed nor inscribed.
shape($minkowski_radius * 2, $minkowski_radius/2);
difference(){
sphere(r=$minkowski_radius, $fn=24);
translate([0,0,-$minkowski_radius])
cube([2*$minkowski_radius,2*$minkowski_radius,2*$minkowski_radius], center=true);
translate([0,0,-$minkowski_radius]){
cube($minkowski_radius * 2, center=true);
}
}
}
}
}
// basic key shape, no dish, no inside
// which is only used for dishing to cut the dish off correctly
// $height_difference used for keytop thickness
@ -71,17 +57,16 @@ module rounded_shape() {
module shape_hull(thickness_difference, depth_difference, extra_slices = 0){
render() {
if ($linear_extrude_shape) {
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
} else {
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
}
}
}
//corollary is hull_shape_hull
// corollary is hull_shape_hull
// extra_slices unused, only to match argument signatures
module linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices = 0){
height = $total_depth - depth_difference;
width_scale = top_total_key_width() / total_key_width();
height_scale = top_total_key_height() / total_key_height();
@ -96,7 +81,6 @@ module linear_extrude_shape_hull(thickness_difference, depth_difference, extra_s
}
module hull_shape_hull(thickness_difference, depth_difference, extra_slices = 0) {
slices = 10;
for (index = [0:$height_slices - 1 + extra_slices]) {
hull() {
shape_slice(index / $height_slices, thickness_difference, depth_difference);
@ -118,10 +102,7 @@ module shape_slice(progress, thickness_difference, depth_difference) {
total_key_width(thickness_difference),
total_key_height(thickness_difference)
],
[
$width_difference,
$height_difference
],
[$width_difference, $height_difference],
progress
);
}
@ -129,78 +110,125 @@ module shape_slice(progress, thickness_difference, depth_difference) {
}
}
module dished(depth_difference, inverted = false) {
if (inverted) {
union() {
children();
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
color([.4078, .3569, .749]) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish, $top_tilt / $key_height);
}
}
} else {
difference() {
children();
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
color([.4078, .3569, .749]) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish, $top_tilt / $key_height);
}
}
// for when you want something to only exist inside the keycap.
// used for the support structure
module inside() {
intersection() {
shape($wall_thickness, $keytop_thickness);
children();
}
}
// puts it's children at the center of the dishing on the key. this DOES rotate them though, it's not straight up
module top_of_key(){
extra_dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - extra_dish_depth]){
// put something at the top of the key, with no adjustments for dishing
module top_placement(depth_difference) {
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
rotate([-$top_tilt,0,0]){
children();
}
}
}
module keytext() {
extra_inset_depth = ($inset_text) ? 0.3 : 0;
// just to DRY up the code
module _dish() {
color(color3) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
}
translate([0, 0, -extra_inset_depth]){
top_of_key(){
linear_extrude(height=$dish_depth){
text(text=$text, font=$font, size=$font_size, halign="center", valign="center");
// for when you want to take the dish out of things
// used for adding the dish to the key shape and making sure stems don't stick out the top
module dished(depth_difference, inverted = false) {
difference() {
children();
top_placement(depth_difference){
difference(){
union() {
translate([-500, -500]) cube(1000);
if (!inverted) _dish();
}
if (inverted) _dish();
}
}
}
}
module connectors() {
intersection() {
for (connector_pos = $connectors) {
translate([connector_pos[0], connector_pos[1], $stem_inset]) {
rotate([0, 0, $stem_rotation]){
color([1, .6941, .2]) connector($stem_profile, $total_depth, $has_brim, $slop, $stem_inset, $support_type);
}
// puts it's children at the center of the dishing on the key, including dish height
// more user-friendly than top_placement
module top_of_key(){
// if there is a dish, we need to account for how much it digs into the top
dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
// if the dish is inverted, we need to account for that too. in this case we do half, otherwise the children would be floating on top of the dish
corrected_dish_depth = ($inverted_dish) ? -dish_depth / 2 : dish_depth;
top_placement(corrected_dish_depth) {
children();
}
}
module keytext(text, depth = 0) {
translate([0, 0, -depth]){
linear_extrude(height=$dish_depth){
text(text=text, font=$font, size=$font_size, halign="center", valign="center");
}
}
}
module keystem_positions() {
for (connector_pos = $connectors) {
translate(connector_pos) {
rotate([0, 0, $stem_rotation]){
children();
}
}
// cut off anything that isn't underneath the keytop
shape($wall_thickness, $keytop_thickness);
}
}
module keystems() {
keystem_positions() {
color(color4) stem($stem_type, $total_depth, $has_brim);
}
}
module keystem_supports() {
keystem_positions() {
color(color4) supports($support_type, $stem_type, $stem_throw, $total_depth - $stem_throw);
}
}
// a fake cherry keyswitch, abstracted out to maybe replace with a better one later
module cherry_keyswitch() {
union() {
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
}
}
//approximate (fully depressed) cherry key to check clearances
module clearance_check() {
if($clearance_check == true && ($stem_profile == "cherry" || $stem_profile == "cherry_rounded")){
color([1,0,0, 0.5]){
if($stem_type == "cherry" || $stem_type == "cherry_rounded"){
color(transparent_red){
translate([0,0,3.6 + $stem_inset - 5]) {
%hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
%hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
cherry_keyswitch();
}
}
}
}
// legends / artisan support
module artisan(legend, depth) {
top_of_key() {
// outset legend
if (legend != "") keytext(legend, depth);
// artisan objects / outset shape legends
children();
}
}
// key with hollowed inside but no stem
module keytop() {
difference(){
if ($rounded_key) {
@ -208,30 +236,50 @@ module keytop() {
} else {
shape(0, 0);
}
translate([0,0,-0.01]) shape($wall_thickness, $keytop_thickness);
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
shape($wall_thickness, $keytop_thickness);
}
}
}
// The final, penultimate key generation function.
// takes all the bits and glues them together. requires configuration with special variables.
module key() {
module key(legend = "", inset = false) {
difference() {
union(){
// the shape of the key, inside and out
keytop();
if($stem_profile != "blank") connectors();
if(!$inset_text) keytext();
clearance_check();
top_of_key() {
children();
}
// additive objects at the top of the key
if(!inset) artisan(legend) children();
// render the clearance check if it's enabled, but don't have it intersect with anything
if ($clearance_check) %clearance_check();
}
// subtractive objects at the top of the key
if (inset) artisan(legend, 0.3) children();
// subtract the clearance check if it's enabled, letting the user see the
// parts of the keycap that will hit the cherry switch
if ($clearance_check) clearance_check();
}
// both stem and support are optional
if ($stem_type){
dished($keytop_thickness, $inverted_dish) {
translate([0, 0, $stem_inset]) keystems();
}
}
if ($support_type){
inside() {
translate([0, 0, $stem_inset]) keystem_supports();
}
if ($inset_text) keytext();
}
}
// actual full key with space carved out and keystem/stabilizer connectors
// this is an example key with all the fixins
// this is an example key with all the fixins from settings.scad
module example_key(){
include <settings.scad>
key();

View File

@ -27,7 +27,7 @@ $total_depth = 11.5;
$top_tilt = -6;
// how skewed towards the back the top is (0 for center)
$top_skew = 1.7;
// what type of dish the key has. 0 for cylindrical, 1 for spherical, 2 for something else idk TODO
// what type of dish the key has. note that unlike stems and supports a dish ALWAYS gets rendered.
$dish_type = "cylindrical";
// how deep the dish 'digs' into the top of the keycap. this is max depth, so you can't find the height from total_depth - dish_depth. besides the top is skewed anyways
$dish_depth = 1;
@ -51,25 +51,21 @@ $connectors = $stabilizers ? [[0,0],[-50,0],[50,0]] : [[0,0]];
$linear_extrude_shape = false;
//should the key be rounded? unnecessary for most printers, and very slow
$rounded_key = false;
// 'cherry', 'alps' or 'cherry_rounded'
$stem_profile = "cherry";
// what type of stem you want. To turn off stems pass false. "cherry", "alps", and "cherry_rounded" supported
$stem_type = "cherry";
// how much higher the stem is than the bottom of the keycap.
// inset stem requires support but is more accurate in some profiles
$stem_inset = 0;
// how many degrees to rotate the stems. useful for sideways keycaps, maybe
$stem_rotation = 0;
//text to be rendered in the center of the key, if any
$text = "";
// is the text on the key inset? inset text is still experimental
$inset_text = false;
// radius of corners of keycap
$corner_radius = 1;
// keystem slop - lengthens the cross and thins out the connector
$slop = 0.3;
// support type. default is 'flared' for easy FDM printing
$stem_slop = 0.3;
// support type. default is "flared" for easy FDM printing. to disable pass false
$support_type = "flared";
// key shape type. default is 'normal'. only other supported option is 'iso_enter'
$key_shape_type = "normal";
// key shape type, determines the shape of the key. default is 'rounded square'
$key_shape_type = "rounded_square";
// ISO enter needs to be linear extruded NOT from the center. this tells the program how far up 'not from the center' is
$linear_extrude_height_adjustment = 0;
// if you need the dish to extend further, you can 'overdraw' the rectangle it will hit
@ -77,4 +73,39 @@ $dish_overdraw_width = 0;
// same as width but for height
$dish_overdraw_height = 0;
// how many slices will be made, to approximate curves on corners. Leave at 1 if you are not curving corners
// if you're doing fancy bowed keycap sides, this controls how many slices you take
$height_slices = 1;
// this enables some fancy and currently hardcoded logic to bow the sides and corners of SA keycaps
$enable_side_sculpting = false;
//minkowski radius. radius of sphere used in minkowski sum for minkowski_key function. 1.75 for G20
$minkowski_radius = .33;
// [ Stem Variables ]
// the stem is the hardest part to print, so this variable controls how much 'slop' there is in the stem
$stem_slop = 0.3;
// how tall in mm the brim is, if there is one. brim sits around the keystem and helps to secure it while printing.
$brim_height = 0.4;
// how far the throw distance of the switch is. determines how far the 'cross' in the cherry switch digs into the stem, and how long the keystem needs to be before supports can start. luckily, alps and cherries have a pretty similar throw. can modify to have stouter keycaps for low profile switches, etc
$stem_throw = 4;
// cherry stem dimensions
$cherry_stem = [7.2 - $stem_slop * 2, 5.5 - $stem_slop * 2];
// .005 purely for aesthetics, to get rid of that ugly crosshatch
$cherry_cross = [
// horizontal tine
[4.03 + $stem_slop, 1.15],
// vertical tine
[1.25, $cherry_stem[1] + .005],
];
// diameter of the outside of the rounded cherry stem
$rounded_cherry_stem_d = 5.5;
// dimensions of alps stem
$alps_stem = [4.45, 2.25];

View File

@ -10,26 +10,25 @@ function corner_sculpting(progress) = pow(progress, 2);
module key_shape(size, delta, progress = 0) {
if ($key_shape_type == "iso_enter") {
ISO_enter(size, delta, progress);
} else if ($key_shape_type == "normal") {
} else if ($key_shape_type == "rounded_square") {
roundedSquare(size, delta, progress);
} else if ($key_shape_type == "circle") {
circle(d=width);
} else if ($key_shape_type == "square") {
square(size - delta, center = true);
} else if ($key_shape_type == "obloid") {
obloid(size, delta, progress);
} else if ($key_shape_type == "spherical") {
spherical(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
}
module obloid(size, delta, progress) {
width = size[0];
height = size[1] - delta[1] * progress; // TODO if we don't account for the delta somehow 1u keys will not render as the offset margin is greater than the size of the key. this does not work however
module spherical(size, delta, progress) {
// .05 is because of offset. if we set offset to be half the height of the shape, and then subtract height from the shape, the height of the shape will be zero (because the shape would be [width - height, height - height]). that doesn't play well with openSCAD (understandably), so we add this tiny fudge factor to make sure the shape we offset has a positive width
height = size[1] - delta[1] * progress - .05;
if (progress < .5 && false) {
circle(d=5.5);
if (progress < 0.5) {
} else {
offset(r=height / 2.1) {
square(size - [height / 1.05, height / 1.05] - delta * progress, center=true);
offset(r=height / 2) {
square(size - [height, height] - delta * progress, center=true);
}
}
}

View File

@ -1,147 +1,80 @@
include <supports.scad>
brim_height = 0.4;
//whole connector, alps or cherry, trimmed to fit
module connector(stem_profile, depth, has_brim, slop, stem_inset, support_type){
echo(slop);
if (stem_profile == "alps") {
alps_stem(depth, has_brim, slop, stem_inset, support_type);
} else if (stem_profile == "cherry_rounded") {
cherry_stem_rounded(depth, has_brim, slop, stem_inset, support_type);
} else if (stem_profile == "cherry") {
cherry_stem(depth, has_brim, slop, stem_inset, support_type);
} else if (stem_profile == "filled") {
//whole stem, alps or cherry, trimmed to fit
module stem(stem_type, depth, has_brim){
if (stem_type == "alps") {
alps_stem(depth, has_brim);
} else if (stem_type == "cherry_rounded") {
cherry_stem_rounded(depth, has_brim);
} else if (stem_type == "cherry") {
cherry_stem(depth, has_brim);
} else if (stem_type == "filled") {
// just a cube, so no args
filled_stem();
} else {
echo("Warning: unsupported $stem_type");
}
}
module cherry_stem(depth, has_brim, slop, stem_inset, support_type) {
stem_width = 7.2 - slop * 2;
stem_height = 5.5 - slop * 2;
module cherry_stem(depth, has_brim) {
difference(){
union() {
// outside shape
linear_extrude(height = depth) {
offset(r=1){
square($cherry_stem - [2,2], center=true);
}
}
vertical_cross_width = 1.25;
// currently unused, as we want a split stem
vertical_cross_length = 3.93;
horizontal_cross_width = 1.15;
horizontal_cross_length = 4.03;
cross_depth = 4;
stem = [stem_width, stem_height];
vertical_cross = [vertical_cross_width, stem_height];
horizontal_cross = [horizontal_cross_length + slop, horizontal_cross_width];
translate([0,0,stem_inset]) {
difference(){
union() {
linear_extrude(height = depth) {
// brim, if applicable
if(has_brim) {
linear_extrude(height = brim_height){
offset(r=1){
square(stem - [2,2], center=true);
square($cherry_stem - [2,2], center=true);
}
}
if(has_brim) {
linear_extrude(height = brim_height){
offset(r=1){
square(stem - [2,2], center=true);
}
}
}
}
linear_extrude(height = cross_depth) {
square(vertical_cross, center=true);
square(horizontal_cross, center=true);
}
}
// supports
if (support_type == "flared") {
flared(cross_depth, (depth - cross_depth), [stem_width, stem_height]) {
roundedSquare(stem, 1, center=true);
// inside cross
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
linear_extrude(height = $stem_throw) {
square($cherry_cross[0], center=true);
square($cherry_cross[1], center=true);
}
} else if (support_type == "flat") {
flat(cross_depth, (depth - cross_depth), [stem_width, stem_height]);
} else if (support_type == "bars") {
bars(cross_depth, (depth - cross_depth), [stem_width, stem_height]);
}
}
}
module cherry_stem_rounded(depth, has_brim, slop, stem_inset, support_type) {
// cross length
cross_length = 4.4;
//dimensions of connector
// outer cross extra length in y
extra_outer_cross_height = 1.1;
// dimensions of cross
// horizontal cross bar width
horizontal_cross_width = 1.4;
// vertical cross bar width
vertical_cross_width = 1.3;
// cross depth, stem height is 3.4mm
cross_depth = 4;
module cherry_stem_rounded(depth, has_brim) {
total_diameter = cross_length+extra_outer_cross_height;
translate([0,0,stem_inset]){
difference(){
union(){
cylinder(d=total_diameter, h=depth);
if(has_brim) {
cylinder(d=total_diameter * 2, h=brim_height);
}
}
//the cross part of the steam
translate([0,0,(cross_depth)/2]){
cube([vertical_cross_width,cross_length,cross_depth], center=true );
cube([cross_length,horizontal_cross_width,cross_depth], center=true );
difference(){
union(){
cylinder(d=$rounded_cherry_stem_d, h=depth);
if(has_brim) {
cylinder(d=$rounded_cherry_stem_d * 2, h=brim_height);
}
}
// supports
if (support_type == "flared") {
flared(cross_depth, (depth - cross_depth)) {
circle(d = cross_length+extra_outer_cross_height);
// inside cross
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
linear_extrude(height = $stem_throw) {
square($cherry_cross[0], center=true);
square($cherry_cross[1], center=true);
}
} else if (support_type == "flat") {
flat(cross_depth, (depth - cross_depth));
} else if (support_type == "bars") {
bars(cross_depth, (depth - cross_depth));
}
}
}
module alps_stem(depth, has_brim, slop, stem_inset, support_type){
// not really cross depth, basically just the max length of stem we need for the key to function properly
cross_depth = 4;
width = 4.45;
height = 2.25;
base_width = 12;
base_height = 15;
translate([0,0,stem_inset]){
if(has_brim) {
translate([0,0,brim_height / 2]) cube([width*2,height*2,brim_height], center = true);
}
translate([0,0,depth/2]){
cube([width,height,depth], center = true);
module alps_stem(depth, has_brim){
if(has_brim) {
linear_extrude(h=brim_height) {
square($alps_stem * [2,2], center = true);
}
}
translate([0, 0, stem_inset]){
if (support_type == "flared") {
flared(cross_depth, (depth - cross_depth)) {
square([width,height]);
}
} else if (support_type == "flat") {
flat(cross_depth, (depth - cross_depth));
} else if (support_type == "bars") {
bars(cross_depth, (depth - cross_depth));
}
linear_extrude(h=depth) {
square($alps_stem, center = true);
}
}

View File

@ -1,19 +1,49 @@
// flared support designed for FDM printing, for the normal cherry stem
module flared(loft, height) {
// figures out the scale factor needed to make a 45 degree wall
function scale_for_45(height, starting_size) = (height * 2 + starting_size) / starting_size;
module supports(type, stem_type, loft, height) {
if (type == "flared") {
flared(stem_type, loft, height);
} else if (type == "flat") {
flat(stem_type, loft, height);
} else if (type == "bars") {
bars(stem_type, loft, height);
} else {
echo("Warning: unsupported $support_type");
}
}
// complicated since we want the different stems to work well
// also kind of messy... oh well
module flared(stem_type, loft, height) {
translate([0,0,loft]){
linear_extrude(height=height, scale = [height/2,height/2]){
children();
if(stem_type == "cherry") {
cherry_scale = [scale_for_45(height, $cherry_stem[0]), scale_for_45(height, $cherry_stem[1])];
linear_extrude(height=height, scale = cherry_scale){
offset(r=1){
square($cherry_stem - [2,2], center=true);
}
}
} else if (stem_type == "cherry_rounded") {
linear_extrude(height=height, scale = scale_for_45(height, $rounded_cherry_stem_d)){
circle(d=$rounded_cherry_stem_d);
}
} else if (stem_type == "alps") {
alps_scale = [scale_for_45(height, $alps_stem[0]), scale_for_45(height, $alps_stem[1])];
linear_extrude(height=height, scale = alps_scale){
square($alps_stem, center=true);
}
}
}
}
module flat(loft, height) {
module flat(stem_type, loft, height) {
translate([0,0,loft + 500]){
cube(1000, center=true);
}
}
module bars(loft, height) {
module bars(stem_type, loft, height) {
translate([0,0,loft + height / 2]){
cube([2, 100, height], center = true);
cube([100, 2, height], center = true);