/* TransiDupe Duplicate tansmissive film. (We are running out of names for slide duplicators.) 1/11/2016 Version .9.008 Remixed from "DupliHood -- a slide copying attachment" by Hank Dietz http://www.thingiverse.com/thing:431624 http://www.instructables.com/id/3D-Printed-Slide-Copy-Attachment/ Modified to work with the PhotoSolve Xtend-a-Slide https://www.photosolve.com/main/product/xtendaslide/index.html TransiDupe is released under the Creative Commons - attribution license http://creativecommons.org/licenses/by/3.0/ requires OpenSCAD version 2015.03, or newer. */ /* Global */ // How many sections? (each section is 23.5mm) // "2" (ea.) is typical for a P&S + closeup lens // "3" (ea.) works for an APS-C (crop) camera + 60mm macro lens for 35mm slides/negatives // "7" (ea.) works for an APS-C (crop) camera + 100mm macro lens for 35mm slides/negatives // Sections are ~50mm in diameter. So probably shouldn't make more than 1 or 2 rear sections // for film6x6 (AKA 120 film) which has approx. 70mm diagonal. number_of_rear_sections=3; // [1:9] number_of_front_sections=3; // [1:9] // Which part do you want to make? part = "exploded"; // [fronttube:The front tube,reartube:The tube that attaches to the step-up ring that is attached to the lens, springpart:The spring cap that holds the slide,diffuser:The optional diffuser,exploded:Exploded view of all three parts (for viewing, not printing),bothtubes:Like "exploded", but only prints the front and rear tubes,calslide:Blank slide for calibration,ruler:Ruler that shows how far the slide should be for the designated lengths of the tubes,playpen1:For experimenting (currently, is about toruses (o-rings...)),negativecarrier:Negative carrier (doesn't work yet),xslidecarrier:Xtend-a-Slide slide carrier] // What is the slide format? (Anything other than "film6x6", exactly, means 35mm.) film = "film6x6x"; // [film6x6:Mounted 6x6cm slides,film35:Mounted 35mm (135 format) slides] // Debugging. "true" makes some parts thinner/shorter for making test prints // (to see if everything fits together.) // Anything other than "true" == false; "truex" == false // i.e., debug="truex" to make normal sized prints. debug="truex"; // [true:Debug mode. Makes prints be shorter, but the same diameter, false:Normal mode, truex: is the same as "false" (but is easier to type in the code.)] // Make the round plates on the tubes makeroundplate = "true"; // [true, false] // Make the tubes maketube = "true"; // [true, false] // Set reardiskdiameter to the diameter of the step-up ring that is mounted on your lens. // Because plastic is soft, I suggest that you mount the rear tube to a step-up adapter *once* // and never remove the step-up adapter from the rear tube. // However you *can* set to the filter size on your lens, if you don't want to bother // with a step-up ring. // reardiskdiameter can't be smaller than 52mm. reardiskdiameter=67; // [52, 147] // Increases the inside diameter of the front tube. Increase this if the front tube can't fit over the back tube. // (Print both tubes in "debug" mode for testing this. And you don't need the plates.) // Normal is = 0.25 front_tube_tol = 0.25; // [0,2] // Number of slits in the front tube (Default is 10.) num_slits = 10; // [0:100] // Slit thickness in mm (Default is 2.) slit_thickness = 2; // Increases the inside diameter of the springpart. // Increase this if the springpart can't fit over the front tube. td2dh_sp=0.0025; // [0,2] // Increases the inside diameter of the diffuser. // Increase this if the diffuser can't fit over the springpart. td2dh_df=0.0025; // [0,2] // Make threads on back plate of rear tube. (Slow...but see finishquality, below) // "Not true" (no threads) implies that you are going to glue the rear tube to a step-up ring. makethreads = "truex"; // [true, false] // Number of threads. Was 3 in original design numthreads=3; // [2,6] // Rendering threads is slow. However, you *must* use fine when printing for real. // (Rendering threads at "fine" adds almost a minute to rendering time.) finishquality="fine"; // [fine:use this when you are going to print for real,draftmode: use this when you are still developing.] // What is the filter thread pitch? (Default is 75) thread_pitch = 75; // [50:Fine 0.5mm, 75:Standard 0.75mm, 100:Coarse 1.0mm, 150:Very coarse 1.5mm] // Tolerance to allow for inaccurate filament placement (usually extrusion diameter/2), in microns? // Default is 100. thread_tolerance = 100; // [0:500] /* [Hidden] */ // Thread rotation angle (to align slide mask with the camera)? // (Shouldn't need to change this.) thread_rotate = 45; // [0:359] /* I don't think that "exploded" is printable. It is handy to see all the parts together. You can load an .stl file into netfabb to see how many cubic centimeter of filiment that all the parts will use. */ // For making test prints to see if the parts fit // (Shorter print time and use less filament.) num_rear_sections=((debug == "true") ? 1 : number_of_rear_sections); num_front_sections=((debug == "true") ? 1 : number_of_front_sections); // Make "sectionheight" be small (5) if you want // to make a test tube to check that the parts fit together properly // before you make the full size part. // 23.5mm is the height of an Xtend-a-slide section //sectionheight = 23.5; sectionheight=((debug == "true") ? 23.5/3 : 23.5 ); cutoutfilmarea = "true"; // Cut out the film area on the Xtend-a-Slide slide carrier // Yes, if supplying your own diffusion // No, if you are printing the carrier in white and it will // be the diffuser. filmx=((film == "film6x6") ? 60 : 36); filmy=((film == "film6x6") ? 60 : 24); framex=((film == "film6x6") ? 70 : 50); framey=((film == "film6x6") ? 70 : 50); negwidth=((film == "film6x6") ? 60.2 : 35.2); framez=((debug == "true") ? 0 : 3.25); frametol=1; lip=2; diag=sqrt(((framex+frametol)*(framex+frametol))+((framey+frametol)*(framey+frametol))); innertall=80; //overlap=5; overlap=((debug == "true") ? 5 : 5); spring=1; // mystep defines how fine to render the threads // The smaller mystep is, the longer it takes to render... // Should be = 5 for final part. // mystep = 5 takes about 53 seconds to render on my quadcore i7 // mystep = 30 takes about 8 seconds... // finishquality="fine" == mystep = 30 mystep=((finishquality == "fine") ? 5 : 30); $fn=((finishquality == "fine") ? 90 : 50); tol=0.25; // Xtend-a-Slideish dimensions // Front tube frontdiskdiameter=((film == "film6x6") ? 110 : 87); frontdiskheight=((debug == "true") ? 1 : 3.65 ); fronttubebackindia=50+front_tube_tol; fronttubefrontindia=framex+front_tube_tol; fronttubethickness=3; // Measured 3.33 fronttubebackthickness=((film == "film6x6") ? fronttubethickness*3 : fronttubethickness); frontrimheight=((debug == "true") ? 3 : 8 ); // Rear tube // Set reardiskdiameter to the diameter of the step-up ring that is mounted on your lens. //reardiskdiameter=67; //reardiskheight=2; reardiskheight=((debug == "true") ? 1 : 2 ); reartubeoutdia=49.5; reartubethickness=2.35; // Xtend-a-Slide carrier // length of notch to fish the slide out of the carrier with your finger xslidefingernotchlength=31; xslidefingernotchwidth=22.5; // diameter of slide carrier xslidedia=88; //xfrontdiskheight=((debug == "true") ? 1 : 2.7); xfrontdiskheight=2.7; slidethickness=1.12; //calc length of front tube // Using the Pythagorean Theorem //http://www.montereyinstitute.org/courses/DevelopmentalMath/COURSE_TEXT2_RESOURCE/U07_L1_T4_text_final.html // (a*a) + (b*b) = (c*c) lega=(fronttubefrontindia-fronttubebackindia)/2; // Height of vertical part legb=sectionheight; // Length of bottom part legc=sqrt((lega*lega) + (legb*legb)); // hypotenuse sectionheight_h = legc; //length_of_both_tubes = (num_rear_sections+num_front_sections)*sectionheight; length_of_both_tubes = (num_rear_sections*sectionheight)+(num_front_sections*sectionheight); echo(str("lega: ", lega, ", legb: ", legb, ", legc: ", legc, ", num_front_sections*sectionheight: ", num_front_sections*sectionheight)); echo(str("film: ", film, ", sectionheight: ", sectionheight, ", sectionheight_h: ", sectionheight_h)); module male_thread(P, D_maj, Tall, tol=0, step=mystep) { // male thread is also called external thread echo(str("Step is ", step, " in male_thread().")); echo(str("Tall is ", Tall, ".")); H=sqrt(3)/2*P; fudge=0.0001; //assign(H=sqrt(3)/2*P) //assign(fudge=0.0001) intersection() { translate([0, 0, Tall/2]) cube([2*D_maj, 2*D_maj, Tall], center=true); for(k=[-P:P:Tall+P]) translate([0, 0, k]) for(i=[0:step:360-step]) hull() for(j = [0,step]) { rotate([0,0,(i+j)]) translate([D_maj/2, 0, (i+j)/360*P]) rotate([90, 0, 0]) linear_extrude(height=0.1, center=true, convexity=10) polygon(points=[ [-H*2/8-P/8-tol, 0], [P/2-H*2/8-P/8-tol, P/2], [-H*2/8-P/8-tol, P], [-D_maj/2-fudge, P], [-D_maj/2-fudge, 0]], paths=[[0,1,2,3,4]], convexity=10); } } } // Calibration slide module calslide () { echo(str("Making calibration slide for ", film, ".")); echo(str("Slide Thickness = ", slidethickness, "mm. ")); difference() { cube([framex+frametol, framey+frametol, slidethickness], center=true); //translate([framex-filmx, framey-filmx, 0]) { cube([filmx,filmy, slidethickness*2], center=true) ////cylinder(h=slidethickness*2,r=slidethickness,center=true) ; //} for (i=[1:8]) { translate ([(framex/10*i)- framex/2.25, (framey/2)-(filmy/2)+1 , 0]) { cube([slidethickness*2, slidethickness/3, slidethickness*2], center=true); cube([slidethickness/3, slidethickness*1, slidethickness*2], center=true); //cylinder(h=slidethickness*2,r=slidethickness,center=true); } } for (i=[1:8]) { translate ([(framex/10*i)- framex/2.25, -((framey/2)- (filmy/2)+1), 0]) { cube([slidethickness*2, slidethickness/3, slidethickness*3], center=true); cube([slidethickness/3, slidethickness*1, slidethickness*2], center=true); //cylinder(h=slidethickness*2,r=slidethickness,center=true); } } } } // Make a ruler to test measurements. // orientation = 90 stands upright to comparing in openSCAD. orientation = 0 is flat (for printing for real) // offset is the distance from 0. (so you can have an upright ruler standing next to the real model.) module makeruler(length = 100, width= 15, offset = 80, orientation = "upright", print_length = "truex") { angle=((orientation == "upright") ? 90 : 0); xoffset=((orientation != "upright") ? length/2 : 0); echo(str("Ruler length = ", length)); rotate([0,-angle,0]) translate([-xoffset,offset,0]){ #cube([length, width, 1.5], center = false); if (print_length == "true") { translate([2,width/4,1.5]) linear_extrude(height= 0.5) { text(text = str(length, "mm"), size=5); } } } } // module makeruler() module fronttube( sections=3, buildplate="true", buildtube="true", slits="true") { echo(str("Making front tube for ", film, ".")); echo(str(sections, " sections, sectionheight ", sectionheight, "mm, total length: ",sections*sectionheight, "mm.")); //echo(str(sections, " sections, sectionheight_h ", sectionheight_h, "mm, total length_h: ",sections*sectionheight_h, "mm.")); // (Maybe) need Pythagorean Theorem here (for film6x6) // Used for calculating fronttube's dimensions shortsection=(film == "film6x6") ? (sections*sectionheight) : (sections*sectionheight); start_straighttube_at=shortsection-(sectionheight*.7); straighttubeheight = (sectionheight*.7); fudgeif1=((sections == 1 && film == "film6x6") ? 1 : 0); // need to lower the straight section if sections == 1. echo(str("Real length of the fronttube: ", shortsection, ".")); if (buildplate == "true" ) { // Start with adding an outer rim on the front disk difference() { cylinder(r=(frontdiskdiameter/2)+(lip*.999), h=frontrimheight); cylinder(r=((frontdiskdiameter-fronttubethickness)/2)+(lip*.999), h=frontrimheight+1); } } difference() { // Temporarily change to "union()" to see what is subtracted // First build a solid front plate and tube union() { if (buildplate == "true" ) { cylinder(r=(frontdiskdiameter/2)+(lip*.999), h=frontdiskheight); } // Then the tube. Solid, at this point if (buildtube == "true" ) { // cylinder(r1=(fronttubefrontindia+fronttubethickness)/2, r2=(fronttubebackindia+fronttubethickness)/2-(fronttubethickness*(fudgeif1/5)), h=start_straighttube_at + fudgeif1); // shortsection-3.9 } } // union() // Now difference() kicks in and eliminates these: //translate([0, 0, (sections*sectionheight)/2+0]) //translate([0, 0, (shortsection)/2+0]) translate([0, 0, -2]) // Eliminate the inner tube cylinder(r1=fronttubefrontindia/2, r2=fronttubebackindia/2, h=start_straighttube_at+4); // make slits by rotating a skinny rectangle around the tube (which are eliminated with "difference()") } // difference() // For debugging. Uncomment to verify tube length calculations (ruler should == tube height) // Normally is commented out! //makeruler(offset=frontdiskdiameter/2 + 4,length=start_straighttube_at+straighttubeheight-1,orientation = "upright"); translate([0, 0, start_straighttube_at -1 - fudgeif1*0]) { difference() { // Normally is difference() if (buildtube == "true" ) { difference() { cylinder(r=(fronttubebackindia+fronttubethickness)/2, h=straighttubeheight); translate([0,0,+2]); cylinder(r=(fronttubebackindia)/2, h=straighttubeheight+4); } } if (slits == "true" && buildtube == "true") { for (i=[1:360/num_slits:360]) { rotate([0,0,i]) cube([fronttubebackindia-(fronttubebackindia*.35), slit_thickness, sectionheight*1.1],center=false); } } } } } // module fronttube() module reartube(sections=3, buildplate="true", buildtube="true", slits="true") { //dia=thread_diameter/10; dia=reardiskdiameter+.4; mag=((dia<49) ? 0.5 : 1); pitch=thread_pitch/100.0; ctol=thread_tolerance/1000.0; threadheight = numthreads * (pitch*.0002); echo(str("Making rear tube for ", film, ".")); //echo(str(sections, " sections.")); echo(str(sections, " sections, sectionheight ", sectionheight, "mm, total length: ",sections*sectionheight, "mm.")); difference() { // Temporarily change to "union()" to see what is subtracted union() { if (buildplate == "true" ) { if (makethreads != "true") { cylinder(r=(reardiskdiameter/2)+(lip*.0), h=reardiskheight); } else { translate([0,0,(threadheight)]) male_thread(pitch, dia-ctol, numthreads, 0.25); } } if (buildtube == "true" ) { //translate([0, 0, reardiskheight]) cylinder(r=reartubeoutdia/2, h=sections*sectionheight); } } // Eliminate the inner tube. translate([0, 0, (sections*sectionheight)/2]) cylinder(r=(reartubeoutdia-reartubethickness)/2, h=(sections*sectionheight)+20,center=true); if (buildtube == "true" ) { // How high should the slits start? translate([0, 0, (sections*sectionheight-sectionheight*.75) + (reardiskheight+1)]) { if (slits == "true" && buildtube == "true") { for (i=[1:360/num_slits:360]) { rotate([0,0,i]) cube([fronttubebackindia-(fronttubebackindia*.35), slit_thickness, sectionheight*1.1],center=false) ; } } } // translate() } // if (buildtube == "true" ) } // difference() } // AKA slide carrier module springpart() { union() { echo(str("Making Spring Holder for ", film, ".")); echo(str("frontdiskdiameter = ", frontdiskdiameter+td2dh_sp, "mm. ")); difference() { // outer rim cylinder(r=(frontdiskdiameter+td2dh_sp)/2+lip+lip, h=framez+spring+overlap); //cylinder(r=(frontdiskdiameter+td2dh_sp)/2, h=framez+spring+overlap); // slide holder translate([0, 0, framez+spring]) cylinder(r=(frontdiskdiameter+td2dh_sp)/2+lip, h=1000) ; // slide removal access, shifted up as of 20140824 translate([0, 500-(framey/2)+frametol/4, 0]) //color("red") cube([framex+frametol, 1000, 1000], center=true) ; } difference() { union() { // spring translate([0, 0, spring/2]) cube([framex, (framey+frametol)*1, spring], center=true); // bump on the spring, thicker as of 20140824 difference() { translate([0, filmy/7, -filmy*2+spring*3]) rotate([0, 90, 0]) if (debug == "true") { cylinder(r=filmy*1.94, h=framex*1, center=true, $fn=180); } else { cylinder(r=filmy*2, h=framex, center=true, $fn=180); } translate([0, 0, -500]) cube([1000, 1000, 1000], center=true) ; } } // clear film area + double tolerance as of 20140824 translate([0, 500-(filmy+frametol)/2-frametol, 0]) cube([filmx+2*frametol, 1000, 1000], center=true) ; } } } // module springpart() module diffuser() { echo(str("Making optional diffuser for ", film, ".")); echo(str("frontdiskdiameter = ", (frontdiskdiameter+td2dh_df), "mm. ")); translate([0, 0, overlap*2+1]) mirror([0, 0, 1]) union() { difference() { // outer rim cylinder(r=(frontdiskdiameter+td2dh_df)/2+lip+lip+lip, h=overlap); cylinder(r=(frontdiskdiameter+td2dh_df)/2+lip+lip, h=1000, center=true); } translate([0, 0, overlap]) difference() { cylinder(r=(frontdiskdiameter+td2dh_df)/2+lip+lip+lip, h=overlap+1); cylinder(r1=(frontdiskdiameter+td2dh_df)/2+lip+lip-1, r2=frontdiskdiameter/2+lip+lip+lip-1, h=overlap); translate([0, 0, -500]) cube([1000, 1000, 1000], center=true); } } } print_part(); // Colors only affect F5 (CGS) preview mode; // These colors go away after F6 (CGAL) render mode module print_part() { min_length = length_of_both_tubes - sectionheight; max_length = length_of_both_tubes - 10; echo(str("length_of_both_tubes: ",length_of_both_tubes )); echo(str("Working length of both tubes is approx. ", min_length , "mm through ", max_length, "mm.")); if (part == "fronttube") { color ("gray") fronttube(sections=num_front_sections, buildplate=makeroundplate, buildtube=maketube); } else if (part == "reartube") { color ("gray") reartube(sections=num_rear_sections, buildplate=makeroundplate, buildtube=maketube); } else if (part == "springpart") { color("white") springpart(); } else if (part == "negativecarrier") { color("white") negativecarrier(); } else if (part == "xslidecarrier") { color("white") xslidecarrier(); } else if (part == "diffuser") { color ("white") diffuser(); } else if (part == "calslide") { color ("white") calslide(); } else if (part == "ruler") { rulerwidth=15; color ("white") echo(str("Ruler is ", length_of_both_tubes-(sectionheight/2), " (length_of_both_tubes-(sectionheight/2))")); translate([0,-rulerwidth*0.5,0]) makeruler(length = length_of_both_tubes-(sectionheight/2), width=rulerwidth, offset = 0, orientation = "uprightx", print_length = "true"); } else if (part == "playpen1") { color ("white") playpen1(); } else if (part == "bothtubes" || part == "bothtube") { union() { color("blue") fronttube(sections=num_front_sections, buildplate=makeroundplate, buildtube=maketube); color("green") translate([0,0,num_front_sections * sectionheight-1]) reartube(sections=num_rear_sections, buildplate=makeroundplate, buildtube=maketube); } } else if (part == "exploded") { union() { color("white") diffuser(); translate([0, 0, (lip*1)+overlap*2+1]) union() { color("red") springpart(); translate([0, 0, lip*6]) color("blue") fronttube(sections=num_front_sections, buildplate=makeroundplate, buildtube=maketube); translate([0, 0, (num_front_sections*sectionheight)+ (sectionheight*.01)+lip*7]) color("green") reartube(sections=num_rear_sections, buildplate=makeroundplate, buildtube=maketube); color("white") translate([0, 0, (num_rear_sections+num_front_sections)*sectionheight+(sectionheight*.1)+lip*8]) // So you can look down through the tubes in "exploded", in debug mode if (debug != "true") { calslide(); } else { //calslide(); } ; } } } else { // ; } } // Experimental or unfinished modules go here. module playpen1() { // Playing with rim and torus torheight=3; if (6 == 9) { // Rim + torus union() { echo(str("Playpen1 ", film, ".")); echo(str("frontdiskdiameter = ", frontdiskdiameter, ". ")); //translate([0, 500-(framey/2)+frametol/4, 0]) //color("red") //cube([framex+frametol, framex+frametol, 1.5], center=true) difference() { // outer rim cylinder(r=frontdiskdiameter/2+lip+lip, h=framez+spring+overlap); //cylinder(r=frontdiskdiameter/2, h=framez+spring+overlap); // slide holder translate([0, 0, 0]) cylinder(r=frontdiskdiameter/2+lip, h=1000) ; // slide removal access, shifted up as of 20140824 translate([0, 500-(framey/2)+frametol/4, 0]) //color("red") //cube([framex+frametol, 1000, 1000], center=true) ; translate([0,0,torheight]){ torus(circle="truex"); } } } } else { // Just torus. translate([0,0,torheight]) torus(circle="truex"); } } // playpen1() module torus (dia =frontdiskdiameter+2, circle="truex" ) { div=.25; torus_dia = .07; scale([dia*div,dia*div,dia*div]) { rotate_extrude(convexity = 5, $fn = 90) translate([2, 0, 0]) if (circle == "true" ) { circle(r = torus_dia, $fn = 90); } else { square([torus_dia*1.25,torus_dia*1.25], $fn = 100); } } } // module torus() // Unfinished. Does not work now. module negativecarrier() { union() { echo(str("Making negative carrier for ", film, ".")); echo(str("frontdiskdiameter = ", frontdiskdiameter*td2dh, "mm. ")); echo(str("Negative width = ", negwidth, "mm.")); enlarge=((film == "film6x6") ? 1 : 4 ); if (6 == 6) { union() { //translate([(frontdiskdiameter*td2dh)- (negwidth*.45),0,3]) translate([((frontdiskdiameter*td2dh)*.5) + ((negwidth*.5)),0,3]) //translate([(frontdiskdiameter*td2dh*1)- (filmy*1.2),0,3]) cube([(frontdiskdiameter*td2dh) , (frontdiskdiameter*td2dh),2], center=true) ; mirror() { translate([(negwidth),0,3]) //cube([(frontdiskdiameter*td2dh) , (frontdiskdiameter*td2dh),2], center=true) ; } } } if (6 == 6) { difference() { // difference() // outer rim cylinder(r=(frontdiskdiameter*td2dh)/2+lip+lip, h=framez+spring+overlap); //cylinder(r=(frontdiskdiameter*td2dh)/2, h=framez+spring+overlap); // slide holder //translate([0, 0, framez+spring]) translate([0, 0, 1.5]) cylinder(r=(frontdiskdiameter*td2dh)/2+lip, h=1000) ; //rotate([0,90,0]) cube([filmy+enlarge,filmx+enlarge, 2000], center=true) // slide removal access, shifted up as of 20140824 translate([0, 500-(framey/2)+frametol/4, 0]) //color("red") //cube([framex+frametol, 1000, 1000], center=true) ; } } } } // negativecarrier() // Slide carrier for Xtend-a-Slide. // (You need to add a layer of Staples adhesive rubber magnet. // that you cut out yourself.) module xslidecarrier () { echo(str("Making slide carrier for ", film, ".")); echo(str("thickness is ", xfrontdiskheight, ".")); difference() { cylinder(r=xslidedia/2, h=xfrontdiskheight); // Bottom plate if (cutoutfilmarea == "true") { cube([filmy+1, filmx+1, xfrontdiskheight+20], center=true); // Cut out the film area } translate([xslidedia/2-13,0,-5]) { // Make pieces for finger notch cylinder(r=xslidefingernotchwidth/2, h=xfrontdiskheight+20); translate([0,-xslidefingernotchwidth/2,0]) cube([xslidefingernotchlength,xslidefingernotchwidth,xfrontdiskheight+20],center=false); } } translate([0,0,xfrontdiskheight*.9]) { // Need to lower it a bit to pervent (mesh) holes difference() { // h=xfrontdiskheight-1.7 sets height of top layer cylinder(r=xslidedia/2, h=xfrontdiskheight-1.9); // 2nd layer translate([-(framex+frametol)/2, -(framex+frametol)/2,0]) // Cut out area for slide cube([(framex+frametol)*2, framey+frametol, xfrontdiskheight*1.1], center=false); // Add bevels to the end of the slide cutout. translate([framex/2,framey/5,0]) rotate([0,0,15]) cube([(framex+frametol)*.5, (framey+frametol)*.3, xfrontdiskheight*2.5], center=false); translate([framex/2,-framey*.5,0]) rotate([0,0,-15]) cube([(framex+frametol)*.5, (framey+frametol)*.3, xfrontdiskheight*2.5], center=false); } } } // xslidecarrier ()