6 Commits

Author SHA1 Message Date
Bob
fd68c281c3 Custom stem example
Here's how to implement a custom stem
2020-07-10 01:14:25 -04:00
Bob
24e280fe3c quick stem updates
probably best to pass the stem throw to the stems eh?
2020-07-10 00:46:06 -04:00
Bob
69175f08e4 Merge pull request #53 from rsheldiii/cherry-profile
Add cherry profile
2020-06-18 16:14:40 -04:00
Bob
f4f595c651 Add cherry profile 2020-06-18 16:11:35 -04:00
Bob
fa49ee0c70 Merge pull request #46 from rsheldiii/3d_surface
Add 3d surface beta dish
2020-05-13 00:43:48 -04:00
Bob
9e3f5f4bcd Add 3d surface beta dish 2020-05-12 22:25:51 -04:00
18 changed files with 703 additions and 56 deletions

View File

@@ -52,7 +52,7 @@ $outset_legends = false;
// Height in units of key. should remain 1 for most uses
$key_height = 1.0;
// Keytop thickness, aka how many millimeters between the inside and outside of the top surface of the key
$keytop_thickness = 2;
$keytop_thickness = 1;
// Wall thickness, aka the thickness of the sides of the keycap. note this is the total thickness, aka 3 = 1.5mm walls
$wall_thickness = 3;
// Radius of corners of keycap
@@ -199,19 +199,16 @@ $tertiary_color = [1, .6941, .2];
$quaternary_color = [.4078, .3569, .749];
$warning_color = [1,0,0, 0.15];
// 3d surface variables
// see functions.scad for the surface function
$3d_surface_size = 10;
$3d_surface_step = 1;
// normally the bottom of the keytop looks like the top - curved, at least
// underneath the support structure. This ensures there's a minimum thickness for the
// underside of the keycap, but it's a fair bit of geometry
$flat_keytop_bottom = true;
// how many facets circles will have when used in these features
$minkowski_facets = 30;
$shape_facets =30;
// 3d surface settings
// unused for now
$3d_surface_size = 100;
// resolution in each axis. 10 = 10 divisions per x/y = 100 points total
$3d_surface_step = 10;
// key width functions
module u(u=1) {
@@ -591,6 +588,54 @@ module grid_row(row=3, column = 0) {
children();
}
}
// based off GMK keycap set
module cherry_row(row=3, column=0) {
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = $bottom_key_width - 11.85;
$height_difference = $bottom_key_height - 14.64;
$dish_type = "cylindrical";
$dish_depth = 0.65;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 2;
$top_tilt_y = side_tilt(column);
extra_height = $double_sculpted ? extra_side_tilt_height(column) : 0;
// NOTE: cherry keycaps have this stem inset, but I'm reticent to turn it on
// since it'll be surprising to folks. the height has been adjusted accordingly
// $stem_inset = 0.6;
extra_stem_inset_height = max(0.6 - $stem_inset, 0);
// <= is a hack so you can do these in a for loop. function row = 0
if (row <= 1) {
$total_depth = 9.8 - extra_stem_inset_height + extra_height;
$top_tilt = 0;
children();
} else if (row == 2) {
$total_depth = 7.45 - extra_stem_inset_height + extra_height;
$top_tilt = 2.5;
children();
} else if (row == 3) {
$total_depth = 6.55 - extra_stem_inset_height + extra_height;
$top_tilt = 5;
children();
} else if (row == 3) {
$total_depth = 6.7 + 0.65 - extra_stem_inset_height + extra_height;
$top_tilt = 11.5;
children();
} else if (row >= 4) {
$total_depth = 6.7 + 0.65 - extra_stem_inset_height + extra_height;
$top_tilt = 11.5;
children();
} else {
children();
}
}
// man, wouldn't it be so cool if functions were first order
module key_profile(key_profile_type, row, column=0) {
@@ -608,6 +653,8 @@ module key_profile(key_profile_type, row, column=0) {
hipro_row(row, column) children();
} else if (key_profile_type == "grid") {
grid_row(row, column) children();
} else if (key_profile_type == "cherry") {
cherry_row(row, column) children();
} else if (key_profile_type == "disable") {
children();
} else {
@@ -925,6 +972,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
$fs=.1;
unit = 19.05;
@@ -1200,6 +1266,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
function sign_x(i,n) =
i < n/4 || i > n*3/4 ? 1 :
i > n/4 && i < n*3/4 ? -1 :
@@ -1367,6 +1452,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -1390,7 +1494,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1444,6 +1548,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
SMALLEST_POSSIBLE = 1/128;
// I use functions when I need to compute special variables off of other special variables
@@ -1487,6 +1610,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -1510,7 +1652,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1523,7 +1665,7 @@ module cherry_stem(depth, slop) {
}
}
module rounded_cherry_stem(depth, slop) {
module rounded_cherry_stem(depth, slop, throw) {
difference(){
cylinder(d=$rounded_cherry_stem_d, h=depth);
@@ -1574,6 +1716,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
SMALLEST_POSSIBLE = 1/128;
// I use functions when I need to compute special variables off of other special variables
@@ -1617,6 +1778,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -1640,7 +1820,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1653,7 +1833,7 @@ module cherry_stem(depth, slop) {
}
}
module box_cherry_stem(depth, slop) {
module box_cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1666,12 +1846,12 @@ module box_cherry_stem(depth, slop) {
inside_cherry_cross(slop);
}
}
module alps_stem(depth, has_brim, slop){
module alps_stem(depth, slop, throw){
linear_extrude(height=depth) {
square($alps_stem, center = true);
}
}
module filled_stem() {
module filled_stem(_depth, _slop, _throw) {
// I broke the crap out of this stem type due to the changes I made around how stems are differenced
// now that we just take the dish out of stems in order to support stuff like
// bare stem keycaps (and buckling spring eventually) we can't just make a
@@ -1723,6 +1903,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -1738,7 +1937,7 @@ module inside_cherry_stabilizer_cross(slop) {
}
}
module cherry_stabilizer_stem(depth, slop) {
module cherry_stabilizer_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1750,22 +1949,36 @@ module cherry_stabilizer_stem(depth, slop) {
inside_cherry_stabilizer_cross(slop);
}
}
thickness = .84;
inner_stem_size = [6,4];
outer_stem_size = inner_stem_size + [thickness, thickness];
module custom_stem(depth, slop, throw){
linear_extrude(height=depth) {
difference() {
square(outer_stem_size + [slop,slop], center = true);
square(inner_stem_size + [slop,slop], center = true);
}
}
}
//whole stem, alps or cherry, trimmed to fit
module stem(stem_type, depth, slop){
module stem(stem_type, depth, slop, throw){
if (stem_type == "alps") {
alps_stem(depth, slop);
alps_stem(depth, slop, throw);
} else if (stem_type == "cherry" || stem_type == "costar_stabilizer") {
cherry_stem(depth, slop);
cherry_stem(depth, slop, throw);
} else if (stem_type == "rounded_cherry") {
rounded_cherry_stem(depth, slop);
rounded_cherry_stem(depth, slop, throw);
} else if (stem_type == "box_cherry") {
box_cherry_stem(depth, slop);
box_cherry_stem(depth, slop, throw);
} else if (stem_type == "filled") {
filled_stem();
} else if (stem_type == "cherry_stabilizer") {
cherry_stabilizer_stem(depth, slop);
cherry_stabilizer_stem(depth, slop, throw);
} else if (stem_type == "custom") {
custom_stem(depth, slop, throw);
} else if (stem_type == "disable") {
children();
} else {
@@ -1815,6 +2028,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
SMALLEST_POSSIBLE = 1/128;
// I use functions when I need to compute special variables off of other special variables
@@ -1858,6 +2090,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -1881,7 +2132,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -1980,6 +2231,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
SMALLEST_POSSIBLE = 1/128;
// I use functions when I need to compute special variables off of other special variables
@@ -2023,6 +2293,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// extra length to the vertical tine of the inside cherry cross
// splits the stem into halves - allows easier fitment
extra_vertical = 0.6;
@@ -2046,7 +2335,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {
@@ -2347,6 +2636,158 @@ module spherical_dish(width, height, depth, inverted){
module flat_dish(width, height, depth, inverted){
cube([width + 100,height + 100, depth], center=true);
}
// thanks Paul https://github.com/openscad/list-comprehension-demos/
SMALLEST_POSSIBLE = 1/128;
// I use functions when I need to compute special variables off of other special variables
// functions need to be explicitly included, unlike special variables, which
// just need to have been set before they are used. hence this file
// cherry stem dimensions
function outer_cherry_stem(slop) = [7.2 - slop * 2, 5.5 - slop * 2];
// cherry stabilizer stem dimensions
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
// box (kailh) switches have a bit less to work with
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
// .005 purely for aesthetics, to get rid of that ugly crosshatch
function cherry_cross(slop, extra_vertical = 0) = [
// horizontal tine
[4.03 + slop, 1.25 + slop / 3],
// vertical tine
[1.15 + slop / 3, 4.23 + extra_vertical + slop / 3 + SMALLEST_POSSIBLE],
];
// actual mm key width and height
function total_key_width(delta = 0) = $bottom_key_width + $unit * ($key_length - 1) - delta;
function total_key_height(delta = 0) = $bottom_key_height + $unit * ($key_height - 1) - delta;
// actual mm key width and height at the top
function top_total_key_width() = $bottom_key_width + ($unit * ($key_length - 1)) - $width_difference;
function top_total_key_height() = $bottom_key_height + ($unit * ($key_height - 1)) - $height_difference;
function side_tilt(column) = asin($unit * column / $double_sculpt_radius);
// tan of 0 is 0, division by 0 is nan, so we have to guard
function extra_side_tilt_height(column) = side_tilt(column) ? ($double_sculpt_radius - (unit * abs(column)) / tan(abs(side_tilt(column)))) : 0;
// (I think) extra length of the side of the keycap due to the keytop being tilted.
// necessary for calculating flat sided keycaps
function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_key_height() - $corner_radius * 2) * 0.5;
// how much you have to expand the front or back of the keytop to make the side
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
module 3d_surface(size=$3d_surface_size, step=$3d_surface_step, bottom=-SMALLEST_POSSIBLE){
function p(x, y) = [ x, y, max(0,surface_function(x, y)) ];
function p0(x, y) = [ x, y, bottom ];
function rev(b, v) = b ? v : [ v[3], v[2], v[1], v[0] ];
function face(x, y) = [ p(x, y + step), p(x + step, y + step), p(x + step, y), p(x + step, y), p(x, y), p(x, y + step) ];
function fan(a, i) =
a == 0 ? [ [ 0, 0, bottom ], [ i, -size, bottom ], [ i + step, -size, bottom ] ]
: a == 1 ? [ [ 0, 0, bottom ], [ i + step, size, bottom ], [ i, size, bottom ] ]
: a == 2 ? [ [ 0, 0, bottom ], [ -size, i + step, bottom ], [ -size, i, bottom ] ]
: [ [ 0, 0, bottom ], [ size, i, bottom ], [ size, i + step, bottom ] ];
function sidex(x, y) = [ p0(x, y), p(x, y), p(x + step, y), p0(x + step, y) ];
function sidey(x, y) = [ p0(x, y), p(x, y), p(x, y + step), p0(x, y + step) ];
points = flatten(concat(
// top surface
[ for (x = [ -size : step : size - step ], y = [ -size : step : size - step ]) face(x, y) ],
// bottom surface as triangle fan
[ for (a = [ 0 : 3 ], i = [ -size : step : size - step ]) fan(a, i) ],
// sides
[ for (x = [ -size : step : size - step ], y = [ -size, size ]) rev(y < 0, sidex(x, y)) ],
[ for (y = [ -size : step : size - step ], x = [ -size, size ]) rev(x > 0, sidey(x, y)) ]
));
tcount = 2 * pow(2 * size / step, 2) + 8 * size / step;
scount = 8 * size / step;
tfaces = [ for (a = [ 0 : 3 : 3 * (tcount - 1) ] ) [ a, a + 1, a + 2 ] ];
sfaces = [ for (a = [ 3 * tcount : 4 : 3 * tcount + 4 * scount ] ) [ a, a + 1, a + 2, a + 3 ] ];
faces = concat(tfaces, sfaces);
polyhedron(points, faces, convexity = 8);
}
module polar_3d_surface(size=$3d_surface_size, step=$3d_surface_step, bottom=-SMALLEST_POSSIBLE){
function to_polar(q, size) = q * (90 / size);
function p(x, y) = [
surface_distribution_function(to_polar(x, size), size),
surface_distribution_function(to_polar(y, size), size),
max(0,surface_function(surface_distribution_function(to_polar(x, size), size), surface_distribution_function(to_polar(y, size), size)))
];
function p0(x, y) = [ x, y, bottom ];
function rev(b, v) = b ? v : [ v[3], v[2], v[1], v[0] ];
function face(x, y) = [ p(x, y + step), p(x + step, y + step), p(x + step, y), p(x + step, y), p(x, y), p(x, y + step) ];
function fan(a, i) =
a == 0 ? [ [ 0, 0, bottom ], [ i, -size, bottom ], [ i + step, -size, bottom ] ]
: a == 1 ? [ [ 0, 0, bottom ], [ i + step, size, bottom ], [ i, size, bottom ] ]
: a == 2 ? [ [ 0, 0, bottom ], [ -size, i + step, bottom ], [ -size, i, bottom ] ]
: [ [ 0, 0, bottom ], [ size, i, bottom ], [ size, i + step, bottom ] ];
function sidex(x, y) = [ p0(x, y), p(x, y), p(x + step, y), p0(x + step, y) ];
function sidey(x, y) = [ p0(x, y), p(x, y), p(x, y + step), p0(x, y + step) ];
points = flatten(concat(
// top surface
[ for (x = [ -size : step : size - step ], y = [ -size : step : size - step ]) face(x, y) ],
// bottom surface as triangle fan
[ for (a = [ 0 : 3 ], i = [ -size : step : size - step ]) fan(a, i) ],
// sides
[ for (x = [ -size : step : size - step ], y = [ -size, size ]) rev(y < 0, sidex(x, y)) ],
[ for (y = [ -size : step : size - step ], x = [ -size, size ]) rev(x > 0, sidey(x, y)) ]
));
tcount = 2 * pow(2 * size / step, 2) + 8 * size / step;
scount = 8 * size / step;
tfaces = [ for (a = [ 0 : 3 : 3 * (tcount - 1) ] ) [ a, a + 1, a + 2 ] ];
sfaces = [ for (a = [ 3 * tcount : 4 : 3 * tcount + 4 * scount ] ) [ a, a + 1, a + 2, a + 3 ] ];
faces = concat(tfaces, sfaces);
polyhedron(points, faces, convexity = 8);
}
// defaults, overridden in functions.scad
function surface_distribution_function(dim, size) = sin(dim) * size;
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
module 3d_surface_dish(width, height, depth, inverted) {
echo(inverted ? "inverted" : "not inverted");
// scale_factor is dead reckoning
// it doesn't have to be dead reckoning for anything but sculpted sides
// we know the angle of the sides from the width difference, height difference,
// skew and tilt of the top. it's a pain to calculate though
scale_factor = 1.1;
// the edges on this behave differently than with the previous dish implementations
scale([width*scale_factor/$3d_surface_size/2,height*scale_factor/$3d_surface_size/2,depth]) rotate([inverted ? 0:180,0,90]) polar_3d_surface(bottom=-10);
/* %scale([width*scale_factor/$3d_surface_size/2,height*scale_factor/$3d_surface_size/2,depth]) rotate([180,0,0]) polar_3d_surface(bottom=-10); */
}
//geodesic looks much better, but runs very slow for anything above a 2u
geodesic=false;
@@ -2361,9 +2802,10 @@ module dish(width, height, depth, inverted) {
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
} else if ($dish_type == "old spherical") {
old_spherical_dish(width, height, depth, inverted);
} else if ($dish_type == "3d_surface") {
3d_surface_dish(width, height, depth, inverted);
} else if ($dish_type == "flat") {
flat_dish(width, height, depth, inverted);
} else if ($dish_type == "disable") {
@@ -2414,6 +2856,25 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */
// TODO this define doesn't do anything besides tell me I used flat() in this file
// is it better than not having it at all?
module flat(stem_type, loft, height) {
@@ -3731,7 +4192,7 @@ module support_for(positions, stem_type) {
module stems_for(positions, stem_type) {
keystem_positions(positions) {
color($tertiary_color) stem(stem_type, $total_depth, $stem_slop);
color($tertiary_color) stem(stem_type, $total_depth, $stem_slop, $stem_throw);
if ($stem_support_type != "disable") {
color($quaternary_color) stem_support($stem_support_type, stem_type, $stem_support_height, $stem_slop);
}
@@ -3901,7 +4362,7 @@ $outset_legends = false;
// Height in units of key. should remain 1 for most uses
$key_height = 1.0;
// Keytop thickness, aka how many millimeters between the inside and outside of the top surface of the key
$keytop_thickness = 2;
$keytop_thickness = 1;
// Wall thickness, aka the thickness of the sides of the keycap. note this is the total thickness, aka 3 = 1.5mm walls
$wall_thickness = 3;
// Radius of corners of keycap
@@ -4048,18 +4509,15 @@ $tertiary_color = [1, .6941, .2];
$quaternary_color = [.4078, .3569, .749];
$warning_color = [1,0,0, 0.15];
// 3d surface variables
// see functions.scad for the surface function
$3d_surface_size = 10;
$3d_surface_step = 1;
// normally the bottom of the keytop looks like the top - curved, at least
// underneath the support structure. This ensures there's a minimum thickness for the
// underside of the keycap, but it's a fair bit of geometry
$flat_keytop_bottom = true;
// how many facets circles will have when used in these features
$minkowski_facets = 30;
$shape_facets =30;
// 3d surface settings
// unused for now
$3d_surface_size = 100;
// resolution in each axis. 10 = 10 divisions per x/y = 100 points total
$3d_surface_step = 10;
key();
}

View File

@@ -9,7 +9,10 @@ include <./includes.scad>
// example key
dcs_row(5) legend("⇪", size=9) key();
/* $stem_throw = 1; */
$stem_type = "custom";
$outset_legends = true;
dcs_row(5) front_legend("j") key();
// example row
/* for (x = [0:1:4]) {
@@ -17,4 +20,4 @@ dcs_row(5) legend("⇪", size=9) key();
} */
// example layout
/* preonic_default("dcs"); */
/* preonic_default("dcs"); */

View File

@@ -5,6 +5,7 @@ include <dishes/old_spherical.scad>
include <dishes/sideways_cylindrical.scad>
include <dishes/spherical.scad>
include <dishes/flat.scad>
include <dishes/3d_surface.scad>
//geodesic looks much better, but runs very slow for anything above a 2u
geodesic=false;
@@ -19,9 +20,10 @@ module dish(width, height, depth, inverted) {
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
} else if ($dish_type == "old spherical") {
old_spherical_dish(width, height, depth, inverted);
} else if ($dish_type == "3d_surface") {
3d_surface_dish(width, height, depth, inverted);
} else if ($dish_type == "flat") {
flat_dish(width, height, depth, inverted);
} else if ($dish_type == "disable") {

View File

@@ -0,0 +1,14 @@
include <../libraries/3d_surface.scad>
module 3d_surface_dish(width, height, depth, inverted) {
echo(inverted ? "inverted" : "not inverted");
// scale_factor is dead reckoning
// it doesn't have to be dead reckoning for anything but sculpted sides
// we know the angle of the sides from the width difference, height difference,
// skew and tilt of the top. it's a pain to calculate though
scale_factor = 1.1;
// the edges on this behave differently than with the previous dish implementations
scale([width*scale_factor/$3d_surface_size/2,height*scale_factor/$3d_surface_size/2,depth]) rotate([inverted ? 0:180,0,90]) polar_3d_surface(bottom=-10);
/* %scale([width*scale_factor/$3d_surface_size/2,height*scale_factor/$3d_surface_size/2,depth]) rotate([180,0,0]) polar_3d_surface(bottom=-10); */
}

View File

@@ -40,3 +40,22 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
// of the keycap a flat plane. 1 = front, -1 = back
// I derived this through a bunch of trig reductions I don't really understand.
function extra_keytop_length_for_flat_sides() = ($width_difference * vertical_inclination_due_to_top_tilt()) / ($total_depth);
// 3d surface functions (still in beta)
// monotonically increasing function that distributes the points of the surface mesh
// only for polar_3d_surface right now
// if it's linear it's a grid. sin(dim) * size concentrates detail around the edges
function surface_distribution_function(dim, size) = sin(dim) * size;
// the function that actually determines what the surface is.
// feel free to override, the last one wins
// debug
function surface_function(x,y) = 1;
// cylindrical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size)));
// spherical
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));
// (statically) random!
/* function surface_function(x,y) = sin(rands(0,90,1,x+y)[0]); */

View File

@@ -299,7 +299,7 @@ module support_for(positions, stem_type) {
module stems_for(positions, stem_type) {
keystem_positions(positions) {
color($tertiary_color) stem(stem_type, $total_depth, $stem_slop);
color($tertiary_color) stem(stem_type, $total_depth, $stem_slop, $stem_throw);
if ($stem_support_type != "disable") {
color($quaternary_color) stem_support($stem_support_type, stem_type, $stem_support_height, $stem_slop);
}

View File

@@ -9,6 +9,7 @@ include <key_profiles/sa.scad>
include <key_profiles/g20.scad>
include <key_profiles/hipro.scad>
include <key_profiles/grid.scad>
include <key_profiles/cherry.scad>
// man, wouldn't it be so cool if functions were first order
module key_profile(key_profile_type, row, column=0) {
@@ -26,6 +27,8 @@ module key_profile(key_profile_type, row, column=0) {
hipro_row(row, column) children();
} else if (key_profile_type == "grid") {
grid_row(row, column) children();
} else if (key_profile_type == "cherry") {
cherry_row(row, column) children();
} else if (key_profile_type == "disable") {
children();
} else {

View File

@@ -0,0 +1,48 @@
// based off GMK keycap set
module cherry_row(row=3, column=0) {
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = $bottom_key_width - 11.85;
$height_difference = $bottom_key_height - 14.64;
$dish_type = "cylindrical";
$dish_depth = 0.65;
$dish_skew_x = 0;
$dish_skew_y = 0;
$top_skew = 2;
$top_tilt_y = side_tilt(column);
extra_height = $double_sculpted ? extra_side_tilt_height(column) : 0;
// NOTE: cherry keycaps have this stem inset, but I'm reticent to turn it on
// since it'll be surprising to folks. the height has been adjusted accordingly
// $stem_inset = 0.6;
extra_stem_inset_height = max(0.6 - $stem_inset, 0);
// <= is a hack so you can do these in a for loop. function row = 0
if (row <= 1) {
$total_depth = 9.8 - extra_stem_inset_height + extra_height;
$top_tilt = 0;
children();
} else if (row == 2) {
$total_depth = 7.45 - extra_stem_inset_height + extra_height;
$top_tilt = 2.5;
children();
} else if (row == 3) {
$total_depth = 6.55 - extra_stem_inset_height + extra_height;
$top_tilt = 5;
children();
} else if (row == 3) {
$total_depth = 6.7 + 0.65 - extra_stem_inset_height + extra_height;
$top_tilt = 11.5;
children();
} else if (row >= 4) {
$total_depth = 6.7 + 0.65 - extra_stem_inset_height + extra_height;
$top_tilt = 11.5;
children();
} else {
children();
}
}

View File

@@ -0,0 +1,79 @@
// thanks Paul https://github.com/openscad/list-comprehension-demos/
include <../functions.scad>
module 3d_surface(size=$3d_surface_size, step=$3d_surface_step, bottom=-SMALLEST_POSSIBLE){
function p(x, y) = [ x, y, max(0,surface_function(x, y)) ];
function p0(x, y) = [ x, y, bottom ];
function rev(b, v) = b ? v : [ v[3], v[2], v[1], v[0] ];
function face(x, y) = [ p(x, y + step), p(x + step, y + step), p(x + step, y), p(x + step, y), p(x, y), p(x, y + step) ];
function fan(a, i) =
a == 0 ? [ [ 0, 0, bottom ], [ i, -size, bottom ], [ i + step, -size, bottom ] ]
: a == 1 ? [ [ 0, 0, bottom ], [ i + step, size, bottom ], [ i, size, bottom ] ]
: a == 2 ? [ [ 0, 0, bottom ], [ -size, i + step, bottom ], [ -size, i, bottom ] ]
: [ [ 0, 0, bottom ], [ size, i, bottom ], [ size, i + step, bottom ] ];
function sidex(x, y) = [ p0(x, y), p(x, y), p(x + step, y), p0(x + step, y) ];
function sidey(x, y) = [ p0(x, y), p(x, y), p(x, y + step), p0(x, y + step) ];
points = flatten(concat(
// top surface
[ for (x = [ -size : step : size - step ], y = [ -size : step : size - step ]) face(x, y) ],
// bottom surface as triangle fan
[ for (a = [ 0 : 3 ], i = [ -size : step : size - step ]) fan(a, i) ],
// sides
[ for (x = [ -size : step : size - step ], y = [ -size, size ]) rev(y < 0, sidex(x, y)) ],
[ for (y = [ -size : step : size - step ], x = [ -size, size ]) rev(x > 0, sidey(x, y)) ]
));
tcount = 2 * pow(2 * size / step, 2) + 8 * size / step;
scount = 8 * size / step;
tfaces = [ for (a = [ 0 : 3 : 3 * (tcount - 1) ] ) [ a, a + 1, a + 2 ] ];
sfaces = [ for (a = [ 3 * tcount : 4 : 3 * tcount + 4 * scount ] ) [ a, a + 1, a + 2, a + 3 ] ];
faces = concat(tfaces, sfaces);
polyhedron(points, faces, convexity = 8);
}
module polar_3d_surface(size=$3d_surface_size, step=$3d_surface_step, bottom=-SMALLEST_POSSIBLE){
function to_polar(q, size) = q * (90 / size);
function p(x, y) = [
surface_distribution_function(to_polar(x, size), size),
surface_distribution_function(to_polar(y, size), size),
max(0,surface_function(surface_distribution_function(to_polar(x, size), size), surface_distribution_function(to_polar(y, size), size)))
];
function p0(x, y) = [ x, y, bottom ];
function rev(b, v) = b ? v : [ v[3], v[2], v[1], v[0] ];
function face(x, y) = [ p(x, y + step), p(x + step, y + step), p(x + step, y), p(x + step, y), p(x, y), p(x, y + step) ];
function fan(a, i) =
a == 0 ? [ [ 0, 0, bottom ], [ i, -size, bottom ], [ i + step, -size, bottom ] ]
: a == 1 ? [ [ 0, 0, bottom ], [ i + step, size, bottom ], [ i, size, bottom ] ]
: a == 2 ? [ [ 0, 0, bottom ], [ -size, i + step, bottom ], [ -size, i, bottom ] ]
: [ [ 0, 0, bottom ], [ size, i, bottom ], [ size, i + step, bottom ] ];
function sidex(x, y) = [ p0(x, y), p(x, y), p(x + step, y), p0(x + step, y) ];
function sidey(x, y) = [ p0(x, y), p(x, y), p(x, y + step), p0(x, y + step) ];
points = flatten(concat(
// top surface
[ for (x = [ -size : step : size - step ], y = [ -size : step : size - step ]) face(x, y) ],
// bottom surface as triangle fan
[ for (a = [ 0 : 3 ], i = [ -size : step : size - step ]) fan(a, i) ],
// sides
[ for (x = [ -size : step : size - step ], y = [ -size, size ]) rev(y < 0, sidex(x, y)) ],
[ for (y = [ -size : step : size - step ], x = [ -size, size ]) rev(x > 0, sidey(x, y)) ]
));
tcount = 2 * pow(2 * size / step, 2) + 8 * size / step;
scount = 8 * size / step;
tfaces = [ for (a = [ 0 : 3 : 3 * (tcount - 1) ] ) [ a, a + 1, a + 2 ] ];
sfaces = [ for (a = [ 3 * tcount : 4 : 3 * tcount + 4 * scount ] ) [ a, a + 1, a + 2, a + 3 ] ];
faces = concat(tfaces, sfaces);
polyhedron(points, faces, convexity = 8);
}
// defaults, overridden in functions.scad
function surface_distribution_function(dim, size) = sin(dim) * size;
function surface_function(x,y) = (sin(acos(x/$3d_surface_size))) * sin(acos(y/$3d_surface_size));

View File

@@ -187,3 +187,9 @@ $warning_color = [1,0,0, 0.15];
// how many facets circles will have when used in these features
$minkowski_facets = 30;
$shape_facets =30;
// 3d surface settings
// unused for now
$3d_surface_size = 100;
// resolution in each axis. 10 = 10 divisions per x/y = 100 points total
$3d_surface_step = 10;

View File

@@ -4,22 +4,25 @@ include <stems/box_cherry.scad>
include <stems/alps.scad>
include <stems/filled.scad>
include <stems/cherry_stabilizer.scad>
include <stems/custom.scad>
//whole stem, alps or cherry, trimmed to fit
module stem(stem_type, depth, slop){
module stem(stem_type, depth, slop, throw){
if (stem_type == "alps") {
alps_stem(depth, slop);
alps_stem(depth, slop, throw);
} else if (stem_type == "cherry" || stem_type == "costar_stabilizer") {
cherry_stem(depth, slop);
cherry_stem(depth, slop, throw);
} else if (stem_type == "rounded_cherry") {
rounded_cherry_stem(depth, slop);
rounded_cherry_stem(depth, slop, throw);
} else if (stem_type == "box_cherry") {
box_cherry_stem(depth, slop);
box_cherry_stem(depth, slop, throw);
} else if (stem_type == "filled") {
filled_stem();
} else if (stem_type == "cherry_stabilizer") {
cherry_stabilizer_stem(depth, slop);
cherry_stabilizer_stem(depth, slop, throw);
} else if (stem_type == "custom") {
custom_stem(depth, slop, throw);
} else if (stem_type == "disable") {
children();
} else {

View File

@@ -1,4 +1,4 @@
module alps_stem(depth, has_brim, slop){
module alps_stem(depth, slop, throw){
linear_extrude(height=depth) {
square($alps_stem, center = true);
}

View File

@@ -1,7 +1,7 @@
include <../functions.scad>
include <cherry.scad>
module box_cherry_stem(depth, slop) {
module box_cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {

View File

@@ -23,7 +23,7 @@ module inside_cherry_cross(slop) {
}
}
module cherry_stem(depth, slop) {
module cherry_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {

View File

@@ -15,7 +15,7 @@ module inside_cherry_stabilizer_cross(slop) {
}
}
module cherry_stabilizer_stem(depth, slop) {
module cherry_stabilizer_stem(depth, slop, throw) {
difference(){
// outside shape
linear_extrude(height = depth) {

12
src/stems/custom.scad Normal file
View File

@@ -0,0 +1,12 @@
thickness = .84;
inner_stem_size = [6,4];
outer_stem_size = inner_stem_size + [thickness, thickness];
module custom_stem(depth, slop, throw){
linear_extrude(height=depth) {
difference() {
square(outer_stem_size + [slop,slop], center = true);
square(inner_stem_size + [slop,slop], center = true);
}
}
}

View File

@@ -1,4 +1,4 @@
module filled_stem() {
module filled_stem(_depth, _slop, _throw) {
// I broke the crap out of this stem type due to the changes I made around how stems are differenced
// now that we just take the dish out of stems in order to support stuff like
// bare stem keycaps (and buckling spring eventually) we can't just make a

View File

@@ -1,7 +1,7 @@
include <../functions.scad>
include <cherry.scad>
module rounded_cherry_stem(depth, slop) {
module rounded_cherry_stem(depth, slop, throw) {
difference(){
cylinder(d=$rounded_cherry_stem_d, h=depth);