#!/usr/bin/python

# all dimensions are mm

from cadmium import *


epsilon = 0.01
noise = epsilon/10

but_top_x = 10.0
but_top_y = but_top_x+5.0
but_top_z = 1.5

but_corner_r = 2.0

but_base_border = 1.0
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


# ----- Helper elements for fillets -------------------------------------------


def fillet_line(x, r):
	s = Box(x, r, r)
	s -= Cylinder(r, h = x+2*epsilon).				\
	    translate(0, 0, -epsilon).					\
	    rotate(Y_axis, 90).						\
	    translate(0, r, r)
	return s.translate(-x/2, 0, 0)

def fillet_circle(r, fillet_r):
	return Cylinder(r+fillet_r, h = fillet_r)-			\
	    Torus(r+fillet_r, fillet_r, center = True).			\
	    translate(0, 0, fillet_r)


# ----- Helper elements for chamfers ------------------------------------------


def chamfer_line (x, r):
	s = Box(x, r+epsilon, r+epsilon)
	s -= Cylinder(r, h = x+2*epsilon).				\
	    translate(0, 0, -epsilon).					\
	    rotate(Y_axis, 90)
	return s.translate(-x/2, -r, -r)

def chamfer_circle(r, fillet_r):
	return Box(2*(r+epsilon), 2*(r+epsilon), fillet_r+epsilon).	\
	    translate(-r-epsilon, -r-epsilon, -fillet_r)-		\
	    Cylinder(r-fillet_r, h = fillet_r).				\
	    translate(0, 0, -fillet_r)-					\
	    Torus(r-fillet_r, fillet_r, center = True).			\
	    translate(0, 0, -fillet_r)


# ----- Box with rounded corners ----------------------------------------------


def rbox_core(x, y, z, r):
	return  Box(x-2*r, y, z, center = True).translate(0, 0, z/2)+ \
	    Box(x, y-2*r, z, center = True).translate(0, 0, z/2)

def rbox(x, y, z, r):
	s = rbox_core(x, y, z, r)
	for dx in [-1, 1]:
		for dy in [-1, 1]:
			s += Cylinder(r, h = z).			\
			    translate(dx*(x/2-r), dy*(y/2-r), 0)
	return s

def rbox_fillet_bottom(x, y, z, r, fillet_r):
	s = None
	for a in [0, 180]:
		t = fillet_line(x-2*r, fillet_r).			\
		    translate(0, y/2, 0).				\
		    rotate(Z_axis, a)
		if s is None:
			s = t
		else:
			s += t
		s += fillet_line(y-2*r, fillet_r).			\
		    translate(0, x/2, 0).				\
		    rotate(Z_axis, a+90)
	for dx in [-1, 1]:
		for dy in [-1, 1]:
			s += fillet_circle(r, fillet_r).		\
			    translate(dx*(x/2-r), dy*(y/2-r), 0)
	return s

def rbox_chamfer_top_corners(x, y, z, r, chamfer_r):
	s = None
	for dx in [-1, 1]:
		for dy in [-1, 1]:
			t = chamfer_circle(r, chamfer_r).		\
			    translate(dx*(x/2-r), dy*(y/2-r), z)
			if s is None:
				s = t
			else:
				s += t
	return s-rbox_core(x-epsilon, y-epsilon, z, r)

def rbox_chamfer_top(x, y, z, r, chamfer_r):
	s = rbox_chamfer_top_corners(x, y, z, r, chamfer_r)
	for a in [0, 180]:
		s += chamfer_line(x-2*r, chamfer_r).			\
		    translate(0, y/2, z+noise).				\
		    rotate(Z_axis, a)
		s += chamfer_line(y-2*r, chamfer_r).			\
		    translate(0, x/2, z+noise).				\
		    rotate(Z_axis, a+90)
	return s

def rbox_chamfer_bottom(x, y, z, r, chamfer_r):
	return rbox_chamfer_top(x, y, z, r, chamfer_r).			\
	    translate(0, 0, -z).					\
	    rotate(X_axis, 180)

# ----- Button ----------------------------------------------------------------


def button_top():
	return 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)

def button_base():
	s = 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)
	return s.translate(0, 0, -but_base_z)

def button():
	return button_top()+button_base()

b = button()
b.toSTL("button.stl")