mirror of
https://github.com/pseudoku/PseudoMakeMeKeyCapProfiles.git
synced 2025-01-20 18:18:06 +00:00
Initial commit
This commit is contained in:
parent
cf5e2c6e63
commit
178bf9938b
52 changed files with 4866359 additions and 209 deletions
BIN
Chicago Stenographer Side and Cut.png
Normal file
BIN
Chicago Stenographer Side and Cut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
BIN
Chicago Stenographer Side.png
Normal file
BIN
Chicago Stenographer Side.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 165 KiB |
174106
ChocThumb.stl
Normal file
174106
ChocThumb.stl
Normal file
File diff suppressed because it is too large
Load diff
192334
ChocThumb125.stl
Normal file
192334
ChocThumb125.stl
Normal file
File diff suppressed because it is too large
Load diff
BIN
Chord1.png
Normal file
BIN
Chord1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
379
Chord1.scad
Normal file
379
Chord1.scad
Normal file
|
@ -0,0 +1,379 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 1, cutLen = 0, Stem =true, Dish = true, visualizeDish = false, crossSection = true, homeDot = false, Legends = true);
|
||||
|
||||
translate([0, 20, 0])rotate([0,0,180])keycap(keyID = 1, cutLen = 0, Stem =true, Dish = true, visualizeDish = false, crossSection = false, homeDot = false, Legends = true);
|
||||
////fullsetee
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [0:0]){
|
||||
// for(Row = [1:2]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = true, crossSection = true,Legends = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 8;
|
||||
stemLen = 6;
|
||||
stemCrossHeight = 1.8;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16, 3, 3, 6, 0, 0, 3, -0, -0, 2, 2, 1, 3, 1, 2], //R5 0
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, 3, -0, -0, 2, 3, 2, 1, 2, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 4, 4, 5, 0, 0, -2, -0, -0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.5, 3, -0, -0, 2, 2, 1, 2, 1, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 2, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16*1.5, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16*1.25, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, 1, 3, 1, 2],
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 5, -42, 5, 1.7, 20, 20, 2, 10, 4, 8, -30, 20, 20, 2], //R5
|
||||
[ 6, 4, 5, -50, 4, 1.2, 13, 19, 2, 6, 4, 5, -15, 13, 19, 2], //R4
|
||||
[ 6, 3, 8, -20, 5, 1.2, 12, 19, 2, 5, 4, 13, -5*0, 12, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8, 15, 2, 6, 4, 10, -30, 8, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.2, 15, 2, 5, 4, 13, -30, 8.2, 16, 2], //R3
|
||||
[ 6, 3, 12, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 9.3, 10, 2, 6, 4, 13, -30, 9.3, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, -30, 8, 15, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 5, 4, 13, -30, 8, 15, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, 30, 8, 16, 2], //R2
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 12, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 17, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.6, 15, 2, 6, 4, 13, -30, 8.6, 16, 2], //R2
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])choc_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
#rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])
|
||||
translate([-1.5,5,KeyHeight(keyID)-2.2])linear_extrude(height = 0.5)
|
||||
text( text = "v.1", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "right" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
384
Chord2.scad
Normal file
384
Chord2.scad
Normal file
|
@ -0,0 +1,384 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
translate([0,0,0])rotate([0,0,0])
|
||||
translate([0,19,0])rotate([0,0,90])
|
||||
translate([-19,19,0])rotate([0,0,180])
|
||||
translate([-19,0,0])rotate([0,0,270])
|
||||
|
||||
keycap(keyID = 1, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = false, homeDot = false, Legends = true);
|
||||
|
||||
}
|
||||
////fullsetee
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [0:0]){
|
||||
// for(Row = [1:2]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = true, crossSection = true,Legends = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 8;
|
||||
stemLen = 6;
|
||||
stemCrossHeight = 1.8;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16, 3, 3, 6, 0, 0, 3, -0, -0, 2, 2, 1, 3, 1, 2], //R5 0
|
||||
[18.16, 18.7, 3, 1.5, 4.5, 0, -.2, 3, -0, -0, 2, 3, 2, 1, 2, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 4, 4, 5, 0, 0, -2, -0, -0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.5, 3, -0, -0, 2, 2, 1, 2, 1, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 2, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16*1.5, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16*1.25, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, 1, 3, 1, 2],
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 5, -42, 5, 1.7, 20, 20, 2, 10, 4, 8, -30, 20, 20, 2], //R5
|
||||
[ 6, 4, 5, -50, 4, 1.2, 13, 19, 2, 6, 4, 5, -15, 13, 19, 2], //R4
|
||||
[ 6, 3, 8, -20, 5, 1.2, 12, 19, 2, 5, 4, 13, -5*0, 12, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8, 15, 2, 6, 4, 10, -30, 8, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.2, 15, 2, 5, 4, 13, -30, 8.2, 16, 2], //R3
|
||||
[ 6, 3, 12, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 9.3, 10, 2, 6, 4, 13, -30, 9.3, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, -30, 8, 15, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 5, 4, 13, -30, 8, 15, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, 30, 8, 16, 2], //R2
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 12, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 17, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.6, 15, 2, 6, 4, 13, -30, 8.6, 16, 2], //R2
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])choc_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
#rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])
|
||||
translate([-1.5,5,KeyHeight(keyID)-2.2])linear_extrude(height = 0.5)
|
||||
text( text = "v.2", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "right" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
257560
Chord2.stl
Normal file
257560
Chord2.stl
Normal file
File diff suppressed because it is too large
Load diff
381
Chord3.scad
Normal file
381
Chord3.scad
Normal file
|
@ -0,0 +1,381 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
//translate([0,0,0])rotate([0,0,0])keycap(keyID = 1, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = false, homeDot = false, Legends = true);
|
||||
|
||||
|
||||
//keycap(keyID = 1, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = false, homeDot = false, Legends = true);
|
||||
|
||||
////fullsetee
|
||||
RowHome = [0,0,5,2.5,0,0];
|
||||
|
||||
for(Col = [0:1]){
|
||||
for(Row = [1:2]){
|
||||
translate([-19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = false, crossSection = false,Legends = false);
|
||||
}
|
||||
}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 8;
|
||||
stemLen = 6;
|
||||
stemCrossHeight = 1.8;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16, 3, 3, 6, 0, 0, 3, -0, -0, 2, 2, 1, 3, 1, 2], //R5 0
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, 3, 3, -0, 2, 3, 2, 1, 2, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, -3, 3, -0, 2, 3, 2, 1, 2, 2], //R3
|
||||
[18.16, 18.16, 4, 4, 5, 0, 0, -2, -0, -0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, 3, -3, -0, 2, 3, 2, 1, 2, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, -3, -3, -0, 2, 3, 2, 1, 2, 2], //R3
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16*1.5, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16*1.25, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, 1, 3, 1, 2],
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 5, -42, 5, 1.7, 20, 20, 2, 10, 4, 8, -30, 20, 20, 2], //R5
|
||||
[ 6, 4, 5, -50, 4, 1.2, 13, 19, 2, 6, 4, 5, -15, 13, 19, 2], //R4
|
||||
[ 6, 4, 5, -15, 4, 1.2, 13, 19, 2, 6, 4, 5, -50, 13, 19, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 4, 5, -50, 4, 1.2, 13, 19, 2, 6, 4, 5, -15, 13, 19, 2], //R4
|
||||
[ 6, 4, 5, -15, 4, 1.2, 13, 19, 2, 6, 4, 5, -50, 13, 19, 2], //R3
|
||||
[ 6, 3, 12, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 9.3, 10, 2, 6, 4, 13, -30, 9.3, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, -30, 8, 15, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 5, 4, 13, -30, 8, 15, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, 30, 8, 16, 2], //R2
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 12, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 17, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.6, 15, 2, 6, 4, 13, -30, 8.6, 16, 2], //R2
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])choc_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
#rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])
|
||||
translate([-1.5,5,KeyHeight(keyID)-2.2])linear_extrude(height = 0.5)
|
||||
text( text = "v.2", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "right" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
241740
Chord_Chicago.stl
Normal file
241740
Chord_Chicago.stl
Normal file
File diff suppressed because it is too large
Load diff
238856
Chord_Phat.stl
Normal file
238856
Chord_Phat.stl
Normal file
File diff suppressed because it is too large
Load diff
126198
DES_Corne/C0R2.stl
Normal file
126198
DES_Corne/C0R2.stl
Normal file
File diff suppressed because it is too large
Load diff
128606
DES_Corne/C0R3.stl
Normal file
128606
DES_Corne/C0R3.stl
Normal file
File diff suppressed because it is too large
Load diff
127598
DES_Corne/C0R4.stl
Normal file
127598
DES_Corne/C0R4.stl
Normal file
File diff suppressed because it is too large
Load diff
143628
DES_Corne/C0R5.stl
Normal file
143628
DES_Corne/C0R5.stl
Normal file
File diff suppressed because it is too large
Load diff
127752
DES_Corne/C1R2.stl
Normal file
127752
DES_Corne/C1R2.stl
Normal file
File diff suppressed because it is too large
Load diff
133618
DES_Corne/C1R3.stl
Normal file
133618
DES_Corne/C1R3.stl
Normal file
File diff suppressed because it is too large
Load diff
129516
DES_Corne/C1R4.stl
Normal file
129516
DES_Corne/C1R4.stl
Normal file
File diff suppressed because it is too large
Load diff
139610
DES_Corne/C1R5.stl
Normal file
139610
DES_Corne/C1R5.stl
Normal file
File diff suppressed because it is too large
Load diff
130006
DES_Corne/C2R2.stl
Normal file
130006
DES_Corne/C2R2.stl
Normal file
File diff suppressed because it is too large
Load diff
131812
DES_Corne/C2R3.stl
Normal file
131812
DES_Corne/C2R3.stl
Normal file
File diff suppressed because it is too large
Load diff
130356
DES_Corne/C2R4.stl
Normal file
130356
DES_Corne/C2R4.stl
Normal file
File diff suppressed because it is too large
Load diff
135942
DES_Corne/C2R5.stl
Normal file
135942
DES_Corne/C2R5.stl
Normal file
File diff suppressed because it is too large
Load diff
127136
DES_Corne/C3R2.stl
Normal file
127136
DES_Corne/C3R2.stl
Normal file
File diff suppressed because it is too large
Load diff
128662
DES_Corne/C3R3.stl
Normal file
128662
DES_Corne/C3R3.stl
Normal file
File diff suppressed because it is too large
Load diff
127332
DES_Corne/C3R4.stl
Normal file
127332
DES_Corne/C3R4.stl
Normal file
File diff suppressed because it is too large
Load diff
182674
DES_Corne/C4R2.stl
Normal file
182674
DES_Corne/C4R2.stl
Normal file
File diff suppressed because it is too large
Load diff
128522
DES_Corne/C4R3.stl
Normal file
128522
DES_Corne/C4R3.stl
Normal file
File diff suppressed because it is too large
Load diff
126492
DES_Corne/C4R4.stl
Normal file
126492
DES_Corne/C4R4.stl
Normal file
File diff suppressed because it is too large
Load diff
126072
DES_Corne/C5R2.stl
Normal file
126072
DES_Corne/C5R2.stl
Normal file
File diff suppressed because it is too large
Load diff
128592
DES_Corne/C5R3.stl
Normal file
128592
DES_Corne/C5R3.stl
Normal file
File diff suppressed because it is too large
Load diff
127332
DES_Corne/C5R4.stl
Normal file
127332
DES_Corne/C5R4.stl
Normal file
File diff suppressed because it is too large
Load diff
361
DES_Cornes.scad
Normal file
361
DES_Cornes.scad
Normal file
|
@ -0,0 +1,361 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 19, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = true, homeDot = false, Legends = false);
|
||||
////fullsetee
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [4:5]){
|
||||
// for(Row = [1:3]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2.25;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 7.2;
|
||||
stemLen = 5.5;
|
||||
stemCrossHeight = 4;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16*1.5, 6, 6, 12, 0, 0, -13, -10, -5, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, 10, -10, -5, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -10, -5, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -10, -10, -5, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -3, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+2.5, 0, 0, -2, -3, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16, 18.16, 6, 6, 11+4, 0, 0, 13, -6, 0, 2, 2, .2, 3, 1, 2], //R5 20
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, 5, -6, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 10, -42, 4, 1.7, 8.5, 12, 2, 10, 4, 8, -30, 8.5, 18, 2], //R5
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 19, 2, 5, 4, 13, -50, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8, 15, 2, 6, 4, 10, -30, 8, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.2, 15, 2, 5, 4, 13, -30, 8.2, 16, 2], //R3
|
||||
[ 6, 3, 12, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 9.3, 10, 2, 6, 4, 13, -30, 9.3, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, -30, 8, 15, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 5, 4, 13, -30, 8, 15, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, 30, 8, 16, 2], //R2
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 12, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 17, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.6, 15, 2, 6, 4, 13, -30, 8.6, 16, 2], //R2
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,4,KeyHeight(keyID)-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
198
Dump/ChocKeyCap.scad
Normal file
198
Dump/ChocKeyCap.scad
Normal file
|
@ -0,0 +1,198 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//TODO: Make Alias for key[n]
|
||||
wallthickness = 2.0;
|
||||
topthickness = 2.0;
|
||||
key =
|
||||
//[
|
||||
// BotWid, BotLen, TopWDif, TopLDif, height, WShift, LShift XAngSkew, YAngSkew, ZAngSkew LExpo, WExpo, CapRadIn, CapRadFn, CapRadExpd
|
||||
[18.16*1.5, 18.16, 4, 4, 3.8, 0, 0, -3, -0, 0, 2, 5, .2, 3, 2];
|
||||
//];
|
||||
|
||||
step = 2;
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
//------------Define the trajectory of the dish shsape cuts
|
||||
FrontTraj = [
|
||||
trajectory(forward = 6, pitch = 12),
|
||||
trajectory(forward = 3, pitch = -50)
|
||||
];
|
||||
|
||||
BackTraj = [
|
||||
trajectory(forward = 6, pitch = 10),
|
||||
trajectory(forward = 4, pitch = -30),
|
||||
// trajectory(forward = 10, pitch = -20, roll = 0)
|
||||
];
|
||||
|
||||
//quantized trajectory to be fed into transform
|
||||
stepsize = 50;
|
||||
fn=60;
|
||||
|
||||
FrontPath = quantize_trajectories(FrontTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2.5, 11, 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(2.5, 11, 1, d = 0)) ];
|
||||
|
||||
FrontCurve2 = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2+2, 10+2, 2, d = 0)) ];
|
||||
|
||||
//--------------For Cap
|
||||
layers = 50;
|
||||
|
||||
function CapTranslation(t) =
|
||||
[
|
||||
((1-t)/layers*key[5]), //X shift
|
||||
((1-t)/layers*key[6]), //Y shift
|
||||
(t/layers*key[4]) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t) =
|
||||
[
|
||||
((1-t)/layers*key[5]), //X shift
|
||||
((1-t)/layers*key[6]), //Y shift
|
||||
(t/layers*(key[4]-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t) =
|
||||
[
|
||||
((1-t)/layers*key[7]), //X shift
|
||||
((1-t)/layers*key[8]), //Y shift
|
||||
((1-t)/layers*key[9]) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t) =
|
||||
[
|
||||
pow(t/layers, key[10])*(key[0]-key[2]) + (1-pow(t/layers, key[10]))*key[0],
|
||||
pow(t/layers, key[11])*(key[1]-key[3]) + (1-pow(t/layers, key[11]))*key[1]
|
||||
];
|
||||
|
||||
function InnerTransform(t) =
|
||||
[
|
||||
pow(t/layers, key[10])*(key[0]-key[2]-wallthickness) + (1-pow(t/layers, key[10]))*(key[0]-wallthickness),
|
||||
pow(t/layers, key[11])*(key[1]-key[3]-wallthickness) + (1-pow(t/layers, key[11]))*(key[1]-wallthickness)
|
||||
];
|
||||
|
||||
function CapRadius(t) = pow(t/layers, key[14])*key[13] + (1-pow(t/layers, key[14]))*key[12];
|
||||
|
||||
|
||||
///KEY Build
|
||||
mirror([0,1,0])difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1])transform(translation(CapTranslation(i)) * rotation(CapRotation(i)), rounded_rectangle_profile(CapTransform(i),fn=fn,r=CapRadius(i)))]);
|
||||
|
||||
//use intersection with stem here?
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1])transform(translation(InnerTranslation(i)) * rotation(CapRotation(i)), rounded_rectangle_profile(InnerTransform(i),fn=fn,r=CapRadius(i)))]);
|
||||
}
|
||||
rotate([0,0,stemRot])choc_stem();
|
||||
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
// #rotate([-key[7],key[8],key[9]])translate([0,4,key[4]-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-key[7],key[8],key[9]])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
#translate([0,.00001,key[4]-1.5])rotate([0,-key[8],0])rotate([0,-90+key[7],90-key[9]])skin(FrontCurve);
|
||||
#translate([0,0,key[4]-1.5])rotate([0,-key[8],0])rotate([0,-90-key[7],270-key[9]])skin(BackCurve);
|
||||
// translate([0,-10-3,-.1])cube([20,20,15],center = true);
|
||||
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = 32;
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
extra_vertical = 0.6;
|
||||
function outer_cherry_stem(slop) = [7.2 - slop * 2, 5.5 - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = 4) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
146050
Dump/ChocKeyCap.stl
Normal file
146050
Dump/ChocKeyCap.stl
Normal file
File diff suppressed because it is too large
Load diff
91590
Dump/ChocT1.stl
Normal file
91590
Dump/ChocT1.stl
Normal file
File diff suppressed because it is too large
Load diff
91590
Dump/Chocthums.stl
Normal file
91590
Dump/Chocthums.stl
Normal file
File diff suppressed because it is too large
Load diff
304
Dump/DES_SwitchCeption.scad
Normal file
304
Dump/DES_SwitchCeption.scad
Normal file
|
@ -0,0 +1,304 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
use <Switch.scad>
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 0, cutLen = 0, Stem =true, Dish = false, visualizeDish = true, crossSection = false, homeDot = false, Legends = false);
|
||||
|
||||
|
||||
//Parameters
|
||||
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2.25;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 7.2;
|
||||
stemLen = 5.5;
|
||||
stemCrossHeight = 4;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
//---SwitchCeption Param
|
||||
ChocAng = [55,5,0];
|
||||
ChocLoc = [0,-6.0 ,7.5];
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16*1.25, 18.16+1, 6, 6, 13, 0, -2, -10, -5, 0, 2, 2, .2, 2, 1, 2], //R5 0
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 10, -42, 4, 1.7, 8.5, 12, 2, 10, 4, 8, -30, 8.5, 18, 2], //R5
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,4,KeyHeight(keyID)-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
//Choc keyhole
|
||||
#translate(ChocLoc)rotate(ChocAng)Keyhole(.1, clipLength = -3, cutThickness = 0);
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
//choc support
|
||||
translate(ChocLoc)rotate(ChocAng)translate([0,-2,.5,])cube([16,11,2],center = true);
|
||||
|
||||
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
328
Dump/KeyCap.scad
Normal file
328
Dump/KeyCap.scad
Normal file
|
@ -0,0 +1,328 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 7, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = false, homeDot = false);
|
||||
////fullset
|
||||
//for(Row = [0:4]){
|
||||
// for(Col = [0:5]){
|
||||
// translate([20*Col, 20*Row, 0])keycap(keyID = Col*5+Row, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2.25;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 60; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx
|
||||
//Column 0
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, -5, -12, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6, 8+4, 0, 0, 5, -10, 10, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6, 7+4, 0, 0, -2, -10, 5, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6, 8+4, 0, 0, -7, -10, -5, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11+4, 0, 0, -13, -10, -10, 2, 2, .2, 3, 1], //R1 4
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 12, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6, 8+2, 0, 0, 5, -3, 0, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6, 7+2, 0, 0, -2, -3, 0, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6, 8+2, 0, 0, -7, -3, 0, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11+2, 0, 0, -13, -3, 0, 2, 2, .2, 3, 1], //R1 9
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6, 8, 0, 0, 5, 0, 0, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6, 8, 0, 0, -7, 0, 0, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11, 0, 0, -13, 0, 0, 2, 2, .2, 3, 1], //R1
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6, 8+3, 0, 0, -7, -4, 0, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, -13, -4, 0, 2, 2, .2, 3, 1], //R1
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6,7+5.5, 0, 0, -2, -10, 0, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6,8+5.5, 0, 0, -7, -10, 0, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, -13, 10, 0, 2, 2, .2, 3, 1], //R1
|
||||
//Column 5
|
||||
[18.16, 18.16, 6, 6, 11+4, 0, 0, 13, -6, 0, 2, 2, .2, 3, 1], //R5
|
||||
[18.16, 18.16, 6, 6, 8+4, 0, 0, 5, -6, 0, 2, 2, .2, 3, 1], //R4
|
||||
[18.16, 18.16, 6, 6, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1], //R3 Home
|
||||
[18.16, 18.16, 6, 6, 8+4, 0, 0, -7, -6, 0, 2, 2, .2, 3, 1], //R2
|
||||
[18.16, 18.16, 6, 6, 11+5, 0, 0, -13, 10, 0, 2, 2, .2, 3, 1], //R1
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 5, 3, 5.8, -42, 3.5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 18, 2], //R5
|
||||
[ 6, 3, 15, -50, 3.5, 1.5, 8.5, 19, 2, 5, 4, 13, -50, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 4, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 18, 2], //R1
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 3.5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 9, 15, 2, 5, 4, 13, -30, 9, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R1
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 3.5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R1
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 3.5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 3.5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 4, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R1
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 3.5, 1.6, 8.6, 12, 2, 6, 4, 13, -30, 8.6, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 3.5, 1.6, 8.5, 17, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 4, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R1
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 3.5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
[ 6, 3, 18, -50, 3.5, 1.5, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2] //R1
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, keyParameters[keyID][14])*keyParameters[keyID][13] + (1-pow(t/layers, keyParameters[keyID][14]))*keyParameters[keyID][12];
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
|
||||
//Cut inner
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true)rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID), slop);
|
||||
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
//Fonts
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,4,KeyHeight(keyID)-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([0,.00001,KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([0,.00001,KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = 32;
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
extra_vertical = 0.6;
|
||||
function outer_cherry_stem(slop) = [7.2 - slop * 2, 5.5 - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = 4) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
186
Dump/MXInception.scad
Normal file
186
Dump/MXInception.scad
Normal file
|
@ -0,0 +1,186 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
use <Switch.scad>
|
||||
//TODO: Make Alias for key[n]
|
||||
wallthickness = 2.5;
|
||||
topthickness = 3.0;
|
||||
key =
|
||||
//[
|
||||
// BotWid, BotLen, TopWDif, TopLDif, height, WShift, LShift XAngSkew, YAngSkew, ZAngSkew LExpo, WExpo, CapRadIn, CapRadFn, CapRadExpd
|
||||
[18.16*1.25, 18.16, 5, 5, 13, 0, 0, -6, -5, 0, 2.5, 2.5, .2, 3, 2];
|
||||
//];
|
||||
|
||||
step = 2;
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
//------------Define the trajectory of the dish shsape cuts
|
||||
FrontTraj = [
|
||||
trajectory(forward = 6, pitch = 12),
|
||||
trajectory(forward = 3, pitch = -50)
|
||||
];
|
||||
|
||||
BackTraj = [
|
||||
trajectory(forward = 6, pitch = 10),
|
||||
trajectory(forward = 4, pitch = -30),
|
||||
// trajectory(forward = 10, pitch = -20, roll = 0)
|
||||
];
|
||||
|
||||
//quantized trajectory to be fed into transform
|
||||
stepsize = 50;
|
||||
fn=60;
|
||||
|
||||
FrontPath = quantize_trajectories(FrontTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2.5, 12, 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(2.5, 12, 1, d = 0)) ];
|
||||
|
||||
FrontCurve2 = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2+2, 10+2, 2, d = 0)) ];
|
||||
|
||||
//--------------For Cap
|
||||
layers = 50;
|
||||
|
||||
function CapTranslation(t) =
|
||||
[
|
||||
((1-t)/layers*key[5]), //X shift
|
||||
((1-t)/layers*key[6]), //Y shift
|
||||
(t/layers*key[4]) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t) =
|
||||
[
|
||||
((1-t)/layers*key[5]), //X shift
|
||||
((1-t)/layers*key[6]), //Y shift
|
||||
(t/layers*(key[4]-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t) =
|
||||
[
|
||||
((1-t)/layers*key[7]), //X shift
|
||||
((1-t)/layers*key[8]), //Y shift
|
||||
((1-t)/layers*key[9]) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t) =
|
||||
[
|
||||
pow(t/layers, key[10])*(key[0]-key[2]) + (1-pow(t/layers, key[10]))*key[0],
|
||||
pow(t/layers, key[11])*(key[1]-key[3]) + (1-pow(t/layers, key[11]))*key[1]
|
||||
];
|
||||
|
||||
function InnerTransform(t) =
|
||||
[
|
||||
pow(t/layers, key[10])*(key[0]-key[2]-wallthickness) + (1-pow(t/layers, key[10]))*(key[0]-wallthickness),
|
||||
pow(t/layers, key[11])*(key[1]-key[3]-wallthickness) + (1-pow(t/layers, key[11]))*(key[1]-wallthickness)
|
||||
];
|
||||
|
||||
function CapRadius(t) = pow(t/layers, key[14])*key[13] + (1-pow(t/layers, key[14]))*key[12];
|
||||
|
||||
|
||||
///KEY Build
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1])transform(translation(CapTranslation(i)) * rotation(CapRotation(i)), rounded_rectangle_profile(CapTransform(i),fn=fn,r=CapRadius(i)))]);
|
||||
|
||||
//use intersection with stem here?
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1])transform(translation(InnerTranslation(i)) * rotation(CapRotation(i)), rounded_rectangle_profile(InnerTransform(i),fn=fn,r=CapRadius(i)))]);
|
||||
}
|
||||
rotate([0,0,stemRot])cherry_stem(10, slop);
|
||||
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
// #rotate([-key[7],key[8],key[9]])translate([0,4,key[4]-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
|
||||
translate([0,.00001,key[4]-1.5])rotate([0,-key[8],0])rotate([0,-90+key[7],90-key[9]])skin(FrontCurve);
|
||||
translate([0,0,key[4]-1.5])rotate([0,-key[8],0])rotate([0,-90-key[7],270-key[9]])skin(BackCurve);
|
||||
#translate([0,-6.6,7.8])rotate([72,0,0])Keyhole(.1, clipLength = -3, cutThickness = 0);
|
||||
// translate([0,0,-.1])cube([15,15,15]);
|
||||
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = 32;
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
extra_vertical = 0.6;
|
||||
function outer_cherry_stem(slop) = [7.2 - slop * 2, 5.5 - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = 4) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
142
Dump/Switch.scad
Normal file
142
Dump/Switch.scad
Normal file
|
@ -0,0 +1,142 @@
|
|||
plate_thickness = 1;
|
||||
plate_size = 15.6;
|
||||
edge_offset = 1;
|
||||
bottom_height = 5;
|
||||
bottom_size = plate_size - 2;
|
||||
|
||||
top_height = 11.6;
|
||||
|
||||
switch_height = 3.0;
|
||||
switch_thick = 1;
|
||||
switch_width = 5;
|
||||
switch_length = 3;
|
||||
|
||||
cap_height = .38*25.4;
|
||||
cap_heightShift = 0.69*25.4;
|
||||
cap_width = 18.3;
|
||||
|
||||
clip_Length = 3; // length clipped
|
||||
|
||||
//dummy key switch with caps to check position
|
||||
module Switch(switchScale= [1,1,1], colors = "teal", clipLength = 0, type = "")
|
||||
{
|
||||
difference(){
|
||||
union(){
|
||||
translate([0,0,1.75]){
|
||||
difference(){
|
||||
translate([0,0,0.5])cube([15,15,1], center = true);
|
||||
//cuts
|
||||
// translate([15/2-1/2,0,.5])cube([1,10.5,2], center = true);
|
||||
// translate([-15/2+1/2,0,.5])cube([1,10.5,2], center = true);
|
||||
}
|
||||
|
||||
translate([0,0,1.5])cube([13,13,2], center = true);
|
||||
color("springGreen")translate([0,0,4])cube([11.4,4,3], center = true);
|
||||
color("springGreen")translate([0,1,4])cube([3,5,3], center = true);
|
||||
color("DarkSlateGray")translate([0,0,-1])cube([13,14,2,],center = true);
|
||||
color("DarkSlateGray")translate([0,0,-2-2.5])cylinder(d=3.3, 2.5);
|
||||
color("DarkSlateGray")translate([5,0,-2-2.5])cylinder(d=1.6, 2.5);
|
||||
color("DarkSlateGray")translate([-5,0,-2-2.5])cylinder(d=1.6, 2.5);
|
||||
|
||||
//cap
|
||||
color("ivory")hull(){
|
||||
translate([0,0,4.5+1])cube([17.5,16.8,2],center = true);
|
||||
translate([0,1.25,4.5+1+1.5])cube([14.5,12.5,1.5],center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clipLength != 0){ // commiting unholy act in name of ergonomics
|
||||
translate([0, -sign(clipLength)*7.8-clipLength, 0])cube([20, 15.6, 40], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Cutter()
|
||||
{
|
||||
bottom_height = 4.5;
|
||||
bottom_chamfer_width = 3;
|
||||
bottom_chamfer_height = 1;
|
||||
bottom_chamfer_thickness = .6;
|
||||
|
||||
bottom_peg_diameter = 4;
|
||||
bottom_peg_height = 3;
|
||||
bottom_peg_chamfer = 1;
|
||||
bottom_peg_side_scale = 1.7/4;
|
||||
|
||||
translate([-bottom_size/2, -bottom_size/2 ,0])cube([bottom_size,bottom_size,bottom_height]);
|
||||
|
||||
translate([0,0, -(bottom_peg_height -bottom_peg_chamfer)]){
|
||||
cylinder(d=bottom_peg_diameter, h= bottom_peg_height -bottom_peg_chamfer);
|
||||
translate([5,0,0])scale(v=[bottom_peg_side_scale,bottom_peg_side_scale,1])cylinder(d=bottom_peg_diameter, h= bottom_peg_height -bottom_peg_chamfer);
|
||||
translate([-5,0,0])scale(v=[bottom_peg_side_scale,bottom_peg_side_scale,1])cylinder(d=bottom_peg_diameter, h= bottom_peg_height -bottom_peg_chamfer);
|
||||
|
||||
translate([0,0, -bottom_peg_chamfer]){
|
||||
cylinder(d2=bottom_peg_diameter , d1 = bottom_peg_diameter -2*bottom_peg_chamfer, h= bottom_peg_chamfer);
|
||||
translate([5,0,0])scale(v=[bottom_peg_side_scale,bottom_peg_side_scale,1])cylinder(d2=bottom_peg_diameter , d1 = bottom_peg_diameter -2*bottom_peg_chamfer, h= bottom_peg_chamfer);
|
||||
translate([-5,0,0])scale(v=[bottom_peg_side_scale,bottom_peg_side_scale,1])cylinder(d2=bottom_peg_diameter , d1 = bottom_peg_diameter -2*bottom_peg_chamfer, h= bottom_peg_chamfer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MX series keyhole
|
||||
// TODO: add alps support?
|
||||
module Keyhole(tol = .1, cutThickness = .5, clipLength = 0)
|
||||
{
|
||||
$fn = 10;
|
||||
bottom_length = 13.9+tol;
|
||||
plate_thickness = 3.51; //mm
|
||||
holeLength = bottom_length+tol*2;
|
||||
//latch nibs
|
||||
nib_radius= 1;
|
||||
nib_length = 3;
|
||||
|
||||
translate([0,0,-1.25])difference(){
|
||||
union(){
|
||||
translate([0,0,1.25])cube([holeLength, holeLength, plate_thickness+tol], center =true);
|
||||
// translate([0,0,.25-cutThickness/2])cube([holeLength+1, holeLength+1, plate_thickness+cutThickness], center =true);
|
||||
}
|
||||
|
||||
union(){
|
||||
if (clipLength != 0){
|
||||
translate([0, -sign(clipLength)*7.8-clipLength, 0])cube([20, 15.6, 40], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Stabilizer(offsets = 23.8/2)
|
||||
{
|
||||
plate_thickness = 3.6; //mm
|
||||
stabilizer_width = 5;
|
||||
stabilizer_length = 12.2;
|
||||
translate([offsets,0,0])cube([stabilizer_width,stabilizer_length,plate_thickness], center = true);
|
||||
translate([-offsets,0,0])cube([stabilizer_width,stabilizer_length,plate_thickness], center = true);
|
||||
}
|
||||
|
||||
module TrackPoint(nibLength = 20)
|
||||
{
|
||||
color("red")translate([0,0,-.5])cube([4.5,4.5,5], center= true); //nib
|
||||
color("gold")cylinder(d = 2, nibLength); //nib
|
||||
color("gold")translate([0,0,nibLength])sphere(2); //nib
|
||||
translate([0,30.3/2-8,-3/2])cube([26.46, 30.3, 3], center = true);
|
||||
}
|
||||
|
||||
module RotaryEncoder(stemLength = 13, Wheel = 0)
|
||||
{
|
||||
color("grey")translate([0,0, -6.1/2])cube([11.5, 13.5, 6.1], center = true);
|
||||
cylinder(d = 7, 7.8);
|
||||
|
||||
translate([0,0,7.8])difference(){
|
||||
cylinder(d = 5.8, stemLength);
|
||||
translate([-5.8/2,5.8/2-1.5,3])cube([11.5, 13.5, stemLength]);
|
||||
}
|
||||
color("grey")translate([0,0,7.8])cylinder(d = Wheel, stemLength);
|
||||
}
|
||||
|
||||
//################ Test Calls ###################
|
||||
//Switch(clipLength = -4);
|
||||
Keyhole(.1, clipLength = -4);
|
||||
//Stabilizer(20);
|
||||
// RotaryEncoder(Wheel = 0);
|
||||
//Switch([1,1.5,1]);
|
||||
//TrackPoint();
|
206
KeyCap.scad
206
KeyCap.scad
|
@ -1,206 +0,0 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
key =
|
||||
// BotWid, BotLen, TopWDif, TopLDif, height, WShift, LShift XAngSkew, YAngSkew, ZAngSkew LExpo, WExpo, CapRadIn, CapRadFn, CapRadExpd
|
||||
[18.16, 18.16, 3, 5, 10, 0, 0, 0, 0, 0, 5, 5, .5, 4, 1];
|
||||
// [18.16, 18.16, 6, 4, 8.5, -1, 1.75, 0, 1, 0, 0, false],//C0R1 unusede
|
||||
// [18.16, 18.16, 6.2, 4, 7.5, 3, 1.75, 0, 1, 0, 0, false],//C0R2 unused
|
||||
//
|
||||
// [18.16, 18.16, 5.7, 4, 7.4, -2, -1.5, 1, 1.2, 0, 0, false],//C1R0 clipped G20 like
|
||||
// [18.16, 18.16, 5.7, 5.7, 7.4, 0, 0, 1, 1.2, 0, 0, false],//C1R1 clipped G20 DSA
|
||||
// [18.16, 18.16, 5.7, 4, 7.4, -5, 1.5, 1, 1.2, 0, 0, false],//C1R2 clipped G20 like
|
||||
//
|
||||
// [18.4, 18.4, 3, 5.7, 7.4, 0, 0, 1, 2, -3, -2, false],//C2R0 clipped tilted
|
||||
// [18.4, 18.4, 3, 5.7, 7.4, 0, 0, 1, 2, -3, 0, false],//C2R1 clipped tilted
|
||||
// [18.4, 18.4, 3, 5.7, 7.4, -5, 1.5, 1, 2, -3, 0, false],//C2R2 clipped tilted
|
||||
//
|
||||
// [18.4, 18.4, 5.7, 5.7, 7.4, -5, -1, 1, 1.2, 0, 0, false],//C3R0
|
||||
// [18.4, 18.4, 5.7, 5.7, 7.4, 0, 0, 1, 1.2, 0, 0, false],//C3R1 Norm DSA
|
||||
// [18.16, 18.16, 5.7, 4, 7.5, -5, 1.5, 0, 1, 0, 0, false],//C3R2
|
||||
//
|
||||
// [18.4, 18.4, 5.7, 5.7, 7.4, -5, 0, 1, 1.2, 0, 0, false],//C4R0
|
||||
// [18.4, 18.4, 5.7, 5.7, 7.4, 0, 0, 1, 1.2, 0, 0, false],//C4R1
|
||||
// [18.16, 18.16, 5.7, 3, 7.5, -5, 1.5, 0, 1, 0, 0, false],//C4R2
|
||||
//
|
||||
// [18.16, 18.16, 5.7, 4, 6.2, 7, 1.75, 0, 1, 0, 0, false],//C5R0
|
||||
// [18.4, 18.4, 5.7, 5.7, 7.4, 0, 0, 1, 1.2, 0, 0, false],//C5R1
|
||||
// [18.16, 18.16, 5.7, 3, 7.5, -5, 1.5, 0, 1, 0, 0, false],//C5R2
|
||||
//
|
||||
// [18.16, 18.16, 4, 6, 7.4, 6, -1.5, 1, 1.2, 0, 0, false],//C6R0
|
||||
// [18.16, 18.16, 4, 5.7, 7.4, 0, 0, 1, .5, 0, 0, false],//C6R1 true
|
||||
// [18.16, 18.16, 4, 3, 7.5, -4, 1.5, 1, 1, 1, -1, false] //C6R2
|
||||
//];
|
||||
|
||||
step = 1;
|
||||
//function path(t) = [t, t, t];
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t), b*sin(t)*(1+d*cos(t))]]; //shape to
|
||||
//
|
||||
//
|
||||
function path(t) = [0,0,t];
|
||||
//
|
||||
//module roundedRect(size = [0,0,0], radius= 1.5) { //simplified to single call using Morphology Util lib
|
||||
// linear_extrude(size[2])rounding(r=radius)square([size[0], size[1]], center = true);
|
||||
//}
|
||||
|
||||
|
||||
function shape1 (a,b,c,d) =
|
||||
concat(
|
||||
[[a,-c]],
|
||||
ellipse(a, b, d = 0, rot2 = 180),
|
||||
[[-a,-c]]
|
||||
);
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
[[c,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270),
|
||||
[[c,-b]]
|
||||
);
|
||||
|
||||
|
||||
//linear_extrude(5)polygon(shape1(1, 1, 1, d = 0));
|
||||
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
//Define the trajectory of the dish shsape cuts
|
||||
FrontTraj = [
|
||||
trajectory(forward = 5, pitch = -10, roll = 5),
|
||||
trajectory(forward = 2, pitch = -60),
|
||||
trajectory(forward = 10, pitch = 10),
|
||||
];
|
||||
|
||||
BackTraj = [
|
||||
trajectory(forward = 5, pitch = 10 , roll = 5),
|
||||
trajectory(forward = 5, pitch = -90),
|
||||
trajectory(forward = 10, pitch = 10),
|
||||
];
|
||||
|
||||
//quantized trajectory to be fed into transform
|
||||
stepsize = 100;
|
||||
fn=60;
|
||||
|
||||
FrontPath = quantize_trajectories(FrontTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTraj, steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2, 10, 3, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(2, 10, 3, d = 0)) ];
|
||||
|
||||
FrontCurve2 = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(2+2, 10+2, 2, d = 0)) ];
|
||||
|
||||
|
||||
|
||||
|
||||
//CapWall(capID,thickness_difference, depth_difference, )
|
||||
layers = 40;
|
||||
|
||||
function CapTranslation(t) =
|
||||
[
|
||||
((1-t)/layers*key[5]), //X shift
|
||||
((1-t)/layers*key[6]), //Y shift
|
||||
(t/layers*key[4]) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t) =
|
||||
[
|
||||
((1-t)/layers*key[7]), //X shift
|
||||
((1-t)/layers*key[8]), //Y shift
|
||||
((1-t)/layers*key[9]) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t) =
|
||||
[
|
||||
pow(t/layers, key[10])*(key[0]-key[2]) + (1-pow(t/layers, key[10]))*key[0],
|
||||
pow(t/layers, key[11])*(key[1]-key[3]) + (1-pow(t/layers, key[11]))*key[1]
|
||||
];
|
||||
|
||||
function CapRadius(t) = pow(t/layers, key[10])*(key[0]-key[2]) + (1-pow(t/layers, key[10]))*key[0],
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1])transform(translation(CapTranslation(i)) * rotation(CapRotation(i)), rounded_rectangle_profile(CapTransform(i),fn=fn,r=.5))]);
|
||||
|
||||
//another skin morph with wall thickness
|
||||
//use intersection with stem here?
|
||||
//cut for fonts and extra pattern for light?
|
||||
|
||||
//#translate([0,0,26])rotate([-80,0,0])sweep(shape1(10, 10, 2, d = 0), path_trans2);
|
||||
|
||||
//#translate([0,0,key[4]+5])rotate([0,-90,90])skin(FrontCurve);
|
||||
//#translate([0,0,key[4]+5])rotate([0,-90,270])skin(BackCurve);
|
||||
}
|
||||
//echo(morph(
|
||||
// profile1 = rounded_rectangle_profile([key[0],key[1]],fn=fn,r=.5),
|
||||
// profile2 = transform(translation([0,0,key[4]+5]), rounded_rectangle_profile([key[0]-key[2],key[1]-key[3]],fn=fn,r=4)),
|
||||
// slices=10)
|
||||
// ););
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
||||
|
||||
powExpo = 2;
|
||||
function interpolate_profile(profile1, profile2, t) = (1-pow(t,powExpo)) * profile1 + pow(t,powExpo)* profile2;
|
||||
//function interpolate_arc_profile(profile1, profile2, t) = (1-sin(t*90)) * profile1 + sin(t*90) * profile2;
|
||||
|
||||
// Morph two profile
|
||||
function morph(profile1, profile2, slices=1, fn=0) = morph0(
|
||||
augment_profile(to_3d(profile1),max(len(profile1),len(profile2),fn)),
|
||||
augment_profile(to_3d(profile2),max(len(profile1),len(profile2),fn)),
|
||||
slices
|
||||
);
|
||||
|
||||
function morph0(profile1, profile2, slices=1) = [
|
||||
for(index = [0:slices-1])
|
||||
interpolate_profile(profile1, profile2, index/(slices-1))
|
||||
];
|
||||
|
||||
|
||||
// The area of a profile
|
||||
//function area(p, index_=0) = index_ >= len(p) ? 0 :
|
||||
function pseudo_centroid(p,index_=0) = index_ >= len(p) ? [0,0,0] :
|
||||
p[index_]/len(p) + pseudo_centroid(p,index_+1);
|
||||
|
||||
|
||||
//// Nongeneric helper functions
|
||||
|
||||
function profile_distance(p1,p2) = norm(pseudo_centroid(p1) - pseudo_centroid(p2));
|
||||
|
||||
function rate(profiles) = [
|
||||
for (index = [0:len(profiles)-2]) [
|
||||
profile_length(profiles[index+1]) - profile_length(profiles[index]),
|
||||
profile_distance(profiles[index], profiles[index+1])
|
||||
]
|
||||
];
|
||||
|
||||
function profiles_lengths(profiles) = [ for (p = profiles) profile_length(p) ];
|
||||
|
||||
function profile_length(profile,i=0) = i >= len(profile) ? 0 :
|
||||
profile_segment_length(profile, i) + profile_length(profile, i+1);
|
||||
|
||||
function expand_profile_vertices(profile,n=32) = len(profile) >= n ? profile : expand_profile_vertices_0(profile,profile_length(profile),n);
|
|
@ -1,4 +1,2 @@
|
|||
# KeyCapProfiles
|
||||
|
||||
|
||||
Make Caps of your dream!
|
||||
Parametric Key Caps
|
||||
|
|
383
RP_MX.scad
Normal file
383
RP_MX.scad
Normal file
|
@ -0,0 +1,383 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DP (Distored Pyramidal) [Double Penetration] Profile
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 10, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = false, homeDot = false, Legends = false);
|
||||
////fullsetee
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [4:4]){
|
||||
// for(Row = [1:3]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = false, crossSection = true);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2.5;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 7.2;
|
||||
stemLen = 5.5;
|
||||
stemCrossHeight = 4;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
dishLayers = 100;
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16*1.5, 6, 6, 12, 0, 0, -13, -10, -5, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, 10, -10, -5, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -10, -5, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -10, -10, -5, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -3, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+2.5, 0, 0, -2, -3, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16, 18.16, 6, 6, 11+4, 0, 0, 13, -6, 0, 2, 2, .2, 3, 1, 2], //R5 20
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, 5, -6, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
// EdOf fn LEx WEx DshDep DishCh, DishEp
|
||||
//Column 0
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
//Column 1
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
//Column 2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .001, 2, 2, 2, .1, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
//Column 3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
//Column 4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
//Column 5
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R2
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R3
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R4
|
||||
[ .1, .005, 2, 2, 2, .001, .9], //R5
|
||||
];
|
||||
|
||||
|
||||
function EdgeOffset(keyID) = dishParameters[keyID][0]; //
|
||||
function LenFinal(keyID) = dishParameters[keyID][1]; //
|
||||
function LenExpo(keyID) = dishParameters[keyID][2]; //
|
||||
function WidExpo(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishCham(keyID) = dishParameters[keyID][5]; //
|
||||
function DishExpo(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
//function FrontTrajectory(keyID) =
|
||||
// [
|
||||
// trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
// trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
// ];
|
||||
//
|
||||
//function BackTrajectory (keyID) =
|
||||
// [
|
||||
// trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
// trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
// ];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
|
||||
//----- Distorted Pyramidal Dish
|
||||
|
||||
function DishTranslation(t, keyID) =
|
||||
[
|
||||
((t)/dishLayers*TopWidShift(keyID)), //X shift
|
||||
((t)/dishLayers*TopLenShift(keyID)), //Y shift
|
||||
KeyHeight(keyID)-(t)/dishLayers*(DishDepth(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function DishRotation(t, keyID) =
|
||||
[
|
||||
(-XAngleSkew(keyID)), //X shift
|
||||
(-YAngleSkew(keyID)), //Y shift
|
||||
(-ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function DishTransform(t, keyID) =
|
||||
[
|
||||
(1-pow(t/dishLayers, WidExpo(keyID)))*(BottomWidth(keyID) -TopLenDiff(keyID)+EdgeOffset(keyID)) + (pow(t/dishLayers, WidExpo(keyID)))*(LenFinal(keyID)),
|
||||
(1-pow(t/dishLayers, LenExpo(keyID)))*(BottomLength(keyID)-TopLenDiff(keyID)+EdgeOffset(keyID)) + (pow(t/dishLayers, LenExpo(keyID)))*(LenFinal(keyID))
|
||||
];
|
||||
|
||||
function DishRadius(t, keyID) = pow(t/dishLayers, DishExpo(keyID))*DishCham(keyID) + (1-pow(t/dishLayers, DishExpo(keyID)))*ChamfFinRad(keyID);
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
// //Set Parameters for dish shape
|
||||
// FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
// BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
//
|
||||
// //Scaling initial and final dim tranformation by exponents
|
||||
// function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
// function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
//
|
||||
// FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
// BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID)-topthickness, slop); // generate mx cherry stem, not compatible with box
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,4,KeyHeight(keyID)-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
#skin([for (i=[0:dishLayers-1]) transform(translation(DishTranslation(i, keyID)) * rotation(DishRotation(i, keyID)), rounded_rectangle_profile(DishTransform(i, keyID),fn=fn,r=DishRadius(i, keyID)))]);
|
||||
} else {
|
||||
#skin([for (i=[0:dishLayers-1]) transform(translation(DishTranslation(i, keyID)) * rotation(DishRotation(i, keyID)), rounded_rectangle_profile(DishTransform(i, keyID),fn=fn,r=DishRadius(i, keyID)))]);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishDepth(keyID)-.1])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
225822
RP_MX/PDA_C3R4.stl
Normal file
225822
RP_MX/PDA_C3R4.stl
Normal file
File diff suppressed because it is too large
Load diff
219606
RP_MX/RP_C3R3.stl
Normal file
219606
RP_MX/RP_C3R3.stl
Normal file
File diff suppressed because it is too large
Load diff
BIN
RP_profile.png
Normal file
BIN
RP_profile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
BIN
RP_profile_cross_section.png
Normal file
BIN
RP_profile_cross_section.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
chocs.png
Normal file
BIN
chocs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
402
chocs.scad
Normal file
402
chocs.scad
Normal file
|
@ -0,0 +1,402 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
|
||||
//TODO add shift
|
||||
keycap(keyID = 1, cutLen = 0, Stem =true, Dish = false, visualizeDish = true, crossSection = false, homeDot = false, Legends = false);
|
||||
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [0:0]){
|
||||
// for(Row = [1:2]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = true, crossSection = true,Legends = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 2;
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 64; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 8;
|
||||
stemLen = 6;
|
||||
stemCrossHeight = 1.8;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapRIn, CapRFn, CapREx, StemEx
|
||||
//Column 0
|
||||
[18.16, 18.16, 3, 3, 6, 0, 0, 3, -0, -0, 2, 2, 1, 3, 1, 2], //R5 0
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.2, 3, -0, -0, 2, 3, 3, 1, 2, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 4, 4, 5, 0, 0, -2, -0, -0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 1
|
||||
[18.16, 18.16, 6, 6, 10, 0, 0, -13, 5, 0, 2, 2, .2, 3, 1, 2], //R5 4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, -.5, 3, -0, -0, 2, 2, 1, 2, 1, 2], //R4
|
||||
[18.16, 18.16, 3, 1.5, 4.5, 0, .5, -3, -0, -0, 2, 2, 1, 2, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -12, -3, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 2 middle
|
||||
[18.16, 18.16, 6, 6, 12, 0, 0, -13, 10, 15, 2, 2, .2, 3, 1, 2], //R5 8
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, 9, 0, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7, 0, 0, -2, 0, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8, 0, 0, -12, 0, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 3
|
||||
[18.16, 18.16, 6, 6, 11+3, 0, 0, 13, -4, 0, 2, 2, .2, 3, 1, 2], //R5 12
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, 5, -4, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7, 7+3, 0, 0, -2, -4, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+3, 0, 0, -10, -4, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 4
|
||||
[18.16, 18.16, 6, 6,11+5.5, 0, 0, 13, -10, 0, 2, 2, .2, 3, 1, 2], //R5 16
|
||||
[18.16, 18.16, 7, 7,8+5.5, 0, 0, 5, -10, 0, 2, 2, .2, 3, 1, 2], //R4
|
||||
[18.16, 18.16, 7, 7,7+5.5, 0, 0, -5, -10, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+4, 0, 0, -12, 5, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
//Column 5
|
||||
[18.16*1.5, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, .2, 3, 1, 2], //R5 0
|
||||
[18.16*1.25, 18.16, 3, 3, 5, 0, 0, -3, -0, -0, 2, 2, 1, 3, 1, 2],
|
||||
[18.16, 18.16, 7, 7, 7+4, 0, 0, -2, -6, 0, 2, 2, .2, 3, 1, 2], //R3 Home
|
||||
[18.16, 18.16, 7, 7, 8+6, 0, 0, -12, 10, 0, 2, 2, .2, 3, 1, 2], //R2
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function ChamfInitRad(keyID) = keyParameters[keyID][12];
|
||||
function ChamfFinRad(keyID) = keyParameters[keyID][13];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][14];
|
||||
function StemExponent(keyID) = keyParameters[keyID][15];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 5, -42, 5, 1.7, 20, 20, 2, 10, 4, 8, -30, 20, 20, 2], //R5
|
||||
[ 6, 4, 5, -50, 4, 1.2, 13, 19, 2, 6, 4, 5, -15, 13, 19, 2], //R4
|
||||
[ 6, 3, 8, -20, 5, 1.2, 12, 19, 2, 5, 4, 13, -5*0, 12, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
//Column 1
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8, 15, 2, 6, 4, 10, -30, 8, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.2, 15, 2, 5, 4, 13, -30, 8.2, 16, 2], //R3
|
||||
[ 6, 3, 12, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 2
|
||||
[ 5, 3.5, 5, -48, 4, 1.7, 9.3, 10, 2, 6, 4, 13, -30, 9.3, 18, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, -30, 8, 15, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 5, 4, 13, -30, 8, 15, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8, 15, 2, 6, 4, 13, 30, 8, 16, 2], //R2
|
||||
//Column 3
|
||||
[ 5, 3, 5, -50, 5, 1.5, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 15, -50, 5, 1.6, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R2
|
||||
//Column 4
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 12, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 17, 2, 6, 4, 10, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 15, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.6, 15, 2, 6, 4, 13, -30, 8.6, 16, 2], //R2
|
||||
//Column 5
|
||||
[ 5, 3, 5, -50, 5, 1.7, 8.5, 10, 2, 6, 4, 13, -30, 8.5, 16, 2], //R5
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 6, 4, 13, -30, 8.5, 16, 2], //R4
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.5, 15, 2, 5, 4, 13, -30, 8.5, 16, 2], //R3
|
||||
[ 6, 3, 18, -50, 5, 1.7, 8.8, 15, 2, 6, 4, 13, -30, 8.8, 16, 2], //R2
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*ChamfFinRad(keyID) + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
// skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(CapTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]); //outer shell
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), elliptical_rectangle(a = [10,10], b = [2,1],fn=fn))]); //outer shell
|
||||
//
|
||||
// //Cut inner shell
|
||||
// if(Stem == true){
|
||||
// translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), rounded_rectangle_profile(InnerTransform(i, keyID),fn=fn,r=CapRadius(i, keyID)))]);
|
||||
// }
|
||||
// }
|
||||
// if(Stem == true){
|
||||
// rotate([0,0,stemRot])choc_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
// translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,4,KeyHeight(keyID)-2.5])linear_extrude(height = 0.5)text( text = "Why?", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function elliptical_rectangle(a = [1,1], b =[1,1], fn=32) = [
|
||||
for (index = [0:fn-1]) // section right
|
||||
let(theta1 = -atan(a[1]/b[1])+ 2*atan(a[1]/b[1])*index/fn)
|
||||
[b[1]*cos(theta1), a[1]*sin(theta1)]
|
||||
+ [a[0]*cos(atan(b[0]/a[0])) , 0]
|
||||
- [b[1]*cos(atan(a[1]/b[1])) , 0],
|
||||
|
||||
for(index = [0:fn-1]) // section Top
|
||||
let(theta2 = atan(b[0]/a[0]) + (180 -2*atan(b[0]/a[0]))*index/fn)
|
||||
[a[0]*cos(theta2), b[0]*sin(theta2)]
|
||||
- [0, b[0]*sin(atan(b[0]/a[0]))]
|
||||
+ [0, a[1]*sin(atan(a[1]/b[1]))],
|
||||
|
||||
for(index = [0:fn-1]) // section left
|
||||
let(theta2 = -atan(a[1]/b[1])+180+ 2*atan(a[1]/b[1])*index/fn)
|
||||
[b[1]*cos(theta2), a[1]*sin(theta2)]
|
||||
- [a[0]*cos(atan(b[0]/a[0])) , 0]
|
||||
+ [b[1]*cos(atan(a[1]/b[1])) , 0],
|
||||
|
||||
for(index = [0:fn-1]) // section Top
|
||||
let(theta2 = atan(b[0]/a[0]) + 180 + (180 -2*atan(b[0]/a[0]))*index/fn)
|
||||
[a[0]*cos(theta2), b[0]*sin(theta2)]
|
||||
+ [0, b[0]*sin(atan(b[0]/a[0]))]
|
||||
- [0, a[1]*sin(atan(a[1]/b[1]))]
|
||||
];
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
366
chocs_ellpticalRectangles.scad
Normal file
366
chocs_ellpticalRectangles.scad
Normal file
|
@ -0,0 +1,366 @@
|
|||
use <scad-utils/morphology.scad> //for cheaper minwoski
|
||||
use <scad-utils/transformations.scad>
|
||||
use <scad-utils/shapes.scad>
|
||||
use <scad-utils/trajectory.scad>
|
||||
use <scad-utils/trajectory_path.scad>
|
||||
use <sweep.scad>
|
||||
use <skin.scad>
|
||||
|
||||
//DES (Distorted Elliptical Saddle) Profile for 6x3 and corne thumb
|
||||
//Stab = 24 for
|
||||
//TODO add shift
|
||||
keycap(keyID = 0, cutLen = 0, Stem =true, Dish = true, Stab = 0 , visualizeDish = false, crossSection = true, homeDot = false, Legends = false);
|
||||
// translate([0,19, 0])keycap(keyID = 3, cutLen = 0, Stem =true, Dish = true, visualizeDish = true, crossSection = true, homeDot = false, Legends = false);
|
||||
// translate([0,38, 0])mirror([0,1,0])keycap(keyID = 2, cutLen = 0, Stem =true, Dish = true, visualizeDish = false, crossSection = true, homeDot = false, Legends = false);
|
||||
RowHome = [0,2.5,5,2.5,0,0];
|
||||
|
||||
//for(Col = [0:0]){
|
||||
// for(Row = [1:2]){
|
||||
// translate([19*Col, 19*Row +RowHome[Col], 0])keycap(keyID = Col*4+Row, cutLen = 0, Stem = true, Dish = true, visualizeDish = true, crossSection = true,Legends = false);
|
||||
// }
|
||||
//}
|
||||
|
||||
////// thumb
|
||||
// translate([-15, -4, 0])rotate([0,0,30])keycap(keyID = 0, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([10, 0, 0])rotate([0,0,15])keycap(keyID = 4, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
// translate([31, 2.2, 0])rotate([0,0,0])keycap(keyID = 8, cutLen = 0, Stem =false, Dish = true, visualizeDish = false, crossSection = false);
|
||||
|
||||
//Parameters
|
||||
wallthickness = 1.75;
|
||||
topthickness = 3; //2 for phat 3 for chicago
|
||||
stepsize = 50; //resolution of Trajectory
|
||||
step = 2; //resolution of ellipes
|
||||
fn = 32; //resolution of Rounded Rectangles: 60 for output
|
||||
layers = 50; //resolution of vertical Sweep: 50 for output
|
||||
|
||||
//---Stem param
|
||||
slop = 0.3;
|
||||
stemRot = 0;
|
||||
stemWid = 8;
|
||||
stemLen = 6;
|
||||
stemCrossHeight = 1.8;
|
||||
extra_vertical = 0.6;
|
||||
stemLayers = 50; //resolution of stem to cap top transition
|
||||
//#square([18.16, 18.16], center = true);
|
||||
keyParameters = //keyParameters[KeyID][ParameterID]
|
||||
[
|
||||
// BotWid, BotLen, TWDif, TLDif, keyh, WSft, LSft XSkew, YSkew, ZSkew, WEx, LEx, CapR0i, CapR0f, CapR1i, CapR1f, CapREx, StemEx
|
||||
//Column 0
|
||||
[36.16, 18.16, 3, 3, 6, 0, 0, 3, -0, -0, 2, 2, 1, 1, 1, 1, 1, 2], //Chicago Thumb
|
||||
[17.26, 17.26, 4.5, 2, 4.5, 0, .0, 5, -0, -0, 2, 3, 2, 3, 2, 6, 2, 2], //Phat Fingers
|
||||
[17.26, 17.26, 7, 4, 5.5, 0, .0, 5, -0, -0, 2, 3, 4, 4, 1, 4, 1, 2], //Chicago Steno R2/R4
|
||||
[17.26, 17.26, 7, 4, 4.5, 0, .0, 0, -0, -0, 2, 3, 4, 4, 1, 4, 1, 2] //Chicago Steno R3 flat
|
||||
|
||||
];
|
||||
|
||||
function BottomWidth(keyID) = keyParameters[keyID][0]; //
|
||||
function BottomLength(keyID) = keyParameters[keyID][1]; //
|
||||
function TopWidthDiff(keyID) = keyParameters[keyID][2]; //
|
||||
function TopLenDiff(keyID) = keyParameters[keyID][3]; //
|
||||
function KeyHeight(keyID) = keyParameters[keyID][4]; //
|
||||
function TopWidShift(keyID) = keyParameters[keyID][5];
|
||||
function TopLenShift(keyID) = keyParameters[keyID][6];
|
||||
function XAngleSkew(keyID) = keyParameters[keyID][7];
|
||||
function YAngleSkew(keyID) = keyParameters[keyID][8];
|
||||
function ZAngleSkew(keyID) = keyParameters[keyID][9];
|
||||
function WidExponent(keyID) = keyParameters[keyID][10];
|
||||
function LenExponent(keyID) = keyParameters[keyID][11];
|
||||
function CapRound0i(keyID) = keyParameters[keyID][12];
|
||||
function CapRound0f(keyID) = keyParameters[keyID][13];
|
||||
function CapRound1i(keyID) = keyParameters[keyID][14];
|
||||
function CapRound1f(keyID) = keyParameters[keyID][15];
|
||||
function ChamExponent(keyID) = keyParameters[keyID][16];
|
||||
function StemExponent(keyID) = keyParameters[keyID][17];
|
||||
|
||||
dishParameters = //dishParameter[keyID][ParameterID]
|
||||
[
|
||||
//FFwd1 FFwd2 FPit1 FPit2 DshDep DshHDif FArcIn FArcFn FArcEx BFwd1 BFwd2 BPit1 BPit2 BArcIn BArcFn BArcEx
|
||||
//Column 0
|
||||
[ 9, 3, 5, -42, 5, 1.7, 20, 20, 2, 10, 4, 8, -30, 20, 20, 2], //R5
|
||||
[ 6, 4, 7, -50, 5, 1.0, 15, 25, 2, 6, 4, 2, -35, 15, 19, 2], //Phat Fingers
|
||||
[ 6, 4, 7, -50, 8, 1.8, 11, 17, 2, 6, 4, 2, -35, 11, 15, 2], //Chicago Steno R2/R4
|
||||
[ 6, 4, 5, -40, 8, 1.8, 11, 15, 2, 6, 4, 5, -40, 11, 15, 2], //Chicago Steno R3 flat
|
||||
];
|
||||
|
||||
|
||||
function FrontForward1(keyID) = dishParameters[keyID][0]; //
|
||||
function FrontForward2(keyID) = dishParameters[keyID][1]; //
|
||||
function FrontPitch1(keyID) = dishParameters[keyID][2]; //
|
||||
function FrontPitch2(keyID) = dishParameters[keyID][3]; //
|
||||
function DishDepth(keyID) = dishParameters[keyID][4]; //
|
||||
function DishHeightDif(keyID) = dishParameters[keyID][5]; //
|
||||
function FrontInitArc(keyID) = dishParameters[keyID][6];
|
||||
function FrontFinArc(keyID) = dishParameters[keyID][7];
|
||||
function FrontArcExpo(keyID) = dishParameters[keyID][8];
|
||||
function BackForward1(keyID) = dishParameters[keyID][9]; //
|
||||
function BackForward2(keyID) = dishParameters[keyID][10]; //
|
||||
function BackPitch1(keyID) = dishParameters[keyID][11]; //
|
||||
function BackPitch2(keyID) = dishParameters[keyID][12]; //
|
||||
function BackInitArc(keyID) = dishParameters[keyID][13];
|
||||
function BackFinArc(keyID) = dishParameters[keyID][14];
|
||||
function BackArcExpo(keyID) = dishParameters[keyID][15];
|
||||
|
||||
|
||||
function FrontTrajectory(keyID) =
|
||||
[
|
||||
trajectory(forward = FrontForward1(keyID), pitch = FrontPitch1(keyID)), //more param available: yaw, roll, scale
|
||||
trajectory(forward = FrontForward2(keyID), pitch = FrontPitch2(keyID)) //You can add more traj if you wish
|
||||
];
|
||||
|
||||
function BackTrajectory (keyID) =
|
||||
[
|
||||
trajectory(forward = BackForward1(keyID), pitch = BackPitch1(keyID)),
|
||||
trajectory(forward = BackForward2(keyID), pitch = BackPitch2(keyID)),
|
||||
];
|
||||
|
||||
//------- function defining Dish Shapes
|
||||
|
||||
function ellipse(a, b, d = 0, rot1 = 0, rot2 = 360) = [for (t = [rot1:step:rot2]) [a*cos(t)+a, b*sin(t)*(1+d*cos(t))]]; //Centered at a apex to avoid inverted face
|
||||
|
||||
function DishShape (a,b,c,d) =
|
||||
concat(
|
||||
// [[c+a,b]],
|
||||
ellipse(a, b, d = 0,rot1 = 90, rot2 = 270)
|
||||
// [[c+a,-b]]
|
||||
);
|
||||
|
||||
function oval_path(theta, phi, a, b, c, deform = 0) = [
|
||||
a*cos(theta)*cos(phi), //x
|
||||
c*sin(theta)*(1+deform*cos(theta)) , //
|
||||
b*sin(phi),
|
||||
];
|
||||
|
||||
path_trans2 = [for (t=[0:step:180]) translation(oval_path(t,0,10,15,2,0))*rotation([0,90,0])];
|
||||
|
||||
|
||||
//--------------Function definng Cap
|
||||
function CapTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*KeyHeight(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function InnerTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/layers*TopLenShift(keyID)), //Y shift
|
||||
(t/layers*(KeyHeight(keyID)-topthickness)) //Z shift
|
||||
];
|
||||
|
||||
function CapRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/layers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/layers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/layers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function CapTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopWidthDiff(keyID)) + (1-pow(t/layers, WidExponent(keyID)))*BottomWidth(keyID) ,
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)) + (1-pow(t/layers, LenExponent(keyID)))*BottomLength(keyID)
|
||||
];
|
||||
function CapRoundness(t, keyID) =
|
||||
[
|
||||
pow(t/layers, ChamExponent(keyID))*(CapRound0f(keyID)) + (1-pow(t/layers, ChamExponent(keyID))*CapRound0i(keyID)),
|
||||
pow(t/layers, ChamExponent(keyID))*(CapRound1f(keyID)) + (1-pow(t/layers, ChamExponent(keyID))*CapRound1i(keyID))
|
||||
];
|
||||
|
||||
function CapRadius(t, keyID) = pow(t/layers, ChamExponent(keyID))*ChamfFinRad(keyID) + (1-pow(t/layers, ChamExponent(keyID)))*ChamfInitRad(keyID);
|
||||
|
||||
function InnerTransform(t, keyID) =
|
||||
[
|
||||
pow(t/layers, WidExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, WidExponent(keyID)))*(BottomWidth(keyID) -wallthickness*2),
|
||||
pow(t/layers, LenExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/layers, LenExponent(keyID)))*(BottomLength(keyID)-wallthickness*2)
|
||||
];
|
||||
|
||||
function StemTranslation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*TopWidShift(keyID)), //X shift
|
||||
((1-t)/stemLayers*TopLenShift(keyID)), //Y shift
|
||||
stemCrossHeight+.1 + (t/stemLayers*(KeyHeight(keyID)- topthickness - stemCrossHeight-.1)) //Z shift
|
||||
];
|
||||
|
||||
function StemRotation(t, keyID) =
|
||||
[
|
||||
((1-t)/stemLayers*XAngleSkew(keyID)), //X shift
|
||||
((1-t)/stemLayers*YAngleSkew(keyID)), //Y shift
|
||||
((1-t)/stemLayers*ZAngleSkew(keyID)) //Z shift
|
||||
];
|
||||
|
||||
function StemTransform(t, keyID) =
|
||||
[
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomWidth(keyID) -TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemWid - 2*slop),
|
||||
pow(t/stemLayers, StemExponent(keyID))*(BottomLength(keyID)-TopLenDiff(keyID)-wallthickness*2) + (1-pow(t/stemLayers, StemExponent(keyID)))*(stemLen - 2*slop)
|
||||
];
|
||||
|
||||
function StemRadius(t, keyID) = pow(t/stemLayers,3)*3 + (1-pow(t/stemLayers, 3))*1;
|
||||
//Stem Exponent
|
||||
|
||||
|
||||
///----- KEY Builder Module
|
||||
module keycap(keyID = 0, cutLen = 0, visualizeDish = false, rossSection = false, Dish = true, Stem = false, homeDot = false, Stab = 0) {
|
||||
|
||||
//Set Parameters for dish shape
|
||||
FrontPath = quantize_trajectories(FrontTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
BackPath = quantize_trajectories(BackTrajectory(keyID), steps = stepsize, loop=false, start_position= $t*4);
|
||||
|
||||
//Scaling initial and final dim tranformation by exponents
|
||||
function FrontDishArc(t) = pow((t)/(len(FrontPath)),FrontArcExpo(keyID))*FrontFinArc(keyID) + (1-pow(t/(len(FrontPath)),FrontArcExpo(keyID)))*FrontInitArc(keyID);
|
||||
function BackDishArc(t) = pow((t)/(len(FrontPath)),BackArcExpo(keyID))*BackFinArc(keyID) + (1-pow(t/(len(FrontPath)),BackArcExpo(keyID)))*BackInitArc(keyID);
|
||||
|
||||
FrontCurve = [ for(i=[0:len(FrontPath)-1]) transform(FrontPath[i], DishShape(DishDepth(keyID), FrontDishArc(i), 1, d = 0)) ];
|
||||
BackCurve = [ for(i=[0:len(BackPath)-1]) transform(BackPath[i], DishShape(DishDepth(keyID), BackDishArc(i), 1, d = 0)) ];
|
||||
|
||||
//builds
|
||||
difference(){
|
||||
union(){
|
||||
difference(){
|
||||
skin([for (i=[0:layers-1]) transform(translation(CapTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), elliptical_rectangle(CapTransform(i, keyID), b = CapRoundness(i,keyID),fn=fn))]); //outer shell
|
||||
|
||||
//Cut inner shell
|
||||
if(Stem == true){
|
||||
translate([0,0,-.001])skin([for (i=[0:layers-1]) transform(translation(InnerTranslation(i, keyID)) * rotation(CapRotation(i, keyID)), elliptical_rectangle(InnerTransform(i, keyID), b = CapRoundness(i,keyID),fn=fn))]);
|
||||
}
|
||||
}
|
||||
if(Stem == true){
|
||||
rotate([0,0,stemRot])choc_stem(KeyHeight(keyID), slop); // generate mx cherry stem, not compatible with box
|
||||
if (Stab != 0){
|
||||
translate([Stab/2,0,0])rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID), slop);
|
||||
translate([-Stab/2,0,0])rotate([0,0,stemRot])cherry_stem(KeyHeight(keyID), slop);
|
||||
}
|
||||
translate([0,0,-.001])skin([for (i=[0:stemLayers-1]) transform(translation(StemTranslation(i,keyID))*rotation(StemRotation(i, keyID)), rounded_rectangle_profile(StemTransform(i, keyID),fn=fn,r=StemRadius(i, keyID)))]); //outer shell
|
||||
|
||||
|
||||
}
|
||||
//cut for fonts and extra pattern for light?
|
||||
}
|
||||
|
||||
//Cuts
|
||||
|
||||
//Fonts
|
||||
if(Legends == true){
|
||||
#rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([-1,-5,KeyHeight(keyID)-2.5])linear_extrude(height = 1)text( text = "ver2", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
// #rotate([-XAngleSkew(keyID),YAngleSkew(keyID),ZAngleSkew(keyID)])translate([0,-3.5,0])linear_extrude(height = 0.5)text( text = "Me", font = "Constantia:style=Bold", size = 3, valign = "center", halign = "center" );
|
||||
}
|
||||
//Dish Shape
|
||||
if(Dish == true){
|
||||
if(visualizeDish == false){
|
||||
translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
} else {
|
||||
#translate([-TopWidShift(keyID),.00001-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)]) rotate([0,-YAngleSkew(keyID),0])rotate([0,-90+XAngleSkew(keyID),90-ZAngleSkew(keyID)])skin(FrontCurve);
|
||||
#translate([-TopWidShift(keyID),-TopLenShift(keyID),KeyHeight(keyID)-DishHeightDif(keyID)])rotate([0,-YAngleSkew(keyID),0])rotate([0,-90-XAngleSkew(keyID),270-ZAngleSkew(keyID)])skin(BackCurve);
|
||||
}
|
||||
}
|
||||
if(crossSection == true) {
|
||||
translate([0,-15,-.1])cube([15,30,15]);
|
||||
}
|
||||
}
|
||||
//Homing dot
|
||||
if(homeDot == true)translate([0,0,KeyHeight(keyID)-DishHeightDif(keyID)-.25])sphere(d = 1);
|
||||
}
|
||||
|
||||
//------------------stems
|
||||
$fn = fn;
|
||||
|
||||
function outer_cherry_stem(slop) = [ stemWid - slop * 2, stemLen - slop * 2];
|
||||
function outer_cherry_stabilizer_stem(slop) = [4.85 - slop * 2, 6.05 - slop * 2];
|
||||
function outer_box_cherry_stem(slop) = [6 - slop, 6 - slop];
|
||||
|
||||
// .005 purely for aesthetics, to get rid of that ugly crosshatch
|
||||
function cherry_cross(slop, extra_vertical = 0) = [
|
||||
// horizontal tine
|
||||
[4.03 + slop, 1.15 + slop / 3],
|
||||
// vertical tine
|
||||
[1.25 + slop / 3, 4.23 + extra_vertical + slop / 3 + .005],
|
||||
];
|
||||
module inside_cherry_cross(slop) {
|
||||
// inside cross
|
||||
// translation purely for aesthetic purposes, to get rid of that awful lattice
|
||||
translate([0,0,-0.005]) {
|
||||
linear_extrude(height = stemCrossHeight) {
|
||||
square(cherry_cross(slop, extra_vertical)[0], center=true);
|
||||
square(cherry_cross(slop, extra_vertical)[1], center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// Guides to assist insertion and mitigate first layer squishing
|
||||
{
|
||||
for (i = cherry_cross(slop, extra_vertical)) hull() {
|
||||
linear_extrude(height = 0.01, center = false) offset(delta = 0.4) square(i, center=true);
|
||||
translate([0, 0, 0.5]) linear_extrude(height = 0.01, center = false) square(i, center=true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module cherry_stem(depth, slop) {
|
||||
difference(){
|
||||
// outside shape
|
||||
linear_extrude(height = depth) {
|
||||
offset(r=1){
|
||||
square(outer_cherry_stem(slop) - [2,2], center=true);
|
||||
}
|
||||
}
|
||||
inside_cherry_cross(slop);
|
||||
}
|
||||
}
|
||||
|
||||
module choc_stem() {
|
||||
|
||||
translate([5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
translate([-5.7/2,0,-3.4/2+2])difference(){
|
||||
cube([1.25,3, 3.4], center= true);
|
||||
translate([3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
translate([-3.9,0,0])cylinder(d=7,3.4,center = true);
|
||||
}
|
||||
|
||||
}
|
||||
/// ----- helper functions
|
||||
function rounded_rectangle_profile(size=[1,1],r=1,fn=32) = [
|
||||
for (index = [0:fn-1])
|
||||
let(a = index/fn*360)
|
||||
r * [cos(a), sin(a)]
|
||||
+ sign_x(index, fn) * [size[0]/2-r,0]
|
||||
+ sign_y(index, fn) * [0,size[1]/2-r]
|
||||
];
|
||||
|
||||
function elliptical_rectangle(a = [1,1], b =[1,1], fn=32) = [
|
||||
for (index = [0:fn-1]) // section right
|
||||
let(theta1 = -atan(a[1]/b[1])+ 2*atan(a[1]/b[1])*index/fn)
|
||||
[b[1]*cos(theta1), a[1]*sin(theta1)]
|
||||
+ [a[0]*cos(atan(b[0]/a[0])) , 0]
|
||||
- [b[1]*cos(atan(a[1]/b[1])) , 0],
|
||||
|
||||
for(index = [0:fn-1]) // section Top
|
||||
let(theta2 = atan(b[0]/a[0]) + (180 -2*atan(b[0]/a[0]))*index/fn)
|
||||
[a[0]*cos(theta2), b[0]*sin(theta2)]
|
||||
- [0, b[0]*sin(atan(b[0]/a[0]))]
|
||||
+ [0, a[1]*sin(atan(a[1]/b[1]))],
|
||||
|
||||
for(index = [0:fn-1]) // section left
|
||||
let(theta2 = -atan(a[1]/b[1])+180+ 2*atan(a[1]/b[1])*index/fn)
|
||||
[b[1]*cos(theta2), a[1]*sin(theta2)]
|
||||
- [a[0]*cos(atan(b[0]/a[0])) , 0]
|
||||
+ [b[1]*cos(atan(a[1]/b[1])) , 0],
|
||||
|
||||
for(index = [0:fn-1]) // section Top
|
||||
let(theta2 = atan(b[0]/a[0]) + 180 + (180 -2*atan(b[0]/a[0]))*index/fn)
|
||||
[a[0]*cos(theta2), b[0]*sin(theta2)]
|
||||
+ [0, b[0]*sin(atan(b[0]/a[0]))]
|
||||
- [0, a[1]*sin(atan(a[1]/b[1]))]
|
||||
]/2;
|
||||
|
||||
function sign_x(i,n) =
|
||||
i < n/4 || i > n-n/4 ? 1 :
|
||||
i > n/4 && i < n-n/4 ? -1 :
|
||||
0;
|
||||
|
||||
function sign_y(i,n) =
|
||||
i > 0 && i < n/2 ? 1 :
|
||||
i > n/2 ? -1 :
|
||||
0;
|
195834
chordv1.stl
Normal file
195834
chordv1.stl
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue