/*
* Bed Release Tab
*
* Attach this part on several spots to 3d printed model, uses thin 0.4mm layer to attach.
*
* At the end of print, printer will wait for bed temp to drop to 35'C and then bumps into
* these tabs from the side to detach them from the bed, then use them as lever pushing
* with its fan shroud on the top platform.
*
*/

// Push force multiplier
MECHANICAL_ADVANTAGE = 2;
// Release tab and model connecting link width
LINK_WIDTH = 12; 
// Gap between release tab and model
LINK_GAP = 2; // ga[ between tab and part should be enough for 
// Release tab link height, multiple of layer 0.2mm. Single layer tears on PLA, use at least 2 layers.
LINK_HEIGHT = 0.4;
// How high should tab lift the model's edge when pressed down
LIFT = 10;
// Release tab wall thickness, make it nozzle multiple
WALL = 1.2;
// Top push platform
TOP_WIDTH = 4;

/* [Hidden] */

// tab's top extends 2x distance of tab's base
BASE_R = LIFT - LINK_GAP; // base circle radius (circle is then stretched to ellipse in Y dimension)
OUTER_SLOPE_L = BASE_R * MECHANICAL_ADVANTAGE;
ANGLE = min(asin(BASE_R / OUTER_SLOPE_L), 45); // leverage side slope, >45deg would result in weak tab
HEIGHT = round(BASE_R / tan(ANGLE));
ANGLE2 = atan2((2*BASE_R - TOP_WIDTH), HEIGHT); // model side slope

echo(str("BASE_R=", round(BASE_R), ", BB=", BASE_R*2+LINK_GAP, "x", LINK_WIDTH, "x", HEIGHT));

$fn = $preview ? 24 : 60;


// helpers

module morphing_ellipse (base_w, base_l, height, top_w, top_l)
{
    linear_extrude(height=height, scale=[top_w/base_w, top_l/base_l])
        scale([1, base_l/base_w])
            circle(d=base_w);
}


//
// main 
//

// bottom
intersection() {
    morphing_ellipse(BASE_R*2, LINK_WIDTH, HEIGHT, BASE_R*4, 0.4*LINK_WIDTH);
    translate([-BASE_R, -LINK_WIDTH/2])
        cube([BASE_R, LINK_WIDTH, LINK_HEIGHT]);
}

// main body
intersection() 
{
    union() 
    {
        // main body
        difference() 
        {
            morphing_ellipse(BASE_R*2, LINK_WIDTH, HEIGHT, 4*BASE_R, 0.4*LINK_WIDTH);
            translate([0, 0, LINK_HEIGHT])
                morphing_ellipse(BASE_R*2-2*WALL, LINK_WIDTH-2*WALL, HEIGHT-LINK_HEIGHT-WALL, 4*BASE_R-2*WALL, 0.4*LINK_WIDTH-2*WALL);
        }

        // strenghten the bottom to 1mm
        intersection()
        {
            morphing_ellipse(BASE_R*2, LINK_WIDTH, HEIGHT, 4*BASE_R, 0.4*LINK_WIDTH);
            translate([-2*BASE_R, -LINK_WIDTH/2])
                cube([2*BASE_R, LINK_WIDTH, 1]);
        }
        
        // inner bracket 
        intersection() 
        {
            morphing_ellipse(BASE_R*2, LINK_WIDTH, HEIGHT, BASE_R*4, 0.4*LINK_WIDTH);
            translate([-2*BASE_R, -WALL/2])
                cube([2*BASE_R, WALL, HEIGHT]);
        }
    }
    rotate([0, -ANGLE2, 0]) translate([-BASE_R*2, -LINK_WIDTH/2])
        cube([BASE_R*2, LINK_WIDTH, HEIGHT/cos(ANGLE2)*2]); // dont feel like calculating exact height of intersection, *2 is easy
}

// gap linkage
translate([-0.5, -LINK_WIDTH/2+0.4])
    cube([2.5, LINK_WIDTH-0.8, LINK_HEIGHT]);
