include $fn=40; rotateAngle=54; leeway=0.7; bodyFaceW=150; bodyFaceH=120; bodyBackW=30; bodyBackH=20; bodyDepth=55; screwHoleDia=2; screwHeight=5; screenWidth=16.5+leeway; // visible screenHeight=13+leeway; // visible screenY=-37; screenX=40; screenCutoutWidth=19+leeway; screenCutoutHeight=19.5+leeway; screenMountWidth=21+leeway; screenMountHeight=21+leeway; screenScrewDia=4; screenBracketHeight=7; keypadWidth=46+leeway; // visible keypadHeight=57+leeway; // visible keypadDepth=4; keypadY=10; keypadX=40; keypadMountDia=3; speakerWidth=45; // visible speakerConeWidth=60; speakerDepth=2.2; speakerY=0; speakerX=-30; sensorWidth=4; // visible sensorDepth=4; sensorY=-5; powerWidth=14; // visible powerHeight=7; powerDepth=10; powerY=0; module speaker(){ diff("hole","mount") translate([0, 0, 0]) rotate([rotateAngle,0,0]) { // body prismoid([bodyBackW, bodyBackH], [bodyFaceW, bodyFaceH], bodyDepth, rounding=4) tag("hole") { attach([TOP]) { // screen translate([screenX,-screenY,0.1]) cuboid([screenWidth,screenHeight,4], anchor=TOP); // screen thickness cutout translate([screenX,-screenY,-1]) cuboid([screenCutoutWidth,screenCutoutHeight,2], anchor=TOP) tag("mount") { position(LEFT+TOP) left(4) up(1) tube(h=screwHeight, od=screenScrewDia, id=screwHoleDia, anchor=TOP); position(RIGHT+TOP) right(4) up(1) tube(h=screwHeight, od=screenScrewDia, id=screwHoleDia, anchor=TOP); } // keypad translate([keypadX,-keypadY,0.1]) cuboid([keypadWidth,keypadHeight,keypadDepth], rounding=4, edges=["Z"], anchor=TOP) tag("mount") { //TODO: actually measure these, consider screws position(FRONT+LEFT+TOP) translate([-.2,-1,-.1]) tube(h=screwHeight, od=keypadMountDia, id=screwHoleDia/2, anchor=TOP); position(BACK+LEFT+TOP) translate([-.2,1,-.1]) tube(h=screwHeight, od=keypadMountDia, id=screwHoleDia/2, anchor=TOP); position(FRONT+RIGHT+TOP) translate([.2,-1,-.1]) tube(h=screwHeight, od=keypadMountDia, id=screwHoleDia/2, anchor=TOP); position(BACK+RIGHT+TOP) translate([.2,1,-.1]) tube(h=screwHeight, od=keypadMountDia, id=screwHoleDia/2, anchor=TOP); } // speaker translate([speakerX,-speakerY,0.1]) cylinder(h=speakerDepth, d1=speakerWidth, d2=speakerConeWidth, anchor=TOP) tag("mount") { zrot_copies([0, 120, 240]) right(speakerConeWidth/2) tube(h=screwHeight, od=4, id=screwHoleDia, anchor=TOP); } } attach(BACK) { // sensor translate([0,-sensorY,0]) cylinder(h=sensorDepth, d=sensorWidth, center=true) tag("mount") { zrot_copies([0, 90, 180, 270]) translate([10,10,0]) tube(h=screwHeight, od=screwHoleDia+3, id=screwHoleDia, anchor=TOP); } } attach(BOTTOM) { // power translate([0,-powerY,0]) cuboid([powerWidth, powerHeight, powerDepth], rounding=1) tag("mount") { zrot_copies([0, 180]) fwd((powerHeight+screwHoleDia+3)/2+1) tube(h=screwHeight, od=screwHoleDia+3, id=screwHoleDia, anchor=TOP); } } // clamshell posts attach(TOP) tag("mount") { // post zrot_copies([0, 180]) fwd(bodyFaceH/2-9) tube(h=screwHeight+1, od=4, id=screwHoleDia, anchor=TOP); // tube zrot_copies([0, 180]) fwd(bodyFaceH/2-9) down(screwHeight+1) { diff("hole"){ tube(h=1, od=5+leeway, id=2.5+leeway, anchor=TOP); tube(h=8, od=6, id=5+leeway, anchor=TOP) tag("hole") position(BOTTOM) rotate([-53,0,0]) cube([20,20,5], anchor=CTR); } tag("hole") cylinder(h=20, d=5+leeway, anchor=TOP); } } // hollow prismoid([bodyBackW-5, bodyBackH-5], [bodyFaceW-6, bodyFaceH-6], bodyDepth-4, rounding=3, center=true); } } } // clamshell halves difference(){ speaker(); translate([0,-bodyDepth-13+7.31,0]) rotate([-rotateAngle+18,0,0]) partition_mask(l=1000, h=1000, w=0.1, gap=0, cutpath="flat"); } // screen mount bracket diff("hole") back(100) cuboid([screenCutoutWidth+16,screenBracketHeight,2], anchor=TOP) tag("hole") { position(LEFT) left(-4) cylinder(h=4, d=screwHoleDia+1, anchor=CTR); position(RIGHT) right(-4) cylinder(h=4, d=screwHoleDia+1, anchor=CTR); } // speaker washers zrot_copies([15,-15]) back(50) tube(h=2, od=(speakerConeWidth-speakerWidth)/2+9, id=screwHoleDia+1);