/*
 * plot3.c
 *
 * 3-d plot of error space
 *
 */


#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/file.h>
#include <X/Xlib.h>
#include "defs.h"
#include "win.h"
#include "plot3.h"

int	plot3_event();
int	plot3;

XAssocTable	*win_table;

plot3_cmd(args)
	char	*args[];
{
	extern	struct win *win_leftmouse();
	extern	struct win *win_create();
	extern	int clean_up();
	extern	Window init_win();
	struct	plot2info *pp;
	char	geom[80];
	struct	win *wp;

	if (args[1]) {
		if (startsame(args[1], "close")) {
			wp = win_leftmouse("hit left mouse in window to be killed\n");
			if (wp == 0)
				return;
			win_destroy(wp);
			XFlush();
			plot3--;
			return;
		}
	}
	printf("bad plot3 command\n");
}

plot3_create(name, numgraphs, numz, data)
	char	*name;
	float	*data;
{
	register Vertex *vp;
	register struct plot3info *pp;
	struct	win *wp;
	int	i;
	int	j;
	int	k;

	if ((wp = win_create(name, 0)) == 0) {
		printf("window creation failed\n");
		return;
	}
	pp = (struct plot3info *) malloc(sizeof(*pp));
	wp->w_data = (caddr_t) pp;
	wp->w_event = plot3_event;
	pp->data = data;
	p3_identity(pp->wcm);
	pp->v_plot = (Vertex *)
		malloc(sizeof(Vertex) * numgraphs * numz);
	vp = pp->v_plot;
	for (k=0; k<2; k++) {
		for (i=0; i<numgraphs; i++) {
			for (j = 0; j<numz; j++) {
				if (j == 0)
					vp->flags = VertexDontDraw;
				else
					vp->flags = VertexDrawLastPoint |
						VertexCurved;
			}
		}
	}
	pp->graphvec = (float *)
		malloc(sizeof(float) * 2 * numgraphs * numz * 4);
	strcpy(pp->axislabel[0], "*");
	strcpy(pp->axislabel[1], "X");
	strcpy(pp->axislabel[2], "Y");
	strcpy(pp->axislabel[3], "Z");
	XMapWindow(wp->w_win);
	(void) win_resize(wp);
	plot3_resize(wp, pp);
	plot3_repaint(wp, pp);	 
	plot3++;
}

plot3_event(ep, wp)
	XEvent	*ep;
	struct	win *wp;
{
	struct	plot3info *pp;

	pp = (struct plot3info *) wp->w_data;
	switch (ep->type) {
	case ExposeWindow:
		if (win_resize(wp)) {
			/*
			 * have to do a lot of work!
			 */
			plot3_resize(wp, pp);
			plot3_redraw(wp, pp);
		}
		/* fall thru to */
	case ExposeRegion:
	case ExposeCopy:
		plot3_repaint(wp, pp);
		break;
	default:
		break;
	}
}

plot3_repaint(wp, pp)
	register struct win *wp;
	register struct plot3info *pp;
{
	extern	Font font;
	register Vertex *axis;

	XClear(wp->w_win);
	XDraw(wp->w_win, pp->v_plot, pp->numgraphs * pp->numz * 2, 1, 1, 
		wp->w_forepixel, GXcopy, AllPlanes);
	XDraw(wp->w_win, pp->v_axis, 6, 1, 1, 
		wp->w_forepixel, GXcopy, AllPlanes);
	axis = pp->v_axis;
	XText(wp->w_win, axis[0].x, axis[0].y, pp->axislabel[0], 1,
		font, wp->w_forepixel, wp->w_backpixel);
	XText(wp->w_win, axis[1].x, axis[1].y, pp->axislabel[1], 1,
		font, wp->w_backpixel, wp->w_forepixel);
	XText(wp->w_win, axis[3].x, axis[3].y, pp->axislabel[2], 1,
		font, wp->w_backpixel, wp->w_forepixel);
	XText(wp->w_win, axis[5].x, axis[5].y, pp->axislabel[3], 1,
		font, wp->w_backpixel, wp->w_forepixel);
	XFlush();
}

plot3_resize(wp, pp)
	struct	win *wp;
	struct	plot3info *pp;
{
	int	max;
	int	nitems;
	register float *src;
	register float *dvec;
	register float half_window_x;
	register float half_window_y;
	register float half_window_z;
	register float scaling;
	int	i;
	int	j;
	int	X_scale;
	int	Y_scale;
	int	Z_scale;

	max = wp->w_width;
	if (wp->w_width < wp->w_height)
		max = wp->w_height;
	pp->window_x = wp->w_width;
	pp->window_y = wp->w_height;
	pp->window_z = max;
	p3_fillaxis(pp->axis, (min_x+xnorm)*Sx,(max_x+xnorm)*Sx,
		(min_y+ynorm)*Sy,(max_y+ynorm)*Sy,
		(min_z+znorm)*Sz,(max_z+znorm)*Sz);
	nitems = pp->numgraphs * pp->numz;
	src = pp->data;
	dvec = pp->graphvec;
	/*
	 * scale the data, vectorize it, and plop it into
	 * the "graphvec" which plot3_redraw requires it in.
	 */
	for (i=0; i < pp->numz; i++) {
		for (j=0; j < pp->numgraphs; j++) {
			dvec[DX] = i * scaling;
			dvec[DY] = j * scaling;
			dvec[DZ] = *src++ * scaling;
			dvec[DS] = 1.0;
			dvec += 4;
		}
	}
	for (i=0; i < pp->numgraphs; i++) {
		for (j=0; j < pp->numz; j++) {
			dvec[DX] = i * scaling;
			dvec[DY] = j * scaling;
			dvec[DZ] = *src++ * scaling;
			dvec[DS] = 1.0;
			dvec += 4;
		}
	}
#ifdef notdef
	scale_mat[0][0] =  .5;
	Sx = (pp->window_x/(max_x - min_x))*(1.0/X_scale);	
	scale_mat[1][1] =  .5;
	Sy = (pp->window_y/(max_y - min_y))*(1.0/Y_scale);	
	scale_mat[2][2] =  .5;
	Sz = (pp->window_z/(max_z - min_z))*(1.0/Z_scale);	
	scale_mat[3][3] = 1.0;
#endif
	half_window_x = pp->window_x * 0.5;
	half_window_y = pp->window_y * 0.5;
	half_window_z = pp->window_z * 0.5;
	/*
	 * Translate so origin is in center of all plots, so we can 
	 * rotate about the center of the image.
	 */
	identity(pp->trans);
	pp->trans[3][0] = (-(half_window_x) * 1.0/X_scale);
	pp->trans[3][1] = (-(half_window_y) * 1.0/Y_scale);
	pp->trans[3][2] = (-(half_window_z) * 1.0/Z_scale); 
	identity(pp->back);
	pp->back[3][0] = ((half_window_x) * 1.0/X_scale); 
	pp->back[3][1] = ((half_window_y) * 1.0/Y_scale); 
	pp->back[3][2] = ((half_window_z) * 1.0/Z_scale); 
	
}


plot3_redraw(pp)
	register struct plot3info *pp;
{
	register Vertex *vptr;
	register int i;
	register int j;
	register float *pvec;
	register float xshift;
	register float yshift;
	float	*tmpvec1;
	float	*tmpvec2;
	float	int_mat[4][4];
	float	axis1[3][2][4];
	float	axis2[3][2][4];
	int	nelem;

	tmpvec1 = (float *)
		alloca(sizeof(float) * 2 * pp->numz * pp->numgraphs * 4);
	tmpvec2 = (float *)
		alloca(sizeof(float) * 2 * pp->numz * pp->numgraphs * 4);
	/*
	 * apply translate to wcm, apply that to our data,
	 * and then apply back-translation to get eveyrthing
	 * back to 0,0
	 */
	nelem = 2 * pp->numgraphs * pp->numz;
	my_mat_mult(pp->graphvec, pp->trans, tmpvec1, nelem, 4);
	my_mat_mult(tmpvec1, pp->wcm, tmpvec2, nelem, 4);
	my_mat_mult(tmpvec2, pp->back, tmpvec1, nelem, 4);
	/*
	 * do axis stuff
	 */
	my_mat_mult(pp->axis, pp->trans, axis1, 6, 4);
	my_mat_mult(axis1, pp->wcm, axis2, 6, 4);
	my_mat_mult(axis2, pp->back, axis1, 6, 4);
	/*
	 * now use this to draw 2-d verticies
	 */
	vptr = pp->v_plot;
	pvec = tmpvec1;
	xshift = (Window_X - (Window_X * 1.0 / X_scale))/2;
	yshift = (Window_Y - (Window_Y * 1.0 / Y_scale))/2;
	for (i = 0; i < pp->numgraphs; i++) {
		for (j = 0; j < pp->numz; j++) {
			vptr->x = pvec[DX] + xshift;
			vptr->y = pvec[DY] + yshift;
			vptr++;
			pvec += 4;
		}
	}
	for (i = 0; i < pp->numz; i++) {
		for (j = 0; j < pp->numgraphs; j++) {
			vptr->x = pvec[DX] + xshift;
			vptr->y = pvec[DY] + yshift;
			vptr++;
		}
	}
	pvec = pp->axis[0][0];
	for (i=0; i<3; i++) {
		for (j=0; j<2; j++) {
			vptr->x = pvec[DX] + xshift;
			vptr->y = pvec[DY] + yshift;
			pvec += 4;
		}
	}
}
