mirror of
https://github.com/rsheldiii/KeyV2.git
synced 2024-11-22 21:23:40 +00:00
SA rounding experimentation with segmented height and better dishes
This commit is contained in:
parent
f9d9197a84
commit
0333f1718d
139512
SAtest.stl
Normal file
139512
SAtest.stl
Normal file
File diff suppressed because it is too large
Load Diff
52
dishes.scad
52
dishes.scad
@ -1,6 +1,7 @@
|
||||
include <libraries/geodesic_sphere.scad>
|
||||
include <util.scad>
|
||||
//rounding factor. increase rounding on dishes
|
||||
$rounding_factor = 1;
|
||||
//geodesic looks much better, but runs very slow for anything above a 2u
|
||||
geodesic=false;
|
||||
|
||||
|
||||
module cylindrical_dish(width, height, depth, inverted, tilt){
|
||||
@ -26,8 +27,38 @@ module cylindrical_dish(width, height, depth, inverted, tilt){
|
||||
}
|
||||
|
||||
module spherical_dish(width, height, depth, inverted, tilt, txt=""){
|
||||
// honestly 1 has problems around 6.25 but its already ridiculously slow
|
||||
$fa=3;
|
||||
|
||||
//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);
|
||||
direction = inverted ? -1 : 1;
|
||||
|
||||
/*intersection(){*/
|
||||
rotate([-tilt,0,0]){
|
||||
translate([0,0,0 * direction]){
|
||||
if (geodesic){
|
||||
$fa=10;
|
||||
geodesic_sphere(r=rad);
|
||||
} else {
|
||||
$fa=1;
|
||||
// rotate 1 because the bottom of the sphere looks like trash.
|
||||
scale([chord/2/depth, chord/2/depth]) {
|
||||
geodesic_sphere(r=depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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);*/
|
||||
/*}*/
|
||||
}
|
||||
|
||||
module oldspherical_dish(width, height, depth, inverted, tilt, txt=""){
|
||||
|
||||
//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
|
||||
|
||||
@ -40,8 +71,17 @@ module spherical_dish(width, height, depth, inverted, tilt, txt=""){
|
||||
/*intersection(){*/
|
||||
rotate([-tilt,0,0]){
|
||||
translate([0,0,chord_length * direction]){
|
||||
//NOTE: if your dish is long at all you might need to increase $fn
|
||||
sphere(r=rad);
|
||||
if (geodesic){
|
||||
$fa=3;
|
||||
geodesic_sphere(r=rad);
|
||||
} else {
|
||||
$fa=1;
|
||||
// rotate 1 because the bottom of the sphere looks like trash.
|
||||
%difference() {
|
||||
sphere(r=rad);
|
||||
translate([0,0,rad]) cube(rad*2, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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()
|
||||
|
50
key.scad
50
key.scad
@ -1,3 +1,4 @@
|
||||
// files
|
||||
include <util.scad>
|
||||
include <stems.scad>
|
||||
include <dishes.scad>
|
||||
@ -74,6 +75,8 @@ stem_rotation = 0;
|
||||
text = "";
|
||||
// is the text on the key inset? inset text is still experimental
|
||||
inset_text = false;
|
||||
// radius of corners of keycap
|
||||
corner_radius = 1;
|
||||
|
||||
|
||||
/* [Hidden] */
|
||||
@ -81,9 +84,8 @@ $fs = .1;
|
||||
//beginning to use unit instead of baked in 19.05
|
||||
unit = 19.05;
|
||||
//minkowski radius. radius of sphere used in minkowski sum for minkowski_key function. 1.75 default for faux G20
|
||||
minkowski_radius = 1.75;
|
||||
//radius of corners of keycap
|
||||
corner_radius = 1.5;
|
||||
$minkowski_radius = .75;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -135,11 +137,11 @@ module shape(thickness_difference, depth_difference){
|
||||
// shape of the key but with soft, rounded edges. much more realistic, MUCH more complex. orders of magnitude more complex
|
||||
module rounded_shape() {
|
||||
minkowski(){
|
||||
shape(minkowski_radius*2, minkowski_radius);
|
||||
shape($minkowski_radius*2, $minkowski_radius);
|
||||
difference(){
|
||||
sphere(r=minkowski_radius, $fn=24);
|
||||
translate([0,0,-minkowski_radius])
|
||||
cube([2*minkowski_radius,2*minkowski_radius,2*minkowski_radius], center=true);
|
||||
sphere(r=$minkowski_radius, $fn=24);
|
||||
translate([0,0,-$minkowski_radius])
|
||||
cube([2*$minkowski_radius,2*$minkowski_radius,2*$minkowski_radius], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,6 +151,35 @@ module rounded_shape() {
|
||||
// which is only used for dishing to cut the dish off correctly
|
||||
// $height_difference used for keytop thickness
|
||||
module shape_hull(thickness_difference, depth_difference, modifier){
|
||||
if ($ISOEnter) {
|
||||
ISOEnterShapeHull(thickness_difference, depth_difference, modifier);
|
||||
} else {
|
||||
slices = 10;
|
||||
for (index = [0:slices-1]) {
|
||||
color("red") hull() {
|
||||
shape_slice(index, slices, thickness_difference, depth_difference, modifier);
|
||||
shape_slice(index + 1, slices, thickness_difference, depth_difference, modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module shape_slice(index, total, thickness_difference, depth_difference, modifier) {
|
||||
progress = index / (total);
|
||||
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 - (($width_difference - abs(index - total)/4) * modifier * progress),
|
||||
total_key_height() - thickness_difference - ($height_difference * modifier * progress),
|
||||
.001
|
||||
],$corner_radius);
|
||||
}
|
||||
}
|
||||
|
||||
module oldshape_hull(thickness_difference, depth_difference, modifier){
|
||||
if ($ISOEnter) {
|
||||
ISOEnterShapeHull(thickness_difference, depth_difference, modifier);
|
||||
} else {
|
||||
@ -156,7 +187,7 @@ module shape_hull(thickness_difference, depth_difference, modifier){
|
||||
// $bottom_key_width + ($key_length -1) * unit is the correct length of the
|
||||
// key. only 1u of the key should be $bottom_key_width long; all others
|
||||
// should be 1u
|
||||
roundedRect([total_key_width() - thickness_difference, total_key_height() - thickness_difference, .001],corner_radius);
|
||||
roundedRect([total_key_width() - thickness_difference, total_key_height() - thickness_difference, .001],$corner_radius);
|
||||
|
||||
//depth_difference outside of modifier because that doesnt make sense
|
||||
translate([0,$top_skew,$total_depth * modifier - depth_difference]){
|
||||
@ -165,7 +196,7 @@ module shape_hull(thickness_difference, depth_difference, modifier){
|
||||
total_key_width() - thickness_difference - $width_difference * modifier,
|
||||
total_key_height() - thickness_difference - $height_difference * modifier,
|
||||
.001
|
||||
],corner_radius);
|
||||
],$corner_radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,6 +316,7 @@ module example_key(){
|
||||
$stem_rotation = stem_rotation;
|
||||
$text = text;
|
||||
$inset_text = inset_text;
|
||||
$corner_radius = corner_radius;
|
||||
|
||||
key();
|
||||
}
|
||||
|
16
keys.scad
16
keys.scad
@ -6,6 +6,8 @@
|
||||
// special variables, but that's a limitation of SCAD we'll have to work around
|
||||
|
||||
/* TODO:
|
||||
* make SA keycaps get more rounded the further up they are (like in real life)
|
||||
* make that rounding thing ^ only happen on certain keycaps via limiting the amount of slives we take to 2
|
||||
* can now measure keycaps very accurately. need to redo measurements: [x] SA [ ] DCS [ ] DSA [ ] OEM?
|
||||
* bowed sides for SA? jebus
|
||||
* sideways cylindrical dish needs to be used for some spacebars but not others. currently none of them use it
|
||||
@ -13,6 +15,7 @@
|
||||
* Pregenerated keysets for DCS (rounded tops too intense) [ ] 60% [ ] TKL [ ] full
|
||||
* Full experimental ISO enter
|
||||
* customizer version where everything is copy/pasted in
|
||||
* I probably need to switch to surfaces for dishes don't I
|
||||
*/
|
||||
|
||||
use <key.scad>
|
||||
@ -41,6 +44,9 @@ $rounded_key = false;
|
||||
$stem_profile = 0;
|
||||
$stem_inset = 0;
|
||||
$stem_rotation = 0;
|
||||
$text = "";
|
||||
$inset_text = false;
|
||||
$corner_radius = 1;
|
||||
|
||||
// key profile definitions
|
||||
|
||||
@ -137,6 +143,7 @@ module g20() {
|
||||
$dish_depth = 0;
|
||||
$dish_skew_x = 0;
|
||||
$dish_skew_y = 0;
|
||||
$minkowski_radius = 1.75;
|
||||
|
||||
//also,
|
||||
$rounded_key = true;
|
||||
@ -340,11 +347,12 @@ module legend(text, inset=false) {
|
||||
$inset_text = inset;
|
||||
}
|
||||
|
||||
translate([0,0,0]){
|
||||
/*translate([0,0,0]){
|
||||
for (x = [1:4]){
|
||||
translate_u(0,(x-1)){
|
||||
sa_row(5-x) blank() key();
|
||||
sa_row(5-x) 2_75u() blank() key();
|
||||
}
|
||||
}
|
||||
translate([-10,-10,-2]) cube([40,80,2]);
|
||||
}
|
||||
}*/
|
||||
|
||||
sa_row(1) rounded() blank() key();
|
||||
|
117
libraries/geodesic_sphere.scad
Normal file
117
libraries/geodesic_sphere.scad
Normal file
@ -0,0 +1,117 @@
|
||||
// from https://www.thingiverse.com/thing:1484333
|
||||
// public domain license
|
||||
$fs = .01;
|
||||
geodesic_sphere(2);
|
||||
|
||||
translate([4, 0, 0])
|
||||
sphere(2);
|
||||
|
||||
// same syntax and semantics as built-in sphere, so should be a drop-in replacement
|
||||
// it's a bit slow for large numbers of facets
|
||||
module geodesic_sphere(r=-1, d=-1) {
|
||||
// if neither parameter specified, radius is taken to be 1
|
||||
rad = r > 0 ? r : d > 0 ? d/2 : 1;
|
||||
|
||||
pentside_pr = 2*sin(36); // side length compared to radius of a pentagon
|
||||
pentheight_pr = sqrt(pentside_pr*pentside_pr - 1);
|
||||
// from center of sphere, icosahedron edge subtends this angle
|
||||
edge_subtend = 2*atan(pentheight_pr);
|
||||
|
||||
// vertical rotation by 72 degrees
|
||||
c72 = cos(72);
|
||||
s72 = sin(72);
|
||||
function zrot(pt) = [ c72*pt[0]-s72*pt[1], s72*pt[0]+c72*pt[1], pt[2] ];
|
||||
|
||||
// rotation from north to vertex along positive x
|
||||
ces = cos(edge_subtend);
|
||||
ses = sin(edge_subtend);
|
||||
function yrot(pt) = [ ces*pt[0] + ses*pt[2], pt[1], ces*pt[2]-ses*pt[0] ];
|
||||
|
||||
// 12 icosahedron vertices generated from north, south, yrot and zrot
|
||||
ic1 = [ 0, 0, 1 ]; // north
|
||||
ic2 = yrot(ic1); // north and +x
|
||||
ic3 = zrot(ic2); // north and +x and +y
|
||||
ic4 = zrot(ic3); // north and -x and +y
|
||||
ic5 = zrot(ic4); // north and -x and -y
|
||||
ic6 = zrot(ic5); // north and +x and -y
|
||||
ic12 = [ 0, 0, -1]; // south
|
||||
ic10 = yrot(ic12); // south and -x
|
||||
ic11 = zrot(ic10); // south and -x and -y
|
||||
ic7 = zrot(ic11); // south and +x and -y
|
||||
ic8 = zrot(ic7); // south and +x and +y
|
||||
ic9 = zrot(ic8); // south and -x and +y
|
||||
|
||||
// start with icosahedron, icos[0] is vertices and icos[1] is faces
|
||||
icos = [ [ic1, ic2, ic3, ic4, ic5, ic6, ic7, ic8, ic9, ic10, ic11, ic12 ],
|
||||
[ [0, 2, 1], [0, 3, 2], [0, 4, 3], [0, 5, 4], [0, 1, 5],
|
||||
[1, 2, 7], [2, 3, 8], [3, 4, 9], [4, 5, 10], [5, 1, 6],
|
||||
[7, 6, 1], [8, 7, 2], [9, 8, 3], [10, 9, 4], [6, 10, 5],
|
||||
[6, 7, 11], [7, 8, 11], [8, 9, 11], [9, 10, 11], [10, 6, 11]]];
|
||||
|
||||
// now for polyhedron subdivision functions
|
||||
|
||||
// given two 3D points on the unit sphere, find the half-way point on the great circle
|
||||
// (euclidean midpoint renormalized to be 1 unit away from origin)
|
||||
function midpt(p1, p2) =
|
||||
let (midx = (p1[0] + p2[0])/2, midy = (p1[1] + p2[1])/2, midz = (p1[2] + p2[2])/2)
|
||||
let (midlen = sqrt(midx*midx + midy*midy + midz*midz))
|
||||
[ midx/midlen, midy/midlen, midz/midlen ];
|
||||
|
||||
// given a "struct" where pf[0] is vertices and pf[1] is faces, subdivide all faces into
|
||||
// 4 faces by dividing each edge in half along a great circle (midpt function)
|
||||
// and returns a struct of the same format, i.e. pf[0] is a (larger) list of vertices and
|
||||
// pf[1] is a larger list of faces.
|
||||
function subdivpf(pf) =
|
||||
let (p=pf[0], faces=pf[1])
|
||||
[ // for each face, barf out six points
|
||||
[ for (f=faces)
|
||||
let (p0 = p[f[0]], p1 = p[f[1]], p2=p[f[2]])
|
||||
// "identity" for-loop saves having to flatten
|
||||
for (outp=[ p0, p1, p2, midpt(p0, p1), midpt(p1, p2), midpt(p0, p2) ]) outp
|
||||
],
|
||||
// now, again for each face, spit out four faces that connect those six points
|
||||
[ for (i=[0:len(faces)-1])
|
||||
let (base = 6*i) // points generated in multiples of 6
|
||||
for (outf =
|
||||
[[ base, base+3, base+5],
|
||||
[base+3, base+1, base+4],
|
||||
[base+5, base+4, base+2],
|
||||
[base+3, base+4, base+5]]) outf // "identity" for-loop saves having to flatten
|
||||
]
|
||||
];
|
||||
|
||||
// recursive wrapper for subdivpf that subdivides "levels" times
|
||||
function multi_subdiv_pf(pf, levels) =
|
||||
levels == 0 ? pf :
|
||||
multi_subdiv_pf(subdivpf(pf), levels-1);
|
||||
|
||||
// subdivision level based on $fa:
|
||||
// level 0 has edge angle of edge_subtend so subdivision factor should be edge_subtend/$fa
|
||||
// must round up to next power of 2.
|
||||
// Take log base 2 of angle ratio and round up to next integer
|
||||
ang_levels = ceil(log(edge_subtend/$fa)/log(2));
|
||||
|
||||
// subdivision level based on $fs:
|
||||
// icosahedron edge length is rad*2*tan(edge_subtend/2)
|
||||
// actually a chord and not circumference but let's say it's close enough
|
||||
// subdivision factor should be rad*2*tan(edge_subtend/2)/$fs
|
||||
side_levels = ceil(log(rad*2*tan(edge_subtend/2)/$fs)/log(2));
|
||||
echo(side_levels);
|
||||
|
||||
// subdivision level based on $fn: (fragments around circumference, not total facets)
|
||||
// icosahedron circumference around equator is about 5 (level 1 is exactly 10)
|
||||
// ratio of requested to equatorial segments is $fn/5
|
||||
// level of subdivison is log base 2 of $fn/5
|
||||
// round up to the next whole level so we get at least $fn
|
||||
facet_levels = ceil(log($fn/5)/log(2));
|
||||
|
||||
// $fn takes precedence, otherwise facet_levels is NaN (-inf) but it's ok
|
||||
// because it falls back to $fa or $fs, whichever translates to fewer levels
|
||||
levels = $fn ? facet_levels : min(ang_levels, side_levels);
|
||||
|
||||
// subdivide icosahedron by these levels
|
||||
subdiv_icos = multi_subdiv_pf(icos, levels);
|
||||
|
||||
scale(rad)
|
||||
polyhedron(points=subdiv_icos[0], faces=subdiv_icos[1]);
|
||||
}
|
11
util.scad
11
util.scad
@ -1,5 +1,16 @@
|
||||
$fs=.1;
|
||||
|
||||
//centered
|
||||
// offset, who knew?
|
||||
module roundedRect(size, radius) {
|
||||
linear_extrude(height = size[2]){
|
||||
offset(r=radius){
|
||||
square([size[0] - radius * 2, size[1] - radius * 2], center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module oldroundedRect(size, radius) {
|
||||
x = size[0];
|
||||
y = size[1];
|
||||
z = size[2];
|
||||
|
Loading…
Reference in New Issue
Block a user