make this library a lot more modular

This commit is contained in:
Bob - Home - Windows 2018-02-04 15:43:17 -05:00
parent 2368961370
commit aa795c4958
31 changed files with 467 additions and 443 deletions

View File

@ -8,7 +8,7 @@ Relevant links:
## Let's Go! I wanna make a keycap!
At the highest level this library supports Cherry and Alps switches, and has pre-defined key profiles for SA, DSA, DCS, and (some form of) OEM keycaps. `keys.scad` is meant as an entry point for everything but the most technical use; there should already be an example at the bottom to get you started! Pre-programmed key profiles can be found at `key_profiles.scad`.
At the highest level this library supports Cherry and Alps switches, and has pre-defined key profiles for SA, DSA, DCS, and (some form of) OEM keycaps. `keys.scad` is meant as an entry point for everything but the most technical use; there should already be an example at the bottom to get you started! Pre-programmed key profiles can be found at the `key_profiles` directory.
Every key starts with defaults that are overridden by each function call. The simplest cherry key you can make would be:
@ -29,7 +29,7 @@ sa_row(2) 2u() cherry() key();
## What if I want to customize my keycaps?
There is a bevy of supporting functions to customize your keycaps. You can add a brim to more easily print the stem, switch up the stem support type, make 2x2 keycaps for a POS system, add legends, rotate stems, and more. These functions can be found in `key_profiles.scad`, `key_sizes.scad`, `key_transformations.scad`, and `key_types.scad` currently, and can be referenced directly in `keys.scad`.
There is a bevy of supporting functions to customize your keycaps. You can add a brim to more easily print the stem, switch up the stem support type, make 2x2 keycaps for a POS system, add legends, rotate stems, and more. These functions can be found in `key_profiles/`, `key_sizes.scad`, `key_transformations.scad`, and `key_types.scad` currently, and can be referenced directly in `keys.scad`.
If you wanted to generate some 2u stabilized keycaps for an Ergodox for instance, you could do something like this:
@ -64,7 +64,7 @@ At the base level this library should function well as a key profile design libr
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.
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 that should allow you to implement your own creations alongside what already exists in their constituent folders.
Here's an example of tweaking the settings and code to make a 'stop sign' key profile:
@ -72,10 +72,18 @@ In `key_shape()` in `shapes.scad`:
```
else if ($key_shape_type == "stop_sign") {
rotate([0,0,22.5]) circle(d=size[0] - delta[0], $fn=8);
stop_sign_shape(size, delta, progress);
}
```
in `src/shapes/stop_sign.scad`:
```
module stop_sign_shape(size, delta, progress){
rotate([0,0,22.5]) circle(d=size[0] - delta[0], $fn=8);
}
```
In `keys.scad`:
```

View File

@ -1,147 +0,0 @@
// key profile definitions
module dcs_row(n=1) {
// names, so I don't go crazy
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 6;
$height_difference = 4;
$dish_type = "cylindrical";
$dish_depth = 1;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 1.75;
if (n == 5) {
$total_depth = 11.5;
$top_tilt = -6;
children();
} else if (n == 1) {
$total_depth = 8.5;
$top_tilt = -1;
children();
} else if (n == 2) {
$total_depth = 7.5;
$top_tilt = 3;
children();
} else if (n == 3) {
$total_depth = 6;
$top_tilt = 7;
children();
} else if (n == 4) {
$total_depth = 6;
$top_tilt = 16;
children();
}
}
module oem_row(n=1) {
$bottom_key_width = 18.05;
$bottom_key_height = 18.05;
$width_difference = 5.8;
$height_difference = 4;
$dish_type = "cylindrical";
$dish_depth = 1;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 1.75;
$stem_inset = 1.2;
if (n == 5) {
$total_depth = 11.2;
$top_tilt = -3;
children();
} else if (n == 1) {
$total_depth = 9.45;
$top_tilt = 1;
children();
} else if (n == 2) {
$total_depth = 9;
$top_tilt = 6;
children();
} else if (n == 3) {
$total_depth = 9.25;
$top_tilt = 9;
children();
} else if (n == 4) {
$total_depth = 9.25;
$top_tilt = 10;
children();
}
}
module dsa_row(n=3) {
$bottom_key_width = 18.24; // 18.4;
$bottom_key_height = 18.24; // 18.4;
$width_difference = 6; // 5.7;
$height_difference = 6; // 5.7;
$total_depth = 8.1;
$top_tilt = (n-1) * 7 - 14;
$top_skew = 0;
$dish_type = "spherical";
$dish_depth = 1.2;
$dish_skew_x = 0;
$dish_skew_y = 0;
$height_slices = 10;
$enable_side_sculpting = true;
// might wanna change this if you don't minkowski
// do you even minkowski bro
$corner_radius = 0.25;
children();
}
module sa_row(n=1) {
$bottom_key_width = 18.4;
$bottom_key_height = 18.4;
$width_difference = 5.7;
$height_difference = 5.7;
$dish_type = "spherical";
$dish_depth = 0.85;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 0;
$height_slices = 10;
$enable_side_sculpting = true;
// might wanna change this if you don't minkowski
// do you even minkowski bro
$corner_radius = 0.25;
if (n == 1){
$total_depth = 14.89;
$top_tilt = -13;
children();
} else if (n == 2) {
$total_depth = 12.925;
$top_tilt = -7;
children();
} else if (n == 3) {
$total_depth = 12.5;
$top_tilt = 0;
children();
} else if (n == 4){
$total_depth = 12.925;
$top_tilt = 7;
children();
}
}
module g20() {
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 2;
$height_difference = 2;
$total_depth = 6;
$top_tilt = 2.5;
$top_skew = 0.75;
$dish_type = "no dish";
$dish_depth = 0;
$dish_skew_x = 0;
$dish_skew_y = 0;
$minkowski_radius = 1.75;
children();
//also,
/*$rounded_key = true;*/
}

View File

@ -11,10 +11,10 @@ unit = 19.05;
use <src/key.scad>
include <src/settings.scad>
include <key_sizes.scad>
include <key_profiles.scad>
include <key_types.scad>
include <key_transformations.scad>
include <src/key_sizes.scad>
include <src/key_profiles.scad>
include <src/key_types.scad>
include <src/key_transformations.scad>
module translate_u(x=0, y=0, z=0){
translate([x * unit, y*unit, z*unit]) children();
@ -25,7 +25,7 @@ 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(3) dsa_row() flat_support() rounded_cherry() key();
translate_u(1, 1) sa_row(3) lshift() cherry() key(inset=true) {
sphere(1);
@ -34,8 +34,15 @@ translate_u(1, 1) sa_row(3) lshift() cherry() key(inset=true) {
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";
$key_shape_type = "oblong";
$support_type = false;
$inverted_dish = true;
key();
}
/* // g20 / dsa sculpting test
for (x = [1:5]) {
translate_u(0, x) dsa_row(x) cherry() key();
translate_u(1, x) g20_row(x) cherry() key();
} */

View File

@ -1,5 +1,10 @@
include <libraries/geodesic_sphere.scad>
include <shapes.scad>
include <dishes/cylindrical.scad>
include <dishes/old_spherical.scad>
include <dishes/sideways_cylindrical.scad>
include <dishes/spherical.scad>
//geodesic looks much better, but runs very slow for anything above a 2u
geodesic=false;
@ -18,93 +23,7 @@ module dish(width, height, depth, inverted) {
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
// switchted to actually diffing a cube here due to changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
}
module cylindrical_dish(width, height, depth, inverted){
// .5 has problems starting around 3u
$fa=.25;
/* we do some funky math here
* basically you want to have the dish "dig in" to the keycap x millimeters
* in order to do that you have to solve a small (2d) system of equations
* where the chord of the spherical cross section of the dish is
* the width of the keycap.
*/
// the distance you have to move the dish so it digs in depth millimeters
chord_length = (pow(width, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(width, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
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){
$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;
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){
//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
// the distance you have to move the dish up so it digs in depth millimeters
chord_length = (pow(chord, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
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){
//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
// the distance you have to move the dish up so it digs in depth millimeters
chord_length = (pow(chord, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
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

@ -0,0 +1,19 @@
module cylindrical_dish(width, height, depth, inverted){
// .5 has problems starting around 3u
$fa=.25;
/* we do some funky math here
* basically you want to have the dish "dig in" to the keycap x millimeters
* in order to do that you have to solve a small (2d) system of equations
* where the chord of the spherical cross section of the dish is
* the width of the keycap.
*/
// the distance you have to move the dish so it digs in depth millimeters
chord_length = (pow(width, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(width, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
translate([0,0, chord_length * direction]){
rotate([90, 0, 0]) cylinder(h=height + 20, r=rad, center=true);
}
}

View File

@ -0,0 +1,25 @@
//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){
//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
// the distance you have to move the dish up so it digs in depth millimeters
chord_length = (pow(chord, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
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

@ -0,0 +1,12 @@
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;
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
}
}

26
src/dishes/spherical.scad Normal file
View File

@ -0,0 +1,26 @@
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
// the distance you have to move the dish up so it digs in depth millimeters
chord_length = (pow(chord, 2) - 4 * pow(depth, 2)) / (8 * depth);
//the radius of the dish
rad = (pow(chord, 2) + 4 * pow(depth, 2)) / (8 * depth);
direction = inverted ? -1 : 1;
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);
}
}
}
}

8
src/key_profiles.scad Normal file
View File

@ -0,0 +1,8 @@
// key profile definitions
// unlike the other files with their own dedicated folders, this one doesn't need a selector. it just collects all the functions
include <key_profiles/dcs.scad>
include <key_profiles/oem.scad>
include <key_profiles/dsa.scad>
include <key_profiles/sa.scad>
include <key_profiles/g20.scad>

34
src/key_profiles/dcs.scad Normal file
View File

@ -0,0 +1,34 @@
module dcs_row(n=1) {
// names, so I don't go crazy
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 6;
$height_difference = 4;
$dish_type = "cylindrical";
$dish_depth = 1;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 1.75;
if (n == 5) {
$total_depth = 11.5;
$top_tilt = -6;
children();
} else if (n == 1) {
$total_depth = 8.5;
$top_tilt = -1;
children();
} else if (n == 2) {
$total_depth = 7.5;
$top_tilt = 3;
children();
} else if (n == 3) {
$total_depth = 6;
$top_tilt = 7;
children();
} else if (n == 4) {
$total_depth = 6;
$top_tilt = 16;
children();
}
}

20
src/key_profiles/dsa.scad Normal file
View File

@ -0,0 +1,20 @@
module dsa_row(n=3) {
$bottom_key_width = 18.24; // 18.4;
$bottom_key_height = 18.24; // 18.4;
$width_difference = 6; // 5.7;
$height_difference = 6; // 5.7;
$total_depth = 8.1 + abs((n-3) * 1);
$top_tilt = (n-3) * -7;
$top_skew = 0;
$dish_type = "spherical";
$dish_depth = 1.2;
$dish_skew_x = 0;
$dish_skew_y = 0;
$height_slices = 10;
$enable_side_sculpting = true;
// might wanna change this if you don't minkowski
// do you even minkowski bro
$corner_radius = 0.25;
children();
}

20
src/key_profiles/g20.scad Normal file
View File

@ -0,0 +1,20 @@
module g20_row(n=3) {
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 2;
$height_difference = 2;
$total_depth = 6;
$top_tilt = 2.5;
$top_tilt = (n-3) * -7 + 2.5;
$top_skew = 0.75;
$dish_type = "no dish";
$dish_depth = 0;
$dish_skew_x = 0;
$dish_skew_y = 0;
$minkowski_radius = 1.75;
//also,
/*$rounded_key = true;*/
children();
}

34
src/key_profiles/oem.scad Normal file
View File

@ -0,0 +1,34 @@
module oem_row(n=1) {
$bottom_key_width = 18.05;
$bottom_key_height = 18.05;
$width_difference = 5.8;
$height_difference = 4;
$dish_type = "cylindrical";
$dish_depth = 1;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 1.75;
$stem_inset = 1.2;
if (n == 5) {
$total_depth = 11.2;
$top_tilt = -3;
children();
} else if (n == 1) {
$total_depth = 9.45;
$top_tilt = 1;
children();
} else if (n == 2) {
$total_depth = 9;
$top_tilt = 6;
children();
} else if (n == 3) {
$total_depth = 9.25;
$top_tilt = 9;
children();
} else if (n == 4) {
$total_depth = 9.25;
$top_tilt = 10;
children();
}
}

34
src/key_profiles/sa.scad Normal file
View File

@ -0,0 +1,34 @@
module sa_row(n=1) {
$bottom_key_width = 18.4;
$bottom_key_height = 18.4;
$width_difference = 5.7;
$height_difference = 5.7;
$dish_type = "spherical";
$dish_depth = 0.85;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 0;
$height_slices = 10;
$enable_side_sculpting = true;
// might wanna change this if you don't minkowski
// do you even minkowski bro
$corner_radius = 0.25;
if (n == 1){
$total_depth = 14.89;
$top_tilt = -13;
children();
} else if (n == 2) {
$total_depth = 12.925;
$top_tilt = -7;
children();
} else if (n == 3) {
$total_depth = 12.5;
$top_tilt = 0;
children();
} else if (n == 4){
$total_depth = 12.925;
$top_tilt = 7;
children();
}
}

View File

@ -1,96 +1,21 @@
$fs=.1;
unit = 19.05;
// side sculpting functions
// bows the sides out on stuff like SA and DSA keycaps
function side_sculpting(progress) = (1 - progress) * 2.5;
// makes the rounded corners of the keycap grow larger as they move upwards
function corner_sculpting(progress) = pow(progress, 2);
include <shapes/ISO_enter.scad>
include <shapes/rounded_square.scad>
include <shapes/square.scad>
include <shapes/oblong.scad>
module key_shape(size, delta, progress = 0) {
if ($key_shape_type == "iso_enter") {
ISO_enter(size, delta, progress);
ISO_enter_shape(size, delta, progress);
} else if ($key_shape_type == "rounded_square") {
roundedSquare(size, delta, progress);
rounded_square_shape(size, delta, progress);
} else if ($key_shape_type == "square") {
square(size - delta, center = true);
} else if ($key_shape_type == "spherical") {
spherical(size, delta, progress);
square_shape(size, delta, progress);
} else if ($key_shape_type == "oblong") {
oblong_shape(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
}
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 < 0.5) {
} else {
offset(r=height / 2) {
square(size - [height, height] - delta * progress, center=true);
}
}
}
module roundedSquare(size, delta, progress, center = true) {
width = size[0];
height = size[1];
width_difference = delta[0];
height_difference = delta[1];
// makes the sides bow
extra_side_size = $enable_side_sculpting ? side_sculpting(progress) : 0;
// makes the rounded corners of the keycap grow larger as they move upwards
extra_corner_size = $enable_side_sculpting ? corner_sculpting(progress) : 0;
// computed values for this slice
extra_width_this_slice = (width_difference - extra_side_size) * progress;
extra_height_this_slice = (height_difference - extra_side_size) * progress;
extra_corner_radius_this_slice = ($corner_radius + extra_corner_size);
offset(r=extra_corner_radius_this_slice){
square(
[
width - extra_width_this_slice - extra_corner_radius_this_slice * 2,
height - extra_height_this_slice - extra_corner_radius_this_slice * 2
],
center=center
);
}
}
// corollary is roundedSquare
// NOT 3D
module ISO_enter(size, delta, progress){
width = size[0];
height = size[1];
function unit_length(length) = unit * (length - 1) + 18.16;
// in order to make the ISO keycap shape generic, we are going to express the
// 'elbow point' in terms of ratios. an ISO enter is just a 1.5u key stuck on
// top of a 1.25u key, but since our key_shape function doesnt understand that
// and wants to pass just width and height, we make these ratios to know where
// to put the elbow joint
width_ratio = unit_length(1.25) / unit_length(1.5);
height_ratio = unit_length(1) / unit_length(2);
pointArray = [
[ 0, 0], // top right
[ 0, -height], // bottom right
[-width * width_ratio, -height], // bottom left
[-width * width_ratio,-height * height_ratio], // inner middle point
[ -width,-height * height_ratio], // outer middle point
[ -width, 0] // top left
];
minkowski(){
circle(r=corner_size);
// gives us rounded inner corner
offset(r=-corner_size*2) {
translate([(width * width_ratio)/2, height/2]) polygon(points=pointArray);
}
}
}

34
src/shapes/ISO_enter.scad Normal file
View File

@ -0,0 +1,34 @@
// corollary is rounded_square
// NOT 3D
module ISO_enter_shape(size, delta, progress){
width = size[0];
height = size[1];
function unit_length(length) = unit * (length - 1) + 18.16;
// in order to make the ISO keycap shape generic, we are going to express the
// 'elbow point' in terms of ratios. an ISO enter is just a 1.5u key stuck on
// top of a 1.25u key, but since our key_shape function doesnt understand that
// and wants to pass just width and height, we make these ratios to know where
// to put the elbow joint
width_ratio = unit_length(1.25) / unit_length(1.5);
height_ratio = unit_length(1) / unit_length(2);
pointArray = [
[ 0, 0], // top right
[ 0, -height], // bottom right
[-width * width_ratio, -height], // bottom left
[-width * width_ratio,-height * height_ratio], // inner middle point
[ -width,-height * height_ratio], // outer middle point
[ -width, 0] // top left
];
minkowski(){
circle(r=corner_size);
// gives us rounded inner corner
offset(r=-corner_size*2) {
translate([(width * width_ratio)/2, height/2]) polygon(points=pointArray);
}
}
}

11
src/shapes/oblong.scad Normal file
View File

@ -0,0 +1,11 @@
module oblong_shape(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 < 0.5) {
} else {
offset(r=height / 2) {
square(size - [height, height] - delta * progress, center=true);
}
}
}

View File

@ -0,0 +1,32 @@
// side sculpting functions
// bows the sides out on stuff like SA and DSA keycaps
function side_sculpting(progress) = (1 - progress) * 2.5;
// makes the rounded corners of the keycap grow larger as they move upwards
function corner_sculpting(progress) = pow(progress, 2);
module rounded_square_shape(size, delta, progress, center = true) {
width = size[0];
height = size[1];
width_difference = delta[0];
height_difference = delta[1];
// makes the sides bow
extra_side_size = $enable_side_sculpting ? side_sculpting(progress) : 0;
// makes the rounded corners of the keycap grow larger as they move upwards
extra_corner_size = $enable_side_sculpting ? corner_sculpting(progress) : 0;
// computed values for this slice
extra_width_this_slice = (width_difference - extra_side_size) * progress;
extra_height_this_slice = (height_difference - extra_side_size) * progress;
extra_corner_radius_this_slice = ($corner_radius + extra_corner_size);
offset(r=extra_corner_radius_this_slice){
square(
[
width - extra_width_this_slice - extra_corner_radius_this_slice * 2,
height - extra_height_this_slice - extra_corner_radius_this_slice * 2
],
center=center
);
}
}

3
src/shapes/square.scad Normal file
View File

@ -0,0 +1,3 @@
module square_shape(size, delta, progress){
square(size - delta * progress, center = true);
}

View File

@ -1,85 +1,20 @@
include <stems/cherry.scad>
include <stems/rounded_cherry.scad>
include <stems/alps.scad>
include <stems/filled.scad>
//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);
rounded_cherry_stem(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) {
difference(){
union() {
// outside shape
linear_extrude(height = depth) {
offset(r=1){
square($cherry_stem - [2,2], center=true);
}
}
// brim, if applicable
if(has_brim) {
linear_extrude(height = brim_height){
offset(r=1){
square($cherry_stem - [2,2], 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);
}
}
}
}
module cherry_stem_rounded(depth, has_brim) {
difference(){
union(){
cylinder(d=$rounded_cherry_stem_d, h=depth);
if(has_brim) {
cylinder(d=$rounded_cherry_stem_d * 2, h=brim_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);
}
}
}
}
module alps_stem(depth, has_brim){
if(has_brim) {
linear_extrude(h=brim_height) {
square($alps_stem * [2,2], center = true);
}
}
linear_extrude(h=depth) {
square($alps_stem, center = true);
}
}
module filled_stem() {
// this is mostly for testing. we don't pass the size of the keycp in here
// so we can't make this work for all keys
cube(1000, center=true);
}

10
src/stems/alps.scad Normal file
View File

@ -0,0 +1,10 @@
module alps_stem(depth, has_brim){
if(has_brim) {
linear_extrude(h=brim_height) {
square($alps_stem * [2,2], center = true);
}
}
linear_extrude(h=depth) {
square($alps_stem, center = true);
}
}

30
src/stems/cherry.scad Normal file
View File

@ -0,0 +1,30 @@
module cherry_stem(depth, has_brim) {
difference(){
union() {
// outside shape
linear_extrude(height = depth) {
offset(r=1){
square($cherry_stem - [2,2], center=true);
}
}
// brim, if applicable
if(has_brim) {
linear_extrude(height = brim_height){
offset(r=1){
square($cherry_stem - [2,2], 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);
}
}
}
}

5
src/stems/filled.scad Normal file
View File

@ -0,0 +1,5 @@
module filled_stem() {
// this is mostly for testing. we don't pass the size of the keycp in here
// so we can't make this work for all keys
cube(1000, center=true);
}

View File

@ -0,0 +1,19 @@
module rounded_cherry_stem(depth, has_brim) {
difference(){
union(){
cylinder(d=$rounded_cherry_stem_d, h=depth);
if(has_brim) {
cylinder(d=$rounded_cherry_stem_d * 2, h=brim_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);
}
}
}
}

View File

@ -1,51 +1,15 @@
// 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;
include <supports/flared.scad>
include <supports/flat.scad>
include <supports/bars.scad>
module supports(type, stem_type, loft, height) {
if (type == "flared") {
flared(stem_type, loft, height);
flared_support(stem_type, loft, height);
} else if (type == "flat") {
flat(stem_type, loft, height);
flat_support(stem_type, loft, height);
} else if (type == "bars") {
bars(stem_type, loft, height);
bars_support(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]){
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(stem_type, loft, height) {
translate([0,0,loft + 500]){
cube(1000, center=true);
}
}
module bars(stem_type, loft, height) {
translate([0,0,loft + height / 2]){
cube([2, 100, height], center = true);
cube([100, 2, height], center = true);
}
}

6
src/supports/bars.scad Normal file
View File

@ -0,0 +1,6 @@
module bars_support(stem_type, loft, height) {
translate([0,0,loft + height / 2]){
cube([2, 100, height], center = true);
cube([100, 2, height], center = true);
}
}

26
src/supports/flared.scad Normal file
View File

@ -0,0 +1,26 @@
// 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;
// complicated since we want the different stems to work well
// also kind of messy... oh well
module flared_support(stem_type, loft, height) {
translate([0,0,loft]){
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);
}
}
}
}

5
src/supports/flat.scad Normal file
View File

@ -0,0 +1,5 @@
module flat_support(stem_type, loft, height) {
translate([0,0,loft + 500]){
cube(1000, center=true);
}
}