include include //geodesic looks much better, but runs very slow for anything above a 2u geodesic=false; //dish selector module dish(width, height, depth, inverted, tilt) { if($dish_type == "cylindrical"){ cylindrical_dish(width, height, depth, inverted, tilt); } else if ($dish_type == "spherical") { spherical_dish(width, height, depth, inverted, tilt); } else if ($dish_type == "sideways cylindrical"){ sideways_cylindrical_dish(width, height, depth, inverted, tilt); } else if ($dish_type == "old spherical") { old_spherical_dish(width, height, depth, inverted, tilt); } // else no dish, "no dish" is the value } module cylindrical_dish(width, height, depth, inverted, tilt){ // .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; rotate([90-tilt,0,0]){ translate([0,chord_length * direction,0]){ cylinder(h=height + 20, r=rad, center=true); } } } module sideways_cylindrical_dish(width, height, depth, inverted, tilt){ $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; rotate([90,tilt,90]){ translate([0,chord_length * direction,0]){ cylinder(h = width + 20,r=rad, center=true); // +20 for fudge factor } } } module spherical_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 // 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=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); } } } } // 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. // generates the largest sphere possible that still contains the chord we are looking for // much more graduated curvature at an immense cost module old_spherical_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 // 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,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); } } } // 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);*/ /*}*/ }