Last active
August 10, 2016 09:41
-
-
Save jinhwanlazy/d98c2b5851e1507c8af122e9724a0c4b to your computer and use it in GitHub Desktop.
3d printable mechanical keyboard, powered by openascad. still work in progress.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
layout = [ | |
["","","","","","","","","","","","","","",""], | |
[{w:1.5},"","","","","","","","","","","","","",{w:1.5},""], | |
[{w:1.75},"","","","","","","","","","","","",{w:2.25},""], | |
[{w:2.25},"","","","","","","","","","","",{w:1.75},"",""], | |
[{x:1.5},"",{w:1.5},"",{w:6},"",{w:1.5},"",""] | |
]; | |
split_pos = [ | |
[5, 4.5, 4.75, 4.25, 4.75], | |
[10, 10.5, 9.75, 10.25, 10], | |
]; | |
screw_pos = [ | |
[1, 4, 6, 9, 11, 14], | |
[], [], [], | |
[0.25, 4.5, 5.25, 9.75, 10.25, 14.75] | |
]; | |
teensy_pos = 7; | |
function getParameterDefinitions() { | |
return [ | |
{ | |
name: 'output', | |
type: 'choice', | |
caption: 'Output', | |
values: ['Plate', 'Case', 'Back covers', | |
'Test 1u', 'Test 1u*4', 'Test 2u', 'Test 6u', 'Test 6.25u'], | |
initial: 'Case' | |
}, | |
{ | |
name: 'split', | |
type: 'choice', | |
caption: 'Split Number', | |
values: ['No'].concat(Array.apply(null, Array(split_pos.length+1)).map(function (_, i) {return i;})), | |
initial: 'No' | |
}, | |
{ | |
name: 'shape', | |
type: 'choice', | |
caption: 'Case Shape', | |
values: ['Square', 'Rounded'], | |
initial: 'Rounded' | |
}, | |
{ | |
name: 'stabilizer', | |
type: 'choice', | |
caption: 'Stabilizer Type', | |
values: ['cherry', 'costar'], | |
captions: ['cherry', 'costar'], | |
initial: 'costar' | |
}, | |
{ | |
name: 'swappable', | |
type: 'choice', | |
caption: 'Hole Shape', | |
values: ['Plain', 'Swappable'], | |
initial: 'Swappable' | |
}, | |
{ | |
name: 'pcb_hole', | |
type: 'choice', | |
caption: 'PCB Mount Hole', | |
values: [true, false], | |
initial: false | |
}, | |
{ | |
name: 'led_hole', | |
type: 'choice', | |
caption: 'LED Lead Hole', | |
values: [true, false], | |
initial: false | |
}, | |
{ | |
name: 'solid', | |
type: 'choice', | |
caption: 'Solid Case', | |
values: [true, false], | |
initial: true | |
} | |
]; | |
} | |
const inf = 98765; | |
const unit = 19.05; | |
const inch = 25.4; | |
const epsilon = 0.01; | |
function costar_stabilizer(A, bridge) { | |
let m = 0.5; | |
let shift = 0.60; | |
return union( | |
square({size: [3.3, 14]}).translate([A/2*inch-3.3/2, -14/2 - shift]), | |
square({size: [3.3+2*m, 0.2]}).translate([A/2*inch-3.3/2-m, -14/2 - shift]), | |
square({size: [3.3+2*m, 0.2]}).translate([A/2*inch-3.3/2-m, +14/2 - shift-0.1]) | |
); | |
} | |
function costar_stabilizer_cutout(A) { | |
let m = 1.0; | |
let ret = cube({size: [3.3, 14+2*m, 3.6]}) | |
.mirroredZ() | |
.translate([A/2*inch-3.3/2, -14/2-0.75-m, -1.4]); | |
return ret; | |
} | |
function cherry_stabilizer(A, bridge) { | |
function bridge_(A) { | |
if (A < 1.5) { | |
return square({size: [A/2*inch, 0.421*inch], center: false}) | |
.translate([-A/2*inch, -0.229*inch]); | |
} else { | |
return square({size: [A/2*inch, 0.18*inch], center: true}) | |
.translate([-A/4*inch, 0]); | |
} | |
} | |
let ret = union( | |
square({size: [0.262*inch, 0.484*inch], center: true}).translate([0, -0.018*inch]), | |
square({size: [4, 2.8], center: false}).translate([0, -0.5]) | |
); | |
if (bridge) { | |
ret = union( | |
ret, | |
bridge_(A), | |
square({size: [0.12*inch, 0.53*inch], center: true}).translate([0, -0.041*inch]) | |
); | |
} else if (A < 1.5) ret = union(ret, bridge_(A)); | |
return ret.translate([A/2*inch, 0]); | |
} | |
function cherry_stabilizer_cutout(A) { | |
let align = [true, false, false]; | |
const snap = 1.4; | |
return union( | |
cube({size: [3, 16, 5-snap], center: align}).translate([A*inch/2, -0.375*inch, 0]), | |
cube({size: [3, 16, 5-snap], center: align}).translate([A*inch/2, -0.375*inch, 0]).mirroredX(), | |
cube({size: [0.262*inch, 0.3*inch, 5-snap], center: align}).translate([A*inch/2, -0.375*inch, 0]), | |
cube({size: [0.262*inch, 0.3*inch, 5-snap], center: align}).translate([A*inch/2, -0.375*inch, 0]).mirroredX(), | |
intersection( // wires goes | |
cube({size: [(A+0.262)*inch, 0.18*inch, 0.2*inch], center: align}).translate([0, -0.375*inch+1, 0]), | |
union( | |
cube({size: [(A+0.262)*inch, 0.18*inch, 0.12*inch], center: align}).translate([0, -0.375*inch+1, 0]), | |
cube({size: [(A+0.262)*inch, 0.18*inch*cos(35), 0.12*inch/cos(35)], center: align}).mirroredZ().rotateX(35).translate([0, -0.375*inch+1, 0.12*inch]), | |
cube({size: [(A+0.262)*inch, 0.08*inch, 0.2*inch], center: align}).translate([0, (-0.225)*inch, 0.05*inch]) | |
) | |
) | |
).translate([0, 0, -5]); | |
} | |
function cherry_mx_2D(w=1, h=1, A=0.94, stabil='costar', swappable=true, bridge=true) { | |
let stabilizer = (stabil == 'costar') ? costar_stabilizer : cherry_stabilizer; | |
let rot90 = false; | |
let ret; | |
if (h > w) { | |
rot90 = true; | |
let tmp = w; w = h; h = tmp; | |
} | |
if (w < 2) { | |
ret = square({size: [0.55*inch, 0.55*inch], center: true}); | |
if (swappable) { | |
ret = union( | |
ret, | |
square({size: [0.614*inch, 0.1378*inch], center: true}).translate([0, (0.1972+0.1378)/2*inch]), | |
square({size: [0.614*inch, 0.1378*inch], center: true}).translate([0, (0.1972+0.1378)/2*inch]).mirroredY() | |
); | |
} | |
// } else if (w == 6){ | |
// ret = union( | |
// cherry_mx_2D(1, 1, A, stabil=stabil, swappable=swappable).translate([0.5*unit, 0, 0]), | |
// stabilizer(3, bridge=bridge).translate([0.5*unit, 0, 0]), | |
// stabilizer(4.5, bridge=bridge).mirroredX().translate([0.5*unit, 0, 0]) | |
// ); | |
} else { | |
ret = union( | |
cherry_mx_2D(1, 1, A, stabil=stabil, swappable=swappable), | |
stabilizer(A, bridge=bridge), | |
stabilizer(A, bridge=bridge).mirroredX() | |
); | |
} | |
ret = ret.rotateZ(-90*rot90); | |
return ret; | |
} | |
function SW(ori, params) | |
{ | |
this.w = ori.w; | |
this.h = ori.h; | |
this.pos = ori.keyCenter(); | |
this.rot = ori.rot; | |
this.ix = new CSG.Vector2D([1, 0]); | |
this.iy = new CSG.Vector2D([0, 1]); | |
this.params = params; | |
if (this.w == 6) this.A = 3; | |
else if (this.w < 3) this.A = 0.94; | |
else if (this.w < 6.25) this.A = 1.5; | |
else if (this.w < 7) this.A = 3.75; | |
else if (this.w < 8) this.A = 4.5; | |
else this.A = 5.25; | |
this.cutout2D = function() { | |
return cherry_mx_2D(this.w, this.h, this.A, this.params.stabilizer, | |
this.params.swappable==='Swappable') | |
.rotateZ(-this.rot).translate(this.pos); | |
}; | |
this.cutout3D = function(pcb_mount_hole=false, led_hole=false, wires=true) { | |
let i = 1.27; | |
let ret = linear_extrude({height:4*i}, | |
cherry_mx_2D(this.w, this.h, this.A, this.params.stabilizer, | |
this.params.swappable==='Swappable', bridge=false)); | |
let c = [true, true, false]; | |
ret = union(ret, | |
cylinder({d:4, h:20, center: c}).mirroredZ().translate([0, 0, -0.2]), // center stem | |
cylinder({d:2.5, h:20, center: c}).mirroredZ().translate([-3*i, 2*i, -0.2]), // lead1 | |
cylinder({d:2.5, h:20, center: c}).mirroredZ().translate([ 2*i, 4*i, -0.2]), // lead2 | |
cube({size:[5, 16, 5-1.4-epsilon], center: c}) | |
.translate([0, 0, 0]) // push fit | |
).translate([0, 0, -5+epsilon]); | |
if (this.params.pcb_hole == 'true') ret = union(ret, this.pcb_mount_hole()); | |
if (this.params.led_hole == 'true') ret = union(ret, this.led_hole()); | |
if (this.w >= 2) { | |
let stabil = this.params.stabilizer == 'costar' | |
? costar_stabilizer_cutout | |
: cherry_stabilizer_cutout; | |
ret = union(ret, stabil(this.A), stabil(this.A).mirroredX()); | |
} | |
ret = ret.rotateZ(-this.rot).translate(this.pos); | |
return ret; | |
}; | |
this.moveX = function(x) { | |
this.pos = this.pos.plus(this.ix.times(x)); | |
}; | |
this.moveY = function(y) { | |
this.pos = this.pos.plus(this.iy.times(y)); | |
}; | |
this.pcb_mount_hole = function () { | |
let i = 1.27; | |
return union( | |
cylinder({d:1.8, h:20, center: [true, true, false]}).mirroredZ().translate([ 4*i, 0, -0.2]), | |
cylinder({d:1.8, h:20, center: [true, true, false]}).mirroredZ().translate([-4*i, 0, -0.2]) | |
).translate([0, 0, -4*i]); | |
}; | |
this.led_hole = function() { | |
let i = 1.27; | |
return union( | |
cylinder({d:1.0, h:20, center: [true, true, false]}).mirroredZ().translate([ 1*i, -4*i, -0.2]), | |
cylinder({d:1.0, h:20, center: [true, true, false]}).mirroredZ().translate([-1*i, -4*i, -0.2]) | |
).translate([0, 0, -4*i]); | |
}; | |
} | |
function Orientation() | |
{ | |
this.ppivot = new CSG.Vector2D([0, 0]); | |
this.pivot = new CSG.Vector2D([0, 0]); | |
this.pos = new CSG.Vector2D([0, 0]); | |
this.ix = new CSG.Vector2D([1, 0]); | |
this.yy = new CSG.Vector2D([0, -1]); | |
this.dx = new CSG.Vector2D([1, 0]); | |
this.dy = new CSG.Vector2D([0, -1]); | |
this.rot = 0; | |
this.h = 1; | |
this.w = 1; | |
this.stack = []; | |
this.moveX = function(x) { | |
this.pos = this.pos.plus(this.dx.times(unit*x)); | |
}; | |
this.moveY = function(y) { | |
this.pivot = this.pivot.plus(this.dy.times(unit*y)); | |
this.pos = this.pos.plus(this.dy.times(unit*y)); | |
}; | |
this.rotate = function(r) { | |
this.rot = r; | |
this.dx = new CSG.Vector2D([Math.cos(r*Math.PI/180), -Math.sin(r*Math.PI/180)]); | |
this.dy = new CSG.Vector2D([-Math.sin(r*Math.PI/180), -Math.cos(r*Math.PI/180)]); | |
}; | |
this.setX = function(x) { | |
this.ppivot = new CSG.Vector2D([x*unit, this.ppivot.y]); | |
this.pivot = new CSG.Vector2D(this.ppivot); | |
this.pos = new CSG.Vector2D(this.pivot); | |
}; | |
this.setY = function(y) { | |
this.ppivot = new CSG.Vector2D([this.pivot.x, -y*unit]); | |
this.pivot = new CSG.Vector2D(this.ppivot); | |
this.pos = new CSG.Vector2D(this.pivot); | |
}; | |
this.nextRow = function() { | |
this.pivot = this.pivot.plus(this.dy.times(unit)); | |
this.pos = new CSG.Vector2D(this.pivot); | |
}; | |
this.keyCenter = function() { | |
return this.pos.plus(this.dx.times(unit*this.w/2)) | |
.plus(this.dy.times(unit*this.h/2)); | |
}; | |
this.update = function(op) { | |
if ('r' in op) this.rotate(op.r); | |
if ('rx' in op) this.setX(op.rx); | |
if ('ry' in op) this.setY(op.ry); | |
if ('x' in op) this.moveX(op.x); | |
if ('y' in op) this.moveY(op.y); | |
if ('w' in op) this.w = op.w; | |
if ('h' in op) this.h = op.h; | |
}; | |
this.resetSize = function() { | |
this.w = 1; | |
this.h = 1; | |
}; | |
} | |
function Dimension() | |
{ | |
this.left = inf; | |
this.right = -inf; | |
this.bottom = inf; | |
this.top_ = -inf; | |
this.update_ = function(pos) { | |
this.left = Math.min(this.left, pos.x); | |
this.right = Math.max(this.right, pos.x); | |
this.bottom = Math.min(this.bottom, pos.y); | |
this.top_ = Math.max(this.top_, pos.y); | |
}; | |
this.update = function(ori) { | |
let pos = new CSG.Vector2D(ori.pos); | |
this.update_(pos); | |
this.update_(pos.plus(ori.dx.times(ori.w*unit))); | |
this.update_(pos.plus(ori.dy.times(ori.h*unit))); | |
this.update_(pos.plus(ori.dx.times(ori.w*unit)) | |
.plus(ori.dy.times(ori.h*unit))); | |
}; | |
this.plate = function() { | |
return square([this.right-this.left, this.top_-this.bottom]) | |
.translate([this.left, this.bottom]); | |
}; | |
this.center = function() { | |
let ret = [(this.right+this.left)/2, (this.top_+this.bottom)/2]; | |
return new CSG.Vector2D(ret); | |
}; | |
this.shell = function(th=1.5) { | |
return square([this.right-this.left, this.top_-this.bottom]) | |
.translate([this.left, this.bottom]).subtract( | |
square([this.right-this.left-th*2, this.top_-this.bottom-th*2]) | |
.translate([this.left+th, this.bottom+th]) | |
); | |
}; | |
this.size = function() { | |
return [this.right-this.left, this.top_-this.bottom]; | |
} | |
} | |
function gen_switches(layout, stabil) | |
{ | |
let switches = []; | |
let ori = new Orientation(); | |
let dim = new Dimension(); | |
for (let r = 0; r < layout.length; r++) { | |
for (let c = 0; c < layout[r].length; c++) { | |
if (typeof layout[r][c] == "string") { | |
switches.push(new SW(ori, stabil)); | |
dim.update(ori); | |
ori.moveX(ori.w); | |
ori.resetSize(); | |
} else { | |
ori.update(layout[r][c]); | |
} | |
} | |
ori.nextRow(); | |
} | |
return [switches, dim]; | |
} | |
function screw_holes(pillar) | |
{ | |
let d = pillar ? 5.2 : 2.6; | |
let h = pillar ? 8.5 : 6; | |
let ret = []; | |
for (let r = 0; r < screw_pos.length; ++r) { | |
for (let c = 0; c < screw_pos[r].length; ++c) { | |
let y = -(0.5+r) * unit; | |
let x = screw_pos[r][c] * unit; | |
ret.push(cylinder({d: d, h: h, center: [true, true, false]}) | |
.translate([x, y, 0])); | |
} | |
} | |
return union(ret); | |
} | |
function back_cover(dim, no=0, split=3, side_th=4) | |
{ | |
const height = 5; | |
const depth = 3; | |
let dx = (dim.right - dim.left) / split; | |
let dy = dim.top_ - dim.bottom; | |
let x = no * dx; | |
let y = -dy; | |
let ret = cube({size: [dx, dy, height]}).translate([x, y, 0]); | |
let cutout = []; | |
let screw_col = []; | |
cutout.push(cube({size: [dx-2*side_th, dy-2*side_th, inf]}) | |
.translate([x+side_th, y+side_th, height-depth])); | |
cutout.push(cube({size: [dx*split-20, dy-20, inf]}) | |
.translate([10, y+10, height-depth+1])); | |
let t = teensy.mount_size(); | |
let m = 0.4; | |
cutout.push(cube({size: [t[0]+m, t[1]+m, t[2]+m], center: [true, false, false]}) | |
.mirroredY().mirroredZ().translate([teensy_pos*unit, y+dy, height])); | |
ret = ret.subtract(union(cutout)); cutout = []; | |
for (let r = 0; r < screw_pos.length; ++r) { | |
for (let c = 0; c < screw_pos[r].length; ++c) { | |
let dy_ = -(0.5+r) * unit; | |
let dx_ = screw_pos[r][c] * unit; | |
screw_col.push( | |
intersection( | |
cylinder({d: 8, h: height, center: [true, true, false]}) .translate([dx_, dy_, 0]), | |
cube({size: [dx, dy, height]}).translate([x, y, 0]) | |
) | |
); | |
cutout.push(cylinder({d: 3, h: 6, center: [true, true, false]}) | |
.translate([dx_, dy_, 0])); | |
} | |
} | |
ret = ret.union(union(screw_col)); | |
ret = ret.subtract(cutout); | |
return ret; | |
} | |
function body(params) | |
{ | |
let switches = gen_switches(layout, params); | |
let sws = switches[0]; | |
let dim = switches[1]; | |
let s = dim.size(); | |
let ret = gen_case(s[0]/unit, s[1]/unit, params).translate([0, -s[1], 0]); | |
let cutout = []; | |
let teensy_y = (params.shape == 'Square' ? -1 : 0); | |
for (let i = 0; i < sws.length; i++) { | |
cutout.push(sws[i].cutout3D().translate([0, 0, 12])); | |
} | |
ret = ret.subtract(cutout); | |
ret = ret.union(union( | |
screw_holes(true).translate([0, 0, 3]), | |
teensy.mount().rotateY(180).translate([teensy_pos*unit, teensy_y, 1.5]) | |
)); | |
ret = ret.subtract(union( | |
screw_holes(false).translate([0, 0, 1]), | |
cube({size: [12, 5, 8], center: [true, false, false]}).translate([teensy_pos*unit, 1, 1.5]), // usb cable | |
teensy.slot().rotateY(180).translate([teensy_pos*unit, teensy_y, 1.5]) | |
)); | |
if (params.split != 'No') | |
ret = ret.intersect(linear_extrude({height: 12}, split_mask_2D(parseInt(params.split)))); | |
return ret; | |
} | |
function plate_2D(params) | |
{ | |
let switches = gen_switches(layout, params); | |
let sws = switches[0]; | |
let dim = switches[1]; | |
let ret = dim.plate() | |
for (let i = 0; i < sws.length; i++) { | |
ret = ret.subtract(sws[i].cutout2D()); | |
} | |
if (params.split != 'No') | |
ret = ret.intersect(split_mask_2D(parseInt(params.split))); | |
ret = ret.translate(dim.center().times(-1)); | |
return ret; | |
} | |
function mini_usb_2D() | |
{ | |
const m = 0.4; | |
return union(chain_hull( | |
circle({r: 0.5}).translate([0.0-m, 0]), | |
circle({r: 0.5}).translate([7.8-1+m, 0]), | |
circle({r: 0.5}).translate([7.8-1+m, 1.89-0.9+0.1]), | |
circle({r: 0.5}).translate([7.3-1+m, 1.89-0.9+0.8]), | |
circle({r: 0.4}).translate([7.3-1+m+0.2, 4-0.8]), | |
circle({r: 0.4}).translate([0.5-m, 4-0.8]), | |
circle({r: 0.5}).translate([0.5-m, 1.89-0.9+0.8]), | |
circle({r: 0.5}).translate([0.0-m, 1.89-0.9+0.1]), | |
circle({r: 0.5}).translate([0.0-m, 0])), | |
square([6.8, 3.6]).translate([0.5, 0]) | |
); | |
} | |
function mini_usb() | |
{ | |
return union( | |
linear_extrude({height: teensy.usb_len+5}, mini_usb_2D()), | |
cube({size: [7.8, 4, 12]})) | |
.translate([-7.8/2, -4, -teensy.usb_len]).rotateX(-90); | |
} | |
const teensy = { | |
x: 18.03, | |
y: 32.00, | |
mount_th: 1, | |
smd_th: 1, | |
pcb_th: 1.63, | |
buf: 2, | |
usb_len: 15, | |
usb_side_wall: 1, | |
size: function() { | |
return [this.x, this.y, this.pcb_th]; | |
}, | |
mount_size: function() { | |
return [ | |
this.x + 2*this.buf, | |
this.y + this.buf + this.usb_side_wall, | |
this.pcb_th + this.smd_th + this.mount_th] | |
}, | |
height: function() { | |
return pcb_th + smd_th + mount_th; | |
}, | |
screw_x: function() { | |
return x / 2 + buf; | |
}, | |
screw_y: function() { | |
return y + buf +usb_side_wall - unit; | |
}, | |
mount: function() { | |
let m = 0.2; | |
let t = this; | |
let h = 5; | |
return union( | |
cube({size: [3, 3, h]}).translate([-t.x/2-1, -2, -5]), | |
cube({size: [3, 3, h]}).translate([t.x/2-2, -2, -5]), | |
cube({size: [3, 3, h]}).translate([-t.x/2-1, -t.y-1, -5]), | |
cube({size: [3, 3, h]}).translate([t.x/2-2, -t.y-1, -5]) | |
).subtract( | |
cube({size: [t.x+m*2, t.y+m*2, t.pcb_th+epsilon], center: [true, false, false]} | |
).translate([0, -t.y-m, -t.pcb_th]) | |
); | |
}, | |
slot: function() { | |
let m = 0.2; | |
let t = this; | |
return cube({size: [t.x+2*m, t.y+2*m, t.pcb_th], center: [true, false, false]} | |
).translate([0, -t.y-m, -t.pcb_th] | |
).union(mini_usb().mirroredZ().translate([0, 0, -t.pcb_th]) | |
); | |
} | |
} | |
function split_mask_2D(num_split=0) | |
{ | |
if (split_pos.length < 1) return body; | |
if (num_split > split_pos.length) return body; | |
let vsize = split_pos[0].length; | |
if (vsize < 1) return body; | |
for (let i = 0; i < split_pos.length; ++i) | |
if (split_pos[i].length != vsize) | |
return body; | |
let left, right; | |
if (num_split === 0) { | |
left = Array.apply(null, Array(vsize)).map(Number.prototype.valueOf, -100); | |
right = split_pos[0]; | |
} else if (num_split == split_pos.length) { | |
left = split_pos[num_split-1]; | |
right = Array.apply(null, Array(vsize)).map(Number.prototype.valueOf, 100); | |
} else { | |
left = split_pos[num_split-1]; | |
right = split_pos[num_split]; | |
} | |
let mask = []; | |
for (let i = 0; i < vsize; i++) { | |
mask.push(square({size: [(right[i]-left[i])*unit, (i == 0 || i == vsize-1 ? 2*unit : unit)]}) .translate([left[i]*unit, (vsize-i-1)*unit-(i == vsize-1 ? unit : 0)])); | |
} | |
mask = union(mask); | |
cutout = [] | |
if (num_split < split_pos.length) { | |
for (let r = 0; r < vsize-1; r++) | |
if (right[r+1] > right[r]) | |
cutout.push(square({size: [1, 1], center: true}) | |
.translate([right[r]*unit, (vsize-r-1)*unit])); | |
for (let r = 1; r < vsize; r++) | |
if (right[r-1] > right[r]) | |
cutout.push(square({size: [1, 1], center: true}) | |
.translate([right[r]*unit, (vsize-r)*unit])); | |
} | |
if (num_split > 0) { | |
for (let r = 0; r < vsize-1; r++) | |
if (left[r+1] < left[r]) | |
cutout.push(square({size: [1, 1], center: true}) | |
.translate([left[r]*unit, (vsize-r-1)*unit])); | |
for (let r = 1; r < vsize; r++) | |
if (left[r-1] < left[r]) | |
cutout.push(square({size: [1, 1], center: true}) | |
.translate([left[r]*unit, (vsize-r)*unit])); | |
} | |
mask = mask.subtract(cutout); | |
return mask.translate([0, -vsize*unit]); | |
} | |
function test_object(w, params) | |
{ | |
let ori = new Orientation(); ori.w = w; | |
let sw = new SW(ori, params); | |
return gen_case(w, 1, params).subtract(sw.cutout3D().translate([0, unit, 12])); | |
} | |
function test_object_4x(params) | |
{ | |
let ori = new Orientation(); | |
let sw = new SW(ori, params); | |
let block = gen_case(2, 2, params); | |
let cutout = []; | |
for (let i = 0; i < 2; ++i) | |
for (let j = 0; j < 2; ++j) | |
cutout.push(sw.cutout3D().translate([unit*i, unit*(1+j), 12])); | |
return block.subtract(union(cutout)); | |
} | |
function gen_case(w, h, params) | |
{ | |
let th = 12; | |
let side_r = 10; | |
let top_r = 5; | |
let o = 1; | |
let ret; | |
let x = w*unit, y = h*unit; | |
if (params.shape == 'Square') { | |
ret = cube({size: [x, y, th]} | |
); | |
} else if(params.shape == 'Rounded') { | |
ret = CSG.roundedCube({ | |
radius: [w*unit/2+2*o, h*unit/2+2*o, th/2+1], | |
roundradius: [4, 4, th/2], | |
resolution: 48 | |
}).translate([w*unit/2, h*unit/2, th/2] | |
).intersect(cube({size: [inf, inf, th]}).translate([-inf/3, -inf/3]) | |
); | |
} | |
ret = ret.subtract(cube({size: [x-2, y-2, 1.5+epsilon]}).translate([1, 1, -epsilon])); | |
if (params.solid == 'false') | |
ret = ret.subtract(cube({size: [x-4, y-4, th-1.4]}).translate([2, 2, 0])); | |
else | |
ret = ret.subtract(cube({size: [x-4, y-4, th-7]}).translate([2, 2, 0])); | |
return ret; | |
} | |
function main(params) | |
{ | |
if (params.output == 'Test 1u') return test_object(1, params); | |
if (params.output == 'Test 1u*4') return test_object_4x(params); | |
if (params.output == 'Test 2u') return test_object(2, params); | |
if (params.output == 'Test 6u') return test_object(6, params); | |
if (params.output == 'Test 6.25u') return test_object(6.25, params); | |
if (params.output == 'Case') return body(params); | |
if (params.output == 'Plate') return plate_2D(params); | |
if (params.output == 'Back covers') { | |
let ret = []; | |
for (let i = 0; i < 3; ++i) { | |
ret.push(back_cover(dim, i, 3, 4).translate([10*i, 0, 0])); | |
} | |
return union(ret); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment