mirror of
https://github.com/rsheldiii/KeyV2.git
synced 2024-11-26 06:45:28 +00:00
large key.scad restructuring
This commit is contained in:
parent
a523c45f4a
commit
c1bbaed9a2
15
CHANGELOG.md
Normal file
15
CHANGELOG.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CHANGELOG:
|
||||||
|
V2.0.0:
|
||||||
|
* added $fa values for minkowski and shape - so you can customize how much rounding there is
|
||||||
|
* rejiggered `key.scad` pipeline for more clarity and less shapes
|
||||||
|
* implemented "3d_surface" dish - still in beta
|
||||||
|
* super cool though, you can even change the distribution of points on the surface! just make sure you use monotonically increasing functions
|
||||||
|
* created "hull" folder to house different ways of creating the overall key shape
|
||||||
|
* promoted "feature" folder to first-class folder with keytext and switch clearance as new residents
|
||||||
|
* wrote this changelog!
|
||||||
|
* implemented `$inner_shape_type`, use "flat" for less geometry or "disable" to make a completely solid key easily. didn't help render rounded keys though
|
||||||
|
* side-printed keycaps are first class! you can use the `sideways()` modifier to set up sideways keycaps that have flat sides to print on.
|
||||||
|
* it's much easier to make quick artisans now that the inside of the keycap is differenced from any additive features placed on top
|
||||||
|
* still todo: add a magic scaling variable so you can scale the whole world up, see if that fixes degeneracy
|
||||||
|
* still todo: rejigger supports
|
||||||
|
* still todo: rejigger inner shape. maybe just always make it flat
|
838
customizer.scad
838
customizer.scad
File diff suppressed because it is too large
Load Diff
27
keys.scad
27
keys.scad
@ -9,7 +9,32 @@ include <./includes.scad>
|
|||||||
|
|
||||||
|
|
||||||
// example key
|
// example key
|
||||||
dcs_row(5) legend("⇪", size=9) key();
|
/* $skin_key_shape = true; */
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
/* top_of_key() { */
|
||||||
|
/* cube(10); */
|
||||||
|
/* } */
|
||||||
|
/* key(); */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simple_layout(lets_split_layout) {
|
||||||
|
dcs_row($row) key();
|
||||||
|
} */
|
||||||
|
|
||||||
|
dcs_row(1) legend("h") front_legend("q"
|
||||||
|
) {
|
||||||
|
$key_length = 2.75;
|
||||||
|
key();
|
||||||
|
}
|
||||||
|
|
||||||
|
translate_u(0,1) dcs_row(1) {
|
||||||
|
$key_length = 0.86;
|
||||||
|
key();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* debug() key(); */
|
||||||
|
|
||||||
|
|
||||||
// example row
|
// example row
|
||||||
/* for (x = [0:1:4]) {
|
/* for (x = [0:1:4]) {
|
||||||
|
14
src/dishes/3d_surface.scad
Normal file
14
src/dishes/3d_surface.scad
Normal 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,180]) 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); */
|
||||||
|
|
||||||
|
}
|
@ -40,3 +40,27 @@ function vertical_inclination_due_to_top_tilt() = sin($top_tilt) * (top_total_ke
|
|||||||
// of the keycap a flat plane. 1 = front, -1 = back
|
// of the keycap a flat plane. 1 = front, -1 = back
|
||||||
// I derived this through a bunch of trig reductions I don't really understand.
|
// 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);
|
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!
|
||||||
|
// ripples
|
||||||
|
/* function surface_function(x,y) = cos(pow(pow(x,2)+pow(y,2),0.5)*10)/4+0.75; */
|
||||||
|
// Rosenbrock's banana
|
||||||
|
/* function surface_function(x,y) = (pow(1-(x/100), 2) + 100 * pow((y/100)-pow((x/100),2),2))/200 + 0.1; */
|
||||||
|
// y=x revolved around the y axis
|
||||||
|
/* function surface_function(x,y) = 1/(pow(pow(x,2)+pow(y,2),0.5)/100 + .01); */
|
||||||
|
19
src/hulls.scad
Normal file
19
src/hulls.scad
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
include <hulls/skin.scad>
|
||||||
|
include <hulls/linear_extrude.scad>
|
||||||
|
include <hulls/hull.scad>
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// extra_slices is a hack to make inverted dishes still work
|
||||||
|
module shape_hull(thickness_difference, depth_difference, extra_slices = 0){
|
||||||
|
render() {
|
||||||
|
if ($skin_extrude_shape) {
|
||||||
|
skin_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
|
||||||
|
} else if ($linear_extrude_shape) {
|
||||||
|
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
|
||||||
|
} else {
|
||||||
|
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/hulls/hull.scad
Normal file
33
src/hulls/hull.scad
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
module hull_shape_hull(thickness_difference, depth_difference, extra_slices = 0) {
|
||||||
|
for (index = [0:$height_slices - 1 + extra_slices]) {
|
||||||
|
hull() {
|
||||||
|
shape_slice(index / $height_slices, thickness_difference, depth_difference);
|
||||||
|
shape_slice((index + 1) / $height_slices, thickness_difference, depth_difference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module shape_slice(progress, thickness_difference, depth_difference) {
|
||||||
|
skew_this_slice = $top_skew * progress;
|
||||||
|
x_skew_this_slice = $top_skew_x * progress;
|
||||||
|
|
||||||
|
depth_this_slice = ($total_depth - depth_difference) * progress;
|
||||||
|
|
||||||
|
tilt_this_slice = -$top_tilt / $key_height * progress;
|
||||||
|
y_tilt_this_slice = $double_sculpted ? (-$top_tilt_y / $key_length * progress) : 0;
|
||||||
|
|
||||||
|
translate([x_skew_this_slice, skew_this_slice, depth_this_slice]) {
|
||||||
|
rotate([tilt_this_slice,y_tilt_this_slice,0]){
|
||||||
|
linear_extrude(height = SMALLEST_POSSIBLE + ($rounded_key ? $minkowski_radius : 0), scale = SMALLEST_POSSIBLE){
|
||||||
|
key_shape(
|
||||||
|
[
|
||||||
|
total_key_width(thickness_difference),
|
||||||
|
total_key_height(thickness_difference)
|
||||||
|
],
|
||||||
|
[$width_difference, $height_difference],
|
||||||
|
progress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/hulls/linear_extrude.scad
Normal file
18
src/hulls/linear_extrude.scad
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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();
|
||||||
|
|
||||||
|
translate([0,$linear_extrude_height_adjustment,0]){
|
||||||
|
linear_extrude(height = height, scale = [width_scale, height_scale]) {
|
||||||
|
translate([0,-$linear_extrude_height_adjustment,0]){
|
||||||
|
key_shape(
|
||||||
|
[total_key_width(thickness_difference), total_key_height(thickness_difference)],
|
||||||
|
[$width_difference, $height_difference]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/hulls/skin.scad
Normal file
34
src/hulls/skin.scad
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// use skin() instead of successive hulls. much more correct, and looks faster
|
||||||
|
// too, in most cases. successive hull relies on overlapping faces which are
|
||||||
|
// not good. But, skin works on vertex sets instead of shapes, which makes it
|
||||||
|
// a lot more difficult to use
|
||||||
|
module skin_extrude_shape_hull(thickness_difference, depth_difference, extra_slices = 0 ) {
|
||||||
|
skin([
|
||||||
|
for (index = [0:$height_slices + extra_slices])
|
||||||
|
let(
|
||||||
|
progress = (index / $height_slices),
|
||||||
|
skew_this_slice = $top_skew * progress,
|
||||||
|
x_skew_this_slice = $top_skew_x * progress,
|
||||||
|
depth_this_slice = ($total_depth - depth_difference) * progress,
|
||||||
|
tilt_this_slice = -$top_tilt / $key_height * progress,
|
||||||
|
y_tilt_this_slice = $double_sculpted ? (-$top_tilt_y / $key_length * progress) : 0
|
||||||
|
)
|
||||||
|
skin_shape_slice(progress, thickness_difference, skew_this_slice, x_skew_this_slice, depth_this_slice, tilt_this_slice, y_tilt_this_slice)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function skin_shape_slice(progress, thickness_difference, skew_this_slice, x_skew_this_slice, depth_this_slice, tilt_this_slice, y_tilt_this_slice) =
|
||||||
|
transform(
|
||||||
|
translation([x_skew_this_slice,skew_this_slice,depth_this_slice]),
|
||||||
|
transform(
|
||||||
|
rotation([tilt_this_slice,y_tilt_this_slice,0]),
|
||||||
|
skin_key_shape([
|
||||||
|
total_key_width(0),
|
||||||
|
total_key_height(0),
|
||||||
|
],
|
||||||
|
[$width_difference, $height_difference],
|
||||||
|
progress,
|
||||||
|
thickness_difference
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
375
src/key.scad
375
src/key.scad
@ -6,6 +6,7 @@ include <stem_supports.scad>
|
|||||||
include <dishes.scad>
|
include <dishes.scad>
|
||||||
include <supports.scad>
|
include <supports.scad>
|
||||||
include <features.scad>
|
include <features.scad>
|
||||||
|
include <hulls.scad>
|
||||||
|
|
||||||
include <libraries/geodesic_sphere.scad>
|
include <libraries/geodesic_sphere.scad>
|
||||||
|
|
||||||
@ -15,210 +16,44 @@ use <libraries/scad-utils/lists.scad>
|
|||||||
use <libraries/scad-utils/shapes.scad>
|
use <libraries/scad-utils/shapes.scad>
|
||||||
use <libraries/skin.scad>
|
use <libraries/skin.scad>
|
||||||
|
|
||||||
|
|
||||||
/* [Hidden] */
|
/* [Hidden] */
|
||||||
SMALLEST_POSSIBLE = 1/128;
|
SMALLEST_POSSIBLE = 1/128;
|
||||||
$fs = .1;
|
// basically disable $fs - though it might be useful for these CGAL problems
|
||||||
|
$fs = .01;
|
||||||
$unit = 19.05;
|
$unit = 19.05;
|
||||||
|
|
||||||
// key shape including dish. used as the ouside and inside shape in hollow_key(). allows for itself to be shrunk in depth and width / height
|
// key shape including dish. used as the ouside and inside shape in hollow_key(). allows for itself to be shrunk in depth and width / height
|
||||||
module shape(thickness_difference, depth_difference=0){
|
module shape(thickness_difference, depth_difference=0){
|
||||||
dished(depth_difference, $inverted_dish) {
|
dished(depth_difference, $inverted_dish) {
|
||||||
color($primary_color) shape_hull(thickness_difference, depth_difference, $inverted_dish ? 2 : 0);
|
color($primary_color) shape_hull(thickness_difference, depth_difference, $inverted_dish ? 200 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shape of the key but with soft, rounded edges. no longer includes dish
|
|
||||||
// randomly doesnt work sometimes
|
|
||||||
// the dish doesn't _quite_ reach as far as it should
|
|
||||||
module rounded_shape() {
|
|
||||||
dished(-$minkowski_radius, $inverted_dish) {
|
|
||||||
color($primary_color) minkowski(){
|
|
||||||
// half minkowski in the z direction
|
|
||||||
color($primary_color) shape_hull($minkowski_radius * 2, $minkowski_radius/2, $inverted_dish ? 2 : 0);
|
|
||||||
/* cube($minkowski_radius); */
|
|
||||||
sphere(r=$minkowski_radius, $fn=$minkowski_facets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* %envelope(); */
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function is more correct, but takes _forever_
|
// this function is more correct, but takes _forever_
|
||||||
// the main difference is minkowski happens after dishing, meaning the dish is
|
// the main difference is minkowski happens after dishing, meaning the dish is
|
||||||
// also minkowski'd
|
// also minkowski'd
|
||||||
/* module rounded_shape() {
|
module rounded_shape() {
|
||||||
color($primary_color) minkowski(){
|
color($primary_color) minkowski(){
|
||||||
// half minkowski in the z direction
|
// half minkowski in the z direction
|
||||||
shape($minkowski_radius * 2, $minkowski_radius/2);
|
shape($minkowski_radius * 2, $minkowski_radius/2);
|
||||||
difference(){
|
minkowski_object();
|
||||||
sphere(r=$minkowski_radius, $fn=20);
|
|
||||||
translate([0,0,-$minkowski_radius]){
|
|
||||||
cube($minkowski_radius * 2, center=true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
|
|
||||||
|
// minkowski places this object at every vertex of the other object then mashes
|
||||||
|
// it all together
|
||||||
|
module minkowski_object() {
|
||||||
|
// alternative minkowski shape that needs the bottom of the keycap to be trimmed
|
||||||
|
/* sphere(1); */
|
||||||
|
|
||||||
|
difference(){
|
||||||
// basic key shape, no dish, no inside
|
sphere(r=$minkowski_radius, $fa=360/$minkowski_facets);
|
||||||
// which is only used for dishing to cut the dish off correctly
|
translate([0,0,-$minkowski_radius]){
|
||||||
// $height_difference used for keytop thickness
|
cube($minkowski_radius * 2, center=true);
|
||||||
// extra_slices is a hack to make inverted dishes still work
|
|
||||||
module shape_hull(thickness_difference, depth_difference, extra_slices = 0){
|
|
||||||
render() {
|
|
||||||
if ($skin_extrude_shape) {
|
|
||||||
skin_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
|
|
||||||
} else if ($linear_extrude_shape) {
|
|
||||||
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
|
|
||||||
} else {
|
|
||||||
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use skin() instead of successive hulls. much more correct, and looks faster
|
|
||||||
// too, in most cases. successive hull relies on overlapping faces which are
|
|
||||||
// not good. But, skin works on vertex sets instead of shapes, which makes it
|
|
||||||
// a lot more difficult to use
|
|
||||||
module skin_extrude_shape_hull(thickness_difference, depth_difference, extra_slices = 0 ) {
|
|
||||||
skin([
|
|
||||||
for (index = [0:$height_slices + extra_slices])
|
|
||||||
let(
|
|
||||||
progress = (index / $height_slices),
|
|
||||||
skew_this_slice = $top_skew * progress,
|
|
||||||
x_skew_this_slice = $top_skew_x * progress,
|
|
||||||
depth_this_slice = ($total_depth - depth_difference) * progress,
|
|
||||||
tilt_this_slice = -$top_tilt / $key_height * progress,
|
|
||||||
y_tilt_this_slice = $double_sculpted ? (-$top_tilt_y / $key_length * progress) : 0
|
|
||||||
)
|
|
||||||
skin_shape_slice(progress, thickness_difference, skew_this_slice, x_skew_this_slice, depth_this_slice, tilt_this_slice, y_tilt_this_slice)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function skin_shape_slice(progress, thickness_difference, skew_this_slice, x_skew_this_slice, depth_this_slice, tilt_this_slice, y_tilt_this_slice) =
|
|
||||||
transform(
|
|
||||||
translation([x_skew_this_slice,skew_this_slice,depth_this_slice]),
|
|
||||||
transform(
|
|
||||||
rotation([tilt_this_slice,y_tilt_this_slice,0]),
|
|
||||||
skin_key_shape([
|
|
||||||
total_key_width(0),
|
|
||||||
total_key_height(0),
|
|
||||||
],
|
|
||||||
[$width_difference, $height_difference],
|
|
||||||
progress,
|
|
||||||
thickness_difference
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
translate([0,$linear_extrude_height_adjustment,0]){
|
|
||||||
linear_extrude(height = height, scale = [width_scale, height_scale]) {
|
|
||||||
translate([0,-$linear_extrude_height_adjustment,0]){
|
|
||||||
key_shape(
|
|
||||||
[total_key_width(thickness_difference), total_key_height(thickness_difference)],
|
|
||||||
[$width_difference, $height_difference]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module hull_shape_hull(thickness_difference, depth_difference, extra_slices = 0) {
|
|
||||||
for (index = [0:$height_slices - 1 + extra_slices]) {
|
|
||||||
hull() {
|
|
||||||
shape_slice(index / $height_slices, thickness_difference, depth_difference);
|
|
||||||
shape_slice((index + 1) / $height_slices, thickness_difference, depth_difference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module shape_slice(progress, thickness_difference, depth_difference) {
|
|
||||||
skew_this_slice = $top_skew * progress;
|
|
||||||
x_skew_this_slice = $top_skew_x * progress;
|
|
||||||
|
|
||||||
depth_this_slice = ($total_depth - depth_difference) * progress;
|
|
||||||
|
|
||||||
tilt_this_slice = -$top_tilt / $key_height * progress;
|
|
||||||
y_tilt_this_slice = $double_sculpted ? (-$top_tilt_y / $key_length * progress) : 0;
|
|
||||||
|
|
||||||
translate([x_skew_this_slice, skew_this_slice, depth_this_slice]) {
|
|
||||||
rotate([tilt_this_slice,y_tilt_this_slice,0]){
|
|
||||||
linear_extrude(height = SMALLEST_POSSIBLE){
|
|
||||||
key_shape(
|
|
||||||
[
|
|
||||||
total_key_width(thickness_difference),
|
|
||||||
total_key_height(thickness_difference)
|
|
||||||
],
|
|
||||||
[$width_difference, $height_difference],
|
|
||||||
progress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for when you want something to only exist outside the keycap
|
|
||||||
module outside() {
|
|
||||||
difference() {
|
|
||||||
children();
|
|
||||||
shape($wall_thickness, $keytop_thickness);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// put something at the top of the key, with no adjustments for dishing
|
|
||||||
module top_placement(depth_difference=0) {
|
|
||||||
top_tilt_by_height = -$top_tilt / $key_height;
|
|
||||||
top_tilt_y_by_length = $double_sculpted ? (-$top_tilt_y / $key_length) : 0;
|
|
||||||
|
|
||||||
minkowski_height = $rounded_key ? $minkowski_radius : 0;
|
|
||||||
|
|
||||||
translate([$top_skew_x + $dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference + minkowski_height/2]){
|
|
||||||
rotate([top_tilt_by_height, top_tilt_y_by_length,0]){
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module front_placement() {
|
|
||||||
// all this math is to take top skew and tilt into account
|
|
||||||
// we need to find the new effective height and depth of the top, front lip
|
|
||||||
// of the keycap to find the angle so we can rotate things correctly into place
|
|
||||||
total_depth_difference = sin(-$top_tilt) * (top_total_key_height()/2);
|
|
||||||
total_height_difference = $top_skew + (1 - cos(-$top_tilt)) * (top_total_key_height()/2);
|
|
||||||
|
|
||||||
angle = atan2(($total_depth - total_depth_difference), ($height_difference/2 + total_height_difference));
|
|
||||||
hypotenuse = ($total_depth -total_depth_difference) / sin(angle);
|
|
||||||
|
|
||||||
translate([0,-total_key_height()/2,0]) {
|
|
||||||
rotate([-(90-angle), 0, 0]) {
|
|
||||||
translate([0,0,hypotenuse/2]){
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// just to DRY up the code
|
|
||||||
module _dish() {
|
|
||||||
color($secondary_color) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
|
|
||||||
}
|
|
||||||
|
|
||||||
module envelope(depth_difference=0) {
|
module envelope(depth_difference=0) {
|
||||||
s = 1.5;
|
s = 1.5;
|
||||||
@ -230,18 +65,6 @@ module envelope(depth_difference=0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I think this is unused
|
|
||||||
module dished_for_show() {
|
|
||||||
difference(){
|
|
||||||
union() {
|
|
||||||
envelope();
|
|
||||||
if ($inverted_dish) top_placement(0) _dish();
|
|
||||||
}
|
|
||||||
if (!$inverted_dish) top_placement(0) _dish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// for when you want to take the dish out of things
|
// 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
|
// used for adding the dish to the key shape and making sure stems don't stick out the top
|
||||||
// creates a bounding box 1.5 times larger in width and height than the keycap.
|
// creates a bounding box 1.5 times larger in width and height than the keycap.
|
||||||
@ -250,15 +73,21 @@ module dished(depth_difference = 0, inverted = false) {
|
|||||||
children();
|
children();
|
||||||
difference(){
|
difference(){
|
||||||
union() {
|
union() {
|
||||||
|
// envelope is needed to "fill in" the rest of the keycap
|
||||||
envelope(depth_difference);
|
envelope(depth_difference);
|
||||||
if (inverted) top_placement(depth_difference) _dish();
|
if (inverted) top_placement(depth_difference) _dish(inverted);
|
||||||
}
|
}
|
||||||
if (!inverted) top_placement(depth_difference) _dish();
|
if (!inverted) top_placement(depth_difference) _dish(inverted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// puts it's children at the center of the dishing on the key, including dish height
|
// just to DRY up the code
|
||||||
|
module _dish(inverted=$inverted_dish) {
|
||||||
|
color($secondary_color) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, inverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
// puts its children at the center of the dishing on the key, including dish height
|
||||||
// more user-friendly than top_placement
|
// more user-friendly than top_placement
|
||||||
module top_of_key(){
|
module top_of_key(){
|
||||||
// if there is a dish, we need to account for how much it digs into the top
|
// if there is a dish, we need to account for how much it digs into the top
|
||||||
@ -271,6 +100,7 @@ module top_of_key(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// puts its children at each keystem position provided
|
||||||
module keystem_positions(positions) {
|
module keystem_positions(positions) {
|
||||||
for (connector_pos = positions) {
|
for (connector_pos = positions) {
|
||||||
translate(connector_pos) {
|
translate(connector_pos) {
|
||||||
@ -296,78 +126,121 @@ module stems_for(positions, stem_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// legends / artisan support
|
// put something at the top of the key, with no adjustments for dishing
|
||||||
module artisan(depth) {
|
module top_placement(depth_difference=0) {
|
||||||
top_of_key() {
|
top_tilt_by_height = -$top_tilt / $key_height;
|
||||||
// artisan objects / outset shape legends
|
top_tilt_y_by_length = $double_sculpted ? (-$top_tilt_y / $key_length) : 0;
|
||||||
color($secondary_color) children();
|
|
||||||
|
minkowski_height = $rounded_key ? $minkowski_radius : 0;
|
||||||
|
|
||||||
|
translate([$top_skew_x + $dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference + minkowski_height/2]){
|
||||||
|
rotate([top_tilt_by_height, top_tilt_y_by_length,0]){
|
||||||
|
children();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// key with hollowed inside but no stem
|
module front_of_key() {
|
||||||
module hollow_key() {
|
// all this math is to take top skew and tilt into account
|
||||||
difference(){
|
// we need to find the new effective height and depth of the top, front lip
|
||||||
if ($rounded_key) {
|
// of the keycap to find the angle so we can rotate things correctly into place
|
||||||
rounded_shape();
|
total_depth_difference = sin(-$top_tilt) * (top_total_key_height()/2);
|
||||||
|
total_height_difference = $top_skew + (1 - cos(-$top_tilt)) * (top_total_key_height()/2);
|
||||||
|
|
||||||
|
angle = atan2(($total_depth - total_depth_difference), ($height_difference/2 + total_height_difference));
|
||||||
|
hypotenuse = ($total_depth -total_depth_difference) / sin(angle);
|
||||||
|
|
||||||
|
translate([0,-total_key_height()/2,0]) {
|
||||||
|
rotate([-(90-angle), 0, 0]) {
|
||||||
|
translate([0,0,hypotenuse/2]){
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module outer_shape() {
|
||||||
|
shape(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
module inner_shape(extra_wall_thickness = 0, extra_keytop_thickness = 0) {
|
||||||
|
translate([0,0,-SMALLEST_POSSIBLE]) {
|
||||||
|
if ($inner_shape_type == "flat") {
|
||||||
|
/* $key_shape_type="square"; */
|
||||||
|
$height_slices = 1;
|
||||||
|
color($primary_color) shape_hull($wall_thickness + extra_wall_thickness, $keytop_thickness + extra_keytop_thickness, 0);
|
||||||
} else {
|
} else {
|
||||||
shape(0, 0);
|
shape($wall_thickness + extra_wall_thickness, $keytop_thickness + extra_keytop_thickness);
|
||||||
}
|
|
||||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
|
||||||
translate([0,0,-SMALLEST_POSSIBLE]) {
|
|
||||||
shape($wall_thickness, $keytop_thickness);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// additive objects at the top of the key
|
||||||
|
module additive_features(inset) {
|
||||||
|
top_of_key() {
|
||||||
|
if($key_bump) keybump($key_bump_depth, $key_bump_edge);
|
||||||
|
if(!inset && $children > 0) color($secondary_color) children();
|
||||||
|
}
|
||||||
|
if($outset_legends) legends(0);
|
||||||
|
// 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
|
||||||
|
module subtractive_features(inset) {
|
||||||
|
top_of_key() {
|
||||||
|
if (inset && $children > 0) color($secondary_color) children();
|
||||||
|
}
|
||||||
|
if(!$outset_legends) legends($inset_legend_depth);
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
module inside_features() {
|
||||||
|
translate([0, 0, $stem_inset]) {
|
||||||
|
// both stem and support are optional
|
||||||
|
if ($stabilizer_type != "disable") stems_for($stabilizers, $stabilizer_type);
|
||||||
|
if ($stem_type != "disable") stems_for($stem_positions, $stem_type);
|
||||||
|
if ($stabilizer_type != "disable") support_for($stabilizers, $stabilizer_type);
|
||||||
|
// always render stem support even if there isn't a stem.
|
||||||
|
// rendering flat support w/no stem is much more common than a hollow keycap
|
||||||
|
// so if you want a hollow keycap you'll have to turn support off entirely
|
||||||
|
if ($support_type != "disable") support_for($stem_positions, $stem_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The final, penultimate key generation function.
|
// The final, penultimate key generation function.
|
||||||
// takes all the bits and glues them together. requires configuration with special variables.
|
// takes all the bits and glues them together. requires configuration with special variables.
|
||||||
module key(inset = false) {
|
module key(inset=false) {
|
||||||
difference() {
|
difference(){
|
||||||
union(){
|
union() {
|
||||||
// the shape of the key, inside and out
|
outer_shape();
|
||||||
hollow_key();
|
additive_features(inset) {
|
||||||
if($key_bump) top_of_key() keybump($key_bump_depth, $key_bump_edge);
|
children();
|
||||||
// additive objects at the top of the key
|
};
|
||||||
// outside() makes them stay out of the inside. it's a bad name
|
|
||||||
if(!inset && $children > 0) outside() artisan(0) children();
|
|
||||||
if($outset_legends) legends(0);
|
|
||||||
// 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 ($inner_shape_type != "disable") difference() {
|
||||||
// no outside() - I can't think of a use for it. will save render time
|
inner_shape();
|
||||||
if (inset && $children > 0) artisan($inset_legend_depth) children();
|
inside_features();
|
||||||
if(!$outset_legends) legends($inset_legend_depth);
|
|
||||||
// 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 != "disable" || ($stabilizers != [] && $stabilizer_type != "disable")) {
|
|
||||||
dished($keytop_thickness, $inverted_dish) {
|
|
||||||
translate([0, 0, $stem_inset]) {
|
|
||||||
if ($stabilizer_type != "disable") stems_for($stabilizers, $stabilizer_type);
|
|
||||||
|
|
||||||
if ($stem_type != "disable") stems_for($stem_positions, $stem_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subtractive_features(inset) {
|
||||||
|
children();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($support_type != "disable"){
|
module display_key(inset=false) {
|
||||||
inside() {
|
minkowski() {
|
||||||
translate([0, 0, $stem_inset]) {
|
outer_shape();
|
||||||
if ($stabilizer_type != "disable") support_for($stabilizers, $stabilizer_type);
|
minkowski_object();
|
||||||
|
// minkowski doesn't work with difference
|
||||||
// always render stem support even if there isn't a stem.
|
additive_features(false) {
|
||||||
// rendering flat support w/no stem is much more common than a hollow keycap
|
children();
|
||||||
// so if you want a hollow keycap you'll have to turn support off entirely
|
};
|
||||||
support_for($stem_positions, $stem_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// actual full key with space carved out and keystem/stabilizer connectors
|
// actual full key with space carved out and keystem/stabilizer connectors
|
||||||
|
@ -177,3 +177,14 @@ module debug() {
|
|||||||
|
|
||||||
%children();
|
%children();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module display() {
|
||||||
|
$height_slices = 30;
|
||||||
|
$minkowski_facets = 64;
|
||||||
|
$shape_facets = 64;
|
||||||
|
$stem_type = "disable";
|
||||||
|
$support_type = "disable";
|
||||||
|
$stem_support_type = "disable";
|
||||||
|
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
include <../layout.scad>
|
include <../layout.scad>
|
||||||
|
|
||||||
// negative numbers are used for spacing
|
// negative numbers are used for spacing
|
||||||
lets_split_mapping = [
|
lets_split_layout = [
|
||||||
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
||||||
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
||||||
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
[1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
|
||||||
@ -9,5 +9,5 @@ lets_split_mapping = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
module lets_split_default(profile) {
|
module lets_split_default(profile) {
|
||||||
layout(lets_split_mapping, profile, row_sculpting_offset=1) children();
|
layout(lets_split_layout, profile, row_sculpting_offset=1) children();
|
||||||
}
|
}
|
||||||
|
@ -187,3 +187,12 @@ $warning_color = [1,0,0, 0.15];
|
|||||||
// how many facets circles will have when used in these features
|
// how many facets circles will have when used in these features
|
||||||
$minkowski_facets = 30;
|
$minkowski_facets = 30;
|
||||||
$shape_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 = 5;
|
||||||
|
|
||||||
|
// "flat" / "dished" / "disable"
|
||||||
|
$inner_shape_type = "flat";
|
||||||
|
Loading…
Reference in New Issue
Block a user