/*
 * Draw a rounded edge in one quadrant
 *
 * Draw a arc from corner point vc plus rector ra to vc+rb. vc+ra is stored
 * in va and vc+rb is stored in vb.
 */

#define	Q(va, vb, vc, ra, rb)		\
    va: vec vc ra;			\
    vb: vec vc rb;			\
    vc##_center: vec va rb;		\
    arc vc##_center va vb

#define QLL(pfx, r) \
    Q(pfx##lly, pfx##llx, pfx##ll, (0mm, r), (r, 0mm))
#define QLR(pfx, r) \
    Q(pfx##lrx, pfx##lry, pfx##lr, (-(r), 0mm), (0mm, r))
#define QUL(pfx, r) \
    Q(pfx##ulx, pfx##uly, pfx##ul, (r, 0mm), (0mm, -(r)))
#define QUR(pfx, r) \
    Q(pfx##ury, pfx##urx, pfx##ur, (0mm, -(r)), (-(r), 0mm))

/*
 * Rectangle with rounded corners.
 *
 * pfx is the prefix for all the names generated by this macro. origin is the
 * lower left corner. w and h are the width and height. r is the radius of the
 * corners.
 */

#define RRECT_SETUP(pfx, origin, w, h)	\
    pfx##ll: vec origin(0mm, 0mm);	\
    pfx##lr: vec pfx##ll(w, 0mm);	\
    pfx##ul: vec pfx##ll(0mm, h);	\
    pfx##ur: vec pfx##ll(w, h);		\

#define	RRECT_DRAW_ARCS(pfx, r)		\
    QLL(pfx, r);			\
    QLR(pfx, r);			\
    QUL(pfx, r);			\
    QUR(pfx, r)

#define RRECT_DRAW_LINES(pfx)	\
    line pfx##llx pfx##lrx;	\
    line pfx##ulx pfx##urx;	\
    line pfx##lly pfx##uly;	\
    line pfx##lry pfx##ury

#define	RRECT(pfx, origin, w, h, r)	\
    RRECT_SETUP(pfx, origin, w, h);	\
    RRECT_DRAW_ARCS(pfx, r);		\
    RRECT_DRAW_LINES(pfx)


/* ----- Top part ---------------------------------------------------------- */


frame top_outline {
	RRECT(edge_, @, width, length, ro_edge)
}

frame top_window {
	loop if = 1, top_window

	set off = topborder+topridge

	frame top_outline @

	win_orig: vec @(off+pcbgap+win_x0, off)
	RRECT(win_, win_orig, win_x1-win_x0, length-2*off, win_r)

	cmp_orig: vec @(off+pcbgap+cmp_x0, off+pcbgap+cmp_y0)
	RRECT(cmp_, cmp_orig, cmp_x1-cmp_x0, cmp_y1-cmp_y0, cmp_r)
}

frame top_pcb {
	loop if = 1, top_pcb

	set inside = topborder+topridge

	frame top_outline @
	ro: vec @(topborder, topborder)
	ri: vec ro(topridge, topridge)
	RRECT(ridge_i_, ri, width-2*inside, length-2*inside, ri_ridge)
}

frame top_ridge {
	loop if = 1, top_ridge

	set inside = topborder+topridge

	ro: vec @(topborder, topborder)
	RRECT(ridge_o_, ro, width-2*topborder, length-2*topborder, ro_ridge)
	ri: vec ro(topridge, topridge)
	RRECT(ridge_i_, ri, width-2*inside, length-2*inside, ri_ridge)
}

frame top_surface {
	loop if = 1, top_surface

	frame top_outline @
}


/* ----- Middle part ------------------------------------------------------- */


frame mid_rrect_ridge {
	RRECT_SETUP(edge_, @, width, length);
    	RRECT_DRAW_ARCS(edge_, ro_edge);

	base: vec @(red, red)
	RRECT_SETUP(ridge_, base, width-2*red, length-2*red);
    	RRECT_DRAW_ARCS(ridge_, r);

	usb_ur: vec edge_ur(-usb_roff, 0mm)
	usb_ul: vec usb_ur(-usb_w, 0mm)
	usb_ll: vec usb_ul(0mm, -red)
	usb_lr: vec usb_ur(0mm, -red)

	line edge_lly edge_uly		/* outside */
	line edge_ulx usb_ul
	line usb_ul usb_ll		/* USB bay */
	line usb_ll ridge_ulx
	line ridge_uly ridge_lly	/* inside */
	line ridge_llx ridge_lrx
	line ridge_lry ridge_ury
	line ridge_urx usb_lr
	line usb_lr usb_ur		/* USB bay */
	line usb_ur edge_urx
	line edge_ury edge_lry		/* outside */
	line edge_lrx edge_llx
}


frame mid_rrect_body {
	RRECT_SETUP(edge_, @, width, length);
    	RRECT_DRAW_ARCS(edge_, ro_edge);

	usb_ur: vec edge_ur(-usb_roff, 0mm)
	usb_ul: vec usb_ur(-usb_w, 0mm)
	usb_ll: vec usb_ul(0mm, -usb_d)
	usb_lr: vec usb_ur(0mm, -usb_d)

	line edge_llx edge_lrx
	line edge_ulx usb_ul

	line usb_ul usb_ll		/* USB bay */
	line usb_ll usb_lr
	line usb_lr usb_ur

	line usb_ur edge_urx
	line edge_lly edge_uly
	line edge_lry edge_ury
}


frame mid_ridge {
	loop if = 1, mid_ridge

	set red = topborder
	set r = ro_ridge
	frame mid_rrect_ridge @
}


frame mid_pcb {
	loop if = 1, mid_pcb

	set red = topborder+topridge
	set r = ri_ridge
	frame mid_rrect_ridge @
}


frame post {
	vec @(r, 0mm)
	circ @ .
}


frame mid_body {
	loop if = 1, mid_body

	frame mid_rrect_body @

	bc: vec @(width/2, batt_y)
	br: vec bc(batt_d/2, 0mm)
	circ bc br

	set r = post_do/2
	vec @(post_x, cvr_f+cvr_d+post_y)
	frame post .
	vec @(width-post_x, cvr_f+cvr_d+post_y)
	frame post .
}


/* ----- Bottom part ------------------------------------------------------- */


frame bot_rrect {
	base: vec @(0mm, cvr_f)

	RRECT_SETUP(edge_, base, width, length-cvr_f);
	QUL(edge_, ro_edge);
	QUR(edge_, ro_edge);

	set side = (width-cvr_w-2*cvr_play)/2-red
	cvr_ll: vec edge_ll(side, 0mm)
	cvr_lr: vec edge_lr(-side, 0mm)
	cvr_ul: vec cvr_ll(0mm, cvr_d+2*cvr_play+red)
	cvr_ur: vec cvr_lr(0mm, cvr_d+2*cvr_play+red)

	line edge_ll cvr_ll		/* outside */

	QUL(cvr_, cvr_r+red+cvr_play)	/* cover bay */
	QUR(cvr_, cvr_r+red+cvr_play)

	line cvr_ll cvr_uly
	line cvr_ulx cvr_urx
	line cvr_ury cvr_lr

	line cvr_lr edge_lr		/* outside */
	line edge_ll edge_uly
	line edge_lr edge_ury
	line edge_ulx edge_urx
}


frame bot_posts {
	loop if = 1, bot_posts

	set r = post_di/2
	vec @(post_x, cvr_f+cvr_d+post_y)
	frame post .
	vec @(width-post_x, cvr_f+cvr_d+post_y)
	frame post .
}


frame bot_base {
	loop if = 1, bot_base

	set red = cvr_foot
	frame bot_rrect @
}


frame bot_surface {
	loop if = 1, bot_surface

	set red = 0mm
	frame bot_rrect @
}


/* ----- Main -------------------------------------------------------------- */


package "$part-$z"
unit mm

table
    { part,		z, top_surface, top_window, top_pcb, top_ridge,
			mid_ridge, mid_pcb, mid_body,
			bot_posts, bot_base, bot_surface}
    { "top_surface",	3.3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    { "top_window",	2.3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }
    { "top_pcb",	1.2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }
    { "top_ridge",	0.5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }
    { "mid_ridge",	0.6, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }
    { "mid_pcb",	1.2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }
    { "mid_body",	4.7, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }
    { "bot_posts",	1.2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }
    { "bot_base",	2.0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }
    { "bot_surface",	2.7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }

table
    { pcbw, pcbl, pcbgap }
    { 20mm, 45mm, 0.2mm }

table
    /* window position relative to left edge of PCB */
    { topridge, topborder, win_x0, win_x1, win_r }
    { 1.0mm,    1.0mm,     1.0mm,  5.0mm,  1.6mm }

table
    /* component area position relative to lower left corner of PCB */
    { cmp_x0, cmp_y0, cmp_x1, cmp_y1, cmp_r }
    { 6.5mm,  1.0mm,  19.5mm, 30.0mm, 2.0mm }

table
    /* usb_roff = offset from right outer case edge */
    /* usb_d = 10 mm for prototypes (mini-USB); reduce to 6.0 mm for micro */
    { usb_w, usb_d, usb_roff }
    { 8.6mm, 10.0mm, 4.9mm }

table
    /* post_y is from the edge of the battery bay. post_x is from the edge */
    { batt_d, batt_y, post_do, post_di, post_y, post_x }
    { 20.2mm, 12.1mm, 4.1mm,   4.0mm,   5.0mm,  4.5mm }

table
    { cvr_w,  cvr_d,  cvr_f, cvr_foot, cvr_play, cvr_r }
    { 20.0mm, 15.0mm, 5.0mm, 0.8mm,    0.1mm,    2.0mm }

set width = pcbw+2*(pcbgap+topridge+topborder)
set length = pcbl+2*(pcbgap+topridge+topborder)

set ri_ridge = 2.0mm
set ro_ridge = ri_ridge+topridge

/*
 * ro_edge is an outer edge, so we can make the radius smaller than ro_ridge,
 * for added strength and less fruity esthetics.
 */

set ro_edge = 1.5mm

frame top_ridge @
frame top_pcb @
frame top_window @
frame top_surface @

frame mid_ridge @
frame mid_pcb @
frame mid_body @

frame bot_posts @
frame bot_base @
frame bot_surface @

measx top_outline.edge_ul -> top_outline.edge_ur 4mm
measy top_outline.edge_ll -> top_outline.edge_ul 4mm
//measx top_pcb.pcb_ul -> top_pcb.pcb_ur 3mm
//measy top_pcb.pcb_ll -> top_pcb.pcb_ul 3mm

measx top_ridge.ridge_o_ul -> top_ridge.ridge_o_ur 4mm
measy top_ridge.ridge_o_ll -> top_ridge.ridge_o_ul 4mm
measx top_ridge.ridge_i_ul -> top_ridge.ridge_i_ur 3mm
measy top_ridge.ridge_i_ll -> top_ridge.ridge_i_ul 3mm

measy bot_rrect.edge_ll -> bot_rrect.edge_ul 4mm
measx bot_rrect.edge_ll -> bot_rrect.cvr_ll -3mm
