
/* 
 * Author:  Graeme W. Gill
 * Date:    2007/3/21
 * Version: 1.00
 *
 * Copyright 2007 Graeme W. Gill
 * All rights reserved.
 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
 * see the License.txt file for licencing details.
 *
 */

/*
 * This is some utility code to subsample the 1 and 5nm spectral
 * data in xspect to wider spacings using ANSI-CGATS the recommended
 * triangular filter.
 */

#include <stdio.h>
#include <math.h>
#include "aconfig.h"
#include "cgats.h"
#include "xspect.h"
#include "numlib.h"
#include "ui.h"

void usage(void) {
	fprintf(stderr,"Downsample spectral data\n");
	fprintf(stderr,"Author: Graeme W. Gill\n");
	fprintf(stderr,"usage: specsubsamp -options\n");
	fprintf(stderr," -i illum        Choose illuminant for print/transparency spectral data:\n");
	fprintf(stderr,"                 A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
	fprintf(stderr," -o observ       Choose CIE Observer for spectral data:\n");
	fprintf(stderr,"                 1931_2, 1964_10, 2012_2, 2012_10, S&B 1955_2, shaw, J&V 1978_2 or file.cmf\n");
	fprintf(stderr," -w st,en,sp     Output start, end and spacing nm\n");
	fprintf(stderr," -5 		     Commenf output wavelegths every 5\n");
	exit(1);
}

int
main(
	int argc,
	char *argv[]
) {
	int fa,nfa;				/* argument we're looking at */
	int verb = 0;
	icxIllumeType illum = icxIT_D50;	/* Spectral defaults */
	xspect cust_illum;			/* Custom illumination spectrum */
	icxObserverType obType = icxOT_CIE_1931_2;
	xspect custObserver[3];				/* If obType = icxOT_custom */
	int obs = 0;				/* If nz output observer */			
	double wl_short = 380.0, wl_long = 730.0, wl_width = 10.0;
	int wl_n = 0;
	int evy5 = 0;

	error_program = argv[0];

	/* Process the arguments */
	for(fa = 1;fa < argc;fa++) {
		nfa = fa;					/* skip to nfa if next argument is used */
		if (argv[fa][0] == '-')	{	/* Look for any flags */
			char *na = NULL;		/* next argument after flag, null if none */

			if (argv[fa][2] != '\000')
				na = &argv[fa][2];		/* next is directly after flag */
			else {
				if ((fa+1) < argc) {
					if (argv[fa+1][0] != '-') {
						nfa = fa + 1;
						na = argv[nfa];		/* next is seperate non-flag argument */
					}
				}
			}

			/* Spectral Illuminant type */
			if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
				fa = nfa;
				if (na == NULL) usage();
				if (strcmp(na, "A") == 0) {
					illum = icxIT_A;
				} else if (strcmp(na, "C") == 0) {
					illum = icxIT_C;
				} else if (strcmp(na, "D50") == 0) {
					illum = icxIT_D50;
				} else if (strcmp(na, "D50M2") == 0) {
					illum = icxIT_D50M2;
				} else if (strcmp(na, "D65") == 0) {
					illum = icxIT_D65;
				} else if (strcmp(na, "F5") == 0) {
					illum = icxIT_F5;
				} else if (strcmp(na, "F8") == 0) {
					illum = icxIT_F8;
				} else if (strcmp(na, "F10") == 0) {
					illum = icxIT_F10;
				} else {	/* Assume it's a filename */
					inst_meas_type mt;

					illum = icxIT_custom;
					if (read_xspect(&cust_illum, &mt, NULL, na) != 0)
						usage();

					if (mt != inst_mrt_none
					 && mt != inst_mrt_emission
					 && mt != inst_mrt_ambient
					 && mt != inst_mrt_emission_flash
					 && mt != inst_mrt_ambient_flash)
						error("Custom illuminant '%s' is wrong measurement type",na);
				}
			}

			/* Spectral Observer type */
			else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
				fa = nfa;
				if (na == NULL) usage();
				if (strcmp(na, "1931_2") == 0) {			/* Classic 2 degree */
					obs = 1;
					obType = icxOT_CIE_1931_2;
				} else if (strcmp(na, "1964_10") == 0) {	/* Classic 10 degree */
					obs = 1;
					obType = icxOT_CIE_1964_10;
				} else if (strcmp(na, "2012_2") == 0) {		/* Latest 2 degree */
					obs = 1;
					obType = icxOT_CIE_2012_2;
				} else if (strcmp(na, "2012_10") == 0) {	/* Latest 10 degree */
					obs = 1;
					obType = icxOT_CIE_2012_10;
				} else if (strcmp(na, "1955_2") == 0) {		/* Stiles and Burch 1955 2 degree */
					obs = 1;
					obType = icxOT_Stiles_Burch_2;
				} else if (strcmp(na, "1978_2") == 0) {		/* Judd and Voss 1978 2 degree */
					obs = 1;
					obType = icxOT_Judd_Voss_2;
				} else if (strcmp(na, "shaw") == 0) {		/* Shaw and Fairchilds 1997 2 degree */
					obs = 1;
					obType = icxOT_Shaw_Fairchild_2;
				} else {	/* Assume it's a filename */
					obs = 1;
					obType = icxOT_custom;
					if (read_cmf(custObserver, na) != 0)
						usage();
				}
			}

			else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
				fa = nfa;
				if (na == NULL) usage();
				if (sscanf(na, " %lf,%lf,%lf ",&wl_short,&wl_long,&wl_width) != 3)

				if (wl_short > wl_long)
					usage();
			}

			else if (argv[fa][1] == '5') {
				evy5 = 1;
			}

			/* Verbosity */
			else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
				verb = 1;
			} else {
				usage();
			}
		}
		else
			break;
	}

	wl_n = (int)((wl_long - wl_short)/wl_width + 1.5);

	if ((fabs(wl_short + (wl_n - 1.0) * wl_width) - wl_long) > 0.001)
		error("Not an integer number of output samples");


	if (obs) {
		int i, j, k;
		xspect *sp[3];

		if (obType == icxOT_custom) {
			sp[0] = &custObserver[0];
			sp[1] = &custObserver[1];
			sp[2] = &custObserver[2];
		} else {
			if (standardObserver(sp, obType) != 0)
				error ("standardObserver returned error");
		}
		printf("/* %f - %f, %f spacing, %d samples */\n",wl_short,wl_long,wl_width,wl_n);
		printf("{\n");
		for (k = 0; k < 3; k++) {

			printf("	{\n");
			for (i = 0; i < wl_n; i++) {
				double cwl, swl, sw, tw, outv;
				int ns;

				cwl = XSPECT_WL(wl_short, wl_long, wl_n, i);
				ns = (int)(wl_width/0.1 + 0.5);
				tw = outv = 0.0;
				for (j = -ns; j <= ns; j++) {
					swl = cwl + (j * wl_width)/ns;
					sw = (ns - abs(j))/(double)ns;
					tw += sw;
					outv += sw * value_xspect(sp[k], swl);
				}
				outv /= tw;
				if (!evy5 || i % 5 == 0)
					printf("		/* %3.1f */	%1.10f%s\n",cwl,outv, i < (wl_n-1) ? "," : "");
				else
					printf("		            %1.10f%s\n",outv, i < (wl_n-1) ? "," : "");
			}
			printf("	}%s\n",k < (3-1) ? "," : "");
		}
		printf("}\n");

	} else {
		int i, j;
		xspect sp;

		if (illum == icxIT_custom)
			sp = cust_illum;
		else {
			if (standardIlluminant(&sp, illum, 0) != 0)
				error ("standardIlluminant returned error");
		}

		printf("/* %f - %f, %f spacing, %d samples */\n",wl_short,wl_long,wl_width,wl_n);
		printf("{\n");
		for (i = 0; i < wl_n; i++) {
			double cwl, swl, sw, tw, outv;
			int ns;

			cwl = XSPECT_WL(wl_short, wl_long, wl_n, i);
//printf("~1 output %f\n",cwl);
			ns = (int)(wl_width/0.1 + 0.5);
			tw = outv = 0.0;
			for (j = -ns; j <= ns; j++) {
				swl = cwl + (j * wl_width)/ns;
				sw = (ns - abs(j))/(double)ns;
				tw += sw;
//printf("~1 sample %f weight %f\n",swl,sw);
				outv += sw * value_xspect(&sp, swl);
			}
			outv /= tw;
			if (!evy5 || i % 5 == 0)
				printf("	/* %3.1f */	%1.10f%s\n",cwl,outv, i < (wl_n-1) ? "," : "");
			else
				printf("	            %1.10f%s\n",outv, i < (wl_n-1) ? "," : "");
		}
		printf("}\n");
	}
	return 0;
}








