diff --git a/dishes.scad b/dishes.scad index ad3aad1..2d90fd0 100644 --- a/dishes.scad +++ b/dishes.scad @@ -1,5 +1,5 @@ include -include +include //geodesic looks much better, but runs very slow for anything above a 2u geodesic=false; @@ -84,9 +84,6 @@ module spherical_dish(width, height, depth, inverted, tilt, txt=""){ } } } - // this line causes openscad to die. maybe re-enable when that doesn't happen instead of differencing the inside() when we add the dish to the shape() - /*translate([0,0,0]) roundedRect([width, height, depth], 1.5);*/ - /*}*/ } //the older, 'more accurate', and MUCH slower spherical dish. @@ -116,7 +113,4 @@ module old_spherical_dish(width, height, depth, inverted, tilt, txt=""){ } } } - // this line causes openscad to die. maybe re-enable when that doesn't happen instead of differencing the inside() when we add the dish to the shape() - /*translate([0,0,0]) roundedRect([width, height, depth], 1.5);*/ - /*}*/ } diff --git a/key.scad b/key.scad index da716a4..1d21406 100644 --- a/key.scad +++ b/key.scad @@ -1,5 +1,5 @@ // files -include +include include include include @@ -53,9 +53,9 @@ inverted_dish = false; // array of positions of all stems. includes stabilizers as well, for now // ternary is a bad hack to keep the stabilizers flag working connectors = stabilizers ? [[0,0],[-50,0],[50,0]] : [[0,0]]; -// whether or not we use the functions to generate an ISO enter -// NOTE this uses data in the profile so be sure to set the profile to ISO enter too -ISOEnter = false; +// use linear_extrude instead of hull slices to make the shape of the key +// should be faster, also required for concave shapes +linear_extrude_shape = false; //should the key be rounded? unnecessary for most printers, and very slow rounded_key = false; // 'cherry', 'alps' or 'cherry_rounded' @@ -73,6 +73,12 @@ inset_text = false; corner_radius = 1; // keystem slop - lengthens the cross and thins out the connector slop = 0.3; +// support type. default is 'flared' for easy FDM printing +support_type = "flared"; +// key shape type. default is 'normal'. only other supported option is 'iso_enter' +key_shape_type = "normal"; +// ISO enter needs to be linear extruded NOT from the center. this tells the program how far up 'not from the center' is +linear_extrude_height_adjustment = 0; @@ -100,22 +106,29 @@ $minkowski_radius = .33; // derived values. can't be variables if we want them to change when the special variables do // actual mm key width and height -function total_key_width() = $bottom_key_width + (unit * ($key_length - 1)); -function total_key_height() = $bottom_key_height + (unit * ($key_height - 1)); +function total_key_width() = $bottom_key_width + unit * ($key_length - 1); +function total_key_height() = $bottom_key_height + unit * ($key_height - 1); // actual mm key width and height at the top function top_total_key_width() = $bottom_key_width + (unit * ($key_length - 1)) - $width_difference; function top_total_key_height() = $bottom_key_height + (unit * ($key_height - 1)) - $height_difference; +// side sculpting functions +// bows the sides out on stuff like SA and DSA keycaps +function side_sculpting(progress) = (1 - progress) * 2.5; +// makes the rounded corners of the keycap grow larger as they move upwards +function corner_sculpting(progress) = pow(progress, 2); + + // key shape including dish. used as the ouside and inside shape in key() module shape(thickness_difference, depth_difference){ intersection(){ dished(depth_difference, $inverted_dish) { - color([.2667,.5882,1]) shape_hull(thickness_difference, depth_difference, 1); + color([.2667,.5882,1]) shape_hull(thickness_difference, depth_difference); } if ($inverted_dish) { // larger shape_hull to clip off bits of the inverted dish - color([.5412, .4784, 1]) shape_hull(thickness_difference, 0, 1, 2); + color([.5412, .4784, 1]) shape_hull(thickness_difference, 0, 2); } } } @@ -135,67 +148,71 @@ module rounded_shape() { } } +// basic key shape, no dish, no inside +// which is only used for dishing to cut the dish off correctly +// $height_difference used for keytop thickness +// extra_slices is a hack to make inverted dishes still work +module shape_hull(thickness_difference, depth_difference, extra_slices = 0){ + render() { + if ($linear_extrude_shape) { + linear_extrude_shape_hull(thickness_difference, depth_difference); + } else { + hull_shape_hull(thickness_difference, depth_difference, extra_slices); + } + } +} + //corollary is shape_hull -module ISOEnterShapeHull(thickness_difference, depth_difference, modifier){ +module linear_extrude_shape_hull(thickness_difference, depth_difference){ 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,19.05 * 0.5,0]) - linear_extrude(height = height, scale = [width_scale, height_scale]) { - // TODO completely making up these numbers here - // 0.86mm is from the unit function, 18.16 - 19.02. no idea what the 18 is, shows me for not leaving better comments - translate([0,-19.05 * 0.5,0]) - fakeISOEnter(thickness_difference/2); - } -} - - -// basic key shape, no dish, no inside -// modifier multiplies the height and top differences of the shape, -// which is only used for dishing to cut the dish off correctly -// $height_difference used for keytop thickness -// extra_slices is a hack to make inverted dishes still work -module shape_hull(thickness_difference, depth_difference, modifier, extra_slices = 0){ - render() { - if ($ISOEnter) { - ISOEnterShapeHull(thickness_difference, depth_difference, modifier); - } else { - slices = 10; - for (index = [0:$height_slices - 1 + extra_slices]) { - hull() { - shape_slice(index, $height_slices, thickness_difference, depth_difference, modifier); - shape_slice(index + 1, $height_slices, thickness_difference, depth_difference, modifier); - } + 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(), total_key_height(), thickness_difference, thickness_difference, $corner_radius); } } } } -module shape_slice(index, total, thickness_difference, depth_difference, modifier) { - progress = index / (total); +module hull_shape_hull(thickness_difference, depth_difference, extra_slices = 0) { + slices = 10; + 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); + } + } +} - // TODO extract these out somehow so you can make custom rounded sides +module shape_slice(progress, thickness_difference, depth_difference) { // makes the sides bow - extra_side_size = $enable_side_sculpting ? (total - index)/4 : 0; + 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 ? pow(progress, 2) : 0; + extra_corner_size = $enable_side_sculpting ? corner_sculpting(progress) : 0; - // width and height differences for this slice - extra_width_difference = ($width_difference - extra_side_size) * progress * modifier; - extra_height_difference = ($height_difference - extra_side_size) * progress * modifier; + // 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; + skew_this_slice = $top_skew * progress; + depth_this_slice = ($total_depth - depth_difference) * progress; + tilt_this_slice = -$top_tilt / $key_height * progress; - translate([ - 0, - $top_skew * progress, - ($total_depth * modifier - depth_difference) * progress - ]) rotate([-$top_tilt / $key_height * progress,0,0]){ - roundedRect([ - total_key_width() - thickness_difference - extra_width_difference, - total_key_height() - thickness_difference - extra_height_difference, - .001 - ],$corner_radius + extra_corner_size); + translate([0, skew_this_slice, depth_this_slice]) { + rotate([tilt_this_slice,0,0]){ + linear_extrude(height = 0.001){ + key_shape( + total_key_width(), + total_key_height(), + thickness_difference+extra_width_this_slice, + thickness_difference+extra_height_this_slice, + $corner_radius + extra_corner_size + ); + } + } } } @@ -244,7 +261,7 @@ module connectors() { for (connector_pos = $connectors) { translate([connector_pos[0], connector_pos[1], $stem_inset]) { rotate([0, 0, $stem_rotation]){ - color([1, .6941, .2]) connector($stem_profile, $has_brim, $slop); + color([1, .6941, .2]) connector($stem_profile, $has_brim, $slop, $support_type); } } } @@ -278,7 +295,7 @@ module keytop() { } else { shape(0, 0); } - shape(wall_thickness, keytop_thickness); + translate([0,0,-0.01]) shape(wall_thickness, keytop_thickness); } } @@ -319,7 +336,7 @@ module example_key(){ $has_brim = has_brim; $inverted_dish = inverted_dish; $connectors = connectors; - $ISOEnter = ISOEnter; + $linear_extrude_shape = linear_extrude_shape; $rounded_key = rounded_key; $stem_profile = stem_profile; $stem_inset = stem_inset; @@ -330,6 +347,9 @@ module example_key(){ $height_slices = height_slices; $enable_side_sculpting = enable_side_sculpting; $slop = slop; + $support_type = support_type; + $linear_extrude_height_adjustment = linear_extrude_height_adjustment; + key(); } diff --git a/key_mold.scad.stl b/key_mold.scad.stl deleted file mode 100644 index 9141098..0000000 --- a/key_mold.scad.stl +++ /dev/null @@ -1,226 +0,0 @@ -solid OpenSCAD_Model - facet normal -1 0 0 - outer loop - vertex 50 0 0 - vertex 50 53.05 30 - vertex 50 53.05 0 - endloop - endfacet - facet normal -1 -0 0 - outer loop - vertex 50 53.05 30 - vertex 50 0 0 - vertex 50 0 30 - endloop - endfacet - facet normal 0 0 1 - outer loop - vertex 103.05 53.05 30 - vertex 101.05 51.05 30 - vertex 103.05 0 30 - endloop - endfacet - facet normal 0 0 1 - outer loop - vertex 103.05 53.05 30 - vertex 52 51.05 30 - vertex 101.05 51.05 30 - endloop - endfacet - facet normal 0 0 1 - outer loop - vertex 52 51.05 30 - vertex 50 53.05 30 - vertex 52 2 30 - endloop - endfacet - facet normal -0 0 1 - outer loop - vertex 50 53.05 30 - vertex 52 51.05 30 - vertex 103.05 53.05 30 - endloop - endfacet - facet normal -0 0 1 - outer loop - vertex 101.05 2 30 - vertex 103.05 0 30 - vertex 101.05 51.05 30 - endloop - endfacet - facet normal -0 0 1 - outer loop - vertex 52 2 30 - vertex 103.05 0 30 - vertex 101.05 2 30 - endloop - endfacet - facet normal 0 0 1 - outer loop - vertex 52 2 30 - vertex 50 0 30 - vertex 103.05 0 30 - endloop - endfacet - facet normal 0 0 1 - outer loop - vertex 50 0 30 - vertex 52 2 30 - vertex 50 53.05 30 - endloop - endfacet - facet normal 1 -0 0 - outer loop - vertex 103.05 0 30 - vertex 103.05 53.05 0 - vertex 103.05 53.05 30 - endloop - endfacet - facet normal 1 0 0 - outer loop - vertex 103.05 53.05 0 - vertex 103.05 0 30 - vertex 103.05 0 0 - endloop - endfacet - facet normal 0 1 -0 - outer loop - vertex 103.05 53.05 0 - vertex 50 53.05 30 - vertex 103.05 53.05 30 - endloop - endfacet - facet normal 0 1 0 - outer loop - vertex 50 53.05 30 - vertex 103.05 53.05 0 - vertex 50 53.05 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 103.05 0 0 - vertex 101.05 2 0 - vertex 103.05 53.05 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 103.05 0 0 - vertex 52 2 0 - vertex 101.05 2 0 - endloop - endfacet - facet normal -0 0 -1 - outer loop - vertex 52 2 0 - vertex 50 0 0 - vertex 52 51.05 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 50 0 0 - vertex 52 2 0 - vertex 103.05 0 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 101.05 51.05 0 - vertex 103.05 53.05 0 - vertex 101.05 2 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 52 51.05 0 - vertex 103.05 53.05 0 - vertex 101.05 51.05 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 52 51.05 0 - vertex 50 53.05 0 - vertex 103.05 53.05 0 - endloop - endfacet - facet normal 0 0 -1 - outer loop - vertex 50 53.05 0 - vertex 52 51.05 0 - vertex 50 0 0 - endloop - endfacet - facet normal 0 -1 0 - outer loop - vertex 50 0 0 - vertex 103.05 0 30 - vertex 50 0 30 - endloop - endfacet - facet normal 0 -1 -0 - outer loop - vertex 103.05 0 30 - vertex 50 0 0 - vertex 103.05 0 0 - endloop - endfacet - facet normal 1 -0 0 - outer loop - vertex 52 2 30 - vertex 52 51.05 0 - vertex 52 51.05 30 - endloop - endfacet - facet normal 1 0 0 - outer loop - vertex 52 51.05 0 - vertex 52 2 30 - vertex 52 2 0 - endloop - endfacet - facet normal -1 0 0 - outer loop - vertex 101.05 2 0 - vertex 101.05 51.05 30 - vertex 101.05 51.05 0 - endloop - endfacet - facet normal -1 -0 0 - outer loop - vertex 101.05 51.05 30 - vertex 101.05 2 0 - vertex 101.05 2 30 - endloop - endfacet - facet normal 0 -1 0 - outer loop - vertex 52 51.05 0 - vertex 101.05 51.05 30 - vertex 52 51.05 30 - endloop - endfacet - facet normal 0 -1 -0 - outer loop - vertex 101.05 51.05 30 - vertex 52 51.05 0 - vertex 101.05 51.05 0 - endloop - endfacet - facet normal 0 1 -0 - outer loop - vertex 101.05 2 0 - vertex 52 2 30 - vertex 101.05 2 30 - endloop - endfacet - facet normal 0 1 0 - outer loop - vertex 52 2 30 - vertex 101.05 2 0 - vertex 52 2 0 - endloop - endfacet -endsolid OpenSCAD_Model diff --git a/keys.scad b/keys.scad index 4183c72..c0beb63 100644 --- a/keys.scad +++ b/keys.scad @@ -35,7 +35,7 @@ $key_height = 1; $has_brim = false; $inverted_dish = false; $connectors = [[0,0]]; -$ISOEnter = false; +$linear_extrude_shape = false; $rounded_key = false; $stem_profile = 0; $stem_inset = 0; @@ -45,6 +45,9 @@ $inset_text = false; $corner_radius = 1; $height_slices = 1; $slop = 0.3; +$support_type = "bars"; +$key_shape_type = "normal"; +$linear_extrude_height_adjustment = 0; // key profile definitions @@ -206,7 +209,10 @@ module fake_iso_enter() { $dish_depth = 1; $dish_skew_x = 0; $dish_skew_y = 0; - $ISOEnter = true; + $key_shape_type = "iso_enter"; + $linear_extrude_shape = true; + $linear_extrude_height_adjustment = 19.05 * 0.5; + stabilized(vertical=true) { children(); @@ -419,4 +425,6 @@ module legend(text, inset=false) { } translate_u(1.125, 0.5) fake_iso_enter() cherry() key(); -translate_u(0, 0) dcs_row(2) cherry() key(); +translate_u(0, 0) sa_row(2) legend("q", inset=true) cherry() { + key(); +} diff --git a/shapes.scad b/shapes.scad new file mode 100644 index 0000000..cce2279 --- /dev/null +++ b/shapes.scad @@ -0,0 +1,53 @@ +$fs=.1; +unit = 19.05; + +module key_shape(width, height, width_difference, height_difference, corner_size) { + if ($key_shape_type == "iso_enter") { + fakeISOEnter(width_difference/2); + } else if ($key_shape_type == "normal") { + roundedSquare([width - width_difference, height - height_difference], corner_size); + } else if ($key_shape_type == "circle") { + circle(d=width - width_difference); + } +} + +// centered +module roundedRect(size, radius, center=true) { + linear_extrude(height = size[2]){ + roundedSquare([size[0], size[1]], radius, center=center); + } +} + +module roundedSquare(size, radius, center = true) { + offset(r=radius){ + square([size[0] - radius * 2, size[1] - radius * 2], center=center); + } +} + +// corollary is roundedSquare +// NOT 3D +module fakeISOEnter(thickness_difference = 0){ + // t is all modifications to the polygon array + // t used to contain a corner radius adjustment, but due to + // the offset we need that expansion back + t = (thickness_difference - (unit - 18.16)); + + function unit(length) = unit * length; + + pointArray = [ + [unit(-.625) + t, unit(-1) + t], + [unit(0.625) - t, unit(-1) + t], + [unit(0.625) - t, unit(1) - t], + [unit(-0.875) + t, unit(1) - t], + [unit(-0.875) + t, unit(0) + t], + [unit(-0.625) + t, unit(0) + t] + ]; + + minkowski(){ + circle(r=$corner_radius); + // gives us rounded inner corner + offset(r=-$corner_radius*2) { + polygon(points=pointArray); + } + } +} diff --git a/stems.scad b/stems.scad index 2b15ee4..28faa75 100644 --- a/stems.scad +++ b/stems.scad @@ -1,6 +1,22 @@ include +include + +stem_depth = 240; + +//whole connector, alps or cherry, trimmed to fit +module connector(stem_profile, has_brim, slop, support_type){ + echo(slop); + if (stem_profile == "alps") { + alps_stem(has_brim, slop); + } else if (stem_profile == "cherry_rounded") { + cherry_stem_rounded(has_brim, slop); + } else if (stem_profile == "cherry") { + cherry_stem(has_brim, slop, support_type); + } else if (stem_profile == "filled") { + filled_stem(); + } +} -stem_depth = 24; module brim(has_brim) { //brim radius. 11 ensconces normal keycap stem in normal keycap @@ -11,10 +27,7 @@ module brim(has_brim) { if (has_brim) color([0,1,0]) cube([brim_radius, brim_radius, brim_depth]); } -module cherry_stem(has_brim, slop) { - - echo(slop); - +module cherry_stem(has_brim, slop, support_type) { stem_width = 7.2 - slop * 2; stem_height = 5.5 - slop * 2; @@ -32,20 +45,23 @@ module cherry_stem(has_brim, slop) { translate([0,0,stem_inset]) { brim(has_brim); - linear_extrude(height = cross_depth) { - difference(){ + difference(){ + linear_extrude(height = stem_depth) { roundedSquare(stem, 1, center=true); - off = 0; - offset(r = off){ - square(vertical_cross + [-off * 2,-off * 2], center=true); - square(horizontal_cross + [-off * 2,-off * 2], center=true); - } + } + linear_extrude(height = cross_depth) { + square(vertical_cross, center=true); + square(horizontal_cross, center=true); } } // flared support - // 6 and 8 are magic numbers I got from trying to make the sides of the flared part of the stem 45 degree overhangs - translate([0,0,cross_depth]) linear_extrude(height=(stem_depth - cross_depth), scale = [6,8]){ - roundedSquare([stem_width, stem_height], 1, center=true); + echo(support_type); + if (support_type == "flared") { + cherry_flared(cross_depth, (stem_depth - cross_depth), [stem_width, stem_height]); + } else if (support_type == "flat") { + flat(cross_depth, (stem_depth - cross_depth), [stem_width, stem_height]); + } else if (support_type == "bars") { + bars(cross_depth, (stem_depth - cross_depth), [stem_width, stem_height]); } } } @@ -99,18 +115,3 @@ module filled_stem() { // so we can't make this work for all keys cube(100, center=true); } - - -//whole connector, alps or cherry, trimmed to fit -module connector(stem_profile, has_brim, slop){ - echo(slop); - if (stem_profile == "alps") { - alps_stem(has_brim, slop); - } else if (stem_profile == "cherry_rounded") { - cherry_stem_rounded(has_brim, slop); - } else if (stem_profile == "cherry") { - cherry_stem(has_brim, slop); - } else if (stem_profile == "filled") { - filled_stem(); - } -} diff --git a/supports.scad b/supports.scad new file mode 100644 index 0000000..978e853 --- /dev/null +++ b/supports.scad @@ -0,0 +1,24 @@ +// flared support designed for FDM printing, for the normal cherry stem +module cherry_flared(loft, height, stem_bottom) { + // 6 and 8 are magic numbers I got from trying to make the sides of the flared part of the stem 45 degree overhangs + translate([0,0,loft]){ + linear_extrude(height=height, scale = [6,8]){ + roundedSquare(stem_bottom, 1, center=true); + } + } +} + +module flat(loft, height, stem_bottom) { + // 6 and 8 are magic numbers I got from trying to make the sides of the flared part of the stem 45 degree overhangs + translate([0,0,loft + 500]){ + cube(1000, center=true); + } +} + +module bars(loft, height, stem_bottom) { + // 6 and 8 are magic numbers I got from trying to make the sides of the flared part of the stem 45 degree overhangs + translate([0,0,loft + height / 2]){ + cube([2, 100, height], center = true); + cube([100, 2, height], center = true); + } +} diff --git a/util.scad b/util.scad deleted file mode 100644 index 8317f3b..0000000 --- a/util.scad +++ /dev/null @@ -1,71 +0,0 @@ -$fs=.1; - -// centered -module roundedRect(size, radius, center=true) { - linear_extrude(height = size[2]){ - roundedSquare([size[0], size[1]], radius, center=center); - } -} - -module roundedSquare(size, radius, center = true) { - offset(r=radius){ - square([size[0] - radius * 2, size[1] - radius * 2], center=center); - } -} - -// corollary is roundedRect -// NOT 3D -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) - - // t is all modifications to the polygon array - // t used to contain a corner radius adjustment, but due to - // the offset we need that expansion back - t = (thickness_difference - (19.05 - 18.16)); - - function unit(length) = 19.05 * length; - - pointArray = [ - [unit(-.625) + t, unit(-1) + t], - [unit(0.625) - t, unit(-1) + t], - [unit(0.625) - t, unit(1) - t], - [unit(-0.875) + t, unit(1) - t], - [unit(-0.875) + t, unit(0) + t], - [unit(-0.625) + t, unit(0) + t] - ]; - - minkowski(){ - circle(r=$corner_radius); - // gives us rounded inner corner - offset(r=-$corner_radius*2) { - polygon(points=pointArray); - } - } -} - -module functional_scaled_extrude(height = 10, slices=[]) { - nominal_height = height / (len(slices) - 1); - for (index = [0 : len(slices)-2]){ - slice1 = slices[index]; - slice2 = slices[index+1]; - hull(){ - translate([0,0,nominal_height * index]) { - scale(slice1) children(); - } - translate([0,0,nominal_height * (index + 1)]) { - scale(slice2) children(); - } - } - } -} - -module progressive_hull() { - for (i = [0 : $children-2]){ - hull(){ - children(i); - children(i+1); - } - } -}