Tweak holes, add LED holes, make PCB transparent.

// Raspberry Pi Case
// Hans Harder 2012
//
// Warning: this is based on the Beta board dimensions...
//          so production models can be slightly different
//          for instance SD card holder height and USB socket dimensions
//
// Since all connectors stick out, case is split on HDMI height
// so the power and sdcard holder goes in first and then the pcb drops into place.
//
// v2: Adapted version after some suggestions from David...
//     removed feet, made both surface flat
// v3: Added fliptop option and smooth the corners of the box
// v4: Different levels of case split (make it 3d printable, thx David)
//     Looks strange but it fits...
//     Added frame mode (so no bottom and top deck)
//     Moved screw locations due to split and added some support structures
//     Unsure about 2nd screw location in combination with GPIO pins
// v5  relocated a lot of code in modules
//     SDslot location was not calculated correctly
// v6  Added pcb drawing
//     Added colors
//     Cut out better so there is no debris around
//     DRAwvars and options seperated, so it is easier to do 1 part
//     Make a low as possible case, let USB stick out
// v7  PCB options
//     Low level case optimisations
//     SD card location alterations
// v8  adapted pcb dimensions, board is really 56mm width
//     adapted support studs, moved some due to component location
//     components locations adapted
// v9  Added logo in seperate dxf file
//     Option added to put logo in middle or using whole deck
//     beautified code, kr style
// v10 Added logosunken and bottomsupport structures
//     Bottom supports are located where no components are located
//       so the pcb is not only supported from the sides
//     Well got my case, so based on what I see I changed:
//     case split level changed, should be better when printed on a reprap
//     Removed screwholes (far to small) for fastening top and added some more studs
//     Made frontstud a little thicker
// v11 Different splitlevel (more simple) on back
//     keep a little margin on back split, so that top and bottom always fit
//     added openlogo option
// v12 Different component locations/sizes
//     keep a little margin on component holes
//     pcbsize to 57.0 x 86.0   (actual it is 56.17 x 85.0)
//     made casestuds wider and added 2 minor holes for self tapping screws
// v13 skip this one.... :)
// v14 Production board measurements...
//	   small differences, sometimes components are soldered differently
//     keep more space
//     should fit like a glove...
// v15 moved the rca and snd a bit to get them more centered
//     Thanks to lincomatic at Thingiverse
//     Added option for GPIO side hole in bottom or top
//     Added showing GPIO pins with component drawing
//
// All parts are draw as default just disable the ones you don't want
DRAWfull        = 0;
DRAWtop         = 1;
DRAWbottom      = 1;
DRAWpcb         = 0;

GPIOHOLE        = 2;        // GPIO opening in :  1=bottom   2=top
GPIOsize        = 2;        // define height of gpiohole

// select how the case should look like
topframe    = false;        // if false, underneath values determines how
topholes    = true;
ledholes    = true;
// ---- holes sizes
holeofs=6;
holesiz=3;
holestep=8;
noholes=7;
holelen=30;
topmiddle   = false;

bottomframe = false;        // if false, underneath values determines how
bottomholes = false;
bottomscrew = false;
bottomsupport = false;         // Added extra support locations for pcb
bottomclick   = true;
bottompcb    = false;		    // just a pcb holder without a top

box_thickness = 2.0;            // minimum = 1.0
inside_h      = 12.5;           // 12.1 = lowprofile    16.5 is full height
pcb_h         = 5.6;            // height needed for SD holder and solder points of pcb
//pcb_h         = box_thickness+3.5;    // height needed for SD holder and solder points of pcb
// 4.1 = no deck, box_thickness+3.5 is with deck

// just some colors to see the difference
CASEcolor="Maroon";
CONNcolor="Silver";

// Define Raspberry Pi pcb dimensions in mm
inside_l = 86.0;                //85.00 is largest length reported, so a bit room on each side
inside_w = 57.2;                //56.17 is largest width  reported, so a bit room on each side
pcb_thickness = 1.7;

// Coordinates based on RJ45 corner = 0,0,0
// pcb connectors and locations. Based on Beta Board measurements of Gert and a real RPi

// Connectors
Crj45_x=2.0;			 //2.0
Crj45_y=-1;
Crj45_w=16.4;			// 15.4
Crj45_d=21.5;           //21.8
Crj45_h=13.8;

Cusb_x=24.5;            // 23.9
Cusb_y=-7.7;
Cusb_w=13.9;            // 13.3
Cusb_d=19.0;			// 17.2
Cusb_h=16.0;

Cpwr_x=3.25;				// 3.5 3.6
Cpwr_y=80.9;
Cpwr_w=8.8;				// 7.8 7.6
Cpwr_d=5.6;
Cpwr_h=2.6;

Csd_x=16.7;
Csd_y=inside_l-24.0;            // 30 mm is the length of a  sdcard
Csd_w=27.8;
Csd_d=29.0;
Csd_h=3.4;                  // under pcb

Chdmi_x=-1.2;
Chdmi_y=32.0;               // 32.4  if 15.1
Chdmi_w=11.4;
Chdmi_d=17.8;				  // 15.7 15.3
Chdmi_h=6.4;

Csnd_x=inside_w - 11.4;
Csnd_y=16.0;
Csnd_w=11.4;
Csnd_d=10.0;
Csnd_h=10.5;
Csnd_r=6.7;
Csnd_z=3.0;
Csnd_l=3.4;

Crca_x=inside_w - 10.0 - 2.1;
Crca_y=34.2;                // 34.6 was 35.2
Crca_w=10.0;
Crca_d=10.4;                 // 9.8
Crca_h=13.0;
Crca_r=8.6;
Crca_z=4;
Crca_l=10;                  // wild guess

pcb_c = pcb_h + pcb_thickness;            // component height
casesplit = pcb_c + Chdmi_h;              // split case at top of hdmi connector
echo("casesplit=",casesplit);
echo("case dimensions: w=",box_w," l=",box_l," h=",box_h);

// side stud sizes for supporting pcb
stud_w = 2;
stud_l = 4;

// calculate box size
box_l  = inside_l + (box_thickness * 2);
box_w  = inside_w + (box_thickness * 2);
box_h  = pcb_c + (pcb_thickness * 2) + inside_h;
box_w1 = box_thickness;
box_w2 = box_w - box_thickness;
box_l1 = box_thickness;
box_l2 = box_l - box_thickness;
box_wc = box_w / 2;                 // center width
box_lc = box_l / 2;                 // center length
box_t2 = box_thickness / 2.0;           // half box_thickness
middle = true;
// rounded corners
corner_radius = box_thickness*2;

// count no of items to draw
DRAWtotal = DRAWfull + DRAWtop + DRAWbottom;

// ====================================================== DRAW items
// if one  draw it centered
if (DRAWtotal == 1) {
    translate(v = [ -box_w/2, -box_l / 2, 0]) {
        if (DRAWfull ) {
           draw_case(0,1);
           translate(v=[0,0,0.2]) draw_case(1,0);
        }
        if (DRAWtop   ) {
            rotate(a=[0,180,0]) translate(v=[-box_w,0,-box_h]) draw_case(0,1);
        }
        if (DRAWbottom) draw_case(1,0);
    }
} else {
// draw each one on there one location
    if (DRAWfull)   {
        translate(v = [ box_w+20, -box_l / 2, 0]) {
            draw_case(1,0);
            translate(v=[0,0,0.2]) draw_case(0,1);
        }
    }
    if (DRAWbottom) {
        translate(v = [ 5, 5, 0]) draw_case(1,0);
    }
    if (DRAWtop)    {
        translate(v = [ - 5,  5, box_h])  rotate(a=[0,180,0]) draw_case(0,1);
    }
}

// ======================================================= END of draw
// Module sections

module make_deckholes(no,w,d,step) {
for ( i = [0 : 1 : no - 1] ) {
        translate(v=[w/2,(i*step)+(step/2),box_thickness/2]) cube([w,d, box_thickness+18], center=true);
    }
}

// create a deck or insert
module make_deck(w,d,z,hole_no,hole_size,hole_step) {
    hole_w=(w - 12) / 2;      // change 12 for middle piece size
    ofs1=4;
    ofs2=w - ofs1 - hole_w;
    hole_ofs= ((d - hole_no*hole_step) / 2) - box_thickness/2;
    translate(v = [(box_w-w)/2, (box_l-d)/2,z]) {
        color(CASEcolor) {
            echo("deck : z=",z," w=",w+0.01," d=",d+0.01);
            difference() {
                cube([w, d, box_thickness], center = false);
                if (top && holes && hole_size>0) {
                    translate(v=[-1,hole_ofs+holeofs,-0.1]) make_deckholes(noholes,holelen,holesiz,holestep);
                    translate(v=[w/2-2,hole_ofs+holeofs,-0.1]) make_deckholes(noholes,holelen,holesiz,holestep);
                }
                if (screwholes) {
                    // --- 2x screw holes in bottom for mounting
                    translate(v = [w/2 - 4, 10-4, -1]) cube([8, 3, 5], center = false);
                    translate(v = [w/2 - 4, 10-3, -1]) cylinder(r=3, h=8, $fn=100, center=true);
                    // 2nd screw hole
                    translate(v = [w/2 - 3, d - 10 +3, -1]) cube([8, 3, 5], center = false);
                    translate(v = [w/2 + 4, d - 10 +4, -1]) cylinder(r=3, h=8, $fn=100);
                    if (!holes) {
                        // middle screw hole
                        translate(v = [w/2 - 4, d/2    , -1]) cube([8, 2, 5], center = false);
                        translate(v = [w/2 - 4, d/2 + 1, -1]) cylinder(r=2, h=8, $fn=100);
                    }
                }
                if (holes && !top) {
                    translate(v=[(w-hole_w)/2,holeofs,-0.1]) make_deckholes(noholes,hole_w,holesiz,holestep);
                }
                if (top && ledholes) {
						translate([w-8,3,-0.1])
	                    cube([5,11,20]);
                }
            }
            color(CASEcolor) {
                if (top && holes) {
                    translate(v = [w/2-box_thickness,12,0]) cube([4,d-13, box_thickness], center = false);
                }
                if (middle) {
                    // --- solid area for sticker
                    translate(v = [w/2-10,d/2-5-box_thickness/2,0]) {
                        cube([20,20, box_thickness], center = false);
                    }
                }
            }
        }
    }
}

module rounded_corner(x,y,rx,ry,cx,cy) {
    translate(v = [x, y, -1]) {
        difference() {
            translate(v=[rx,ry,0])    cube([corner_radius,corner_radius,box_h+2], center=false);
            translate(v=[cx, cy, -1]) cylinder(r=corner_radius, h=box_h+2, $fn=100);
        }
    }
}

module make_topcomponents(alpha=1) {
    color(CONNcolor, alpha=alpha) translate(v=[box_w1,box_l1,pcb_c]) {
        translate(v=[Crj45_x,Crj45_y,0]) cube([Crj45_w,Crj45_d,Crj45_h],center=false);
        translate(v=[Cusb_x,Cusb_y,0])   cube([Cusb_w,Cusb_d,Cusb_h],center=false);
        translate(v=[Cpwr_x,Cpwr_y,0])   cube([Cpwr_w,Cpwr_d,Cpwr_h],center=false);
        translate(v=[Chdmi_x,Chdmi_y,0]) cube([Chdmi_w,Chdmi_d,Chdmi_h],center=false);

        //SND
        translate(v=[Csnd_x,Csnd_y,0]) cube([Csnd_w+0.1,Csnd_d,Csnd_h],center=false);
        translate(v=[Csnd_x+Csnd_w,Csnd_y+Csnd_d/2,Csnd_z+Csnd_r/2]) rotate(a=90,v=[0,1,0]) cylinder(r=Csnd_r/2, h=Csnd_l, $fn=100);

        //RCA
        translate(v=[Crca_x,Crca_y,0]) cube([Crca_w+0.2,Crca_d,Crca_h],center=false);
        translate(v=[Crca_x+Crca_w,Crca_y+Crca_d/2,Crca_z+Crca_r/2]) rotate(a=90,v=[0,1,0]) cylinder(r=Crca_r/2, h=Crca_l+0.1, $fn=100);
    }
    for ( i = [0 : 1 : 12] ) {
        color("black", alpha=alpha) translate(v=[box_w2-6.6,box_l2-1-34+(i*2.54),pcb_c]) cube([5.08,2.53,2.5]);
        color("Gainsboro", alpha=alpha) translate(v=[box_w2-6.6+0.97,box_l2-1-34+(i*2.54)+0.95,pcb_c-3])  cube([0.6,0.6,11.5]);
        color("Gainsboro", alpha=alpha) translate(v=[box_w2-6.6+3.61,box_l2-1-34+(i*2.54)+0.95,pcb_c-3])  cube([0.6,0.6,11.5]);

    }
}

module make_connholes() {
    // =================================== cut outs, offset from 0,0
    //RJ45:    2mm offset, 15.5mm width, 13.1mm height
    set_cutout(box_w1+Crj45_x,box_l1+Crj45_y-3,pcb_c,   Crj45_w+0.1,Crj45_d+3,Crj45_h);
    //usb:  23.9mm offset, 13.3mm width, 15.4mm height
    set_cutout(box_w1+Cusb_x,box_l1+Cusb_y,pcb_c,   Cusb_w,Cusb_d,Cusb_h+0.1);

    //power: 3.4mm offset,    8mm width,    3mm height
    set_cutout(box_w1+Cpwr_x,box_l1+Cpwr_y,pcb_c,   Cpwr_w,Cpwr_d+4,Cpwr_h+0.01);
    //sd:   15mm offset,   28mm width,    3.5mm height under pcb
    if (pcb_h >= (Csd_h+1.5) ) {
        set_cutout(box_w1+Csd_x-0.3,box_l2-28,pcb_h-Csd_h,Csd_w+0.6,box_thickness+30,Csd_h+0.1);
    } else {
        set_cutout(box_w1+Csd_x-0.3,box_l2-32,pcb_h-20,Csd_w+0.6,40,20.01);
    }
    //HDMI: 32.9mm offset,  15.3mm width,   6.3mm height
    set_cutoutv(box_w1+Chdmi_x-3,box_l1+Chdmi_y,pcb_c,    Chdmi_w+3.1,Chdmi_d,Chdmi_h+0.1);

    // snd:   14mm offset,  12mm width,   8.2 mm height
    set_cutout(box_w1+Csnd_x,box_l1+Csnd_y,pcb_c+2,    Csnd_w+7,Csnd_d,Csnd_h-2);

    // RCA:   35mm offset,  10mm width     10mm height
    translate(v=[box_w1+Crca_x+Crca_w,box_l1+Crca_y+Crca_d/2,pcb_c+Crca_z+Crca_r/2]) {
        rotate(a=90,v=[0,1,0]) cylinder(r=Crca_r/2+1, h=Crca_l, $fn=100);
    }
    translate(v=[box_w1+Crca_x+Crca_w,box_l1+Crca_y+(Crca_d-Crca_r)/2-1,pcb_c+Crca_z-1]) {
        cube([5,Crca_r+2,Crca_r/2+1]);
    }
}

module make_pcb(alpha=1) {
    translate(v=[box_w1,box_l1,pcb_h]) {
        color("darkgreen", alpha=alpha) cube([inside_w,inside_l,pcb_thickness], center=false);
    }
    color(CONNcolor, alpha=alpha) {
        translate(v=[box_w1+Csd_x,box_l1+Csd_y,pcb_h-Csd_h]) cube([Csd_w,Csd_d,Csd_h],center=false);
    }
    make_topcomponents(alpha=alpha);
}

// put extra supports on free spaces, used beta board image
module make_supports() {
    if (!bottomframe) {
        translate(v=[box_w1+10 ,box_l1+28,0.1]) cube([3, 2,pcb_h-0.1]);
        translate(v=[box_w2-7.5,box_l1+28,0.1]) cube([3, 2,pcb_h-0.1]);

        translate(v=[box_w1+7  ,box_l2-35,0.1])  cube([5, 5,pcb_h-0.1]);
        translate(v=[box_w2-13 ,box_l2-35,0.1])  cube([5, 5,pcb_h-0.1]);

        translate(v=[box_w1+12 ,box_l2-16,0.1])  cube([1.5 ,5,pcb_h-0.1]);
        translate(v=[box_w2-9  ,box_l2-16,0.1])  cube([1.5 ,5,pcb_h-0.1]);
    }
}

// width,depth,height,boxthickness,ledgethickness
module make_case(w,d,h,bt,lt) {
    dt=bt+lt;    // box+ledge thickness
    bt2=bt+bt;    // 2x box thickness
    // Now we just substract the shape we have created in the four corners
    color(CASEcolor) difference() {
        cube([w,d,h], center=false);
        if (rounded) {
            rounded_corner(-0.1,d+0.1, 0             ,-corner_radius,  corner_radius,-corner_radius);
            rounded_corner(w+0.1,d+0.1, -corner_radius,-corner_radius, -corner_radius,-corner_radius);
            rounded_corner(w+0.1,-0.1, -corner_radius,0             , -corner_radius, corner_radius);
            rounded_corner(-0.1,-0.1, 0             ,0             ,  corner_radius, corner_radius);
        }
        // empty inside, but keep a ledge for strength
        translate(v = [bt, bt, dt])   cube([w-bt2, d-bt2, h-(dt*2)], center = false);
        translate(v = [dt,dt,bt])     cube([w-(dt*2), d-(dt*2), h-bt2], center = false);
        // remove bottom and top deck
        translate(v = [box_thickness+2, box_thickness+5,-2]) {
            cube([inside_w-4, inside_l-10, box_h+4], center = false);
        }
    }
    if (!topframe) {
        make_deck(inside_w-4,inside_l-4,box_h-box_thickness, 12,3,5, holes=topholes, ledholes=ledholes, middle=topmiddle,screwholes=false,top=true);
    }
    if (!bottomframe) {
        make_deck(inside_w-4,inside_l-4,0, 12,3,5, holes=bottomholes,screwholes=bottomscrew,middle=false,top=false);
        if (bottomsupport) {
            make_supports();
        }
    }
}

module make_stud(x,y,z,w,h,l) {
    translate(v = [x, y, z]) cube([w, l, h], center = false);
}

module set_cutout(x,y,z,w,l,h) {
    color(CASEcolor)    translate(v = [x+(w/2), y+(l/2), z+(h/2)]) cube([w+0.4, l+0.2, h+0.2], center = true);
}

module set_cutoutv(x,y,z,w,l,h) {
    color(CASEcolor)    translate(v = [x+(w/2), y+(l/2), z+(h/2)]) cube([w+0.2, l+0.4, h+0.2], center = true);
}

module draw_pcbhold() {
  if (bottomclick) {
    color(CASEcolor) {
        translate(v=[0  ,22,2]) cube([box_thickness,4,pcb_c]);
        translate(v=[box_w1-0.1  ,22.5,pcb_c+0.1]) {
            difference() {
                cube([1, 3,2]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[0  ,60.5,2]) cube([box_thickness,5,pcb_c]);
        translate(v=[box_w1-0.1  ,61.5,pcb_c+0.1]) {
            difference() {
                cube([1,3,2]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[box_w2,29.5,2]) cube([box_thickness,4,pcb_c]);
        translate(v=[box_w2+0.1  ,30+3,pcb_c+0.1]) {
            rotate(a=180, v=[0,0,1]) difference() {
                cube([1, 3,3]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[box_w2,60.5,2]) cube([box_thickness,5,pcb_c]);
        translate(v=[box_w2+0.1  ,61+3.5,pcb_c+0.1]) {
            rotate(a=180, v=[0,0,1]) difference() {
                cube([1,3,3]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
    }
  }
}

module split_top() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w1+Csd_x - 12;   // min 16.5+28
    split4=box_w2 - 7;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, casesplit-0.2])    cube([box_w+2, 21, 0.4], center = false);
    // back on 3 different levels
    translate(v = [-1,  20, casesplit-0.2])    cube([split1+1     , box_l, 0.4], center = false);
    translate(v = [split2, 20, pcb_c-0.2])     cube([split3-split2, box_l, 0.4], center = false);
    translate(v = [split3, 20, pcb_h-0.2])     cube([split4-split3, box_l, 0.4], center = false);
    translate(v = [split4, 20, casesplit-0.2]) cube([20           , box_l, 0.4], center = false);
}

module remove_top() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w2 - 12;
    possd1=box_w1 + Csd_x - 0.3;
    widesd1=Csd_w+0.6;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, casesplit])    cube([100,100, box_h], center = false);
    // back on 3 different levels
    translate(v = [split1, 20, pcb_c])     cube([split3-split1, box_l, box_h], center = false);
    translate(v = [possd1, 60, pcb_h-0.1])  cube([widesd1, box_l, 2], center = false);
//    translate(v = [split1, 20, pcb_c])     cube([20, box_l, box_h], center = false);
//    translate(v = [split2, 20, pcb_h])     cube([split3-split2, box_l, box_h], center = false);
  if (bottompcb) {
    translate(v = [-1,  -1, pcb_c])    cube([100,100, box_h], center = false);
  }
}

module remove_bottom() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w2 - 12.1;
    possd1=box_w1 + Csd_x - 0.2;
    widesd1=Csd_w+0.6;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, -1])    cube([box_w+2, box_l-6, casesplit+1], center = false);
    // back on 3 different levels
    translate(v = [-1, 20, -1])     cube([box_w+2  , box_l, pcb_c+1.1], center = false);
    translate(v = [-1, 20, -1])     cube([split1+1.1 , box_l, casesplit+1], center = false);
    translate(v = [-1, 20, -1])     cube([split2+1.1 , box_l, pcb_c+Cpwr_h+1.1], center = false);
    translate(v = [split3, 20, -1]) cube([20       , box_l, casesplit+1], center = false);
}

module draw_case(bottom, top) {
    difference() {
        union() {
            // make empty case
            difference() {
                make_case(box_w,box_l,box_h, box_thickness,stud_w, rounded=true);
                if (top != 0 && bottom == 0)    remove_bottom();
                if (top == 0 && bottom != 0)    remove_top();
            }
            color(CASEcolor) {
                if (bottom != 0 ) {
                    // add bottom studs for pcb
                    // add bottom studs for pcb
                    make_stud(box_w1       , box_l1         , 0, 4,pcb_h,4);      // rj45
                    make_stud(box_w1       , box_lc-stud_l/2, 0, stud_w,pcb_h,stud_l);      // hdmi
                    make_stud(box_w1, box_lc/2, 0, 4,pcb_h,stud_l);
                    make_stud(box_w1, box_lc+(box_lc/2)-5, 0, 4,pcb_h,stud_l);

                    make_stud(box_w1, box_l2-stud_l-8, 0, stud_w,pcb_h,stud_l);        // BEFORE pwr
                    make_stud(box_w2-stud_w, box_l1         , 0, stud_w,pcb_h,stud_l);      // leds
                    make_stud(box_w2-4, box_lc-stud_l/2, 0, 4,pcb_h,stud_l);                // RCA
                    make_stud(box_w2-stud_w, box_l2-stud_l  , 0, stud_w,pcb_h,stud_l);      // GPIO

                    translate(v=[box_w1+Cusb_x-6,box_l1,1])  cube([3.0, 4,pcb_h-1.1]);
                    translate(v=[box_w2-15.8    ,box_l1,1])  cube([3.0, 4,pcb_h-1.1]);

                    draw_pcbhold();
                }

                if (top != 0) {
                    // --- screw connection plates
                    translate(v = [box_w1 + Crj45_x+Crj45_w, box_l1, casesplit - 5.4]) {
                        cube([10, 3, box_h-(casesplit-5.4)], center = false);
                    }
                    translate(v = [box_w2-15, box_l2 - 1.5, casesplit - 5.4]) {
                            cube([8, 1.5, box_h-(casesplit-5.4)], center = false);
                    }
                    // extra support for shell
                    translate(v = [box_w1, box_l1, pcb_c+0.4]) {
                        cube([stud_w, 8, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w1, box_l2-10, pcb_c+0.4]) {
     	                   cube([stud_w, 10, box_h-pcb_c-1], center = false) ;
					 }
                    translate(v = [box_w1, box_l1+Chdmi_y+Chdmi_d+1.5, pcb_c+0.4]) {
                        cube([stud_w, 4, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w2-stud_w, box_l1, pcb_c+0.4]) {
                        cube([stud_w,10, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w2-stud_w, box_l1+Crca_y+Crca_d+1, pcb_c+0.4]) {
                        cube([stud_w, 4, box_h-pcb_c-1], center = false);
                    }
                }
            } // color
        } // end union
        // conn plate hole
        color(CASEcolor) {
        translate(v = [box_w1-5, box_l2-5, casesplit-3]) {
				rotate([0,90,0]) cylinder(r=0.5, h=10, $fn=100);
		 }
        translate(v = [box_w2-5, box_l1+5, casesplit-3]) {
				rotate([0,90,0]) cylinder(r=0.5, h=10, $fn=100);
		 }
        if (GPIOHOLE == 1 && bottom != 0) {
		     translate(v = [box_w2-5, box_l1+51, casesplit-GPIOsize]) cube([10,33.2,GPIOsize+0.1]);
        }
        if (GPIOHOLE == 2 && top != 0) {
		     translate(v = [box_w2-5, box_l1+51, casesplit-0.1]) cube([10,33.2,GPIOsize]);
        }
        }
        if (bottom != 0) {
            if (top == 0) {
                remove_top();
            } else {
                split_top();
            }
        }
        make_connholes();
    }
    if (bottom) {
        draw_pcbhold();
        if (DRAWpcb == 1)  make_pcb(alpha=0.5);
    }
} // end module

// Raspberry Pi Case
// Hans Harder 2012
//
// Warning: this is based on the Beta board dimensions...
//          so production models can be slightly different
//          for instance SD card holder height and USB socket dimensions
//
// Since all connectors stick out, case is split on HDMI height
// so the power and sdcard holder goes in first and then the pcb drops into place.
//
// v2: Adapted version after some suggestions from David...
//     removed feet, made both surface flat
// v3: Added fliptop option and smooth the corners of the box
// v4: Different levels of case split (make it 3d printable, thx David)
//     Looks strange but it fits...
//     Added frame mode (so no bottom and top deck)
//     Moved screw locations due to split and added some support structures
//     Unsure about 2nd screw location in combination with GPIO pins
// v5  relocated a lot of code in modules
//     SDslot location was not calculated correctly
// v6  Added pcb drawing
//     Added colors
//     Cut out better so there is no debris around
//     DRAwvars and options seperated, so it is easier to do 1 part
//     Make a low as possible case, let USB stick out
// v7  PCB options
//     Low level case optimisations
//     SD card location alterations
// v8  adapted pcb dimensions, board is really 56mm width
//     adapted support studs, moved some due to component location
//     components locations adapted
// v9  Added logo in seperate dxf file
//     Option added to put logo in middle or using whole deck
//     beautified code, kr style
// v10 Added logosunken and bottomsupport structures
//     Bottom supports are located where no components are located
//       so the pcb is not only supported from the sides
//     Well got my case, so based on what I see I changed:
//     case split level changed, should be better when printed on a reprap
//     Removed screwholes (far to small) for fastening top and added some more studs
//     Made frontstud a little thicker
// v11 Different splitlevel (more simple) on back
//     keep a little margin on back split, so that top and bottom always fit
//     added openlogo option
// v12 Different component locations/sizes
//     keep a little margin on component holes
//     pcbsize to 57.0 x 86.0   (actual it is 56.17 x 85.0)
//     made casestuds wider and added 2 minor holes for self tapping screws
// v13 skip this one.... :)
// v14 Production board measurements...
//	   small differences, sometimes components are soldered differently
//     keep more space
//     should fit like a glove...
// v15 moved the rca and snd a bit to get them more centered
//     Thanks to lincomatic at Thingiverse
//     Added option for GPIO side hole in bottom or top
//     Added showing GPIO pins with component drawing
//
// All parts are draw as default just disable the ones you don't want
DRAWfull        = 0;
DRAWtop         = 1;
DRAWbottom      = 1;
DRAWpcb         = 0;

GPIOHOLE        = 2;        // GPIO opening in :  1=bottom   2=top
GPIOsize        = 2;        // define height of gpiohole

// select how the case should look like
topframe    = false;        // if false, underneath values determines how
topholes    = true;
// ---- holes sizes
holeofs=2;
holesiz=3;
holestep=10;
noholes=6;					// 12 for top,  20 for bottom
holelen=24;
topmiddle   = false;

bottomframe = false;        // if false, underneath values determines how
bottomholes = false;
bottomscrew = false;
bottomsupport = false;         // Added extra support locations for pcb
bottomclick   = true;
bottompcb    = false;		    // just a pcb holder without a top

box_thickness = 2.0;            // minimum = 1.0
inside_h      = 12.5;           // 12.1 = lowprofile    16.5 is full height
pcb_h         = 5.6;            // height needed for SD holder and solder points of pcb
//pcb_h         = box_thickness+3.5;    // height needed for SD holder and solder points of pcb
// 4.1 = no deck, box_thickness+3.5 is with deck

// just some colors to see the difference
CASEcolor="Maroon";
CONNcolor="Silver";

// Define Raspberry Pi pcb dimensions in mm
inside_l = 86.0;                //85.00 is largest length reported, so a bit room on each side
inside_w = 57.2;                //56.17 is largest width  reported, so a bit room on each side
pcb_thickness = 1.7;

// Coordinates based on RJ45 corner = 0,0,0
// pcb connectors and locations. Based on Beta Board measurements of Gert and a real RPi

// Connectors
Crj45_x=2.0;			 //2.0
Crj45_y=-1;
Crj45_w=16.4;			// 15.4
Crj45_d=21.5;           //21.8
Crj45_h=13.8;

Cusb_x=24.5;            // 23.9
Cusb_y=-7.7;
Cusb_w=13.9;            // 13.3
Cusb_d=19.0;			// 17.2
Cusb_h=16.0;

Cpwr_x=3.25;				// 3.5 3.6
Cpwr_y=80.9;
Cpwr_w=8.8;				// 7.8 7.6
Cpwr_d=5.6;
Cpwr_h=2.6;

Csd_x=16.7;
Csd_y=inside_l-24.0;            // 30 mm is the length of a  sdcard
Csd_w=27.8;
Csd_d=29.0;
Csd_h=3.4;                  // under pcb

Chdmi_x=-1.2;
Chdmi_y=32.0;               // 32.4  if 15.1
Chdmi_w=11.4;
Chdmi_d=17.8;				  // 15.7 15.3
Chdmi_h=6.4;

Csnd_x=inside_w - 11.4;
Csnd_y=16.0;
Csnd_w=11.4;
Csnd_d=10.0;
Csnd_h=10.5;
Csnd_r=6.7;
Csnd_z=3.0;
Csnd_l=3.4;

Crca_x=inside_w - 10.0 - 2.1;
Crca_y=34.2;                // 34.6 was 35.2
Crca_w=10.0;
Crca_d=10.4;                 // 9.8
Crca_h=13.0;
Crca_r=8.6;
Crca_z=4;
Crca_l=10;                  // wild guess

pcb_c = pcb_h + pcb_thickness;            // component height
casesplit = pcb_c + Chdmi_h;              // split case at top of hdmi connector
echo("casesplit=",casesplit);
echo("case dimensions: w=",box_w," l=",box_l," h=",box_h);

// side stud sizes for supporting pcb
stud_w = 2;
stud_l = 4;

// calculate box size
box_l  = inside_l + (box_thickness * 2);
box_w  = inside_w + (box_thickness * 2);
box_h  = pcb_c + (pcb_thickness * 2) + inside_h;
box_w1 = box_thickness;
box_w2 = box_w - box_thickness;
box_l1 = box_thickness;
box_l2 = box_l - box_thickness;
box_wc = box_w / 2;                 // center width
box_lc = box_l / 2;                 // center length
box_t2 = box_thickness / 2.0;           // half box_thickness
middle = true;
// rounded corners
corner_radius = box_thickness*2;

// count no of items to draw
DRAWtotal = DRAWfull + DRAWtop + DRAWbottom;

// ====================================================== DRAW items
// if one  draw it centered
if (DRAWtotal == 1) {
    translate(v = [ -box_w/2, -box_l / 2, 0]) {
        if (DRAWfull ) {
           draw_case(0,1);
           translate(v=[0,0,0.2]) draw_case(1,0);
        }
        if (DRAWtop   ) {
            rotate(a=[0,180,0]) translate(v=[-box_w,0,-box_h]) draw_case(0,1);
        }
        if (DRAWbottom) draw_case(1,0);
    }
} else {
// draw each one on there one location
    if (DRAWfull)   {
        translate(v = [ box_w+20, -box_l / 2, 0]) {
            draw_case(1,0);
            translate(v=[0,0,0.2]) draw_case(0,1);
        }
    }
    if (DRAWbottom) {
        translate(v = [ 5, 5, 0]) draw_case(1,0);
    }
    if (DRAWtop)    {
        translate(v = [ - 5,  5, box_h])  rotate(a=[0,180,0]) draw_case(0,1);
    }
}

// ======================================================= END of draw
// Module sections

module make_deckholes(no,w,d,step) {
for ( i = [0 : 1 : no - 1] ) {
        translate(v=[w/2,(i*step)+(step/2),box_thickness/2]) cube([w,d, box_thickness+18], center=true);
    }
}

// create a deck or insert
module make_deck(w,d,z,hole_no,hole_size,hole_step) {
    hole_w=(w - 12) / 2;      // change 12 for middle piece size
    ofs1=4;
    ofs2=w - ofs1 - hole_w;
    hole_ofs= ((d - hole_no*hole_step) / 2) - box_thickness/2;
    translate(v = [(box_w-w)/2, (box_l-d)/2,z]) {
        color(CASEcolor) {
            echo("deck : z=",z," w=",w+0.01," d=",d+0.01);
            difference() {
                cube([w, d, box_thickness], center = false);
                if (top && holes && hole_size>0) {
                    translate(v=[-1,hole_ofs+holeofs,-0.1]) make_deckholes(noholes,holelen,holesiz,holestep);
                    translate(v=[w/2-2,hole_ofs+holeofs,-0.1]) make_deckholes(noholes,holelen,holesiz,holestep);
                }
                if (screwholes) {
                    // --- 2x screw holes in bottom for mounting
                    translate(v = [w/2 - 4, 10-4, -1]) cube([8, 3, 5], center = false);
                    translate(v = [w/2 - 4, 10-3, -1]) cylinder(r=3, h=8, $fn=100, center=true);
                    // 2nd screw hole
                    translate(v = [w/2 - 3, d - 10 +3, -1]) cube([8, 3, 5], center = false);
                    translate(v = [w/2 + 4, d - 10 +4, -1]) cylinder(r=3, h=8, $fn=100);
                    if (!holes) {
                        // middle screw hole
                        translate(v = [w/2 - 4, d/2    , -1]) cube([8, 2, 5], center = false);
                        translate(v = [w/2 - 4, d/2 + 1, -1]) cylinder(r=2, h=8, $fn=100);
                    }
                }
                if (holes && !top) {
                    translate(v=[(w-hole_w)/2,holeofs,-0.1]) make_deckholes(noholes,hole_w,holesiz,holestep);
                }
            }
            color(CASEcolor) {
                if (top && holes) {
                    translate(v = [w/2-box_thickness,12,0]) cube([4,d-13, box_thickness], center = false);
                }
                if (middle) {
                    // --- solid area for sticker
                    translate(v = [w/2-10,d/2-5-box_thickness/2,0]) {
                        cube([20,20, box_thickness], center = false);
                    }
                }
            }
        }
    }
}

module rounded_corner(x,y,rx,ry,cx,cy) {
    translate(v = [x, y, -1]) {
        difference() {
            translate(v=[rx,ry,0])    cube([corner_radius,corner_radius,box_h+2], center=false);
            translate(v=[cx, cy, -1]) cylinder(r=corner_radius, h=box_h+2, $fn=100);
        }
    }
}

module make_topcomponents() {
    color(CONNcolor) translate(v=[box_w1,box_l1,pcb_c]) {
        translate(v=[Crj45_x,Crj45_y,0]) cube([Crj45_w,Crj45_d,Crj45_h],center=false);
        translate(v=[Cusb_x,Cusb_y,0])   cube([Cusb_w,Cusb_d,Cusb_h],center=false);
        translate(v=[Cpwr_x,Cpwr_y,0])   cube([Cpwr_w,Cpwr_d,Cpwr_h],center=false);
        translate(v=[Chdmi_x,Chdmi_y,0]) cube([Chdmi_w,Chdmi_d,Chdmi_h],center=false);

        //SND
        translate(v=[Csnd_x,Csnd_y,0]) cube([Csnd_w+0.1,Csnd_d,Csnd_h],center=false);
        translate(v=[Csnd_x+Csnd_w,Csnd_y+Csnd_d/2,Csnd_z+Csnd_r/2]) rotate(a=90,v=[0,1,0]) cylinder(r=Csnd_r/2, h=Csnd_l, $fn=100);

        //RCA
        translate(v=[Crca_x,Crca_y,0]) cube([Crca_w+0.2,Crca_d,Crca_h],center=false);
        translate(v=[Crca_x+Crca_w,Crca_y+Crca_d/2,Crca_z+Crca_r/2]) rotate(a=90,v=[0,1,0]) cylinder(r=Crca_r/2, h=Crca_l+0.1, $fn=100);
    }
    for ( i = [0 : 1 : 12] ) {
        color("black") translate(v=[box_w2-6.6,box_l2-1-34+(i*2.54),pcb_c]) cube([5.08,2.53,2.5]);
        color("Gainsboro") translate(v=[box_w2-6.6+0.97,box_l2-1-34+(i*2.54)+0.95,pcb_c-3])  cube([0.6,0.6,11.5]);
        color("Gainsboro") translate(v=[box_w2-6.6+3.61,box_l2-1-34+(i*2.54)+0.95,pcb_c-3])  cube([0.6,0.6,11.5]);

    }
}

module make_connholes() {
    // =================================== cut outs, offset from 0,0
    //RJ45:    2mm offset, 15.5mm width, 13.1mm height
    set_cutout(box_w1+Crj45_x,box_l1+Crj45_y-3,pcb_c,   Crj45_w+0.1,Crj45_d+3,Crj45_h);
    //usb:  23.9mm offset, 13.3mm width, 15.4mm height
    set_cutout(box_w1+Cusb_x,box_l1+Cusb_y,pcb_c,   Cusb_w,Cusb_d,Cusb_h+0.1);

    //power: 3.4mm offset,    8mm width,    3mm height
    set_cutout(box_w1+Cpwr_x,box_l1+Cpwr_y,pcb_c,   Cpwr_w,Cpwr_d+4,Cpwr_h+0.01);
    //sd:   15mm offset,   28mm width,    3.5mm height under pcb
    if (pcb_h >= (Csd_h+1.5) ) {
        set_cutout(box_w1+Csd_x-0.3,box_l2-28,pcb_h-Csd_h,Csd_w+0.6,box_thickness+30,Csd_h+0.1);
    } else {
        set_cutout(box_w1+Csd_x-0.3,box_l2-32,pcb_h-20,Csd_w+0.6,40,20.01);
    }
    //HDMI: 32.9mm offset,  15.3mm width,   6.3mm height
    set_cutoutv(box_w1+Chdmi_x-3,box_l1+Chdmi_y,pcb_c,    Chdmi_w+3.1,Chdmi_d,Chdmi_h+0.1);

    // snd:   14mm offset,  12mm width,   8.2 mm height
    set_cutout(box_w1+Csnd_x,box_l1+Csnd_y,pcb_c+2,    Csnd_w+7,Csnd_d,Csnd_h-2);

    // RCA:   35mm offset,  10mm width     10mm height
    translate(v=[box_w1+Crca_x+Crca_w,box_l1+Crca_y+Crca_d/2,pcb_c+Crca_z+Crca_r/2]) {
        rotate(a=90,v=[0,1,0]) cylinder(r=Crca_r/2+1, h=Crca_l, $fn=100);
    }
    translate(v=[box_w1+Crca_x+Crca_w,box_l1+Crca_y+(Crca_d-Crca_r)/2-1,pcb_c+Crca_z-1]) {
        cube([5,Crca_r+2,Crca_r/2+1]);
    }
}

module make_pcb() {
    translate(v=[box_w1,box_l1,pcb_h]) {
        color("darkgreen") cube([inside_w,inside_l,pcb_thickness], center=false);
    }
    color(CONNcolor) {
        translate(v=[box_w1+Csd_x,box_l1+Csd_y,pcb_h-Csd_h]) cube([Csd_w,Csd_d,Csd_h],center=false);
    }
    make_topcomponents();
}

// put extra supports on free spaces, used beta board image
module make_supports() {
    if (!bottomframe) {
        translate(v=[box_w1+10 ,box_l1+28,0.1]) cube([3, 2,pcb_h-0.1]);
        translate(v=[box_w2-7.5,box_l1+28,0.1]) cube([3, 2,pcb_h-0.1]);

        translate(v=[box_w1+7  ,box_l2-35,0.1])  cube([5, 5,pcb_h-0.1]);
        translate(v=[box_w2-13 ,box_l2-35,0.1])  cube([5, 5,pcb_h-0.1]);

        translate(v=[box_w1+12 ,box_l2-16,0.1])  cube([1.5 ,5,pcb_h-0.1]);
        translate(v=[box_w2-9  ,box_l2-16,0.1])  cube([1.5 ,5,pcb_h-0.1]);
    }
}

// width,depth,height,boxthickness,ledgethickness
module make_case(w,d,h,bt,lt) {
    dt=bt+lt;    // box+ledge thickness
    bt2=bt+bt;    // 2x box thickness
    // Now we just substract the shape we have created in the four corners
    color(CASEcolor) difference() {
        cube([w,d,h], center=false);
        if (rounded) {
            rounded_corner(-0.1,d+0.1, 0             ,-corner_radius,  corner_radius,-corner_radius);
            rounded_corner(w+0.1,d+0.1, -corner_radius,-corner_radius, -corner_radius,-corner_radius);
            rounded_corner(w+0.1,-0.1, -corner_radius,0             , -corner_radius, corner_radius);
            rounded_corner(-0.1,-0.1, 0             ,0             ,  corner_radius, corner_radius);
        }
        // empty inside, but keep a ledge for strength
        translate(v = [bt, bt, dt])   cube([w-bt2, d-bt2, h-(dt*2)], center = false);
        translate(v = [dt,dt,bt])     cube([w-(dt*2), d-(dt*2), h-bt2], center = false);
        // remove bottom and top deck
        translate(v = [box_thickness+2, box_thickness+5,-2]) {
            cube([inside_w-4, inside_l-10, box_h+4], center = false);
        }
    }
    if (!topframe) {
        make_deck(inside_w-4,inside_l-4,box_h-box_thickness, 12,3,5, holes=topholes,middle=topmiddle,screwholes=false,top=true);
    }
    if (!bottomframe) {
        make_deck(inside_w-4,inside_l-4,0, 12,3,5, holes=bottomholes,screwholes=bottomscrew,middle=false,top=false);
        if (bottomsupport) {
            make_supports();
        }
    }
}

module make_stud(x,y,z,w,h,l) {
    translate(v = [x, y, z]) cube([w, l, h], center = false);
}

module set_cutout(x,y,z,w,l,h) {
    color(CASEcolor)    translate(v = [x+(w/2), y+(l/2), z+(h/2)]) cube([w+0.4, l+0.2, h+0.2], center = true);
}

module set_cutoutv(x,y,z,w,l,h) {
    color(CASEcolor)    translate(v = [x+(w/2), y+(l/2), z+(h/2)]) cube([w+0.2, l+0.4, h+0.2], center = true);
}

module draw_pcbhold() {
  if (bottomclick) {
    color(CASEcolor) {
        translate(v=[0  ,22,2]) cube([box_thickness,4,pcb_c]);
        translate(v=[box_w1-0.1  ,22.5,pcb_c+0.1]) {
            difference() {
                cube([1, 3,2]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[0  ,60.5,2]) cube([box_thickness,5,pcb_c]);
        translate(v=[box_w1-0.1  ,61.5,pcb_c+0.1]) {
            difference() {
                cube([1,3,2]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[box_w2,29.5,2]) cube([box_thickness,4,pcb_c]);
        translate(v=[box_w2+0.1  ,30+3,pcb_c+0.1]) {
            rotate(a=180, v=[0,0,1]) difference() {
                cube([1, 3,3]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
        translate(v=[box_w2,60.5,2]) cube([box_thickness,5,pcb_c]);
        translate(v=[box_w2+0.1  ,61+3.5,pcb_c+0.1]) {
            rotate(a=180, v=[0,0,1]) difference() {
                cube([1,3,3]);
                translate(v=[1,-0.1,0])  rotate(a=-30, v=[0,1,0])  cube([1.6, 3.2, 4]);
            }
        }
    }
  }
}

module split_top() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w1+Csd_x - 12;   // min 16.5+28
    split4=box_w2 - 7;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, casesplit-0.2])    cube([box_w+2, 21, 0.4], center = false);
    // back on 3 different levels
    translate(v = [-1,  20, casesplit-0.2])    cube([split1+1     , box_l, 0.4], center = false);
    translate(v = [split2, 20, pcb_c-0.2])     cube([split3-split2, box_l, 0.4], center = false);
    translate(v = [split3, 20, pcb_h-0.2])     cube([split4-split3, box_l, 0.4], center = false);
    translate(v = [split4, 20, casesplit-0.2]) cube([20           , box_l, 0.4], center = false);
}

module remove_top() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w2 - 12;
    possd1=box_w1 + Csd_x - 0.3;
    widesd1=Csd_w+0.6;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, casesplit])    cube([100,100, box_h], center = false);
    // back on 3 different levels
    translate(v = [split1, 20, pcb_c])     cube([split3-split1, box_l, box_h], center = false);
    translate(v = [possd1, 60, pcb_h-0.1])  cube([widesd1, box_l, 2], center = false);
//    translate(v = [split1, 20, pcb_c])     cube([20, box_l, box_h], center = false);
//    translate(v = [split2, 20, pcb_h])     cube([split3-split2, box_l, box_h], center = false);
  if (bottompcb) {
    translate(v = [-1,  -1, pcb_c])    cube([100,100, box_h], center = false);
  }
}

module remove_bottom() {
    split1=box_w1+Cpwr_x;
    split2=split1+Cpwr_w;
    split3=box_w2 - 12.1;
    possd1=box_w1 + Csd_x - 0.2;
    widesd1=Csd_w+0.6;
    // Different splitlevels for the shells
    // 1st half on split level
    translate(v = [-1,  -1, -1])    cube([box_w+2, box_l-6, casesplit+1], center = false);
    // back on 3 different levels
    translate(v = [-1, 20, -1])     cube([box_w+2  , box_l, pcb_c+1.1], center = false);
    translate(v = [-1, 20, -1])     cube([split1+1.1 , box_l, casesplit+1], center = false);
    translate(v = [-1, 20, -1])     cube([split2+1.1 , box_l, pcb_c+Cpwr_h+1.1], center = false);
    translate(v = [split3, 20, -1]) cube([20       , box_l, casesplit+1], center = false);
}

module draw_case(bottom, top) {
    difference() {
        union() {
            // make empty case
            difference() {
                make_case(box_w,box_l,box_h, box_thickness,stud_w, rounded=true);
                if (top != 0 && bottom == 0)    remove_bottom();
                if (top == 0 && bottom != 0)    remove_top();
            }
            color(CASEcolor) {
                if (bottom != 0 ) {
                    // add bottom studs for pcb
                    // add bottom studs for pcb
                    make_stud(box_w1       , box_l1         , 0, 4,pcb_h,4);      // rj45
                    make_stud(box_w1       , box_lc-stud_l/2, 0, stud_w,pcb_h,stud_l);      // hdmi
                    make_stud(box_w1, box_lc/2, 0, 4,pcb_h,stud_l);
                    make_stud(box_w1, box_lc+(box_lc/2)-5, 0, 4,pcb_h,stud_l);

                    make_stud(box_w1, box_l2-stud_l-8, 0, stud_w,pcb_h,stud_l);        // BEFORE pwr
                    make_stud(box_w2-stud_w, box_l1         , 0, stud_w,pcb_h,stud_l);      // leds
                    make_stud(box_w2-4, box_lc-stud_l/2, 0, 4,pcb_h,stud_l);                // RCA
                    make_stud(box_w2-stud_w, box_l2-stud_l  , 0, stud_w,pcb_h,stud_l);      // GPIO

                    translate(v=[box_w1+Cusb_x-6,box_l1,1])  cube([3.0, 4,pcb_h-1.1]);
                    translate(v=[box_w2-15.8    ,box_l1,1])  cube([3.0, 4,pcb_h-1.1]);

                    draw_pcbhold();
                }

                if (top != 0) {
                    // --- screw connection plates
                    translate(v = [box_w1 + Crj45_x+Crj45_w, box_l1, casesplit - 5.4]) {
                        cube([10, 3, box_h-(casesplit-5.4)], center = false);
                    }
                    translate(v = [box_w2-15, box_l2 - 1.5, casesplit - 5.4]) {
                            cube([8, 1.5, box_h-(casesplit-5.4)], center = false);
                    }
                    // extra support for shell
                    translate(v = [box_w1, box_l1, pcb_c+0.4]) {
                        cube([stud_w, 8, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w1, box_l2-10, pcb_c+0.4]) {
     	                   cube([stud_w, 10, box_h-pcb_c-1], center = false) ;
					 }
                    translate(v = [box_w1, box_l1+Chdmi_y+Chdmi_d+1.5, pcb_c+0.4]) {
                        cube([stud_w, 4, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w2-stud_w, box_l1, pcb_c+0.4]) {
                        cube([stud_w,10, box_h-pcb_c-1], center = false);
                    }
                    translate(v = [box_w2-stud_w, box_l1+Crca_y+Crca_d+1, pcb_c+0.4]) {
                        cube([stud_w, 4, box_h-pcb_c-1], center = false);
                    }
                }
            } // color
        } // end union
        // conn plate hole
        color(CASEcolor) {
        translate(v = [box_w1-5, box_l2-5, casesplit-3]) {
				rotate([0,90,0]) cylinder(r=0.5, h=10, $fn=100);
		 }
        translate(v = [box_w2-5, box_l1+5, casesplit-3]) {
				rotate([0,90,0]) cylinder(r=0.5, h=10, $fn=100);
		 }
        if (GPIOHOLE == 1 && bottom != 0) {
		     translate(v = [box_w2-5, box_l1+51, casesplit-GPIOsize]) cube([10,33.2,GPIOsize+0.1]);
        }
        if (GPIOHOLE == 2 && top != 0) {
		     translate(v = [box_w2-5, box_l1+51, casesplit-0.1]) cube([10,33.2,GPIOsize]);
        }
        }
        if (bottom != 0) {
            if (top == 0) {
                remove_top();
            } else {
                split_top();
            }
        }
        make_connholes();
    }
    if (bottom) {
        draw_pcbhold();
        if (DRAWpcb == 1)  make_pcb();
    }
} // end module


Mask panel improvements.

Mask panel improvements.

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014 - Nov, 2015
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.

// 0.100" Acrylic:
acrylic_thickness = 2.4;
    // 2.4mm = 0.094" (looks good based on cut test piece for acrylic slotting into itself)

// 1/8" Hardboard:
hardboard_thickness = 3.1;
    // 2.8mm = 0.110"
    //   * looked good based on cut test piece for hardboard slotting into hardboard
    //   * 2015-03-06: Hanging supports didn't fit into cutouts (or did only with lots of force)
    // 3.1mm for some breathing room

// Assign materials: window/back wall and everything else
//window_thickness = acrylic_thickness;
window_thickness = hardboard_thickness;
thickness = hardboard_thickness;

// Interior box dimensions
// The variables are used below to control placement of **centerpoints** centerpoints of walls,
// so material thickness is added to account for that.
width = 290 + thickness;    // x = 29cm wall-to-wall
depth = 348 + thickness;    // y = 34.8cm to accomodate 34.8cm tank length
i_height = 190 + thickness; // z = 19cm to accomodate 16cm tank height plus cover
                            // (i_height because 'height' is used for height of entire box)

// amount faces extend past each other at corners
overhang = 15;

// amount horizontal support tabs extend past side supports (technically, it will go this distance minus thickness/2)
outset = thickness+2;

// tank base plate
base_height = overhang/2;

// create height var to account for raised base
height = i_height + base_height;

// hanging support thickness and drop (distance it "sits down" after in place)
support_w = 10;
support_drop = support_w/2;

// x-position of mask piece inside box
mask_offset = 74;
mask_loc = width - mask_offset - thickness/2;  // accounting for thickness of panel
// dimensions for mask view opening
view_opening_right = 80;
view_opening_bottom = 28;
view_opening_width = 190;
view_opening_height = 91;

// position of rpi and related parts
rpi_ypos = depth/2 + 60;

// for slight offsets/tweaks
epsilon = 1;

// set precision of all arcs/spheres/cylinders/etc.
$fn = 50;

// vars to control projection for DXF export (see makefile)
if (DXF_TOP) {
    projection() top_cover();
} else if (DXF_BOTTOM) {
    projection() tank_base();
} else if (DXF_SIDE1) {
    projection() rotate(a=[90,0,0]) side(y=0);
} else if (DXF_SIDE2) {
    projection() rotate(a=[90,0,0]) side(y=depth);
} else if (DXF_END1) {
    projection() rotate(a=[0,90,0]) vert_face(x=0);
} else if (DXF_END2) {
    projection() rotate(a=[0,90,0]) vert_face(x=width);
} else if (DXF_MASK) {
    projection() rotate(a=[0,90,0]) mask(x=mask_loc);
} else if (DXF_CAMERA_SUPPORT) {
    projection() rotate(a=[90,0,0]) camera_supports(justone=true);
} else if (DXF_RPI_SUPPORT) {
    projection() rotate(a=[90,0,0]) rpi_support();
}
else {
    // 3D model
    // components to include (comment out unwanted)
    //vert_face(x=0);      // "near face, transparent for monitor
    //vert_face(x=width);  // "far" face, with camera, rpi, etc.
    mask(x=mask_loc);
    //side(y=0);
    side(y=depth);
    tank_base();
/*
    camera_supports(x=width, y=depth/2, z=height/2);
    rpi_support(x=width, y=rpi_ypos-10, z=height/2);
    mock_rpi(x=width, y=rpi_ypos, z=height/2);
    top_cover();
*/
}

//////////////////////////////////////////////////////////////////
// Module definitions
//

module mask(x) {
    difference() {
        vert_face_base(x, top_offset=thickness, bottom_offset=base_height-thickness);
        side(y=0);
        side(y=depth);
        translate([x-thickness/2, -overhang, 0]) {
            translate([0, 0, 0])
                rounded_truncation(width=overhang-thickness/2, up=false);
            translate([0, depth+overhang+thickness/2, 0])
                rounded_truncation(width=overhang-thickness/2, up=false);
        }
        // opening for tank view
        translate([0,view_opening_right+thickness/2, view_opening_bottom+base_height+thickness/2])
            cube([width, view_opening_width, view_opening_height]);
        // opening for wires
        translate([0, thickness, base_height+thickness])
        rotate(a=[0,90,0])
            cylinder(r=10, h=width);
        // tabs for rigidity w/ bottom panel
        cutouts(4,depth-thickness,outset*2,rot=[-90,0,90],trans=[x+thickness/2,(depth-thickness)/2,base_height+thickness/2]);
    }
}

module vert_face(x=0) {
    difference() {
        if (x == 0) {
            vert_face_base(0, window_thickness);
        }
        else {
            vert_face_base(x);
        }
        camera_opening();
        // round=false so we get the full width of the piece in the cutout, not reduced because we hit the rounded corner
        camera_supports(x=width+thickness*2, y=depth/2, z=height/2+support_drop, round=false);
        rpi_support(x=width+thickness*2, y=rpi_ypos-10, z=height/2+support_drop, round=false);
        wire_opening();
        // CAUTION: OpenSCAD won't let me make a projection of vert_face(x=0)
        //   if tank_base is put after side(y=depth) here... bug.  :(
        tank_base();
        top_cover();
        side(y=0);
        side(y=depth);
        translate([x-thickness/2, -overhang, 0]) {
            translate([0, depth+overhang+thickness/2, 3/4*height])
                rounded_truncation(width=overhang-thickness/2, up=true);
            translate([0, 0, 3/4*height])
                rounded_truncation(width=overhang-thickness/2, up=true);
        }
    }
}

module vert_face_base(x, face_thickness=thickness, top_offset=0, bottom_offset=0) {
    translate([x-face_thickness/2, -overhang, bottom_offset])
        cube([face_thickness,depth+overhang*2,height-top_offset-bottom_offset]);
}

module rounded_truncation(width, up, rot=[0,0,0]) {
    truncation_height=height/4;
    rotate(a=rot)
    difference() {
        translate([-50,-epsilon,0])
            cube([100, width+2*epsilon, truncation_height]);
        if (up) {
            translate([-50, width/2, 0])
            rotate(a=[0, 90, 0])
                cylinder(d=width, h=100);
        }
        else {
            translate([-50, width/2, truncation_height])
            rotate(a=[0, 90, 0])
                cylinder(d=width, h=100);
        }
    }
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module camera_supports(x, y, z, justone=false, round=true) {
    spacing = 20;
    out = 11;
    up = 36;
    hanging_support(x, y + spacing/2, z, out, up, round=round);
    if (!justone) {
        hanging_support(x, y - spacing/2, z, out, up, round=round);
    }
}

module rpi_support(x, y, z, round=true) {
    hanging_support(x, y, z, out=4, up=85, round=round);
}

module hanging_support(x, y, z, out, up, round=true) {
    inner_w = out+thickness;
    inner_h = up;
    color("Red", alpha=0.5)
    translate([x,y,z])
    // push inner opening up against vert face
    translate([out/2,0,0])
    difference() {
        if (round) {
            rounded_rect(inner_w+support_w*2, thickness, inner_h+support_w*2, center=true, radius=support_w);
        }
        else {
            cube([inner_w+support_w*2, thickness, inner_h+support_w*2], center=true);
        }
        // cutout for object
        cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-(inner_w/2+support_w/2),0,-support_drop/2])
            cube([support_w+2*epsilon, thickness*2, inner_h-support_drop], center=true);
        // bottom cutout
        translate([-out/2,0,-(inner_h/2+support_w-support_drop/2)])
            cube([thickness, thickness*2, support_drop], center=true);
    }
}

// rounded corners in x,z directions
module rounded_rect(x,y,z, center, radius) {
    difference() {
        cube([x,y,z], center);

        translate([x/2-radius, 50, z/2-radius])
        rotate(a=[90,0,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([-x/2+radius, 50, z/2-radius])
        rotate(a=[90,-90,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([x/2-radius, 50, -z/2+radius])
        rotate(a=[90,90,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([-x/2+radius, 50, -z/2+radius])
        rotate(a=[90,180,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([-outset,-outset,height-thickness])
    difference() {
        cube([width+outset*2,depth+outset*2,thickness]);
        cutouts(5,width-thickness,outset,rot=0,trans=[width/2+outset,0,0]);
        cutouts(5,width-thickness,outset,rot=180,trans=[width/2+outset,depth+outset*2,0]);
        cutouts(5,depth-thickness,outset,rot=-90,trans=[0,depth/2+outset,0]);
        cutouts(5,depth-thickness,outset,rot=90,trans=[width+outset*2,depth/2+outset,0]);
    }
}

module tank_base() {
    difference() {
        translate([-outset,thickness/2,base_height])
            difference() {
                cube([width+outset*2, depth-thickness, thickness]);
                cutouts(5,depth,outset,rot=-90,trans=[0,(depth-thickness)/2,0]);
                cutouts(5,depth,outset,rot=90,trans=[width+outset*2,(depth-thickness)/2,0]);
            }
        mask(x=mask_loc);
    }
}

module cutouts(num, width, outset, rot, trans) {
    w = width / ((num-1) * 2);
    translate(trans)
    rotate([0,0,1], a=rot)
    for (i = [0 : num-1]) {
        translate([-width/2 - w/2 + i*2*w, -thickness/2, -thickness/2])
            cube([w, outset+thickness, thickness*2]);
    }
}

module wire_opening() {
    translate([width, rpi_ypos-35, overhang+20])
    scale([1,2,1])
    rotate(a=[0,90,0])
        cylinder(d=12, h=thickness+epsilon, center=true);
}

module side(y=0) {
    difference() {
        side_base(y);
        translate([0,0,height/2])
        scale([1,1,0.5])
            vert_face_base(x=mask_loc);
        scale([1,1,0.5])
            vert_face_base(0, window_thickness);
        scale([1,1,0.5])
            vert_face_base(width);
        top_cover();
    }
}

module side_base(y) {
    translate([-overhang,y-thickness/2,overhang/2])
    difference() {
        cube([width+overhang*2, thickness, height-overhang/2]);
        translate([width+overhang+thickness/2, 0, 0])
            rounded_truncation(width=overhang-thickness/2, up=false, rot=[0,0,-90]);
        translate([0, 0, 0])
            rounded_truncation(width=overhang-window_thickness/2, up=false, rot=[0,0,-90]);
    }
}

module mock_rpi(x, y, z) {
    color("Blue", alpha=0.5)
    translate([x+thickness, y, z])
        rotate(a=[0,-90,180])
            translate([-85/2, -56/2, 0])
                union() {
                    cube([85, 56, 2]);
                    // USB1
                    translate([67, 41, 2])
                        cube([20, 12, 12]);
                    // USB2
                    translate([67, 23, 2])
                        cube([20, 12, 12]);
                }
}

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014 - Nov, 2015
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.

// 0.100" Acrylic:
acrylic_thickness = 2.4;
    // 2.4mm = 0.094" (looks good based on cut test piece for acrylic slotting into itself)

// 1/8" Hardboard:
hardboard_thickness = 3.1;
    // 2.8mm = 0.110"
    //   * looked good based on cut test piece for hardboard slotting into hardboard
    //   * 2015-03-06: Hanging supports didn't fit into cutouts (or did only with lots of force)
    // 3.1mm for some breathing room

// Assign materials: window/back wall and everything else
//window_thickness = acrylic_thickness;
window_thickness = hardboard_thickness;
thickness = hardboard_thickness;

// Interior box dimensions
// The variables are used below to control placement of **centerpoints** centerpoints of walls,
// so material thickness is added to account for that.
width = 290 + thickness;    // x = 29cm wall-to-wall
depth = 348 + thickness;    // y = 34.8cm to accomodate 34.8cm tank length
i_height = 190 + thickness; // z = 19cm to accomodate 16cm tank height plus cover
                            // (i_height because 'height' is used for height of entire box)

// amount faces extend past each other at corners
overhang = 15;

// amount horizontal support tabs extend past side supports (technically, it will go this distance minus thickness/2)
outset = thickness+2;

// tank base plate
base_height = overhang/2;

// create height var to account for raised base
height = i_height + base_height;

// hanging support thickness and drop (distance it "sits down" after in place)
support_w = 10;
support_drop = support_w/2;

// x-position of mask piece inside box
mask_offset = 74;
mask_loc = width - mask_offset - thickness/2;  // accounting for thickness of panel
// dimensions for mask view opening
view_opening_right = 80;
view_opening_bottom = 28;
view_opening_width = 190;
view_opening_height = 91;

// position of rpi and related parts
rpi_ypos = depth/2 + 60;

// for slight offsets/tweaks
epsilon = 1;

// set precision of all arcs/spheres/cylinders/etc.
$fn = 50;

// vars to control projection for DXF export (see makefile)
if (DXF_TOP) {
    projection() top_cover();
} else if (DXF_BOTTOM) {
    projection() tank_base();
} else if (DXF_SIDE1) {
    projection() rotate(a=[90,0,0]) side(y=0);
} else if (DXF_SIDE2) {
    projection() rotate(a=[90,0,0]) side(y=depth);
} else if (DXF_END1) {
    projection() rotate(a=[0,90,0]) vert_face(x=0);
} else if (DXF_END2) {
    projection() rotate(a=[0,90,0]) vert_face(x=width);
} else if (DXF_MASK) {
    projection() rotate(a=[0,90,0]) mask(x=mask_loc);
} else if (DXF_CAMERA_SUPPORT) {
    projection() rotate(a=[90,0,0]) camera_supports(justone=true);
} else if (DXF_RPI_SUPPORT) {
    projection() rotate(a=[90,0,0]) rpi_support();
}
else {
    // 3D model
    // components to include (comment out unwanted)
    //vert_face(x=0);      // "near face, transparent for monitor
    //vert_face(x=width);  // "far" face, with camera, rpi, etc.
    mask(x=mask_loc);
    //side(y=0);
    side(y=depth);
    tank_base();
/*
    camera_supports(x=width, y=depth/2, z=height/2);
    rpi_support(x=width, y=rpi_ypos-10, z=height/2);
    mock_rpi(x=width, y=rpi_ypos, z=height/2);
    top_cover();
*/
}

//////////////////////////////////////////////////////////////////
// Module definitions
//

module mask(x) {
    difference() {
        vert_face_base(x, top_offset=outset, bottom_offset=base_height+thickness);
        side(y=0);
        side(y=depth);
        translate([x-thickness/2, -overhang, 0]) {
            translate([0, 0, 0])
                rounded_truncation(width=overhang-thickness/2, up=false);
            translate([0, depth+overhang+thickness/2, 0])
                rounded_truncation(width=overhang-thickness/2, up=false);
        }
        // opening for tank view
        translate([0,view_opening_right+thickness/2, view_opening_bottom+base_height+thickness/2])
            cube([width, view_opening_width, view_opening_height]);
        // opening for wires
        translate([0, thickness, base_height+thickness])
        rotate(a=[0,90,0])
            cylinder(r=10, h=width);
    }
}

module vert_face(x=0) {
    difference() {
        if (x == 0) {
            vert_face_base(0, window_thickness);
        }
        else {
            vert_face_base(x);
        }
        camera_opening();
        // round=false so we get the full width of the piece in the cutout, not reduced because we hit the rounded corner
        camera_supports(x=width+thickness*2, y=depth/2, z=height/2+support_drop, round=false);
        rpi_support(x=width+thickness*2, y=rpi_ypos-10, z=height/2+support_drop, round=false);
        wire_opening();
        // CAUTION: OpenSCAD won't let me make a projection of vert_face(x=0)
        //   if tank_base is put after side(y=depth) here... bug.  :(
        tank_base();
        top_cover();
        side(y=0);
        side(y=depth);
        translate([x-thickness/2, -overhang, 0]) {
            translate([0, depth+overhang+thickness/2, 3/4*height])
                rounded_truncation(width=overhang-thickness/2, up=true);
            translate([0, 0, 3/4*height])
                rounded_truncation(width=overhang-thickness/2, up=true);
        }
    }
}

module vert_face_base(x, face_thickness=thickness, top_offset=0, bottom_offset=0) {
    translate([x-face_thickness/2, -overhang, bottom_offset])
        cube([face_thickness,depth+overhang*2,height-top_offset-bottom_offset]);
}

module rounded_truncation(width, up, rot=[0,0,0]) {
    truncation_height=height/4;
    rotate(a=rot)
    difference() {
        translate([-50,-epsilon,0])
            cube([100, width+2*epsilon, truncation_height]);
        if (up) {
            translate([-50, width/2, 0])
            rotate(a=[0, 90, 0])
                cylinder(d=width, h=100);
        }
        else {
            translate([-50, width/2, truncation_height])
            rotate(a=[0, 90, 0])
                cylinder(d=width, h=100);
        }
    }
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module camera_supports(x, y, z, justone=false, round=true) {
    spacing = 20;
    out = 11;
    up = 36;
    hanging_support(x, y + spacing/2, z, out, up, round=round);
    if (!justone) {
        hanging_support(x, y - spacing/2, z, out, up, round=round);
    }
}

module rpi_support(x, y, z, round=true) {
    hanging_support(x, y, z, out=4, up=85, round=round);
}

module hanging_support(x, y, z, out, up, round=true) {
    inner_w = out+thickness;
    inner_h = up;
    color("Red", alpha=0.5)
    translate([x,y,z])
    // push inner opening up against vert face
    translate([out/2,0,0])
    difference() {
        if (round) {
            rounded_rect(inner_w+support_w*2, thickness, inner_h+support_w*2, center=true, radius=support_w);
        }
        else {
            cube([inner_w+support_w*2, thickness, inner_h+support_w*2], center=true);
        }
        // cutout for object
        cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-(inner_w/2+support_w/2),0,-support_drop/2])
            cube([support_w+2*epsilon, thickness*2, inner_h-support_drop], center=true);
        // bottom cutout
        translate([-out/2,0,-(inner_h/2+support_w-support_drop/2)])
            cube([thickness, thickness*2, support_drop], center=true);
    }
}

// rounded corners in x,z directions
module rounded_rect(x,y,z, center, radius) {
    difference() {
        cube([x,y,z], center);

        translate([x/2-radius, 50, z/2-radius])
        rotate(a=[90,0,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([-x/2+radius, 50, z/2-radius])
        rotate(a=[90,-90,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([x/2-radius, 50, -z/2+radius])
        rotate(a=[90,90,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
        translate([-x/2+radius, 50, -z/2+radius])
        rotate(a=[90,180,0])
        difference() {
            cube([radius,radius,100]);
            cylinder(r=radius, h=100);
        }
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([-outset,-outset,height-thickness])
    difference() {
        cube([width+outset*2,depth+outset*2,thickness]);
        cutouts(5,width-thickness,outset,rot=0,trans=[width/2+outset,0,0]);
        cutouts(5,width-thickness,outset,rot=180,trans=[width/2+outset,depth+outset*2,0]);
        cutouts(5,depth-thickness,outset,rot=-90,trans=[0,depth/2+outset,0]);
        cutouts(5,depth-thickness,outset,rot=90,trans=[width+outset*2,depth/2+outset,0]);
    }
}

module tank_base() {
    translate([-outset,thickness/2,base_height])
    difference() {
        cube([width+outset*2, depth-thickness, thickness]);
        cutouts(5,depth,outset,rot=-90,trans=[0,(depth-thickness)/2,0]);
        cutouts(5,depth,outset,rot=90,trans=[width+outset*2,(depth-thickness)/2,0]);
    }
}

module cutouts(num, width, outset, rot, trans) {
    w = width / ((num-1) * 2);
    translate(trans)
    rotate([0,0,1], a=rot)
    for (i = [0 : num-1]) {
        translate([-width/2 - w/2 + i*2*w, -thickness/2, -thickness/2])
            cube([w, outset+thickness, thickness*2]);
    }
}

module wire_opening() {
    translate([width, rpi_ypos-35, overhang+20])
    scale([1,2,1])
    rotate(a=[0,90,0])
        cylinder(d=12, h=thickness+epsilon, center=true);
}

module side(y=0) {
    difference() {
        side_base(y);
        translate([0,0,height/2])
        scale([1,1,0.5])
            vert_face_base(x=mask_loc);
        scale([1,1,0.5])
            vert_face_base(0, window_thickness);
        scale([1,1,0.5])
            vert_face_base(width);
        top_cover();
    }
}

module side_base(y) {
    translate([-overhang,y-thickness/2,overhang/2])
    difference() {
        cube([width+overhang*2, thickness, height-overhang/2]);
        translate([width+overhang+thickness/2, 0, 0])
            rounded_truncation(width=overhang-thickness/2, up=false, rot=[0,0,-90]);
        translate([0, 0, 0])
            rounded_truncation(width=overhang-window_thickness/2, up=false, rot=[0,0,-90]);
    }
}

module mock_rpi(x, y, z) {
    color("Blue", alpha=0.5)
    translate([x+thickness, y, z])
        rotate(a=[0,-90,180])
            translate([-85/2, -56/2, 0])
                union() {
                    cube([85, 56, 2]);
                    // USB1
                    translate([67, 41, 2])
                        cube([20, 12, 12]);
                    // USB2
                    translate([67, 23, 2])
                        cube([20, 12, 12]);
                }
}


[3d] Remove a bit extra from the top of the probe holster

// Total number of probes supported (0 for just an endpiece)
count = 4; // [0,1,2,3,4]

// Wall thickness, set to multiple of perimeter width
wall = 2.5;
// Flat thickness
wall_t = 2;

// Overall width of flat
oa_w = 60;
// Overall depth of flat
oa_d = 95;
// Interior height between flats
height = 7;
// Center hole ratio
center_ratio = 3;

// Diameter of probe-holding hole
probe_d = 4.75;
// Length of probe holder
probe_l = 25;
// Distance of probe holder offset
probe_off = 7;
// Reduce thickness of probe holder (allow wire to pass more easily)
probe_cut = 0.75;

// Include holes around the perimeter of the flat?
flat_has_holes = true;
// Include the probe holder flat stub on endpiece as well? (can help retain wire)
end_has_stub = true;

/* [Hidden] */
// Center hole width
center_w = oa_w / center_ratio;
// Center hole depth
center_d = (oa_d - oa_w) + center_w;
// Diameter of holes in flat
flat_hole_d = (oa_w - center_w) / 4 - 0.5;

e=0.01;

do_render();

module do_render() {
  if (count == 0)
    half(true);
  else if (count == 1)
    single();
  else if (count == 2)
    complete_2();
  else if (count == 3)
    complete_3();
  else if (count == 4)
    complete_4();
}

module single() {
  half(false);
  translate([-oa_w - 1,0,0]) rotate(180) half(true);
}

module complete_2() {
  half(false);
  translate([oa_w + probe_off + probe_d + 1, 0, 0]) rotate(180) half(false);
  translate([0, oa_d + 1,0]) rotate(180) half(true);
}

module complete_3() {
  complete_2();
  translate([oa_w + probe_off + probe_d + 1, oa_d + 1, 0]) rotate(180) half(false);
}

module complete_4() {
  single();
  translate([oa_w + probe_off + probe_d + 1, 0, 0]) rotate(180) half(false);
  translate([0, oa_d + 1, 0]) half(false);
  translate([oa_w + probe_off + probe_d + 1, oa_d + 1, 0]) rotate(180) half(false);
}

module half(is_end) {
  probe_x=oa_w/2 + probe_off;
  probe_y=-probe_l - 5; // -oa_w/2 - 0;

  difference() {
    union() {
      flat();

      if (!is_end) {
        // probe holster
        intersection() {
          translate([probe_x, probe_y, probe_d/2+wall]) rotate([-90]) {
            difference() {
              union() {
                cylinder(probe_l, d=probe_d+2*wall, $fn=24);
                translate([-probe_d/2-wall,0,0])
                  cube([probe_d+2*wall, probe_d/2+wall, probe_l]);
              }
              translate([0,0,-e]) cylinder(probe_l+2*e, d=probe_d, $fn=16);
            }
          }
          // Keep the height of the cylinder less than the height of the layer
          translate([probe_x-probe_d/2-wall, probe_y, 0])
            cube([probe_d+2*wall, probe_l, height+wall_t-probe_cut]);
        } // interection
      } // if !is_end

      if (!is_end)
        // connect to holster
        translate([center_w/2+wall, probe_y, 0])
          cube([probe_x-center_w/2+probe_d/2, probe_l, wall_t]);
      else if (end_has_stub)
        // connect to holster
        mirror([0,1,0])
          translate([center_w/2+wall, probe_y, 0])
            cube([probe_x-center_w/2+probe_d/2, probe_l, wall_t]);

      // lip round
      translate([0,-(center_d-center_w)/2,0]) rotate(180)
        rotate_extrude(angle=180, $fn=45) translate([center_w/2,0,0]) lip_poly(is_end, height);
      translate([0,(center_d-center_w)/2,0])
        rotate_extrude(angle=180, $fn=45) translate([center_w/2,0,0]) lip_poly(is_end, height);
      // lip flat
      translate([center_w/2,(center_d-center_w)/2,0]) rotate([90])
        linear_extrude(center_d-center_w) lip_poly(is_end, height);
      translate([-center_w/2,-(center_d-center_w)/2,0]) rotate([90,0,180])
        linear_extrude(center_d-center_w) lip_poly(is_end, height);
    }  // end union

    if (is_end)
      mirror([0,1,0]) flat_holes();
    else
       flat_holes();

    // chip away a bit of snap in mating area
    translate([-4/2, -center_d/2-wall-e, wall_t+height-wall])
      cube([4, center_d+2*(wall+e), height*2]);
  } // end diff
}

module flat_hole() {
  rotate(20) {
    cylinder(wall_t+2*e, d=flat_hole_d);
    cube([flat_hole_d/2,flat_hole_d/2,wall_t+2*e]);
  }
}

module flat_holes() {
  flat_hole_offset = (oa_w - center_w)/4 + center_w/2;

  if (flat_has_holes) {
    translate([0, -(oa_d-oa_w)/2, 0]) for (rot=[0:180/4:180])
      rotate(-rot) translate([flat_hole_offset,0,-e]) flat_hole();
    translate([0, (oa_d-oa_w)/2, 0]) for (rot=[0:180/4:180])
      rotate(rot) translate([flat_hole_offset,0,-e]) flat_hole();
    translate([flat_hole_offset,0,-e]) flat_hole();
    translate([-flat_hole_offset,0,-e]) rotate(180) flat_hole();
  }
}

module flat() {
  difference() {
    hull() {
      translate([0, -(oa_d-oa_w)/2, 0]) cylinder(wall_t, d=oa_w, $fn=60);
      translate([0, (oa_d-oa_w)/2, 0]) cylinder(wall_t, d=oa_w, $fn=60);
    }

    // Center hole
    hull() {
      translate([0, -(center_d-center_w)/2, -e]) cylinder(wall_t+2*e, d=center_w+2, $fn=34);
      translate([0, (center_d-center_w)/2, -e]) cylinder(wall_t+2*e, d=center_w+2, $fn=34);
    }
  }
}

module lip_poly(is_end, interior_h) {
  if (is_end)
    lip_poly_stack_end();
  else
    lip_poly_stack(interior_h);
}

module lip_poly_stack(interior_h) {
  h=interior_h+wall_t;
  t_sock=wall;
  t_plug=t_sock;
  // Back the top snap portion away from the mating area by this amount
  // The lip is only 0.6mm so err needs to be less than this for any engagement to occur
  err_h=0.15;
  // Raise the snap lip this extra amount to account for a non-smooth surface
  // or layer rounding error, 1/2 a layer height is good
  err_v=0.12;

  polygon([
    // origin is bottom center, moving counterclockwise
    [0.5, 0], [t_sock,0], [t_sock, h], [-err_h, h],
    [-err_h, h+1+err_v],
      [0.6-err_h, h+1+0.6+err_v], [0.6-err_h, h+1+0.6+0.4+err_v],
    [-err_h, h+1+0.8+0.8+err_v],
    [-t_plug-err_h, h+1+0.8+0.8], [-t_plug-err_h, h], [0, h-t_plug-err_h],
    [0, 1+0.8+0.8], [0.8, 1+0.8], [0, 1], [0, 0.5]
  ]);
}

module lip_poly_stack_end() {
  t_sock = wall;
  stub = wall_t - 1.8;

  polygon([
    [0, 0], [t_sock, 0],
    // these points define the height, should be 1+0.8+0.8=2.6
    // but cut down to wall_t to be flush with flat(), this means wall_t
    // needs to be at least 1.8 to form a proper-sided socket
    [t_sock, wall_t], [0.5, wall_t], [0, wall_t-0.5], [0, wall_t-1],
    [0.8, wall_t-1-0.8], [0.8-stub, wall_t-1-0.8-stub]
  ]);
}

// Total number of probes supported (0 for just an endpiece)
count = 4; // [0,1,2,3,4]

// Wall thickness, set to multiple of perimeter width
wall = 2.45;
// Flat thickness
wall_t = 2;

// Overall width of flat
oa_w = 60;
// Overall depth of flat
oa_d = 95;
// Interior height between flats
height = 7;
// Center hole ratio
center_ratio = 3;

// Diameter of probe-holding hole
probe_d = 4.75;
// Length of probe holder
probe_l = 25;
// Distance of probe holder offset
probe_off = 7;

// Include holes around the perimeter of the flat?
flat_has_holes = true;
// Include the probe holder flat stub on endpiece as well? (can help retain wire)
end_has_stub = true;

/* [Hidden] */
// Center hole width
center_w = oa_w / center_ratio;
// Center hole depth
center_d = (oa_d - oa_w) + center_w;
// Diameter of holes in flat
flat_hole_d = (oa_w - center_w) / 4 - 0.5;

e=0.01;

do_render();

module do_render() {
  if (count == 0)
    half(true);
  else if (count == 1)
    single();
  else if (count == 2)
    complete_2();
  else if (count == 3)
    complete_3();
  else if (count == 4)
    complete_4();
}

module single() {
  half(false);
  translate([-oa_w - 1,0,0]) rotate(180) half(true);
}

module complete_2() {
  half(false);
  translate([oa_w + probe_off + probe_d + 1, 0, 0]) rotate(180) half(false);
  translate([0, oa_d + 1,0]) rotate(180) half(true);
}

module complete_3() {
  complete_2();
  translate([oa_w + probe_off + probe_d + 1, oa_d + 1, 0]) rotate(180) half(false);
}

module complete_4() {
  single();
  translate([oa_w + probe_off + probe_d + 1, 0, 0]) rotate(180) half(false);
  translate([0, oa_d + 1, 0]) half(false);
  translate([oa_w + probe_off + probe_d + 1, oa_d + 1, 0]) rotate(180) half(false);
}

module half(is_end) {
  probe_x=oa_w/2 + probe_off;
  probe_y=-probe_l - 5; // -oa_w/2 - 0;

  difference() {
    union() {
      flat();

      if (!is_end) {
        // probe holster
        intersection() {
          translate([probe_x, probe_y, probe_d/2+wall]) rotate([-90]) {
            difference() {
              union() {
                cylinder(probe_l, d=probe_d+2*wall, $fn=24);
                translate([-probe_d/2-wall,0,0])
                  cube([probe_d+2*wall, probe_d/2+wall, probe_l]);
              }
              translate([0,0,-e]) cylinder(probe_l+2*e, d=probe_d, $fn=16);
            }
          }
          // Keep the height of the cylinder less than the height of the layer
          translate([probe_x-probe_d/2-wall, probe_y, 0])
            cube([probe_d+2*wall, probe_l, height+wall_t]);
        } // interection
      } // if !is_end

      if (!is_end)
        // connect to holster
        translate([center_w/2+wall, probe_y, 0])
          cube([probe_x-center_w/2-wall, probe_l, wall_t]);
      else if (end_has_stub)
        // connect to holster
        mirror([0,1,0])
          translate([center_w/2+wall, probe_y, 0])
            cube([probe_x-center_w/2-wall, probe_l, wall_t]);

      // lip round
      translate([0,-(center_d-center_w)/2,0]) rotate(180)
        rotate_extrude(angle=180, $fn=45) translate([center_w/2,0,0]) lip_poly(is_end, height);
      translate([0,(center_d-center_w)/2,0])
        rotate_extrude(angle=180, $fn=45) translate([center_w/2,0,0]) lip_poly(is_end, height);
      // lip flat
      translate([center_w/2,(center_d-center_w)/2,0]) rotate([90])
        linear_extrude(center_d-center_w) lip_poly(is_end, height);
      translate([-center_w/2,-(center_d-center_w)/2,0]) rotate([90,0,180])
        linear_extrude(center_d-center_w) lip_poly(is_end, height);
    }  // end union

    if (is_end)
      mirror([0,1,0]) flat_holes();
    else
       flat_holes();

    // chip away a bit of snap in mating area
    translate([-4/2, -center_d/2-wall-e, wall_t+height-wall])
      cube([4, center_d+2*(wall+e), height*2]);
  } // end diff
}

module flat_hole() {
  rotate(20) {
    cylinder(wall_t+2*e, d=flat_hole_d);
    cube([flat_hole_d/2,flat_hole_d/2,wall_t+2*e]);
  }
}

module flat_holes() {
  flat_hole_offset = (oa_w - center_w)/4 + center_w/2;

  if (flat_has_holes) {
    translate([0, -(oa_d-oa_w)/2, 0]) for (rot=[0:180/4:180])
      rotate(-rot) translate([flat_hole_offset,0,-e]) flat_hole();
    translate([0, (oa_d-oa_w)/2, 0]) for (rot=[0:180/4:180])
      rotate(rot) translate([flat_hole_offset,0,-e]) flat_hole();
    translate([flat_hole_offset,0,-e]) flat_hole();
    translate([-flat_hole_offset,0,-e]) rotate(180) flat_hole();
  }
}

module flat() {
  difference() {
    hull() {
      translate([0, -(oa_d-oa_w)/2, 0]) cylinder(wall_t, d=oa_w, $fn=60);
      translate([0, (oa_d-oa_w)/2, 0]) cylinder(wall_t, d=oa_w, $fn=60);
    }

    // Center hole
    hull() {
      translate([0, -(center_d-center_w)/2, -e]) cylinder(wall_t+2*e, d=center_w+2, $fn=34);
      translate([0, (center_d-center_w)/2, -e]) cylinder(wall_t+2*e, d=center_w+2, $fn=34);
    }
  }
}

module lip_poly(is_end, interior_h) {
  if (is_end)
    lip_poly_stack_end();
  else
    lip_poly_stack(interior_h);
}

module lip_poly_stack(interior_h) {
  h=interior_h+wall_t;
  t_sock=wall;
  t_plug=t_sock;
  // Back the top snap portion away from the mating area by this amount
  // The lip is only 0.6mm so err needs to be less than this for any engagement to occur
  err_h=0.15;
  // Raise the snap lip this extra amount to account for a non-smooth surface
  // or layer rounding error, 1/2 a layer height is good
  err_v=0.12;

  polygon([
    // origin is bottom center, moving counterclockwise
    [0.5, 0], [t_sock,0], [t_sock, h], [-err_h, h],
    [-err_h, h+1+err_v],
      [0.6-err_h, h+1+0.6+err_v], [0.6-err_h, h+1+0.6+0.4+err_v],
    [-err_h, h+1+0.8+0.8+err_v],
    [-t_plug-err_h, h+1+0.8+0.8], [-t_plug-err_h, h], [0, h-t_plug-err_h],
    [0, 1+0.8+0.8], [0.8, 1+0.8], [0, 1], [0, 0.5]
  ]);
}

module lip_poly_stack_end() {
  t_sock = wall;
  stub = wall_t - 1.8;

  polygon([
    [0, 0], [t_sock, 0],
    // these points define the height, should be 1+0.8+0.8=2.6
    // but cut down to wall_t to be flush with flat(), this means wall_t
    // needs to be at least 1.8 to form a proper-sided socket
    [t_sock, wall_t], [0.5, wall_t], [0, wall_t-0.5], [0, wall_t-1],
    [0.8, wall_t-1-0.8], [0.8-stub, wall_t-1-0.8-stub]
  ]);
}


add a parameter for the number of sides in the pyramid

/**
 *
 */
module roundedPyramid(h,
					  r1,
					  r2,
					  cornerRadius,
//TODO: clarify this parameter
					  cylinderFn = 4,
					  sides=30,
					  sidesOnly=false)
{
//TODO: clarify this parameter
	$fn=sides;

	minkowski()
	{
		cylinder(h=h, r1=r1, r2=r2, $fn=cylinderFn);

	    if(sidesOnly)
	    {
	    	cylinder(r=cornerRadius);
	    }
	    else
	    {
	    	sphere(r=cornerRadius);

    	}
	}
}

/**
 *
 */
module roundedPyramid(h, r1, r2, cornerRadius, sides=30, sidesOnly=false)
//module roundedPyramid(size, cornerRadius, sides=30, sidesOnly=false)
{
	$fn=sides;

	minkowski()//size, cornerRadius)
	{
		cylinder(h=h, r1=r1, r2=r2, $fn=4);

	    if(sidesOnly)
	    {
	    	cylinder(r=cornerRadius);
	    }
	    else
	    {
	    	sphere(r=cornerRadius);

    	}
	}
}


make the cutout go all the way through

make the cutout go all the way through

use <../../../shapes/open-cylinder/open-cylinder.scad>

module waterPumpFilter(baseHeight = 30,
					   innerRadius = 25,
					   snorkel = false,
					   snorkelHeight = 40,
					   snorkelOuterRadius = 7,
					   xLength = 54)
{
	union()
	{
		zTranslate = baseHeight / 2.0;
		translate([0,0, zTranslate-0.1])
		waterPumpFilter_connector(innerRadius = innerRadius);

		yLength = (innerRadius * 2) + 4;
		waterPumpFilter_base(height = baseHeight,
							 innerRadius = innerRadius,
							 snorkel = snorkel,
							 snorkelOuterRadius = snorkelOuterRadius,
							 xLength = xLength,
							 yLength = yLength);
	}
}

module waterPumpFilter_connector(innerRadius)
{
	openCylinder(height = 5,
				 innerRadius = innerRadius,
				 outerRadius = innerRadius + 2);
}

module waterPumpFilter_base(height,
							innerRadius,
							snorkel,
							snorkelOuterRadius,
							xLength,
							yLength)
{
	difference()
	{
		// this is the outer cube
		cube([xLength, yLength, height], center = true);

		color("pink")
		translate([0,0,10])
		cylinder(r=innerRadius, h=30, center=true);

		innerCubeDifference = 4;
		color("green")
		waterPumpFilter_base_innerCube(xLength - innerCubeDifference,
									   yLength - innerCubeDifference,
									   height - innerCubeDifference);

		cutoutHeight = height - 4;

		waterPumpFilter_xCutouts(height = cutoutHeight,
								 length = xLength - 8);

		waterPumpFilter_yCutouts(height = cutoutHeight);

		if(snorkel == true)
		{
			waterPump_snorkel(filter_baseHeight = height,
							  filter_xLength = xLength,
							  filter_yLength = yLength,
							  height = 20,
							  snorkelOuterRadius = snorkelOuterRadius);
		}
	}
}

module waterPumpFilter_base_innerCube(xyLength, yLength, height)
{
	cube([xyLength, yLength, height], center = true);
}

module waterPump_snorkel(filter_baseHeight,
						 filter_xLength,
						 filter_yLength,
						 height,
						 snorkelOuterRadius)
{
	xTranslate = (filter_xLength / 2.0) - snorkelOuterRadius - 2;
	yTranslate = (filter_yLength / 2.0) - snorkelOuterRadius -2;
	zTranslate = (filter_baseHeight / 2.0) - 4;

	color("green")
	translate([xTranslate, yTranslate, zTranslate])
	cylinder(h = height, r = snorkelOuterRadius, fn = 50);

	translate([-xTranslate, -yTranslate, zTranslate])
			 cylinder(h = height, r = snorkelOuterRadius, $fn = 100);
}

module waterPumpFilter_xCutouts(height, length)
{
	step = 5;

	for(x = [-length : step : length])
	{
		translate([x, 0, 0])
		cube([2, 100, height], center = true);
	}
}

module waterPumpFilter_yCutouts(height = 10, length = 20)
{
	step = 5;

	for(y = [-length : step : length])
	{
		translate([0, y, 0])
		cube([101, 2, height], center = true);
	}
}

use <../../../shapes/open-cylinder/open-cylinder.scad>

module waterPumpFilter(baseHeight = 30,
					   innerRadius = 25,
					   snorkel = false,
					   snorkelHeight = 40,
					   snorkelOuterRadius = 7,
					   xLength = 54)
{
	union()
	{
		zTranslate = baseHeight / 2.0;
		translate([0,0, zTranslate-0.1])
		waterPumpFilter_connector(innerRadius = innerRadius);

		yLength = (innerRadius * 2) + 4;
		waterPumpFilter_base(height = baseHeight,
							 innerRadius = innerRadius,
							 snorkel = snorkel,
							 snorkelOuterRadius = snorkelOuterRadius,
							 xLength = xLength,
							 yLength = yLength);
	}
}

module waterPumpFilter_connector(innerRadius)
{
	openCylinder(height = 5,
				 innerRadius = innerRadius,
				 outerRadius = innerRadius + 2);
}

module waterPumpFilter_base(height,
							innerRadius,
							snorkel,
							snorkelOuterRadius,
							xLength,
							yLength)
{
	difference()
	{
		// this is the outer cube
		cube([xLength, yLength, height], center = true);

		color("pink")
		translate([0,0,10])
		cylinder(r=innerRadius, h=30, center=true);

		innerCubeDifference = 4;
		color("green")
		waterPumpFilter_base_innerCube(xLength - innerCubeDifference,
									   yLength - innerCubeDifference,
									   height - innerCubeDifference);

		cutoutHeight = height - 4;

		waterPumpFilter_xCutouts(height = cutoutHeight,
								 length = xLength - 8);

		waterPumpFilter_yCutouts(height = cutoutHeight);

		if(snorkel == true)
		{
			waterPump_snorkel(filter_baseHeight = height,
							  filter_xLength = xLength,
							  filter_yLength = yLength,
							  height = 20,
							  snorkelOuterRadius = snorkelOuterRadius);
		}
	}
}

module waterPumpFilter_base_innerCube(xyLength, yLength, height)
{
	cube([xyLength, yLength, height], center = true);
}

module waterPump_snorkel(filter_baseHeight,
						 filter_xLength,
						 filter_yLength,
						 height,
						 snorkelOuterRadius)
{
	xTranslate = (filter_xLength / 2.0) - snorkelOuterRadius - 2;
	yTranslate = (filter_yLength / 2.0) - snorkelOuterRadius -2;
	zTranslate = (filter_baseHeight / 2.0) - 4;

	color("green")
	translate([xTranslate, yTranslate, zTranslate])
	cylinder(h = height, r = snorkelOuterRadius, fn = 50);

	translate([-xTranslate, -yTranslate, zTranslate])
			 cylinder(h = height, r = snorkelOuterRadius, $fn = 100);
}

module waterPumpFilter_xCutouts(height, length)
{
	step = 5;

	for(x = [-length : step : length])
	{
		translate([x, 0, 0])
		cube([2, 100, height], center = true);
	}
}

module waterPumpFilter_yCutouts(height = 10, length = 20)
{
	step = 5;

	for(y = [-length : step : length])
	{
		translate([0, y, 0])
		cube([100, 2, height], center = true);
	}
}