From 67a830c48969fcd1bf3ce265c9745edb458b4c3a Mon Sep 17 00:00:00 2001 From: Robert Sheldon Date: Mon, 4 Jun 2018 21:13:09 -0400 Subject: [PATCH] convert all tabs to spaces --- customizer.scad | 710 +++++++++--------- src/dishes.scad | 32 +- src/dishes/cylindrical.scad | 24 +- src/dishes/old_spherical.scad | 32 +- src/dishes/sideways_cylindrical.scad | 14 +- src/dishes/spherical.scad | 38 +- src/features/key_bump.scad | 4 +- src/key.scad | 322 ++++---- src/key_profiles/dcs.scad | 10 +- src/key_profiles/dsa.scad | 32 +- src/key_profiles/g20.scad | 30 +- src/key_profiles/oem.scad | 10 +- src/key_profiles/sa.scad | 26 +- src/key_transformations.scad | 18 +- src/key_types.scad | 22 +- src/libraries/scad-utils/README.md | 7 +- src/libraries/scad-utils/hull.scad | 340 ++++----- src/libraries/scad-utils/linalg.scad | 4 +- src/libraries/scad-utils/mirror.scad | 24 +- src/libraries/scad-utils/morphology.scad | 106 +-- src/libraries/scad-utils/se3.scad | 16 +- src/libraries/scad-utils/shapes.scad | 16 +- src/libraries/scad-utils/so3.scad | 74 +- src/libraries/scad-utils/spline.scad | 25 +- src/libraries/scad-utils/trajectory.scad | 36 +- src/libraries/scad-utils/trajectory_path.scad | 135 ++-- src/libraries/scad-utils/transformations.scad | 30 +- src/libraries/skin.scad | 86 +-- src/shapes.scad | 20 +- src/shapes/ISO_enter.scad | 34 +- src/shapes/oblong.scad | 16 +- src/shapes/rounded_square.scad | 42 +- src/stems.scad | 14 +- 33 files changed, 1172 insertions(+), 1177 deletions(-) diff --git a/customizer.scad b/customizer.scad index 6fd6818..54a41df 100644 --- a/customizer.scad +++ b/customizer.scad @@ -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(); + } } diff --git a/src/dishes.scad b/src/dishes.scad index 39c1ab4..6b7ca36 100644 --- a/src/dishes.scad +++ b/src/dishes.scad @@ -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); + } } diff --git a/src/dishes/cylindrical.scad b/src/dishes/cylindrical.scad index 5040865..37c50e2 100644 --- a/src/dishes/cylindrical.scad +++ b/src/dishes/cylindrical.scad @@ -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]){ diff --git a/src/dishes/old_spherical.scad b/src/dishes/old_spherical.scad index c2726fe..b59bbde 100644 --- a/src/dishes/old_spherical.scad +++ b/src/dishes/old_spherical.scad @@ -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); + } + } } diff --git a/src/dishes/sideways_cylindrical.scad b/src/dishes/sideways_cylindrical.scad index 6d357b1..370d9e7 100644 --- a/src/dishes/sideways_cylindrical.scad +++ b/src/dishes/sideways_cylindrical.scad @@ -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 + } } diff --git a/src/dishes/spherical.scad b/src/dishes/spherical.scad index 6d7b151..4bed845 100644 --- a/src/dishes/spherical.scad +++ b/src/dishes/spherical.scad @@ -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); + } + } } } diff --git a/src/features/key_bump.scad b/src/features/key_bump.scad index 9c5b44c..a12cfe0 100644 --- a/src/features/key_bump.scad +++ b/src/features/key_bump.scad @@ -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); - } + } } diff --git a/src/key.scad b/src/key.scad index 3032466..a5a84c3 100644 --- a/src/key.scad +++ b/src/key.scad @@ -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 - key(); + include + key(); } example_key(); diff --git a/src/key_profiles/dcs.scad b/src/key_profiles/dcs.scad index fcb0312..0a2430f 100644 --- a/src/key_profiles/dcs.scad +++ b/src/key_profiles/dcs.scad @@ -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; diff --git a/src/key_profiles/dsa.scad b/src/key_profiles/dsa.scad index 3ec217b..b207713 100644 --- a/src/key_profiles/dsa.scad +++ b/src/key_profiles/dsa.scad @@ -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(); } diff --git a/src/key_profiles/g20.scad b/src/key_profiles/g20.scad index d07d8f3..67b93a7 100644 --- a/src/key_profiles/g20.scad +++ b/src/key_profiles/g20.scad @@ -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(); } diff --git a/src/key_profiles/oem.scad b/src/key_profiles/oem.scad index c3d78e1..5ee6948 100644 --- a/src/key_profiles/oem.scad +++ b/src/key_profiles/oem.scad @@ -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; diff --git a/src/key_profiles/sa.scad b/src/key_profiles/sa.scad index 3333959..45fa9ff 100644 --- a/src/key_profiles/sa.scad +++ b/src/key_profiles/sa.scad @@ -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; diff --git a/src/key_transformations.scad b/src/key_transformations.scad index 43f8729..ae8abc9 100644 --- a/src/key_transformations.scad +++ b/src/key_transformations.scad @@ -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(); } diff --git a/src/key_types.scad b/src/key_types.scad index 6ec0f30..362ded3 100644 --- a/src/key_types.scad +++ b/src/key_types.scad @@ -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(); + } } diff --git a/src/libraries/scad-utils/README.md b/src/libraries/scad-utils/README.md index 8fdd4e3..911c037 100644 --- a/src/libraries/scad-utils/README.md +++ b/src/libraries/scad-utils/README.md @@ -16,8 +16,8 @@ contains basic 2D morphology operations - positive values of d places the shell on the outside - negative values of d places the shell on the inside - center=true and positive d places the shell centered on the edge - - + + ### Examples With a basic sample polygon shape, @@ -72,10 +72,9 @@ contains simple mirroring functions mirror_x() mirror_y() mirror_z() - + 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]]); } - diff --git a/src/libraries/scad-utils/hull.scad b/src/libraries/scad-utils/hull.scad index 5e0302e..1f12f30 100644 --- a/src/libraries/scad-utils/hull.scad +++ b/src/libraries/scad-utils/hull.scad @@ -1,204 +1,204 @@ // NOTE: this code uses -// * experimental let() syntax +// * experimental let() syntax // * experimental list comprehension syntax // * search() bugfix and feature addition // * vector min()/max() -// Calculates the convex hull of a set of points. -// The result is expressed in point indices. -// If the points are collinear (or 2d), the result is a convex -// polygon [i1,i2,i3,...], otherwise a triangular +// Calculates the convex hull of a set of points. +// The result is expressed in point indices. +// If the points are collinear (or 2d), the result is a convex +// polygon [i1,i2,i3,...], otherwise a triangular // 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) : []; +function hull(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 ], - - polygon = area_2d(points[a], points[b], points[c]) > 0 ? [a,b,c] : [b,a,c] + 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] ) 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_], +function convex_hull_iterative_2d(points, polygon, remaining, i_=0) = i_ >= len(remaining) ? polygon : + 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; +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; // 3d version -function convexhull3d(points) = -len(points) < 3 ? [ for(i = [0:1:len(points)-1]) i ] : let ( +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), - - d = find_first_noncoplanar(plane, points, 3) + // 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 == 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], - - triangles = [ - [a,b,c], - [d,b,a], - [c,d,a], - [b,d,c], - ], + // 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], - // calculate the plane equations - planes = [ for (t = triangles) plane(points, t[0], t[1], t[2]) ] + 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]) ] ) 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_], +function convex_hull_iterative(points, triangles, planes, remaining, i_=0) = i_ >= len(remaining) ? triangles : + 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; +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; -function find_first_noncoplanar(plane, points, 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]) ]; @@ -255,13 +255,13 @@ 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) +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) ]; testpoints_spherical = [ for(p = testpoints_on_sphere) spherical(p) ]; @@ -299,26 +299,26 @@ visualize_hull(testpoints3d); module visualize_hull(points) { - hull = hull(points); - - %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); - } - } - } - - function hull_contains_index(hull, index) = - search(index,hull,1,0) || - search(index,hull,1,1) || - search(index,hull,1,2); + hull = hull(points); + + %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); + } + } + } + + function hull_contains_index(hull, index) = + search(index,hull,1,0) || + search(index,hull,1,1) || + search(index,hull,1,2); } diff --git a/src/libraries/scad-utils/linalg.scad b/src/libraries/scad-utils/linalg.scad index 959a38e..8c839af 100644 --- a/src/libraries/scad-utils/linalg.scad +++ b/src/libraries/scad-utils/linalg.scad @@ -8,7 +8,7 @@ function vec3(p) = len(p) < 3 ? concat(p,0) : p; function vec4(p) = let (v3=vec3(p)) len(v3) < 4 ? concat(v3,1) : v3; function unit(v) = v/norm(v); -function identity3()=[[1,0,0],[0,1,0],[0,0,1]]; +function identity3()=[[1,0,0],[0,1,0],[0,0,1]]; function identity4()=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]; @@ -24,7 +24,7 @@ function transpose_3(m) = [[m[0][0],m[1][0],m[2][0]],[m[0][1],m[1][1],m[2][1]],[ function transpose_4(m) = [[m[0][0],m[1][0],m[2][0],m[3][0]], [m[0][1],m[1][1],m[2][1],m[3][1]], [m[0][2],m[1][2],m[2][2],m[3][2]], - [m[0][3],m[1][3],m[2][3],m[3][3]]]; + [m[0][3],m[1][3],m[2][3],m[3][3]]]; function invert_rt(m) = construct_Rt(transpose_3(rotation_part(m)), -(transpose_3(rotation_part(m)) * translation_part(m))); function construct_Rt(R,t) = [concat(R[0],t[0]),concat(R[1],t[1]),concat(R[2],t[2]),[0,0,0,1]]; diff --git a/src/libraries/scad-utils/mirror.scad b/src/libraries/scad-utils/mirror.scad index bb7bbc0..1efcc98 100644 --- a/src/libraries/scad-utils/mirror.scad +++ b/src/libraries/scad-utils/mirror.scad @@ -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(); + } } diff --git a/src/libraries/scad-utils/morphology.scad b/src/libraries/scad-utils/morphology.scad index 96ff221..148df4a 100644 --- a/src/libraries/scad-utils/morphology.scad +++ b/src/libraries/scad-utils/morphology.scad @@ -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 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(); + } + } + } } diff --git a/src/libraries/scad-utils/se3.scad b/src/libraries/scad-utils/se3.scad index 48b59e6..02f6474 100644 --- a/src/libraries/scad-utils/se3.scad +++ b/src/libraries/scad-utils/se3.scad @@ -10,21 +10,21 @@ function se3_exp_1(t,w) = concat( ); function se3_exp_2(t,w) = se3_exp_2_0(t,w,w*w); -function se3_exp_2_0(t,w,theta_sq) = +function se3_exp_2_0(t,w,theta_sq) = se3_exp_23( - so3_exp_2(theta_sq), + so3_exp_2(theta_sq), C = (1.0 - theta_sq/20) / 6, t=t,w=w); function se3_exp_3(t,w) = se3_exp_3_0(t,w,sqrt(w*w)*180/PI,1/sqrt(w*w)); -function se3_exp_3_0(t,w,theta_deg,inv_theta) = +function se3_exp_3_0(t,w,theta_deg,inv_theta) = se3_exp_23( so3_exp_3_0(theta_deg = theta_deg, inv_theta = inv_theta), C = (1 - sin(theta_deg) * inv_theta) * (inv_theta * inv_theta), t=t,w=w); -function se3_exp_23(AB,C,t,w) = +function se3_exp_23(AB,C,t,w) = [AB[0], AB[1], t + AB[1] * cross(w,t) + C * cross(w,cross(w,t)) ]; function se3_exp(mu) = se3_exp_0(t=take3(mu),w=tail3(mu)/180*PI); @@ -32,7 +32,7 @@ function se3_exp(mu) = se3_exp_0(t=take3(mu),w=tail3(mu)/180*PI); function se3_exp_0(t,w) = combine_se3_exp(w, // Evaluate by Taylor expansion when near 0 - w*w < 1e-8 + w*w < 1e-8 ? se3_exp_1(t,w) : w*w < 1e-6 ? se3_exp_2(t,w) @@ -42,7 +42,7 @@ combine_se3_exp(w, function se3_ln(m) = se3_ln_to_deg(se3_ln_rad(m)); function se3_ln_to_deg(v) = concat(take3(v),tail3(v)*180/PI); -function se3_ln_rad(m) = se3_ln_0(m, +function se3_ln_rad(m) = se3_ln_0(m, rot = so3_ln_rad(rotation_part(m))); function se3_ln_0(m,rot) = se3_ln_1(m,rot, theta = sqrt(rot*rot)); @@ -50,8 +50,8 @@ function se3_ln_1(m,rot,theta) = se3_ln_2(m,rot,theta, shtot = theta > 0.00001 ? sin(theta/2*180/PI)/theta : 0.5, halfrotator = so3_exp_rad(rot * -.5)); function se3_ln_2(m,rot,theta,shtot,halfrotator) = -concat( (halfrotator * translation_part(m) - - (theta > 0.001 +concat( (halfrotator * translation_part(m) - + (theta > 0.001 ? rot * ((translation_part(m) * rot) * (1-2*shtot) / (rot*rot)) : rot * ((translation_part(m) * rot)/24) )) / (2 * shtot), rot); diff --git a/src/libraries/scad-utils/shapes.scad b/src/libraries/scad-utils/shapes.scad index 6d33d8a..f82e969 100644 --- a/src/libraries/scad-utils/shapes.scad +++ b/src/libraries/scad-utils/shapes.scad @@ -4,13 +4,13 @@ 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], +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], ]; -// FIXME: Move rectangle and rounded rectangle from extrusion \ No newline at end of file +// FIXME: Move rectangle and rounded rectangle from extrusion diff --git a/src/libraries/scad-utils/so3.scad b/src/libraries/scad-utils/so3.scad index 83308aa..2daaa8a 100644 --- a/src/libraries/scad-utils/so3.scad +++ b/src/libraries/scad-utils/so3.scad @@ -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)); +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)); -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 - ); +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 + ); 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); diff --git a/src/libraries/scad-utils/spline.scad b/src/libraries/scad-utils/spline.scad index dbf487b..cf6923a 100644 --- a/src/libraries/scad-utils/spline.scad +++ b/src/libraries/scad-utils/spline.scad @@ -20,11 +20,11 @@ z4=[0,0,0,0]; function matrix_power(m,n)= n==0? (len(m)==3?identity3():identity4()) : n==1 ? m : (n%2==1) ? matrix_power(m*m,floor(n/2))*m : matrix_power(m*m,n/2); - + function det(m) = let(r=[for(i=[0:1:len(m)-1]) i]) det_help(m, 0, r); // Construction indices list is inefficient, but currently there is no way to imperatively // assign to a list element -function det_help(m, i, r) = len(r) == 0 ? 1 : +function det_help(m, i, r) = len(r) == 0 ? 1 : m[len(m)-len(r)][r[i]]*det_help(m,0,remove(r,i)) - (i+1=len(s)?len(s)-1: floor(t), t2=t-i) [1,t2,t2*t2,t2*t2*t2]*s[i]; - +// t - defines point on curve. each segment length is 1. I.e. t= 0..1 is first segment, t=1..2 - second. +function spline(s, t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [1,t2,t2*t2,t2*t2*t2]*s[i]; + function spline_tan(s, t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [0,1,2*t2,3*t2*t2]*s[i]; function spline_tan_unit(s, t)= unit(spline_tan(s,t)); function spline_d2(s,t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [0,0,2,6*t2]*s[i]; function spline_binormal_unit(s,t)= unit(cross(spline_tan(s, t), spline_d2(s,t))); function spline_normal_unit(s,t)= unit(cross(spline_tan(s, t), spline_binormal_unit(s,t))); - + function spline_transform(s, t)= construct_Rt(transpose_3([spline_normal_unit(s,t), spline_binormal_unit(s,t), spline_tan_unit(s,t)]), spline(s,t)); - + // Unit tests __s = spline_args([[0,10,0], [10,0,0],[0,-5,2]], v1=[0,1,0], v2=[-1,0,0], closed=true); for(t=[0:0.01:len(__s)]) translate(spline(__s, t)) @@ -107,7 +107,4 @@ 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); - - - + multmatrix(spline_transform(__s3,t)) cube([1,1,0.1],center=true); diff --git a/src/libraries/scad-utils/trajectory.scad b/src/libraries/scad-utils/trajectory.scad index 1a0e737..d1323b9 100644 --- a/src/libraries/scad-utils/trajectory.scad +++ b/src/libraries/scad-utils/trajectory.scad @@ -8,36 +8,36 @@ function is_undef(x) = len(x) > 0 ? vec_is_undef(x) : x == undef; // Either a or b, but not both function either(a,b,default=undef) = is_undef(a) ? (is_undef(b) ? default : b) : is_undef(b) ? a : undef; -function translationv(left=undef,right=undef,up=undef,down=undef,forward=undef,backward=undef,translation=undef) = +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; +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; 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)); diff --git a/src/libraries/scad-utils/trajectory_path.scad b/src/libraries/scad-utils/trajectory_path.scad index f9fffe3..3c49773 100644 --- a/src/libraries/scad-utils/trajectory_path.scad +++ b/src/libraries/scad-utils/trajectory_path.scad @@ -2,88 +2,87 @@ use use 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); +function trajectories_length(trajectories, i_=0) = i_ >= len(trajectories) ? 0 + : 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_])); - +function trajectories_end_position(rt,i_=0,last_=identity4()) = + i_ >= len(rt) ? last_ : + trajectories_end_position(rt, i_+1, last_ * se3_exp(rt[i_])); diff --git a/src/libraries/scad-utils/transformations.scad b/src/libraries/scad-utils/transformations.scad index 89edff6..40cedfa 100644 --- a/src/libraries/scad-utils/transformations.scad +++ b/src/libraries/scad-utils/transformations.scad @@ -8,32 +8,32 @@ use xyz = euler angles = rz * ry * rx 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()); +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()); /*! 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 diff --git a/src/libraries/skin.scad b/src/libraries/skin.scad index f97d3c4..e372074 100644 --- a/src/libraries/skin.scad +++ b/src/libraries/skin.scad @@ -3,69 +3,69 @@ use // 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 use 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() = [ diff --git a/src/shapes.scad b/src/shapes.scad index 5a496d0..2854a36 100644 --- a/src/shapes.scad +++ b/src/shapes.scad @@ -7,15 +7,15 @@ include include 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"); + } } diff --git a/src/shapes/ISO_enter.scad b/src/shapes/ISO_enter.scad index b70adaa..ab976aa 100644 --- a/src/shapes/ISO_enter.scad +++ b/src/shapes/ISO_enter.scad @@ -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); + } + } } diff --git a/src/shapes/oblong.scad b/src/shapes/oblong.scad index fff567a..60b5d4a 100644 --- a/src/shapes/oblong.scad +++ b/src/shapes/oblong.scad @@ -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); + } + } } diff --git a/src/shapes/rounded_square.scad b/src/shapes/rounded_square.scad index 4beca23..391b17b 100644 --- a/src/shapes/rounded_square.scad +++ b/src/shapes/rounded_square.scad @@ -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 + ); + } } diff --git a/src/stems.scad b/src/stems.scad index 82e64cb..26fcd11 100644 --- a/src/stems.scad +++ b/src/stems.scad @@ -6,13 +6,13 @@ include //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");