epsilon = 0.01;

but_top_x = 10;
but_top_y = but_top_x+5;
but_top_z = 1.5;

but_corner_r = 2;

but_base_border = 1;
but_base_x = but_top_x+2*but_base_border;
but_base_y = but_top_y+2*but_base_border;
but_base_z = 0.5;

but_fillet_r = 0.4;
but_chamfer_r = 0.2;

$fn = 40;


/* ----- Basic solids ------------------------------------------------------ */


module torus(r0, r1)
{
	rotate_extrude()
	    translate([r0, 0, 0])
	    circle(r = r1);
}


/* ----- Helper elements for fillets --------------------------------------- */


module fillet_line(x, r)
{
	translate([-x/2, 0, 0])
	    difference() {
		cube([x, r, r]);
		translate([0, r, r])
		    rotate([0, 90, 0])
		    translate([0, 0, -epsilon])
		    cylinder(h = x+2*epsilon, r = r);
	}
}


module fillet_circle(r, fillet_r)
{
	difference() {
		cylinder(h = fillet_r, r = r+fillet_r);
		translate([0, 0, fillet_r])
		    torus(r+fillet_r, fillet_r);
	}
}


/* ----- Helper elements for chamfers -------------------------------------- */


module chamfer_line(x, r)
{
	translate([-x/2, -r, -r])
	    difference() {
		cube([x, r+epsilon, r+epsilon]);
		rotate([0, 90, 0])
		    translate([0, 0, -epsilon])
		    cylinder(h = x+2*epsilon, r = r);
	}
}


module chamfer_circle(r, fillet_r)
{
	difference() {
		translate([-r-epsilon, -r-epsilon, -fillet_r])
		    cube([2*(r+epsilon), 2*(r+epsilon), fillet_r+epsilon]);
		translate([0, 0, -fillet_r])
		    cylinder(h = fillet_r, r = r-fillet_r);
		translate([0, 0, -fillet_r])
		    torus(r-fillet_r, fillet_r);
	}
}


/* ----- Box with rounded corners ------------------------------------------ */


module rbox_core(x, y, z, r)
{
	union() {
		translate([0, 0, z/2])
		    cube([x-2*r, y, z], center = true);
		translate([0, 0, z/2])
		    cube([x, y-2*r, z], center = true);
	}
}


module rbox(x, y, z, r)
{
	union() {
		rbox_core(x, y, z, r);
		for (dx = [-1, 1]) {
			for (dy = [-1, 1]) {
				translate([dx*(x/2-r), dy*(y/2-r), 0])
		    		    cylinder(h = z, r = r);
			}
		}
	}
}


module rbox_fillet_bottom(x, y, z, r, fillet_r)
{
	union() {
		for (a = [0, 180]) {
			rotate([0, 0, a])
			    translate([0, y/2, 0]) 
			    fillet_line(x-2*r, fillet_r);
			rotate([0, 0, a+90])
			    translate([0, x/2, 0]) 
			    fillet_line(y-2*r, fillet_r);
		}
		for (dx = [-1, 1]) {
			for (dy = [-1, 1]) {
				translate([dx*(x/2-r), dy*(y/2-r), 0])
				    fillet_circle(r, fillet_r);
			}
		}
	}
}


module rbox_chamfer_top_corners(x, y, z, r, chamfer_r)
{
	difference() {
		union() {
			for (dx = [-1, 1]) {
				for (dy = [-1, 1]) {
					translate([dx*(x/2-r), dy*(y/2-r), z])
					    chamfer_circle(r, chamfer_r);
				}
			}
		}
		rbox_core(x-epsilon, y-epsilon, z, r);
	}
}


module rbox_chamfer_top(x, y, z, r, chamfer_r)
{
	union() {
		for (a = [0, 180]) {
			rotate([0, 0, a])
			    translate([0, y/2, z]) 
			    chamfer_line(x-2*r, chamfer_r);
			rotate([0, 0, a+90])
			    translate([0, x/2, z]) 
			    chamfer_line(y-2*r, chamfer_r);
		}
		rbox_chamfer_top_corners(x, y, z, r, chamfer_r);
	}
}


module rbox_chamfer_bottom(x, y, z, r, chamfer_r)
{
	rotate([180, 0, 0])
	    translate([0, 0, -z])
	    rbox_chamfer_top(x, y, z, r, chamfer_r);
}


/* ----- Button ------------------------------------------------------------ */


module button_top()
{
	union() {
		difference() {
			rbox(but_top_x, but_top_y, but_top_z, but_corner_r);
			rbox_chamfer_top(but_top_x, but_top_y, but_top_z,				     but_corner_r, but_chamfer_r);
		}
		rbox_fillet_bottom(but_top_x, but_top_y, but_top_z,
		     but_corner_r, but_fillet_r);
	}
}


module button_base()
{
	translate([0, 0, -but_base_z])
	    difference() {
		rbox(but_base_x, but_base_y, but_base_z, but_corner_r);
		rbox_chamfer_top(but_base_x, but_base_y, but_base_z,
		    but_corner_r, but_chamfer_r);
		rbox_chamfer_bottom(but_base_x, but_base_y, but_base_z,
		    but_corner_r, but_chamfer_r);
	}
}


module button()
{
	union() {
		button_top();
		button_base();
	}
}


button();
