#!/bin/sh

photo=0
grid_unit="mil"

annotation=pins

while test $# -gt 0
do
	case $1 in
		--photo|p) photo=1;;
		--grid-unit|g) grid_unit=$2; shift 1;;
		--mm) grid_unit="mm";;
		--diamond) diamond=1;;
		--annotation) annotation=$2; shift 1;;
	esac
	shift 1
done



awk -v "photo=$photo" -v "grid_unit=$grid_unit" -v "diamond=$diamond" -v "annotation=$annotation" '

BEGIN {
	diamond_x = 0
	diamond_y = 0

	dim_arrow_len = 2000

	q="\""

	ds = 100*20
	offs_3d = 150

	if (photo) {
		clr_board[-1] = "#003300"
		clr_board[0]  = "#006600"
		clr_board[1]  = "#22AA22"

		clr_plated[-1] = "#555555"
		clr_plated[0]  = "#777777"
		clr_plated[1]  = "#999999"

		clr_silk[-1] = "#AAAAAA"
		clr_silk[0] = "#CCCCCC"
		clr_silk[1] = "#FFFFFF"

		clr_solderstop[0] = "#00BB00"


		clr_hole[0] = "black"
		clr_grid[0] = "blue"
	}
	else {
		clr_board[0] = "darkgreen"
		clr_plated[0] = "#777777"
		clr_hole[0] = "white"
		clr_silk[0] = "black"
		clr_solderstop[0] = "white"
		clr_grid[0] = "blue"
	}

	clr_annotation[0] = "#ff0000"
	clr_annotationbg[0] = "#ffffff"

	marg=100000

	if (annotation != "none") {
		enable_annot = 1
		if (annotation ~ "pins")
			enable_pinnum = 1
		if (annotation ~ "dimname")
			enable_dim_name = 1
		if (annotation ~ "dimvalue")
			enable_dim_value = 1
		if (annotation ~ "background")
			enable_annotbg = 1
	}

	if (grid_unit == "mil") {
		gstep = 10000
		gmul = 1/100
	}
	else {
		gstep = 3937
		gmul = 1/3937
	}

	vf_data = vf_load("/usr/share/animator/romansimplexmono")
}

### vector font ###
function vf_load(fn,       s)
{
	while((getline < fn) == 1) {
		if ($1 == "!")
			glyphw[$2] = $3
		else if ($1 == "!font")
			for(i=32; i<=127; i++)
				font[$2 sprintf("%c", i)] = $(i-29)
		else
			s = s "\n" $0
	}
	close(fn)
	return s
}

function vf_textwidth(fnt, text,                           x,k) {
	x=0
	for(k=1; k<=length(text); k+=1)
		x += glyphw[font[fnt substr(text,k,1)]]
	return x
}

function vf_show(fnt, text,                                  k,s) {
	for(k=1; k<=length(text); k+=1)
		s = s "\ninvoke hf" font[fnt substr(text,k,1)]
	return s
}

###

function directive(term     ,tmp)
{
	while(!($0 ~ term "[ \t]*$")) {
		if ((getline tmp) < 1) {
			print "Premature end of file looking for " term " of " $1 > "/dev/stderr"
			exit 1
		}
		$0 = $0 " " tmp
	}
#	print "directive: |" term "|" $0 "|" > "/dev/stderr"
}

function edges(x, y)
{
	if ((xmin == "") || (x < xmin))
		xmin = x
	if ((ymin == "") || (y < ymin))
		ymin = y
	if ((xmax == "") || (x > xmax))
		xmax = x
	if ((ymax == "") || (y > ymax))
		ymax = y
}

# draw a line with rounded ends
# do not draw end circles if omit_ends is non-zero
# extend both ends by length_bloat
function rline(x1, y1, x2, y2, width    ,omit_ends , length_bloat    ,nx,ny,vx,vy, len)
{

	nx = y2-y1
	ny = -(x2-x1)

	len=sqrt(nx*nx+ny*ny)
	if (len != 0) {
		nx /= len
		ny /= len
		vx = -ny
		vy = nx

		if (length_bloat != 0) {
			x1 -= length_bloat * vx
			x2 += length_bloat * vx
			y1 -= length_bloat * vy
			y2 += length_bloat * vy
		}

# if there are no end circles, we are square and should extend by extra width/2
		if (omit_ends) {
			x1 -= (width/2) * vx
			x2 += (width/2) * vx
			y1 -= (width/2) * vy
			y2 += (width/2) * vy
		}

		print "poly", x1+nx*width/2, y1+ny*width/2, x2+nx*width/2, y2+ny*width/2, x2-nx*width/2, y2-ny*width/2, x1-nx*width/2, y1-ny*width/2
		edges(x1+nx*width/2, y1+ny*width/2)
		edges(x2+nx*width/2, y2+ny*width/2)
		edges(x2-nx*width/2, y2-ny*width/2)
		edges(x1-nx*width/2, y1-ny*width/2)
	}

	if (!omit_ends) {
		print "fillcircle", x1, y1, width/2, width/10
		if ((x1 != x2) || (y1 != y2))
			print "fillcircle", x2, y2, width/2, width/10

		edges(x1-width/2, y1-width/2)
		edges(x2+width/2, y2+width/2)
	}

	edges(x1, y1)
	edges(x2, y2)
}

function deg2rad(d)
{
	return d/180*3.141592654
}

function rarc(cx, cy, rx, ry, a_start, a_delta, width   ,a1, a2)
{
	if ((rx < 0) || (ry < 0))
		return

	if (a_delta < 0) {
		a_start = 180-a_start
		a_delta = -a_delta
	}

	step = a_delta * 100 * 2 / (((rx > ry) ? rx : ry) + 1)
	if (step > 45)
		step = 45

	for(a1 = a_start; a1 < a_start + a_delta - step; a1 += step) {
		a2 = a1+step
		rline( cx - rx * cos(deg2rad(a1)), cy + ry * sin(deg2rad(a1)),
		       cx - rx * cos(deg2rad(a2)), cy + ry * sin(deg2rad(a2)),
		       width, 0)
	}

	a1 = a2;
	a2 = a_start+a_delta
	rline( cx - rx * cos(deg2rad(a1)), cy + ry * sin(deg2rad(a1)),
	       cx - rx * cos(deg2rad(a2)), cy + ry * sin(deg2rad(a2)),
	       width, 0)

}

function rsquare(x1, y1, x2, y2, r   ,tmp)
{
	if (x1 < x2) {
		tmp=x1
		x1 = x2
		x2 = tmp
	}
	if (y1 < y2) {
		tmp=y1
		y1 = y2
		y2 = tmp
	}

	print "poly", x1, y1-r,x1-r, y1,  x2+r,y1, x2, y1-r,    x2, y2+r,   x2+r,y2,     x1-r, y2,  x1, y2+r
	print "fillcircle", x1-r, y1-r, r, r/10
	print "fillcircle", x2+r, y2+r, r, r/10
	print "fillcircle", x2+r, y1-r, r, r/10
	print "fillcircle", x1-r, y2+r, r, r/10
}

function flash(x, y, dia, square, roundr)
{
	if (square) {
		if (roundr != "")
			rsquare(x-dia/2, y-dia/2, x+dia/2, y+dia/2, roundr)
		else
			print "fillrect", x-dia/2, y-dia/2, dia, dia
	}
	else
		print "fillcircle", x, y, dia/2, dia/10
}

function hole(x, y, ring, clr, mask, drill, name, square)
{
	if (photo) {
		print "macro push mask"
		flash(x, y, (ring+clr), square, (ring+clr)/10)
		print "endmacro"
	}

	print "macro push copper"
	flash(x, y, ring, square)
	print "endmacro"

	has_hole=1
	print "macro push hole"
	flash(x, y, drill, 0)
	print "endmacro"

	if (enable_pinnum) {
		gsub("[\"]", "", name)
		annot(x, y, name, 0, 0, 1)
	}

	edges(x-(ring+clr)/2, y-(ring+clr)/2)
	edges(x+(ring+clr)/2, y+(ring+clr)/2)
}

function pad(x1, y1, x2, y2, thickness, clr, mask, name, square)
{
	if (photo) {
		print "macro push mask"
		rline(x1, y1, x2, y2, thickness+clr, square)
		print "endmacro"
	}


	print "macro push copper"
	rline(x1, y1, x2, y2, thickness, square)
	print "endmacro"

	if (enable_pinnum) {
		gsub("[\"]", "", name)
		annot((x2+x1)/2, (y2+y1)/2, name, 0, 0, 1)
	}
}

function vf_text(x, y, txt, rot, elev, vcenter   ,TXT,v,n,W,maxw,s,sep,bg,maxh)
{
	gsub("[|]", "", txt)

	v = split(txt, TXT, "[|]")
	sep = " "

	s = s "\n" "push"
	s = s "\n" "shift "  x sep y
	if (rot)
		s = s "\n" "shift " (-1*elev) sep 0
	else
		s = s "\n" "shift " 0 sep (-1*elev)

	s = s "\n" "scale %textscale% %textscale%"
	s = s "\n" "scale 1 -1"

	for(n = 1; n <= v; n++) {
		W[n] = vf_textwidth("roman-simplex-mono", TXT[n])
		if (W[n] > maxw)
			maxw = W[n]
		maxh++
	}

	if (vcenter)
		s = s "\n" "shift 0 " (-maxh/2)

	if (rot)
		s = s "\n" "rotate 90"

	for(n = v; n > 0; n--) {
		s = s "\n" "!TXT " TXT[n]
		s = s "\n" "push"

		s = s "\n" "shift " ((maxw - W[n])/(2)) - maxw/2 sep 0

		if (enable_annotbg) {
			s = s "\n" "color " clr_annotationbg[0]
			s = s "\n" "alpha 0.2"
			s = s "\n" "fillrect " W[n]*-0.1 sep -0.1 "-" sep W[n]*1.1 sep 1.1
			s = s "\n" "alpha 0.1"
			s = s "\n" "fillrect " W[n]*-0.17 sep -0.17 "-" sep W[n]*1.17 sep 1.17
			s = s "\n" "alpha 1"
			s = s "\n" "color " clr_annotation[0]
		}

#		s = s "\n" "thick %textthick%"
		s = s "\n" vf_show("roman-simplex-mono", TXT[n])
#		s = s "\n" "thick 1"
		s = s "\n" "pop"
		s = s "\n" "shift 0 1.15"
	}
	s = s "\n" "pop"
	return s
}



function annot(x, y, txt, rot, elev, hcenter)
{
	annot_pend = annot_pend "\n" vf_text(x, y, txt, rot, elev, hcenter)
}


function dimension(x1, y1, x2, y2, dist, name, value     ,vx,vy,nx,ny,X1,Y1,X2,Y2,len,alen,awidth,tmp, ang,negdist,cx,cy,dx,dy,D)
{
	alen = dim_arrow_len

	vx = x2-x1
	vy = y2-y1
	len = vx*vx+vy*vy
	if (len == 0)
		return
	len = sqrt(len)
	vx = vx/len
	vy = vy/len
	nx = vy
	ny = -vx

	if (dist ~ "^[@]") {
		cx = (x1+x2)/2
		cy = (y1+y2)/2
		sub("@", "", dist)
		split(dist, D, ";")
		nx = D[1] - cx
		ny = D[2] - cy

		X1 = x1+nx
		Y1 = y1+ny
		X2 = x2+nx
		Y2 = y2+ny

		dist = nx*nx+ny*ny
		if (dist > 0)
			dist = sqrt(dist)

		nx /= dist
		ny /= dist
	}
	else {
		if (dist < 0) {
			tmp = x1
			x1 = x2
			x2 = tmp
			tmp = y1
			y1 = y2
			y2 = tmp
			dist = -dist

			vx = -vx
			vy = -vy
			nx = -nx
			ny = -ny
		}

		X1 = x1+nx*dist
		Y1 = y1+ny*dist
		X2 = x2+nx*dist
		Y2 = y2+ny*dist
	}


	if (alen > len/4)
		alen=len/4

	awidth=alen/6

	ang = atan2(vx, vy)

	print "macro push annotation"
	print "line", x1, y1, X1+nx*awidth, Y1+ny*awidth
	print "line", x2, y2, X2+nx*awidth, Y2+ny*awidth
	print "line", X1, Y1, X2, Y2

	print "poly", X1, Y1,  X1+vx*alen+nx*awidth, Y1+vy*alen+ny*awidth ,  X1+vx*alen-nx*awidth, Y1+vy*alen-ny*awidth
	print "poly", X2, Y2,  X2-vx*alen+nx*awidth, Y2-vy*alen+ny*awidth ,  X2-vx*alen-nx*awidth, Y2-vy*alen-ny*awidth
	print "endmacro"

	if (enable_dim_value) {
		if (value == "")
			value = len
		else if (value == "!")
			value = ""
		if (value != "")
			value *= gmul
	}
	else
		value = ""

	if (!enable_dim_name)
		name = ""

	if ((name != "") && (value != ""))
		name = name "=|" value
	else if ((value != "") && (name == ""))
		name = value

	if (name != "") {
		if (ang < 0)
			ang = -ang
		if ((ang < 3.1415*3/4) && (ang > 3.1415*1/4))
			annot((X1+X2)/2, (Y1+Y2)/2, name, 0, awidth*1.1,0)
		else
			annot((X1+X2)/2, (Y1+Y2)/2, name, 1, awidth*1.1,0)
	}

	edges(X1+nx*awidth, Y1+ny*awidth)
	edges(X2+nx*awidth, Y2+ny*awidth)
}

/^[ \t]*#dimension/ {
	if ((enable_dim_name) || (enable_dim_value))
		dimension($2, $3, $4, $5, $6, $7, $8)
}

/^[ \t]*#/ { next }

/ElementLine[ \t]*[[]/ {
	directive("]")
	sub(".*ElementLine[ \t]*[[]", "", $0)
	sub("]$", "", $0)

	print "macro push silk"
	rline($1, $2, $3, $4, $5)
	print "endmacro"

	next
}

/ElementLine[ \t]*[(]/ {
	directive(")")
	sub(".*ElementLine[ \t]*[(]", "", $0)
	sub(")$", "", $0)

	print "macro push silk"
	rline($1*100, $2*100, $3*100, $4*100, $5*100)
	print "endmacro"

	next
}



/ElementArc[ \t]*[[]/ {
	directive("]")
	sub(".*ElementArc[ \t]*[[]", "", $0)
	sub("]$", "", $0)

	print "macro push silk"
	rarc($1, $2,  $3, $4,  $5, $6,  $7)
	print "endmacro"

	next
}

#   ElementArc(0 0 59 59    45  90 10)
/ElementArc[ \t]*[(]/ {
	directive(")")
	sub(".*ElementArc[ \t]*[(]", "", $0)
	sub(")$", "", $0)

	print "macro push silk"
	rarc($1*100, $2*100,  $3*100, $4*100,  $5, $6,  $7*100)
	print "endmacro"

	next
}


#	Pin[0 0 8000 5000 8600 3937 "" "1" "square"]
/Pin[ \t]*[[]/ {
	directive("]")
	sub(".*Pin[ \t]*[[]", "", $0)
	sub("]$", "", $0)
	hole($1, $2, $3, $4, $5, $6, $8, ($9 ~ "square"))
}

#	Pin(300 800 90 60 "3" 0x01)
/Pin[ \t]*[(]/ {
	directive(")")
	sub(".*Pin[ \t]*[(]", "", $0)
	sub("]$", "", $0)
	hole($1*100, $2*100, $3*100, $4*100, 3000, 2000, $5, ($6 ~ "0x10"))
}

#	Pad[ 0 0 0 0 0 5000 8600 "" "4" ""]
/Pad[ \t]*[[]/ {
	directive("]")
	sub(".*Pad[ \t]*[[]", "", $0)
	sub("]$", "", $0)

	pad($1, $2, $3, $4, $5, $6, $7, $9,   ($10 ~ "square"))
}

/Pad[ \t]*[(]/ {
	directive(")")
	sub(".*Pad[ \t]*[(]", "", $0)
	sub(")$", "", $0)

	if (NF > 8)
		pad($1*100, $2*100, $3*100, $4*100, $5*100, $6*100, $7*100, $9,   1)
	else
		pad($1*100, $2*100, $3*100, $4*100, $5*100, $6*100, $7*100, $6,   1)

}

/Mark[ \t]*[(]/ {
	directive(")")
	sub(".*Mark[ \t]*[(]", "", $0)
	sub(")$", "", $0)

	diamond_x = $1*100
	diamond_y = $2*100
}


function layer_3d(name, color,  offs)
{
	if ((offs == "") || (offs == 1))
		offs = offs_3d
	else if (offs == -1)
		offs = -offs_3d

	if (1 in color) {
		print "push"
		print "shift", (-1*offs), (-1*offs)
		print "color", color[1]
		print "invoke ", name
		print "pop"
	}

	if (-1 in color) {
		print "push"
		print "shift", (offs), (offs)
		print "color", color[-1]
		print "invoke ", name
		print "pop"
	}

	if (0 in color) {
		print "color", color[0]
		print "invoke ", name
	}
}

function draw_grid()
{
	while ((size/gstep) > 10)
		gstep=gstep*2

	for(x = 0 - int(marg/gstep)*gstep; x < size+marg; x+=gstep) {
		print "line", x, ymin-marg, x, ymin+size+marg
		print "line", xmin-marg, x, xmin+size+marg, x
		print "text", x, ymax+gstep/2, q x*gmul "\\n" grid_unit q
		print "text", xmax+gstep/2, x, q x*gmul "\\n" grid_unit q
	}

}

END {
	print "frame"
	print vf_data

# make sure all macros exist even if the footprint does not use them
	print "macro push silk\nendmacro"
	print "macro push copper\nendmacro"
	print "macro push mask\nendmacro"
	print "macro push annotation\nendmacro"

	if (photo) {
		xmin -= offs_3d*2
		ymin -= offs_3d*2
		xmax += offs_3d*2
		ymax += offs_3d*2
	}

	sx = xmax-xmin
	sy = ymax-ymin


	size = sx > sy ? sx : sy

	print "scale 1 -1"
	print "viewport", xmin, ymin, "-", xmin+size, ymin+size
	print "bg", clr_solderstop[0]
	print "shift", (size-sx)/2, (size-sy)/2
	print "scale 0.85"


	print "dash 0xaaaa"
	print "color", clr_grid[0]

	if ((grid_unit != "") == (grid_unit != "none"))
		draw_grid()

	print "dash 0xffff"

	if (diamond) {
		print "macro push annotation"
		print "lines", diamond_x-ds, diamond_y,   diamond_x,diamond_y+ds,   diamond_x+ds,diamond_y,   diamond_x,diamond_y-ds,   diamond_x-ds,diamond_y
		print "endmacro"
	}


	if (photo) {
		layer_3d("mask", clr_board, -1)
	}


	print "color", clr_plated[0]
	print "invoke copper"
	layer_3d("copper", clr_plated, 1)
	if (has_hole) {
		layer_3d("hole", clr_hole, -1)
	}


	layer_3d("silk", clr_silk)

	if (enable_annot) {
		gsub("%textscale%", size/40, annot_pend)
#		gsub("%textthick%", size/15000, annot_pend)

		print "macro push annotation"
		print annot_pend
		print "endmacro"

		print "color", clr_annotation[0]
		print "invoke annotation"
	}

	print "flush"
}

'
