#!/bin/sh
#
# stickfig - generate stick figure from ProAnalyst's exported limb coordinates
#
# Usage: stickfig [-n num] [-s rec] [-e rec] [-c col] [-f nf] [-x fn] [-y fn] \
#			[-m mul] [-g gap] [-b] [-v] input.csv > output.plt
#
# where: -n num	specifies a frame rate divisor for reducing the amount of
#		output, such that only the first of each "num" input records
#		will appear in the output (default is 10)
#	 -s rec	specifies the starting record number (default is 1)
#	 -e rec	specifies the ending record number (default is all)
#		only the records between the specified start and end will
#		be included in the output.  If instead of a record number,
#		the start or end is specified as a time value followed by "s"
#		(for seconds), then the record with a matching time value in
#		column 2 will be used as the start or end. If the record number
#		is followed by "i" (for index) the record with a matching index
#		value in column 1 will be used.  If the number is followed by
#		"ss" it is taken as seconds from the start, i.e. the first
#		record.
#	 -c col	specifies the starting column for the first X coordinate
#		(default is 3)
#	 -f nf	specifies the number of features (coordinate pairs) in the
#		input file (default is the number of pairs in the first record)
#	 -x fn	specifies a feature number on which to normalize the X position
#		(default is 0, meaning no normalization)
#	 -y fn	specifies a feature number on which to normalize the height (Y)
#		(default is 0, meaning no normalization)
#	 -m mul	specifies the scaling factor by which the coordinates will be
#		multiplied (default is 1). By default, the figures are scaled
#		so that they occupy the middle third of a plotter page, and are
#		spaced apart to fill the whole width. Increasing the scaling
#		will cause them to appear larger but be spaced closer together.
#		The multiplier is relative to the automatic scaling that will
#		be used to convert the input coordinates to the HPGL coordinate
#		system. You can specify an absolute scaling factor by appending
#		the string "abs" to the number, e.g. 120abs, to get fixed
#		scaling of the data across several data sets.
#	 -g gap	specifies the x-axis spacing or gap between successive limb
#		figures, overriding the automatic spacing calculation.  The
#		gap is specified in HPGL plotter units.  (default is automatic)
#	 -b	specifies that a scale bar should be shown at the bottom left
#	 -v	specifies verbose output, which will show some calculated
#		parameters
#	 input.csv is the name of the file exported from ProAnalyst
#	 output.plt is the name of the HPGL plot file that is output
#
# Copyright (c) 2010-2011, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

nopt=10
sopt=1
eopt=2000000000
copt=3
fopt=1000
xopt=0
yopt=0
mopt=1
gopt=
bopt=0
vopt=0
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-n[0-9]*)	nopt=`expr "x$1" : 'x-n\(.*\)'`; shift ;;
	-n)	shift; nopt="$1"; shift ;;
	-s[-0-9]*)	sopt=`expr "x$1" : 'x-s\(.*\)'`; shift ;;
	-s)	shift; sopt="$1"; shift ;;
	-e[-0-9]*)	eopt=`expr "x$1" : 'x-e\(.*\)'`; shift ;;
	-e)	shift; eopt="$1"; shift ;;
	-c[0-9]*)	copt=`expr "x$1" : 'x-c\(.*\)'`; shift ;;
	-c)	shift; copt="$1"; shift ;;
	-f[0-9]*)	fopt=`expr "x$1" : 'x-f\(.*\)'`; shift ;;
	-f)	shift; fopt="$1"; shift ;;
	-x[0-9]*)	xopt=`expr "x$1" : 'x-x\(.*\)'`; shift ;;
	-x)	shift; xopt="$1"; shift ;;
	-y[0-9]*)	yopt=`expr "x$1" : 'x-y\(.*\)'`; shift ;;
	-y)	shift; yopt="$1"; shift ;;
	-m[-.0-9]*)	mopt=`expr "x$1" : 'x-m\(.*\)'`; shift ;;
	-m)	shift; mopt="$1"; shift ;;
	-g[-.0-9]*)	gopt=`expr "x$1" : 'x-g\(.*\)'`; shift ;;
	-g)	shift; gopt="$1"; shift ;;
	-b)	bopt=1; shift ;;
	-v)	vopt=1; shift ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done

case "$#" in
0)	echo "Usage: stickfig [-n num] [-s rec] [-e rec] [-c col] [-f nf] [-x fn] [-y fn] \\
		[-m mul] [-g gap] [-b] [-v] input.csv > output.plt
	or stickfig --help	for detailed usage information" >&2; exit 1 ;;
esac

awk -F, 'BEGIN {
		n = '"$nopt"'
		starttime = ""
		sttrel = 0
		start = "'"$sopt"'"
		if (start ~ /.*[is]$/) {
			sttcol = 2
			if (start ~ /.*i$/) sttcol = 1
			if (start ~ /.*ss$/) sttrel = 1
			starttime = start
			sub(/[is]s*$/, "", starttime)
			starttime = starttime * 1.0;
			start = 2^30;
		} else
			start += 0;
		endtime = ""
		entrel = 0
		end = "'"$eopt"'"
		if (end ~ /.*[is]$/) {
			entcol = 2
			if (end ~ /.*i$/) entcol = 1
			if (end ~ /.*ss$/) entrel = 1
			endtime = end
			sub(/[is]s*$/, "", endtime)
			endtime = endtime * 1.0;
			end = 2^30;
		} else
			end += 0;
		stcol = '"$copt"'
		pairs = '"$fopt"'
		xnorm = '"$xopt"'
		ynorm = '"$yopt"'
		mult = "'"$mopt"'"
		gap = "'"$gopt"'"
		bars = '"$bopt"'
		verbose = '"$vopt"'
		irec = 0
		orec = 0
		xmin = 0
		xmax = 0
		ymin = 0
		ymax = 0
		xoff = 0
		yoff = 0
	}
	/^[ 	]*-*[0-9][0-9]*,/ && NF >= stcol+3 {
		if (sttrel && irec == 0 && NF >= sttcol)
			starttime += $(sttcol)
		if (starttime != "" && NF > sttcol && $(sttcol)*1.0 >= starttime) {
			starttime = ""
			start = irec+1
		}
		if (entrel && irec == 0 && NF >= entcol)
			endtime += $(entcol)
		if (endtime != "" && NF > entcol && $(entcol)*1.0 > endtime) {
			endtime = ""
			end = irec
		}
		if (irec == 0) {
			if (sttcol > 0 && sttcol <= NF)
				frec = $(sttcol)
			else
				frec = irec
			if (entcol > 0 && entcol <= NF)
				ferec = $(entcol)
			else
				ferec = irec
		}
		if (sttcol > 0 && sttcol <= NF)
			lrec = $(sttcol)
		else
			lrec = irec
		if (entcol > 0 && entcol <= NF)
			lerec = $(entcol)
		else
			lerec = irec
		if (++irec >= start && irec <= end && (irec-start) % n == 0) {
			++orec
			if (orec <= 1 && pairs > (NF+1-stcol)/2)
				pairs = (NF+1-stcol)/2
			if (xnorm > 0 && orec > 1)
				xoff = $(xnorm*2+stcol-2) - x[1 "," xnorm]
			if (ynorm > 0 && orec > 1)
				yoff = $(ynorm*2+stcol-1) - y[1 "," ynorm]
			for (j = 1; j <= pairs; ++j) {
				x[orec "," j] = $(j*2+stcol-2)-xoff
				y[orec "," j] = $(j*2+stcol-1)-yoff
				if (orec <= 1 || xmin > x[orec "," j])
					xmin = x[orec "," j]
				if (orec <= 1 || xmax < x[orec "," j])
					xmax = x[orec "," j]
				if (orec <= 1 || ymin > y[orec "," j])
					ymin = y[orec "," j]
				if (orec <= 1 || ymax < y[orec "," j])
					ymax = y[orec "," j]
			}
		}
	}
	END {
		ymid = (ymin+ymax) / 2
		if (mult ~ /.*abs/) {
			sub(/abs/, "", mult)
			mult *= 1.0
			if (verbose)
				printf("abs mult=%g\n",mult) >> "/dev/stderr"
		} else if (ymax > ymin)
			mult *= 2400 / (ymax-ymin)
		yoff = 320 + 3600
		xoff = 80
		xgap = 0
		if (orec > 1)
			xgap = (10000 - (xmax-xmin)*mult) / (orec-1)
		else if (orec == 0) {
			if (irec == 0)
				printf("stickfig: no input records found in data file\n") >> "/dev/stderr"
			else {
				printf("stickfig: no matching records found within specified start and end\n") >> "/dev/stderr"
				if (sttrel) {
					lrec -= frec
					frec = 0
				}
				if (sttcol == entcol && sttrel == entrel)
					printf("          start and end should be between %g and %g\n", frec, lrec) >> "/dev/stderr"
				else {
					if (entrel) {
						lerec -= ferec
						ferec = 0
					}
					printf("          start should be between %g and %g, end between %g and %g\n", frec, lrec, ferec, lerec) >> "/dev/stderr"
				}
			}
		}
		if (gap != "")
			xgap = gap * 1.0
		if (verbose) {
			printf("start=%g, end=%g, irec=%g, orec=%g, n=%g\n",start,end,irec,orec,n) >> "/dev/stderr"
			printf("xmin=%g, xmax=%g, xoff=%g, xgap=%g\n",xmin,xmax,xoff,xgap) >> "/dev/stderr"
			printf("ymin=%g, ymax=%g, yoff=%g, ymid=%g, mult=%g\n",ymin,ymax,yoff,ymid,mult) >> "/dev/stderr"
		}
		printf("PU;PA;SC80,10080,320,7520;\nPU;SP1;\n")
		if (bars) {
			len = 500
			while (len*mult > 2000)
				len /= 10
			barsize = int(len*mult)
			yoff -= 3600
			printf("PU%d,%d;PD%d,%d;\n", xoff, yoff+barsize, xoff, yoff)
			printf("PU%d,%d;LB%g\003;\n", xoff+50, yoff+barsize/2, len)
#			printf("PU%d,%d;PD%d,%d;PD%d,%d;\n", xoff, yoff+barsize, xoff, yoff, xoff+barsize, yoff)
#			printf("PU%d,%d;LB%g\003;\n", xoff+50, yoff+barsize*2/3, len)
#			printf("PU%d,%d;LB%g\003;\n", xoff+50+barsize*2/3, yoff+50, len)
			yoff += 3600
		}
		for (i = 1; i <= orec; ++i) {
			p = "PU"
			for (j = 1; j <= pairs; ++j) {
				x[i "," j] = int((x[i "," j]-xmin)*mult+xoff)
				y[i "," j] = int((y[i "," j]-ymid)*mult+yoff)
				printf("%s%d,%d;", p, x[i "," j], y[i "," j])
				p = "PD"
			}
			xoff += xgap
			printf("\n")
		}
	}' ${@+"$@"}
