convert all tabs to spaces

This commit is contained in:
Robert Sheldon 2018-06-04 21:13:09 -04:00
parent bc70ca109b
commit 67a830c489
33 changed files with 1172 additions and 1177 deletions

View File

@ -236,19 +236,19 @@ unit = 19.05;
// 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;
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
// 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);
width_ratio = unit_length(1.25) / unit_length(1.5);
height_ratio = unit_length(1) / unit_length(2);
pointArray = [
[ 0, 0], // top right
@ -259,13 +259,13 @@ module ISO_enter_shape(size, delta, progress){
[ -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);
}
}
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);
}
}
}
// side sculpting functions
@ -275,30 +275,30 @@ function side_sculpting(progress) = (1 - progress) * 2.5;
function corner_sculpting(progress) = pow(progress, 2);
module rounded_square_shape(size, delta, progress, center = true) {
width = size[0];
height = size[1];
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;
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);
// 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
);
}
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
);
}
}
@ -308,30 +308,30 @@ module square_shape(size, delta, progress){
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;
// .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);
}
}
if (progress < 0.5) {
} else {
offset(r=height / 2) {
square(size - [height, height] - delta * progress, center=true);
}
}
}
module key_shape(size, delta, progress = 0) {
if ($key_shape_type == "iso_enter") {
ISO_enter_shape(size, delta, progress);
} else if ($key_shape_type == "rounded_square") {
rounded_square_shape(size, delta, progress);
} else if ($key_shape_type == "square") {
square_shape(size, delta, progress);
if ($key_shape_type == "iso_enter") {
ISO_enter_shape(size, delta, progress);
} else if ($key_shape_type == "rounded_square") {
rounded_square_shape(size, delta, progress);
} else if ($key_shape_type == "square") {
square_shape(size, delta, progress);
} else if ($key_shape_type == "oblong") {
oblong_shape(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
oblong_shape(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
}
module cherry_stem(depth, has_brim) {
@ -406,13 +406,13 @@ module filled_stem() {
//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") {
rounded_cherry_stem(depth, has_brim);
} else if (stem_type == "cherry") {
cherry_stem(depth, has_brim);
} else if (stem_type == "filled") {
if (stem_type == "alps") {
alps_stem(depth, has_brim);
} else if (stem_type == "cherry_rounded") {
rounded_cherry_stem(depth, has_brim);
} else if (stem_type == "cherry") {
cherry_stem(depth, has_brim);
} else if (stem_type == "filled") {
filled_stem();
} else {
echo("Warning: unsupported $stem_type");
@ -420,18 +420,18 @@ module stem(stem_type, depth, has_brim){
}
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);
// .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]){
@ -444,64 +444,64 @@ module cylindrical_dish(width, height, depth, inverted){
// 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
//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);
// 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);
}
}
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);
}
}
}
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);
$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
}
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
//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);
// 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);
}
}
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);
}
}
}
}
@ -510,22 +510,22 @@ geodesic=false;
//dish selector
module dish(width, height, depth, inverted) {
if($dish_type == "cylindrical"){
cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "spherical") {
spherical_dish(width, height, depth, inverted);
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
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 changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
if($dish_type == "cylindrical"){
cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "spherical") {
spherical_dish(width, height, depth, inverted);
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
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 changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
}
// figures out the scale factor needed to make a 45 degree wall
@ -601,25 +601,25 @@ function top_total_key_height() = $bottom_key_height + (unit * ($key_height - 1)
// key shape including dish. used as the ouside and inside shape in keytop(). allows for itself to be shrunk in depth and width / height
module shape(thickness_difference, depth_difference){
dished(depth_difference, $inverted_dish) {
color(color1) shape_hull(thickness_difference, depth_difference, 1);
}
dished(depth_difference, $inverted_dish) {
color(color1) shape_hull(thickness_difference, depth_difference, 1);
}
}
// shape of the key but with soft, rounded edges. much more realistic, MUCH more complex. orders of magnitude more complex
module rounded_shape() {
render(){
color(color1) minkowski(){
// half minkowski. that means the shape is neither circumscribed nor inscribed.
shape($minkowski_radius * 2, $minkowski_radius/2);
difference(){
sphere(r=$minkowski_radius, $fn=24);
translate([0,0,-$minkowski_radius]){
cube($minkowski_radius * 2, center=true);
}
}
}
}
render(){
color(color1) minkowski(){
// half minkowski. that means the shape is neither circumscribed nor inscribed.
shape($minkowski_radius * 2, $minkowski_radius/2);
difference(){
sphere(r=$minkowski_radius, $fn=24);
translate([0,0,-$minkowski_radius]){
cube($minkowski_radius * 2, center=true);
}
}
}
}
}
@ -628,227 +628,227 @@ module rounded_shape() {
// $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 ($linear_extrude_shape) {
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
} else {
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
}
}
render() {
if ($linear_extrude_shape) {
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
} else {
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
}
}
}
// corollary is hull_shape_hull
// 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();
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));
}
}
}
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));
}
}
}
}
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);
}
}
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;
depth_this_slice = ($total_depth - depth_difference) * progress;
tilt_this_slice = -$top_tilt / $key_height * progress;
skew_this_slice = $top_skew * progress;
depth_this_slice = ($total_depth - depth_difference) * progress;
tilt_this_slice = -$top_tilt / $key_height * progress;
translate([0, skew_this_slice, depth_this_slice]) {
rotate([tilt_this_slice,0,0]){
linear_extrude(height = 0.001){
key_shape(
[
total_key_width(thickness_difference),
total_key_height(thickness_difference)
],
[$width_difference, $height_difference],
progress
);
}
}
}
translate([0, skew_this_slice, depth_this_slice]) {
rotate([tilt_this_slice,0,0]){
linear_extrude(height = 0.001){
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();
}
intersection() {
shape($wall_thickness, $keytop_thickness);
children();
}
}
// put something at the top of the key, with no adjustments for dishing
module top_placement(depth_difference) {
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
rotate([-$top_tilt / top_total_key_height(),0,0]){
children();
}
}
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
rotate([-$top_tilt / top_total_key_height(),0,0]){
children();
}
}
}
// just to DRY up the code
module _dish() {
color(color3) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
color(color3) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
}
// for when you want to take the dish out of things
// used for adding the dish to the key shape and making sure stems don't stick out the top
module dished(depth_difference, inverted = false) {
difference() {
children();
top_placement(depth_difference){
difference(){
union() {
translate([-500, -500]) cube(1000);
if (!inverted) _dish();
}
if (inverted) _dish();
}
}
}
difference() {
children();
top_placement(depth_difference){
difference(){
union() {
translate([-500, -500]) cube(1000);
if (!inverted) _dish();
}
if (inverted) _dish();
}
}
}
}
// puts it's children at the center of the dishing on the key, including dish height
// more user-friendly than top_placement
module top_of_key(){
// if there is a dish, we need to account for how much it digs into the top
dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
// if the dish is inverted, we need to account for that too. in this case we do half, otherwise the children would be floating on top of the dish
corrected_dish_depth = ($inverted_dish) ? -dish_depth / 2 : dish_depth;
// if there is a dish, we need to account for how much it digs into the top
dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
// if the dish is inverted, we need to account for that too. in this case we do half, otherwise the children would be floating on top of the dish
corrected_dish_depth = ($inverted_dish) ? -dish_depth / 2 : dish_depth;
top_placement(corrected_dish_depth) {
children();
}
top_placement(corrected_dish_depth) {
children();
}
}
module keytext(text, depth = 0) {
translate([0, 0, -depth]){
linear_extrude(height=$dish_depth){
text(text=text, font=$font, size=$font_size, halign="center", valign="center");
}
}
translate([0, 0, -depth]){
linear_extrude(height=$dish_depth){
text(text=text, font=$font, size=$font_size, halign="center", valign="center");
}
}
}
module keystem_positions() {
for (connector_pos = $connectors) {
translate(connector_pos) {
rotate([0, 0, $stem_rotation]){
children();
}
}
}
for (connector_pos = $connectors) {
translate(connector_pos) {
rotate([0, 0, $stem_rotation]){
children();
}
}
}
}
module keystems() {
keystem_positions() {
color(color4) stem($stem_type, $total_depth, $has_brim);
}
keystem_positions() {
color(color4) stem($stem_type, $total_depth, $has_brim);
}
}
module keystem_supports() {
keystem_positions() {
color(color4) supports($support_type, $stem_type, $stem_throw, $total_depth - $stem_throw);
}
keystem_positions() {
color(color4) supports($support_type, $stem_type, $stem_throw, $total_depth - $stem_throw);
}
}
// a fake cherry keyswitch, abstracted out to maybe replace with a better one later
module cherry_keyswitch() {
union() {
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
}
union() {
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
}
}
//approximate (fully depressed) cherry key to check clearances
module clearance_check() {
if($stem_type == "cherry" || $stem_type == "cherry_rounded"){
color(transparent_red){
translate([0,0,3.6 + $stem_inset - 5]) {
cherry_keyswitch();
}
}
}
if($stem_type == "cherry" || $stem_type == "cherry_rounded"){
color(transparent_red){
translate([0,0,3.6 + $stem_inset - 5]) {
cherry_keyswitch();
}
}
}
}
// legends / artisan support
module artisan(legend, depth) {
top_of_key() {
// outset legend
if (legend != "") keytext(legend, depth);
// artisan objects / outset shape legends
children();
}
top_of_key() {
// outset legend
if (legend != "") keytext(legend, depth);
// artisan objects / outset shape legends
children();
}
}
// key with hollowed inside but no stem
module keytop() {
difference(){
if ($rounded_key) {
rounded_shape();
} else {
shape(0, 0);
}
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
shape($wall_thickness, $keytop_thickness);
}
}
difference(){
if ($rounded_key) {
rounded_shape();
} else {
shape(0, 0);
}
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
shape($wall_thickness, $keytop_thickness);
}
}
}
// The final, penultimate key generation function.
// takes all the bits and glues them together. requires configuration with special variables.
module key(legend = "", inset = false) {
difference() {
union(){
// the shape of the key, inside and out
keytop();
// additive objects at the top of the key
if(!inset) artisan(legend) children();
// render the clearance check if it's enabled, but don't have it intersect with anything
if ($clearance_check) %clearance_check();
}
difference() {
union(){
// the shape of the key, inside and out
keytop();
// additive objects at the top of the key
if(!inset) artisan(legend) children();
// render the clearance check if it's enabled, but don't have it intersect with anything
if ($clearance_check) %clearance_check();
}
// subtractive objects at the top of the key
if (inset) artisan(legend, 0.3) children();
// subtract the clearance check if it's enabled, letting the user see the
// parts of the keycap that will hit the cherry switch
if ($clearance_check) clearance_check();
}
// subtractive objects at the top of the key
if (inset) artisan(legend, 0.3) children();
// subtract the clearance check if it's enabled, letting the user see the
// parts of the keycap that will hit the cherry switch
if ($clearance_check) clearance_check();
}
// both stem and support are optional
if ($stem_type){
dished($keytop_thickness, $inverted_dish) {
translate([0, 0, $stem_inset]) keystems();
}
}
// both stem and support are optional
if ($stem_type){
dished($keytop_thickness, $inverted_dish) {
translate([0, 0, $stem_inset]) keystems();
}
}
if ($support_type){
inside() {
translate([0, 0, $stem_inset]) keystem_supports();
}
}
if ($support_type){
inside() {
translate([0, 0, $stem_inset]) keystem_supports();
}
}
}
// key width functions
@ -925,11 +925,11 @@ module 6_25uh() {
// unlike the other files with their own dedicated folders, this one doesn't need a selector. it just collects all the functions
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;
// 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;
@ -960,16 +960,16 @@ module dcs_row(n=1) {
}
module oem_row(n=1) {
$bottom_key_width = 18.05;
$bottom_key_height = 18.05;
$width_difference = 5.8;
$height_difference = 4;
$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;
$stem_inset = 1.2;
if (n == 5) {
$total_depth = 11.2;
@ -995,41 +995,41 @@ module oem_row(n=1) {
}
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;
$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();
}
module sa_row(n=1) {
$bottom_key_width = 18.4;
$bottom_key_height = 18.4;
$width_difference = 5.7;
$height_difference = 5.7;
$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;
$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;
@ -1051,24 +1051,24 @@ module sa_row(n=1) {
}
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;
$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();
children();
}
// man, wouldn't it be so cool if functions were first order
@ -1089,7 +1089,7 @@ module key_profile(key_profile_type, row) {
module spacebar() {
$inverted_dish = true;
$dish_type = "sideways cylindrical";
6_25u() stabilized(mm=50) children();
6_25u() stabilized(mm=50) children();
}
module lshift() {
@ -1130,20 +1130,20 @@ module stepped_caps_lock() {
}
module iso_enter() {
$key_length = 1.5;
$key_height = 2;
$key_length = 1.5;
$key_height = 2;
$top_tilt = 0;
$key_shape_type = "iso_enter";
$linear_extrude_shape = true;
$linear_extrude_height_adjustment = 19.05 * 0.5;
// (unit_length(1.5) - unit_length(1.25)) / 2
$dish_overdraw_width = 2.38125;
$top_tilt = 0;
$key_shape_type = "iso_enter";
$linear_extrude_shape = true;
$linear_extrude_height_adjustment = 19.05 * 0.5;
// (unit_length(1.5) - unit_length(1.25)) / 2
$dish_overdraw_width = 2.38125;
stabilized(vertical=true) {
children();
}
children();
}
}

View File

@ -10,20 +10,20 @@ geodesic=false;
//dish selector
module dish(width, height, depth, inverted) {
if($dish_type == "cylindrical"){
cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "spherical") {
spherical_dish(width, height, depth, inverted);
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
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 changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
if($dish_type == "cylindrical"){
cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "spherical") {
spherical_dish(width, height, depth, inverted);
}
else if ($dish_type == "sideways cylindrical"){
sideways_cylindrical_dish(width, height, depth, inverted);
}
else if ($dish_type == "old spherical") {
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 changes to stems being differenced from the dish instead of the inside
translate([0,0,500]) cube([width, height, 1000], center=true);
}
}

View File

@ -1,16 +1,16 @@
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);
// .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]){

View File

@ -3,23 +3,23 @@
// 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
//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);
// 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);
}
}
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

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

View File

@ -1,26 +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
//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);
// 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=6.5;
// rotate 1 because the bottom of the sphere looks like trash.
scale([chord/2/depth, chord/2/depth]) {
sphere(r=depth);
}
}
translate([0,0,0 * direction]){
if (geodesic){
$fa=20;
scale([chord/2/depth, chord/2/depth]) {
geodesic_sphere(r=depth);
}
} else {
$fa=6.5;
// rotate 1 because the bottom of the sphere looks like trash.
scale([chord/2/depth, chord/2/depth]) {
sphere(r=depth);
}
}
}
}

View File

@ -1,7 +1,7 @@
module keybump(depth = 0, edge_inset=0.4) {
radius = 0.5;
translate([0, -top_total_key_height()/2 + edge_inset, depth]){
translate([0, -top_total_key_height()/2 + edge_inset, depth]){
rotate([90,0,90]) cylinder($font_size, radius, radius, true);
translate([0,0,-radius]) cube([$font_size, radius*2, radius*2], true);
}
}
}

View File

@ -30,23 +30,23 @@ function top_total_key_height() = $bottom_key_height + (unit * ($key_height - 1)
// key shape including dish. used as the ouside and inside shape in keytop(). allows for itself to be shrunk in depth and width / height
module shape(thickness_difference, depth_difference){
dished(depth_difference, $inverted_dish) {
color(color1) shape_hull(thickness_difference, depth_difference, 2);
}
dished(depth_difference, $inverted_dish) {
color(color1) shape_hull(thickness_difference, depth_difference, 2);
}
}
// shape of the key but with soft, rounded edges. much more realistic, MUCH more complex. orders of magnitude more complex
module rounded_shape() {
color(color1) minkowski(){
// half minkowski in the z direction
shape($minkowski_radius * 2, $minkowski_radius/2);
difference(){
sphere(r=$minkowski_radius, $fn=20);
translate([0,0,-$minkowski_radius]){
cube($minkowski_radius * 2, center=true);
}
}
}
color(color1) minkowski(){
// half minkowski in the z direction
shape($minkowski_radius * 2, $minkowski_radius/2);
difference(){
sphere(r=$minkowski_radius, $fn=20);
translate([0,0,-$minkowski_radius]){
cube($minkowski_radius * 2, center=true);
}
}
}
}
@ -55,239 +55,239 @@ module rounded_shape() {
// $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 ($linear_extrude_shape) {
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
} else {
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
}
}
render() {
if ($linear_extrude_shape) {
linear_extrude_shape_hull(thickness_difference, depth_difference, extra_slices);
} else {
hull_shape_hull(thickness_difference, depth_difference, extra_slices);
}
}
}
// corollary is hull_shape_hull
// 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();
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));
}
}
}
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));
}
}
}
}
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);
}
}
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;
depth_this_slice = ($total_depth - depth_difference) * progress;
tilt_this_slice = -$top_tilt / $key_height * progress;
skew_this_slice = $top_skew * progress;
depth_this_slice = ($total_depth - depth_difference) * progress;
tilt_this_slice = -$top_tilt / $key_height * progress;
translate([0, skew_this_slice, depth_this_slice]) {
rotate([tilt_this_slice,0,0]){
linear_extrude(height = 0.001){
key_shape(
[
total_key_width(thickness_difference),
total_key_height(thickness_difference)
],
[$width_difference, $height_difference],
progress
);
}
}
}
translate([0, skew_this_slice, depth_this_slice]) {
rotate([tilt_this_slice,0,0]){
linear_extrude(height = 0.001){
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();
}
intersection() {
shape($wall_thickness, $keytop_thickness);
children();
}
}
// put something at the top of the key, with no adjustments for dishing
module top_placement(depth_difference) {
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
rotate([-$top_tilt / $key_height,0,0]){
children();
}
}
translate([$dish_skew_x, $top_skew + $dish_skew_y, $total_depth - depth_difference]){
rotate([-$top_tilt / $key_height,0,0]){
children();
}
}
}
// just to DRY up the code
module _dish() {
color(color3) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
color(color3) dish(top_total_key_width() + $dish_overdraw_width, top_total_key_height() + $dish_overdraw_height, $dish_depth, $inverted_dish);
}
// for when you want to take the dish out of things
// used for adding the dish to the key shape and making sure stems don't stick out the top
module dished(depth_difference, inverted = false) {
difference() {
children();
top_placement(depth_difference){
difference(){
union() {
translate([-500, -500]) cube(1000);
if (!inverted) _dish();
}
if (inverted) _dish();
}
}
}
difference() {
children();
top_placement(depth_difference){
difference(){
union() {
translate([-500, -500]) cube(1000);
if (!inverted) _dish();
}
if (inverted) _dish();
}
}
}
}
// puts it's children at the center of the dishing on the key, including dish height
// more user-friendly than top_placement
module top_of_key(){
// if there is a dish, we need to account for how much it digs into the top
dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
// if the dish is inverted, we need to account for that too. in this case we do half, otherwise the children would be floating on top of the dish
corrected_dish_depth = ($inverted_dish) ? -dish_depth / 2 : dish_depth;
// if there is a dish, we need to account for how much it digs into the top
dish_depth = ($dish_type == "no dish") ? 0 : $dish_depth;
// if the dish is inverted, we need to account for that too. in this case we do half, otherwise the children would be floating on top of the dish
corrected_dish_depth = ($inverted_dish) ? -dish_depth / 2 : dish_depth;
top_placement(corrected_dish_depth) {
children();
}
top_placement(corrected_dish_depth) {
children();
}
}
module keytext(text, position, font_size, depth) {
woffset = (top_total_key_width()/3.5) * position[0];
hoffset = (top_total_key_height()/3.5) * -position[1];
translate([woffset, hoffset, -depth]){
linear_extrude(height=$dish_depth){
text(text=text, font=$font, size=font_size, halign="center", valign="center");
}
}
translate([woffset, hoffset, -depth]){
linear_extrude(height=$dish_depth){
text(text=text, font=$font, size=font_size, halign="center", valign="center");
}
}
}
module keystem_positions() {
for (connector_pos = $connectors) {
translate(connector_pos) {
rotate([0, 0, $stem_rotation]){
children();
}
}
}
for (connector_pos = $connectors) {
translate(connector_pos) {
rotate([0, 0, $stem_rotation]){
children();
}
}
}
}
module keystems() {
keystem_positions() {
color(color4) stem($stem_type, $total_depth, $has_brim);
}
keystem_positions() {
color(color4) stem($stem_type, $total_depth, $has_brim);
}
}
module keystem_supports() {
keystem_positions() {
color(color4) supports($support_type, $stem_type, $stem_throw, $total_depth - $stem_throw);
}
keystem_positions() {
color(color4) supports($support_type, $stem_type, $stem_throw, $total_depth - $stem_throw);
}
}
// a fake cherry keyswitch, abstracted out to maybe replace with a better one later
module cherry_keyswitch() {
union() {
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
}
union() {
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,1,5 - 0.01]) cube([10.5,9.5, 0.01], center=true);
}
hull() {
cube([15.6, 15.6, 0.01], center=true);
translate([0,0,-5.5]) cube([13.5,13.5,0.01], center=true);
}
}
}
//approximate (fully depressed) cherry key to check clearances
module clearance_check() {
if($stem_type == "cherry" || $stem_type == "cherry_rounded"){
color(transparent_red){
translate([0,0,3.6 + $stem_inset - 5]) {
cherry_keyswitch();
}
}
}
if($stem_type == "cherry" || $stem_type == "cherry_rounded"){
color(transparent_red){
translate([0,0,3.6 + $stem_inset - 5]) {
cherry_keyswitch();
}
}
}
}
// legends / artisan support
module artisan(depth) {
top_of_key() {
// outset legend
top_of_key() {
// outset legend
for (i=[0:len($legends)-1]) {
keytext($legends[i][0], $legends[i][1], $legends[i][2], depth);
}
// artisan objects / outset shape legends
children();
}
// artisan objects / outset shape legends
children();
}
}
// key with hollowed inside but no stem
module keytop() {
difference(){
if ($rounded_key) {
rounded_shape();
} else {
shape(0, 0);
}
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
shape($wall_thickness, $keytop_thickness);
}
}
difference(){
if ($rounded_key) {
rounded_shape();
} else {
shape(0, 0);
}
// translation purely for aesthetic purposes, to get rid of that awful lattice
translate([0,0,-0.005]) {
shape($wall_thickness, $keytop_thickness);
}
}
}
// The final, penultimate key generation function.
// takes all the bits and glues them together. requires configuration with special variables.
module key(inset = false) {
difference() {
union(){
// the shape of the key, inside and out
keytop();
difference() {
union(){
// the shape of the key, inside and out
keytop();
if($key_bump) top_of_key() keybump($key_bump_depth, $key_bump_edge);
// additive objects at the top of the key
if(!inset) artisan() children();
// render the clearance check if it's enabled, but don't have it intersect with anything
if ($clearance_check) %clearance_check();
}
// additive objects at the top of the key
if(!inset) artisan() children();
// render the clearance check if it's enabled, but don't have it intersect with anything
if ($clearance_check) %clearance_check();
}
// subtractive objects at the top of the key
if (inset) artisan(0.3) children();
// subtract the clearance check if it's enabled, letting the user see the
// parts of the keycap that will hit the cherry switch
if ($clearance_check) clearance_check();
}
// subtractive objects at the top of the key
if (inset) artisan(0.3) children();
// subtract the clearance check if it's enabled, letting the user see the
// parts of the keycap that will hit the cherry switch
if ($clearance_check) clearance_check();
}
// both stem and support are optional
if ($stem_type){
dished($keytop_thickness, $inverted_dish) {
translate([0, 0, $stem_inset]) keystems();
}
}
// both stem and support are optional
if ($stem_type){
dished($keytop_thickness, $inverted_dish) {
translate([0, 0, $stem_inset]) keystems();
}
}
if ($support_type){
inside() {
translate([0, 0, $stem_inset]) keystem_supports();
}
}
if ($support_type){
inside() {
translate([0, 0, $stem_inset]) keystem_supports();
}
}
}
// actual full key with space carved out and keystem/stabilizer connectors
// this is an example key with all the fixins from settings.scad
module example_key(){
include <settings.scad>
key();
include <settings.scad>
key();
}
example_key();

View File

@ -1,9 +1,9 @@
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;
// 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;

View File

@ -1,21 +1,21 @@
module dsa_row(n=3) {
depth_raisers = [0, 3.5, 1, 0, 1, 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 + depth_raisers[n];
$top_tilt = n == 5 ? -21 : (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;
$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 + depth_raisers[n];
$top_tilt = n == 5 ? -21 : (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();
}

View File

@ -1,22 +1,22 @@
module g20_row(n=3) {
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 2;
$height_difference = 2;
$total_depth = 6 + abs((n-3) * 0.5);
$top_tilt = 2.5;
$top_tilt = n == 5 ? -18.5 : (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;
$bottom_key_width = 18.16;
$bottom_key_height = 18.16;
$width_difference = 2;
$height_difference = 2;
$total_depth = 6 + abs((n-3) * 0.5);
$top_tilt = 2.5;
$top_tilt = n == 5 ? -18.5 : (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;
$key_bump_depth = 0.6;
$key_bump_edge = 2;
//also,
$rounded_key = true;
$rounded_key = true;
children();
children();
}

View File

@ -1,14 +1,14 @@
module oem_row(n=1) {
$bottom_key_width = 18.05;
$bottom_key_height = 18.05;
$width_difference = 5.8;
$height_difference = 4;
$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;
$stem_inset = 1.2;
if (n == 5) {
$total_depth = 11.2;

View File

@ -1,22 +1,22 @@
module sa_row(n=1) {
$bottom_key_width = 18.4;
$bottom_key_height = 18.4;
$width_difference = 5.7;
$height_difference = 5.7;
$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;
// 5th row is usually unsculpted or the same as the row below it
// making a super-sculpted top row (or bottom row!) would be real easy
// bottom row would just be 13 tilt and 14.89 total depth
// top row would be something new entirely - 18 tilt maybe?
$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;
// 5th row is usually unsculpted or the same as the row below it
// making a super-sculpted top row (or bottom row!) would be real easy
// bottom row would just be 13 tilt and 14.89 total depth
// top row would be something new entirely - 18 tilt maybe?
if (n == 1 || n == 5){
$total_depth = 14.89;
$top_tilt = -13;

View File

@ -24,8 +24,8 @@ module inverted() {
}
module rotated() {
$stem_rotation = 90;
children();
$stem_rotation = 90;
children();
}
module stabilized(mm=12, vertical = false) {
@ -54,13 +54,13 @@ module dishless() {
}
module inset(val=1) {
$stem_inset = val;
children();
$stem_inset = val;
children();
}
module filled() {
$stem_type = "filled";
children();
$stem_type = "filled";
children();
}
module blank() {
@ -69,19 +69,19 @@ module blank() {
}
module cherry(slop = 0.3) {
$stem_slop = slop;
$stem_slop = slop;
$stem_type = "cherry";
children();
}
module alps(slop = 0.3) {
$stem_slop = slop;
$stem_slop = slop;
$stem_type = "alps";
children();
}
module rounded_cherry(slop = 0.3) {
$stem_slop = slop;
$stem_slop = slop;
$stem_type = "cherry_rounded";
children();
}

View File

@ -1,7 +1,7 @@
module spacebar() {
$inverted_dish = true;
$dish_type = "sideways cylindrical";
6_25u() stabilized(mm=50) children();
6_25u() stabilized(mm=50) children();
}
module lshift() {
@ -42,18 +42,18 @@ module stepped_caps_lock() {
}
module iso_enter() {
$key_length = 1.5;
$key_height = 2;
$key_length = 1.5;
$key_height = 2;
$top_tilt = 0;
$key_shape_type = "iso_enter";
$linear_extrude_shape = true;
$linear_extrude_height_adjustment = 19.05 * 0.5;
// (unit_length(1.5) - unit_length(1.25)) / 2
$dish_overdraw_width = 2.38125;
$top_tilt = 0;
$key_shape_type = "iso_enter";
$linear_extrude_shape = true;
$linear_extrude_height_adjustment = 19.05 * 0.5;
// (unit_length(1.5) - unit_length(1.25)) / 2
$dish_overdraw_width = 2.38125;
stabilized(vertical=true) {
children();
}
children();
}
}

View File

@ -78,4 +78,3 @@ example:
module arrow(l=1,w=.6,t=0.15) {
mirror_y() polygon([[0,0],[l,0],[l-w/2,w/2],[l-w/2-sqrt(2)*t,w/2],[l-t/2-sqrt(2)*t,t/2],[0,t/2]]);
}

View File

@ -1,6 +1,6 @@
// NOTE: this code uses
// * experimental let() syntax
// * experimental let() syntax
// * experimental list comprehension syntax
// * search() bugfix and feature addition
// * vector min()/max()
@ -12,193 +12,193 @@
// polyhedron [[i1,i2,i3],[i2,i3,i4],...]
function hull(points) =
!(len(points) > 0) ? [] :
len(points[0]) == 2 ? convexhull2d(points) :
len(points[0]) == 3 ? convexhull3d(points) : [];
!(len(points) > 0) ? [] :
len(points[0]) == 2 ? convexhull2d(points) :
len(points[0]) == 3 ? convexhull3d(points) : [];
epsilon = 1e-9;
// 2d version
function convexhull2d(points) =
len(points) < 3 ? [] : let(
a=0, b=1,
a=0, b=1,
c = find_first_noncollinear([a,b], points, 2)
c = find_first_noncollinear([a,b], points, 2)
) c == len(points) ? convexhull_collinear(points) : let(
remaining = [ for (i = [2:len(points)-1]) if (i != c) i ],
remaining = [ for (i = [2:len(points)-1]) if (i != c) i ],
polygon = area_2d(points[a], points[b], points[c]) > 0 ? [a,b,c] : [b,a,c]
polygon = area_2d(points[a], points[b], points[c]) > 0 ? [a,b,c] : [b,a,c]
) convex_hull_iterative_2d(points, polygon, remaining);
// Adds the remaining points one by one to the convex hull
function convex_hull_iterative_2d(points, polygon, remaining, i_=0) = i_ >= len(remaining) ? polygon :
let (
// pick a point
i = remaining[i_],
let (
// pick a point
i = remaining[i_],
// find the segments that are in conflict with the point (point not inside)
conflicts = find_conflicting_segments(points, polygon, points[i])
// find the segments that are in conflict with the point (point not inside)
conflicts = find_conflicting_segments(points, polygon, points[i])
// no conflicts, skip point and move on
) len(conflicts) == 0 ? convex_hull_iterative_2d(points, polygon, remaining, i_+1) : let(
// no conflicts, skip point and move on
) len(conflicts) == 0 ? convex_hull_iterative_2d(points, polygon, remaining, i_+1) : let(
// find the first conflicting segment and the first not conflicting
// conflict will be sorted, if not wrapping around, do it the easy way
polygon = remove_conflicts_and_insert_point(polygon, conflicts, i)
) convex_hull_iterative_2d(
points,
polygon,
remaining,
i_+1
);
// find the first conflicting segment and the first not conflicting
// conflict will be sorted, if not wrapping around, do it the easy way
polygon = remove_conflicts_and_insert_point(polygon, conflicts, i)
) convex_hull_iterative_2d(
points,
polygon,
remaining,
i_+1
);
function find_conflicting_segments(points, polygon, point) = [
for (i = [0:len(polygon)-1]) let(j = (i+1) % len(polygon))
if (area_2d(points[polygon[i]], points[polygon[j]], point) < 0)
i
for (i = [0:len(polygon)-1]) let(j = (i+1) % len(polygon))
if (area_2d(points[polygon[i]], points[polygon[j]], point) < 0)
i
];
// remove the conflicting segments from the polygon
function remove_conflicts_and_insert_point(polygon, conflicts, point) =
conflicts[0] == 0 ? let(
nonconflicting = [ for(i = [0:len(polygon)-1]) if (!contains(conflicts, i)) i ],
new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
polygon = concat([ for (i = new_indices) polygon[i] ], point)
) polygon : let(
prior_to_first_conflict = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
after_last_conflict = [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
polygon = concat(prior_to_first_conflict, point, after_last_conflict)
) polygon;
conflicts[0] == 0 ? let(
nonconflicting = [ for(i = [0:len(polygon)-1]) if (!contains(conflicts, i)) i ],
new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
polygon = concat([ for (i = new_indices) polygon[i] ], point)
) polygon : let(
prior_to_first_conflict = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
after_last_conflict = [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
polygon = concat(prior_to_first_conflict, point, after_last_conflict)
) polygon;
// 3d version
function convexhull3d(points) =
len(points) < 3 ? [ for(i = [0:1:len(points)-1]) i ] : let (
// start with a single triangle
a=0, b=1, c=2,
plane = plane(points,a,b,c),
// start with a single triangle
a=0, b=1, c=2,
plane = plane(points,a,b,c),
d = find_first_noncoplanar(plane, points, 3)
d = find_first_noncoplanar(plane, points, 3)
) d == len(points) ? /* all coplanar*/ let (
pts2d = [ for (p = points) plane_project(p, points[a], points[b], points[c]) ],
hull2d = convexhull2d(pts2d)
pts2d = [ for (p = points) plane_project(p, points[a], points[b], points[c]) ],
hull2d = convexhull2d(pts2d)
) hull2d : let(
remaining = [for (i = [3:len(points)-1]) if (i != d) i],
remaining = [for (i = [3:len(points)-1]) if (i != d) i],
// Build an initial tetrahedron
// Build an initial tetrahedron
// swap b,c if d is in front of triangle t
bc = in_front(plane, points[d]) ? [c,b] : [b,c],
b = bc[0], c = bc[1],
// swap b,c if d is in front of triangle t
bc = in_front(plane, points[d]) ? [c,b] : [b,c],
b = bc[0], c = bc[1],
triangles = [
[a,b,c],
[d,b,a],
[c,d,a],
[b,d,c],
],
triangles = [
[a,b,c],
[d,b,a],
[c,d,a],
[b,d,c],
],
// calculate the plane equations
planes = [ for (t = triangles) plane(points, t[0], t[1], t[2]) ]
// calculate the plane equations
planes = [ for (t = triangles) plane(points, t[0], t[1], t[2]) ]
) convex_hull_iterative(points, triangles, planes, remaining);
// A plane equation (normal, offset)
function plane(points, a, b, c) = let(
normal = unit(cross(points[c]-points[a], points[b]-points[a]))
normal = unit(cross(points[c]-points[a], points[b]-points[a]))
) [
normal,
normal * points[a]
normal,
normal * points[a]
];
// Adds the remaining points one by one to the convex hull
function convex_hull_iterative(points, triangles, planes, remaining, i_=0) = i_ >= len(remaining) ? triangles :
let (
// pick a point
i = remaining[i_],
let (
// pick a point
i = remaining[i_],
// find the triangles that are in conflict with the point (point not inside)
conflicts = find_conflicts(points[i], planes),
// find the triangles that are in conflict with the point (point not inside)
conflicts = find_conflicts(points[i], planes),
// for all triangles that are in conflict, collect their halfedges
halfedges = [
for(c = conflicts)
for(i = [0:2]) let(j = (i+1)%3)
[triangles[c][i], triangles[c][j]]
],
// for all triangles that are in conflict, collect their halfedges
halfedges = [
for(c = conflicts)
for(i = [0:2]) let(j = (i+1)%3)
[triangles[c][i], triangles[c][j]]
],
// find the outer perimeter of the set of conflicting triangles
horizon = remove_internal_edges(halfedges),
// find the outer perimeter of the set of conflicting triangles
horizon = remove_internal_edges(halfedges),
// generate a new triangle for each horizon halfedge together with the picked point i
new_triangles = [ for (h = horizon) concat(h,i) ],
// generate a new triangle for each horizon halfedge together with the picked point i
new_triangles = [ for (h = horizon) concat(h,i) ],
// calculate the corresponding plane equations
new_planes = [ for (t = new_triangles) plane(points, t[0], t[1], t[2]) ]
// calculate the corresponding plane equations
new_planes = [ for (t = new_triangles) plane(points, t[0], t[1], t[2]) ]
) convex_hull_iterative(
points,
// remove the conflicting triangles and add the new ones
concat(remove_elements(triangles, conflicts), new_triangles),
concat(remove_elements(planes, conflicts), new_planes),
remaining,
i_+1
);
) convex_hull_iterative(
points,
// remove the conflicting triangles and add the new ones
concat(remove_elements(triangles, conflicts), new_triangles),
concat(remove_elements(planes, conflicts), new_planes),
remaining,
i_+1
);
function convexhull_collinear(points) = let(
n = points[1] - points[0],
a = points[0],
points1d = [ for(p = points) (p-a)*n ],
min_i = min_index(points1d),
max_i = max_index(points1d)
n = points[1] - points[0],
a = points[0],
points1d = [ for(p = points) (p-a)*n ],
min_i = min_index(points1d),
max_i = max_index(points1d)
) [ min_i, max_i ];
function min_index(values,min_,min_i_,i_) =
i_ == undef ? min_index(values,values[0],0,1) :
i_ >= len(values) ? min_i_ :
values[i_] < min_ ? min_index(values,values[i_],i_,i_+1)
: min_index(values,min_,min_i_,i_+1);
i_ == undef ? min_index(values,values[0],0,1) :
i_ >= len(values) ? min_i_ :
values[i_] < min_ ? min_index(values,values[i_],i_,i_+1)
: min_index(values,min_,min_i_,i_+1);
function max_index(values,max_,max_i_,i_) =
i_ == undef ? max_index(values,values[0],0,1) :
i_ >= len(values) ? max_i_ :
values[i_] > max_ ? max_index(values,values[i_],i_,i_+1)
: max_index(values,max_,max_i_,i_+1);
i_ == undef ? max_index(values,values[0],0,1) :
i_ >= len(values) ? max_i_ :
values[i_] > max_ ? max_index(values,values[i_],i_,i_+1)
: max_index(values,max_,max_i_,i_+1);
function remove_elements(array, elements) = [
for (i = [0:len(array)-1])
if (!search(i, elements))
array[i]
for (i = [0:len(array)-1])
if (!search(i, elements))
array[i]
];
function remove_internal_edges(halfedges) = [
for (h = halfedges)
if (!contains(halfedges, reverse(h)))
h
for (h = halfedges)
if (!contains(halfedges, reverse(h)))
h
];
function plane_project(point, a, b, c) = let(
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u),
relpoint = point-a
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u),
relpoint = point-a
) [relpoint * u, relpoint * w];
function plane_unproject(point, a, b, c) = let(
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u)
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u)
) a + point[0] * u + point[1] * w;
function reverse(arr) = [ for (i = [len(arr)-1:-1:0]) arr[i] ];
@ -206,22 +206,22 @@ function reverse(arr) = [ for (i = [len(arr)-1:-1:0]) arr[i] ];
function contains(arr, element) = search([element],arr)[0] != [] ? true : false;
function find_conflicts(point, planes) = [
for (i = [0:len(planes)-1])
if (in_front(planes[i], point))
i
for (i = [0:len(planes)-1])
if (in_front(planes[i], point))
i
];
function find_first_noncollinear(line, points, i) =
i >= len(points) ? len(points) :
collinear(points[line[0]],
points[line[1]],
points[i]) ? find_first_noncollinear(line, points, i+1)
: i;
i >= len(points) ? len(points) :
collinear(points[line[0]],
points[line[1]],
points[i]) ? find_first_noncollinear(line, points, i+1)
: i;
function find_first_noncoplanar(plane, points, i) =
i >= len(points) ? len(points) :
coplanar(plane, points[i]) ? find_first_noncoplanar(plane, points, i+1)
: i;
coplanar(plane, points[i]) ? find_first_noncoplanar(plane, points, i+1)
: i;
function distance(plane, point) = plane[0] * point - plane[1];
@ -232,9 +232,9 @@ function coplanar(plane, point) = abs(distance(plane,point)) <= epsilon;
function unit(v) = v/norm(v);
function area_2d(a,b,c) = (
a[0] * (b[1] - c[1]) +
b[0] * (c[1] - a[1]) +
c[0] * (a[1] - b[1])) / 2;
a[0] * (b[1] - c[1]) +
b[0] * (c[1] - a[1]) +
c[0] * (a[1] - b[1])) / 2;
function collinear(a,b,c) = abs(area_2d(a,b,c)) < epsilon;
@ -244,9 +244,9 @@ function spherical(cartesian) = [
];
function cartesian(spherical) = [
cos(spherical[1]) * cos(spherical[0]),
cos(spherical[1]) * sin(spherical[0]),
sin(spherical[1])
cos(spherical[1]) * cos(spherical[0]),
cos(spherical[1]) * sin(spherical[0]),
sin(spherical[1])
];
@ -256,12 +256,12 @@ function cartesian(spherical) = [
phi = 1.618033988749895;
testpoints_on_sphere = [ for(p =
[
[1,phi,0], [-1,phi,0], [1,-phi,0], [-1,-phi,0],
[0,1,phi], [0,-1,phi], [0,1,-phi], [0,-1,-phi],
[phi,0,1], [-phi,0,1], [phi,0,-1], [-phi,0,-1]
])
unit(p)
[
[1,phi,0], [-1,phi,0], [1,-phi,0], [-1,-phi,0],
[0,1,phi], [0,-1,phi], [0,1,-phi], [0,-1,-phi],
[phi,0,1], [-phi,0,1], [phi,0,-1], [-phi,0,-1]
])
unit(p)
];
testpoints_spherical = [ for(p = testpoints_on_sphere) spherical(p) ];
@ -299,26 +299,26 @@ visualize_hull(testpoints3d);
module visualize_hull(points) {
hull = hull(points);
hull = hull(points);
%if (len(hull) > 0 && len(hull[0]) > 0)
polyhedron(points=points, faces = hull);
else
polyhedron(points=points, faces = [hull]);
%if (len(hull) > 0 && len(hull[0]) > 0)
polyhedron(points=points, faces = hull);
else
polyhedron(points=points, faces = [hull]);
for (i = [0:len(points)-1]) assign(p = points[i], $fn = 16) {
translate(p) {
if (hull_contains_index(hull,i)) {
color("blue") sphere(1);
} else {
color("red") sphere(1);
}
}
}
for (i = [0:len(points)-1]) assign(p = points[i], $fn = 16) {
translate(p) {
if (hull_contains_index(hull,i)) {
color("blue") sphere(1);
} else {
color("red") sphere(1);
}
}
}
function hull_contains_index(hull, index) =
search(index,hull,1,0) ||
search(index,hull,1,1) ||
search(index,hull,1,2);
function hull_contains_index(hull, index) =
search(index,hull,1,0) ||
search(index,hull,1,1) ||
search(index,hull,1,2);
}

View File

@ -9,22 +9,22 @@
module mirror_x() {
union() {
child();
scale([-1,1,1]) child();
}
union() {
child();
scale([-1,1,1]) child();
}
}
module mirror_y() {
union() {
child();
scale([1,-1,1]) child();
}
union() {
child();
scale([1,-1,1]) child();
}
}
module mirror_z() {
union() {
child();
scale([1,1,-1]) child();
}
union() {
child();
scale([1,1,-1]) child();
}
}

View File

@ -13,12 +13,12 @@
// - center=true and positive d places the shell centered on the edge
module outset(d=1) {
// Bug workaround for older OpenSCAD versions
if (version_num() < 20130424) render() outset_extruded(d) child();
else minkowski() {
circle(r=d);
child();
}
// Bug workaround for older OpenSCAD versions
if (version_num() < 20130424) render() outset_extruded(d) child();
else minkowski() {
circle(r=d);
child();
}
}
module outset_extruded(d=1) {
@ -29,47 +29,47 @@ module outset_extruded(d=1) {
}
module inset(d=1) {
render() inverse() outset(d=d) inverse() child();
render() inverse() outset(d=d) inverse() child();
}
module fillet(r=1) {
inset(d=r) render() outset(d=r) child();
inset(d=r) render() outset(d=r) child();
}
module rounding(r=1) {
outset(d=r) inset(d=r) child();
outset(d=r) inset(d=r) child();
}
module shell(d,center=false) {
if (center && d > 0) {
difference() {
outset(d=d/2) child();
inset(d=d/2) child();
}
}
if (!center && d > 0) {
difference() {
outset(d=d) child();
child();
}
}
if (!center && d < 0) {
difference() {
child();
inset(d=-d) child();
}
}
if (d == 0) child();
if (center && d > 0) {
difference() {
outset(d=d/2) child();
inset(d=d/2) child();
}
}
if (!center && d > 0) {
difference() {
outset(d=d) child();
child();
}
}
if (!center && d < 0) {
difference() {
child();
inset(d=-d) child();
}
}
if (d == 0) child();
}
// Below are for internal use only
module inverse() {
difference() {
square(1e5,center=true);
child();
}
difference() {
square(1e5,center=true);
child();
}
}
@ -78,32 +78,32 @@ module inverse() {
use <mirror.scad>
module arrow(l=1,w=.6,t=0.15) {
mirror_y() polygon([[0,0],[l,0],[l-w/2,w/2],[l-w/2-sqrt(2)*t,w/2],[l-t/2-sqrt(2)*t,t/2],[0,t/2]]);
mirror_y() polygon([[0,0],[l,0],[l-w/2,w/2],[l-w/2-sqrt(2)*t,w/2],[l-t/2-sqrt(2)*t,t/2],[0,t/2]]);
}
module shape() {
polygon([[0,0],[1,0],[1.5,1],[2.5,1],[2,-1],[0,-1]]);
polygon([[0,0],[1,0],[1.5,1],[2.5,1],[2,-1],[0,-1]]);
}
if(0) assign($fn=32) {
for (p = [0:10*3-1]) assign(o=floor(p/3)) {
translate([(p%3)*2.5,-o*3]) {
//%if (p % 3 == 1) translate([0,0,1]) shape();
if (p % 3 == 0) shape();
if (p % 3 == 1) translate([0.6,0]) arrow();
if (p % 3 == 2) {
if (o == 0) inset(d=0.3) shape();
if (o == 1) outset(d=0.3) shape();
if (o == 2) rounding(r=0.3) shape();
if (o == 3) fillet(r=0.3) shape();
if (o == 4) shell(d=0.3) shape();
if (o == 5) shell(d=-0.3) shape();
if (o == 6) shell(d=0.3,center=true) shape();
if (o == 7) rounding(r=0.3) fillet(r=0.3) shape();
if (o == 8) shell(d=0.3,center=true) fillet(r=0.3) rounding(r=0.3) shape();
if (o == 9) shell(d=-0.3) fillet(r=0.3) rounding(r=0.3) shape();
}
}
}
for (p = [0:10*3-1]) assign(o=floor(p/3)) {
translate([(p%3)*2.5,-o*3]) {
//%if (p % 3 == 1) translate([0,0,1]) shape();
if (p % 3 == 0) shape();
if (p % 3 == 1) translate([0.6,0]) arrow();
if (p % 3 == 2) {
if (o == 0) inset(d=0.3) shape();
if (o == 1) outset(d=0.3) shape();
if (o == 2) rounding(r=0.3) shape();
if (o == 3) fillet(r=0.3) shape();
if (o == 4) shell(d=0.3) shape();
if (o == 5) shell(d=-0.3) shape();
if (o == 6) shell(d=0.3,center=true) shape();
if (o == 7) rounding(r=0.3) fillet(r=0.3) shape();
if (o == 8) shell(d=0.3,center=true) fillet(r=0.3) rounding(r=0.3) shape();
if (o == 9) shell(d=-0.3) fillet(r=0.3) rounding(r=0.3) shape();
}
}
}
}

View File

@ -5,12 +5,12 @@ function circle(r) = [for (i=[0:$fn-1]) let (a=i*360/$fn) r * [cos(a), sin(a)]];
function regular(r, n) = circle(r, $fn=n);
function rectangle_profile(size=[1,1]) = [
// The first point is the anchor point, put it on the point corresponding to [cos(0),sin(0)]
[ size[0]/2, 0],
[ size[0]/2, size[1]/2],
[-size[0]/2, size[1]/2],
[-size[0]/2, -size[1]/2],
[ size[0]/2, -size[1]/2],
// The first point is the anchor point, put it on the point corresponding to [cos(0),sin(0)]
[ size[0]/2, 0],
[ size[0]/2, size[1]/2],
[-size[0]/2, size[1]/2],
[-size[0]/2, -size[1]/2],
[ size[0]/2, -size[1]/2],
];
// FIXME: Move rectangle and rounded rectangle from extrusion

View File

@ -11,28 +11,28 @@ function rodrigues_so3_exp(w, A, B) = [
function so3_exp(w) = so3_exp_rad(w/180*PI);
function so3_exp_rad(w) =
combine_so3_exp(w,
w*w < 1e-8
? so3_exp_1(w*w)
: w*w < 1e-6
? so3_exp_2(w*w)
: so3_exp_3(w*w));
w*w < 1e-8
? so3_exp_1(w*w)
: w*w < 1e-6
? so3_exp_2(w*w)
: so3_exp_3(w*w));
function combine_so3_exp(w,AB) = rodrigues_so3_exp(w,AB[0],AB[1]);
// Taylor series expansions close to 0
function so3_exp_1(theta_sq) = [
1 - 1/6*theta_sq,
0.5
1 - 1/6*theta_sq,
0.5
];
function so3_exp_2(theta_sq) = [
1.0 - theta_sq * (1.0 - theta_sq/20) / 6,
0.5 - 0.25/6 * theta_sq
1.0 - theta_sq * (1.0 - theta_sq/20) / 6,
0.5 - 0.25/6 * theta_sq
];
function so3_exp_3_0(theta_deg, inv_theta) = [
sin(theta_deg) * inv_theta,
(1 - cos(theta_deg)) * (inv_theta * inv_theta)
sin(theta_deg) * inv_theta,
(1 - cos(theta_deg)) * (inv_theta * inv_theta)
];
function so3_exp_3(theta_sq) = so3_exp_3_0(sqrt(theta_sq)*180/PI, 1/sqrt(theta_sq));
@ -42,41 +42,41 @@ function rot_axis_part(m) = [m[2][1] - m[1][2], m[0][2] - m[2][0], m[1][0] - m[0
function so3_ln(m) = 180/PI*so3_ln_rad(m);
function so3_ln_rad(m) = so3_ln_0(m,
cos_angle = rot_cos_angle(m),
preliminary_result = rot_axis_part(m));
cos_angle = rot_cos_angle(m),
preliminary_result = rot_axis_part(m));
function so3_ln_0(m, cos_angle, preliminary_result) =
so3_ln_1(m, cos_angle, preliminary_result,
sin_angle_abs = sqrt(preliminary_result*preliminary_result));
sin_angle_abs = sqrt(preliminary_result*preliminary_result));
function so3_ln_1(m, cos_angle, preliminary_result, sin_angle_abs) =
cos_angle > sqrt(1/2)
? sin_angle_abs > 0
? preliminary_result * asin(sin_angle_abs)*PI/180 / sin_angle_abs
: preliminary_result
: cos_angle > -sqrt(1/2)
? preliminary_result * acos(cos_angle)*PI/180 / sin_angle_abs
: so3_get_symmetric_part_rotation(
preliminary_result,
m,
angle = PI - asin(sin_angle_abs)*PI/180,
d0 = m[0][0] - cos_angle,
d1 = m[1][1] - cos_angle,
d2 = m[2][2] - cos_angle
);
cos_angle > sqrt(1/2)
? sin_angle_abs > 0
? preliminary_result * asin(sin_angle_abs)*PI/180 / sin_angle_abs
: preliminary_result
: cos_angle > -sqrt(1/2)
? preliminary_result * acos(cos_angle)*PI/180 / sin_angle_abs
: so3_get_symmetric_part_rotation(
preliminary_result,
m,
angle = PI - asin(sin_angle_abs)*PI/180,
d0 = m[0][0] - cos_angle,
d1 = m[1][1] - cos_angle,
d2 = m[2][2] - cos_angle
);
function so3_get_symmetric_part_rotation(preliminary_result, m, angle, d0, d1, d2) =
so3_get_symmetric_part_rotation_0(preliminary_result,angle,so3_largest_column(m, d0, d1, d2));
function so3_get_symmetric_part_rotation_0(preliminary_result, angle, c_max) =
angle * unit(c_max * preliminary_result < 0 ? -c_max : c_max);
angle * unit(c_max * preliminary_result < 0 ? -c_max : c_max);
function so3_largest_column(m, d0, d1, d2) =
d0*d0 > d1*d1 && d0*d0 > d2*d2
? [d0, (m[1][0]+m[0][1])/2, (m[0][2]+m[2][0])/2]
: d1*d1 > d2*d2
? [(m[1][0]+m[0][1])/2, d1, (m[2][1]+m[1][2])/2]
: [(m[0][2]+m[2][0])/2, (m[2][1]+m[1][2])/2, d2];
d0*d0 > d1*d1 && d0*d0 > d2*d2
? [d0, (m[1][0]+m[0][1])/2, (m[0][2]+m[2][0])/2]
: d1*d1 > d2*d2
? [(m[1][0]+m[0][1])/2, d1, (m[2][1]+m[1][2])/2]
: [(m[0][2]+m[2][0])/2, (m[2][1]+m[1][2])/2, d2];
__so3_test = [12,-125,110];
echo(UNITTEST_so3=norm(__so3_test-so3_ln(so3_exp(__so3_test))) < 1e-8);

View File

@ -108,6 +108,3 @@ for(t=[0:0.05:len(__s3)]) translate(spline(__s3, t)) {
translate([0,0,9]) for(t=[0:0.025:len(__s3)])
multmatrix(spline_transform(__s3,t)) cube([1,1,0.1],center=true);

View File

@ -10,34 +10,34 @@ function either(a,b,default=undef) = is_undef(a) ? (is_undef(b) ? default : b) :
function translationv(left=undef,right=undef,up=undef,down=undef,forward=undef,backward=undef,translation=undef) =
translationv_2(
x = either(up,-down),
y = either(right,-left),
z = either(forward,-backward),
translation = translation);
x = either(up,-down),
y = either(right,-left),
z = either(forward,-backward),
translation = translation);
function translationv_2(x,y,z,translation) =
x == undef && y == undef && z == undef ? translation :
is_undef(translation) ? [val(x,0),val(y,0),val(z,0)]
: undef;
x == undef && y == undef && z == undef ? translation :
is_undef(translation) ? [val(x,0),val(y,0),val(z,0)]
: undef;
function rotationv(pitch=undef,yaw=undef,roll=undef,rotation=undef) =
rotation == undef ? [val(yaw,0),val(pitch,0),val(roll,0)] :
pitch == undef && yaw == undef && roll == undef ? rotation :
undef;
rotation == undef ? [val(yaw,0),val(pitch,0),val(roll,0)] :
pitch == undef && yaw == undef && roll == undef ? rotation :
undef;
function trajectory(
left=undef, right=undef,
up=undef, down=undef,
forward=undef, backward=undef,
translation=undef,
left=undef, right=undef,
up=undef, down=undef,
forward=undef, backward=undef,
translation=undef,
pitch=undef,
yaw=undef,
roll=undef,
rotation=undef
) = concat(
translationv(left=left,right=right,up=up,down=down,forward=forward,backward=backward,translation=translation),
rotationv(pitch=pitch,yaw=yaw,roll=roll,rotation=rotation)
translationv(left=left,right=right,up=up,down=down,forward=forward,backward=backward,translation=translation),
rotationv(pitch=pitch,yaw=yaw,roll=roll,rotation=rotation)
);
function rotationm(rotation=undef,pitch=undef,yaw=undef,roll=undef) = so3_exp(rotationv(rotation=rotation,pitch=pitch,yaw=yaw,roll=roll));

View File

@ -2,88 +2,87 @@ use <linalg.scad>
use <se3.scad>
function left_multiply(a,bs,i_=0) = i_ >= len(bs) ? [] :
concat([
a * bs[i_]
], left_multiply(a,bs,i_+1));
concat([
a * bs[i_]
], left_multiply(a,bs,i_+1));
function right_multiply(as,b,i_=0) = i_ >= len(as) ? [] :
concat([
as[i_] * b
], right_multiply(as,b,i_+1));
concat([
as[i_] * b
], right_multiply(as,b,i_+1));
function quantize_trajectory(trajectory,step=undef,start_position=0,steps=undef,i_=0,length_=undef) =
length_ == undef ? quantize_trajectory(
trajectory=trajectory,
start_position=(step==undef?norm(take3(trajectory))/steps*start_position:start_position),
length_=norm(take3(trajectory)),
step=step,steps=steps,i_=i_) :
(steps==undef?start_position > length_:i_>=steps) ? [] :
concat([
// if steps is defined, ignore start_position
se3_exp(trajectory*(steps==undef ? start_position/length_
length_ == undef ? quantize_trajectory(
trajectory=trajectory,
start_position=(step==undef?norm(take3(trajectory))/steps*start_position:start_position),
length_=norm(take3(trajectory)),
step=step,steps=steps,i_=i_) :
(steps==undef?start_position > length_:i_>=steps) ? [] :
concat([
// if steps is defined, ignore start_position
se3_exp(trajectory*(steps==undef ? start_position/length_
: i_/(steps>1?steps-1:1)))
], quantize_trajectory(trajectory=trajectory,step=step,start_position=(steps==undef?start_position+step:start_position),steps=steps,i_=i_+1,length_=length_));
], quantize_trajectory(trajectory=trajectory,step=step,start_position=(steps==undef?start_position+step:start_position),steps=steps,i_=i_+1,length_=length_));
function close_trajectory_loop(trajectories) = concat(trajectories,[se3_ln(invert_rt(trajectories_end_position(trajectories)))]);
function quantize_trajectories(trajectories,step=undef,start_position=0,steps=undef,loop=false,last_=identity4(),i_=0,current_length_=undef,j_=0) =
// due to quantization differences, the last step may be missed. In that case, add it:
loop==true ? quantize_trajectories(
trajectories=close_trajectory_loop(trajectories),
step=step,
start_position = start_position,
steps=steps,
loop=false,
last_=last_,
i_=i_,
current_length_=current_length_,
j_=j_) :
i_ >= len(trajectories) ? (j_ < steps ? [last_] : []) :
current_length_ == undef ?
quantize_trajectories(
trajectories=trajectories,
step = (step == undef ? trajectories_length(trajectories) / steps : step),
start_position = (step == undef ? start_position * trajectories_length(trajectories) / steps : start_position),
steps=steps,
loop=loop,
last_=last_,
i_=i_,
current_length_=norm(take3(trajectories[i_])),
j_=j_) :
concat(
left_multiply(last_,quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step)),
quantize_trajectories(
trajectories=trajectories,
step=step,
start_position = start_position > current_length_
? start_position - current_length_
: step - ((current_length_-start_position) % step),
steps=steps,
loop=loop,
last_=last_ * se3_exp(trajectories[i_]),
i_=i_+1,
current_length_ = undef,
j_=j_+len(
// due to quantization differences, the last step may be missed. In that case, add it:
loop==true ? quantize_trajectories(
trajectories=close_trajectory_loop(trajectories),
step=step,
start_position = start_position,
steps=steps,
loop=false,
last_=last_,
i_=i_,
current_length_=current_length_,
j_=j_) :
i_ >= len(trajectories) ? (j_ < steps ? [last_] : []) :
current_length_ == undef ?
quantize_trajectories(
trajectories=trajectories,
step = (step == undef ? trajectories_length(trajectories) / steps : step),
start_position = (step == undef ? start_position * trajectories_length(trajectories) / steps : start_position),
steps=steps,
loop=loop,
last_=last_,
i_=i_,
current_length_=norm(take3(trajectories[i_])),
j_=j_) :
concat(
left_multiply(last_,quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step)),
quantize_trajectories(
trajectories=trajectories,
step=step,
start_position = start_position > current_length_
? start_position - current_length_
: step - ((current_length_-start_position) % step),
steps=steps,
loop=loop,
last_=last_ * se3_exp(trajectories[i_]),
i_=i_+1,
current_length_ = undef,
j_=j_+len(
quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step
quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step
))
))
))
))
;
function trajectories_length(trajectories, i_=0) = i_ >= len(trajectories) ? 0
: norm(take3(trajectories[i_])) + trajectories_length(trajectories,i_+1);
: norm(take3(trajectories[i_])) + trajectories_length(trajectories,i_+1);
function trajectories_end_position(rt,i_=0,last_=identity4()) =
i_ >= len(rt) ? last_ :
trajectories_end_position(rt, i_+1, last_ * se3_exp(rt[i_]));
i_ >= len(rt) ? last_ :
trajectories_end_position(rt, i_+1, last_ * se3_exp(rt[i_]));

View File

@ -9,31 +9,31 @@ use <lists.scad>
axis = rotation_axis * rotation_angle
*/
function rotation(xyz=undef, axis=undef) =
xyz != undef && axis != undef ? undef :
xyz == undef ? se3_exp([0,0,0,axis[0],axis[1],axis[2]]) :
len(xyz) == undef ? rotation(axis=[0,0,xyz]) :
(len(xyz) >= 3 ? rotation(axis=[0,0,xyz[2]]) : identity4()) *
(len(xyz) >= 2 ? rotation(axis=[0,xyz[1],0]) : identity4()) *
(len(xyz) >= 1 ? rotation(axis=[xyz[0],0,0]) : identity4());
xyz != undef && axis != undef ? undef :
xyz == undef ? se3_exp([0,0,0,axis[0],axis[1],axis[2]]) :
len(xyz) == undef ? rotation(axis=[0,0,xyz]) :
(len(xyz) >= 3 ? rotation(axis=[0,0,xyz[2]]) : identity4()) *
(len(xyz) >= 2 ? rotation(axis=[0,xyz[1],0]) : identity4()) *
(len(xyz) >= 1 ? rotation(axis=[xyz[0],0,0]) : identity4());
/*!
Creates a scaling matrix
*/
function scaling(v) = [
[v[0],0,0,0],
[0,v[1],0,0],
[0,0,v[2],0],
[0,0,0,1],
[v[0],0,0,0],
[0,v[1],0,0],
[0,0,v[2],0],
[0,0,0,1],
];
/*!
Creates a translation matrix
*/
function translation(v) = [
[1,0,0,v[0]],
[0,1,0,v[1]],
[0,0,1,v[2]],
[0,0,0,1],
[1,0,0,v[0]],
[0,1,0,v[1]],
[0,0,1,v[2]],
[0,0,0,1],
];
// Convert between cartesian and homogenous coordinates

View File

@ -3,69 +3,69 @@ use <scad-utils/lists.scad>
// Skin a set of profiles with a polyhedral mesh
module skin(profiles, loop=false /* unimplemented */) {
P = max_len(profiles);
N = len(profiles);
P = max_len(profiles);
N = len(profiles);
profiles = [
for (p = profiles)
for (pp = augment_profile(to_3d(p),P))
pp
];
profiles = [
for (p = profiles)
for (pp = augment_profile(to_3d(p),P))
pp
];
function quad(i,P,o) = [[o+i, o+i+P, o+i%P+P+1], [o+i, o+i%P+P+1, o+i%P+1]];
function quad(i,P,o) = [[o+i, o+i+P, o+i%P+P+1], [o+i, o+i%P+P+1, o+i%P+1]];
function profile_triangles(tindex) = [
for (index = [0:P-1])
let (qs = quad(index+1, P, P*(tindex-1)-1))
for (q = qs) q
];
function profile_triangles(tindex) = [
for (index = [0:P-1])
let (qs = quad(index+1, P, P*(tindex-1)-1))
for (q = qs) q
];
triangles = [
for(index = [1:N-1])
for(t = profile_triangles(index))
t
];
for(index = [1:N-1])
for(t = profile_triangles(index))
t
];
start_cap = [range([0:P-1])];
end_cap = [range([P*N-1 : -1 : P*(N-1)])];
start_cap = [range([0:P-1])];
end_cap = [range([P*N-1 : -1 : P*(N-1)])];
polyhedron(convexity=2, points=profiles, faces=concat(start_cap, triangles, end_cap));
polyhedron(convexity=2, points=profiles, faces=concat(start_cap, triangles, end_cap));
}
// Augments the profile with steiner points making the total number of vertices n
function augment_profile(profile, n) =
subdivide(profile,insert_extra_vertices_0([profile_lengths(profile),dup(0,len(profile))],n-len(profile))[1]);
subdivide(profile,insert_extra_vertices_0([profile_lengths(profile),dup(0,len(profile))],n-len(profile))[1]);
function subdivide(profile,subdivisions) = let (N=len(profile)) [
for (i = [0:N-1])
let(n = len(subdivisions)>0 ? subdivisions[i] : subdivisions)
for (p = interpolate(profile[i],profile[(i+1)%N],n+1))
p
for (i = [0:N-1])
let(n = len(subdivisions)>0 ? subdivisions[i] : subdivisions)
for (p = interpolate(profile[i],profile[(i+1)%N],n+1))
p
];
function interpolate(a,b,subdivisions) = [
for (index = [0:subdivisions-1])
let(t = index/subdivisions)
a*(1-t)+b*t
for (index = [0:subdivisions-1])
let(t = index/subdivisions)
a*(1-t)+b*t
];
function distribute_extra_vertex(lengths_count,ma_=-1) = ma_<0 ? distribute_extra_vertex(lengths_count, max_element(lengths_count[0])) :
concat([set(lengths_count[0],ma_,lengths_count[0][ma_] * (lengths_count[1][ma_]+1) / (lengths_count[1][ma_]+2))], [increment(lengths_count[1],max_element(lengths_count[0]),1)]);
concat([set(lengths_count[0],ma_,lengths_count[0][ma_] * (lengths_count[1][ma_]+1) / (lengths_count[1][ma_]+2))], [increment(lengths_count[1],max_element(lengths_count[0]),1)]);
function insert_extra_vertices_0(lengths_count,n_extra) = n_extra <= 0 ? lengths_count :
insert_extra_vertices_0(distribute_extra_vertex(lengths_count),n_extra-1);
insert_extra_vertices_0(distribute_extra_vertex(lengths_count),n_extra-1);
// Find the index of the maximum element of arr
function max_element(arr,ma_,ma_i_=-1,i_=0) = i_ >= len(arr) ? ma_i_ :
i_ == 0 || arr[i_] > ma_ ? max_element(arr,arr[i_],i_,i_+1) : max_element(arr,ma_,ma_i_,i_+1);
i_ == 0 || arr[i_] > ma_ ? max_element(arr,arr[i_],i_,i_+1) : max_element(arr,ma_,ma_i_,i_+1);
function max_len(arr) = max([for (i=arr) len(i)]);
function increment(arr,i,x=1) = set(arr,i,arr[i]+x);
function profile_lengths(profile) = [
for (i = [0:len(profile)-1])
profile_segment_length(profile,i)
for (i = [0:len(profile)-1])
profile_segment_length(profile,i)
];
function profile_segment_length(profile,i) = norm(profile[(i+1)%len(profile)] - profile[i]);
@ -85,14 +85,14 @@ use <scad-utils/trajectory.scad>
use <scad-utils/shapes.scad>
module fakeISOEnter(thickness_difference = 0){
// 1u is the space taken upy by a 1u keycap.
// unit is the space taken up by a unit space for a keycap.
// formula is 1u + unit *(length - 1)
// 1u is the space taken upy by a 1u keycap.
// unit is the space taken up by a unit space for a keycap.
// formula is 1u + unit *(length - 1)
// t is all modifications to the polygon array
t = thickness_difference/2 - (19.02 - 18.16);
// t is all modifications to the polygon array
t = thickness_difference/2 - (19.02 - 18.16);
function unit(length) = 19.02 * length;
function unit(length) = 19.02 * length;
pointArray = [
[19.05 * (-.5) + t, 19.05 * (-1) + t],
@ -104,12 +104,12 @@ module fakeISOEnter(thickness_difference = 0){
];
/*translate([unit(-.5), unit(-1) + 0.86]){*/
minkowski() {
/*translate([unit(-.5), unit(-1) + 0.86]){*/
minkowski() {
circle($corner_radius, $fn=20);
offset(r=-$corner_radius * 2, $fn=20) polygon(points=pointArray);
}
/*}*/
}
/*}*/
}
function isoEnter() = [

View File

@ -7,15 +7,15 @@ include <shapes/square.scad>
include <shapes/oblong.scad>
module key_shape(size, delta, progress = 0) {
if ($key_shape_type == "iso_enter") {
ISO_enter_shape(size, delta, progress);
} else if ($key_shape_type == "rounded_square") {
rounded_square_shape(size, delta, progress);
} else if ($key_shape_type == "square") {
square_shape(size, delta, progress);
if ($key_shape_type == "iso_enter") {
ISO_enter_shape(size, delta, progress);
} else if ($key_shape_type == "rounded_square") {
rounded_square_shape(size, delta, progress);
} else if ($key_shape_type == "square") {
square_shape(size, delta, progress);
} else if ($key_shape_type == "oblong") {
oblong_shape(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
oblong_shape(size, delta, progress);
} else {
echo("Warning: unsupported $key_shape_type");
}
}

View File

@ -1,19 +1,19 @@
// 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;
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
// 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);
width_ratio = unit_length(1.25) / unit_length(1.5);
height_ratio = unit_length(1) / unit_length(2);
pointArray = [
[ 0, 0], // top right
@ -24,11 +24,11 @@ module ISO_enter_shape(size, delta, progress){
[ -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);
}
}
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);
}
}
}

View File

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

View File

@ -5,28 +5,28 @@ function side_sculpting(progress) = (1 - progress) * 2.5;
function corner_sculpting(progress) = pow(progress, 2);
module rounded_square_shape(size, delta, progress, center = true) {
width = size[0];
height = size[1];
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;
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);
// 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
);
}
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
);
}
}

View File

@ -6,13 +6,13 @@ 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") {
rounded_cherry_stem(depth, has_brim);
} else if (stem_type == "cherry") {
cherry_stem(depth, has_brim);
} else if (stem_type == "filled") {
if (stem_type == "alps") {
alps_stem(depth, has_brim);
} else if (stem_type == "cherry_rounded") {
rounded_cherry_stem(depth, has_brim);
} else if (stem_type == "cherry") {
cherry_stem(depth, has_brim);
} else if (stem_type == "filled") {
filled_stem();
} else {
echo("Warning: unsupported $stem_type");