 /*
	graph.c		-	Bill Nickerson, 1988

	Functions for graphing formulas.

	Export: DrawFormula
	Static: none
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include "enter.h"
#include "main.h"

/*
	Imported functions and variables.
*/
extern struct IntuiMessage *GetMsg();
extern struct Window *OpenWindow();
extern void CloseWindow(), Wait(), ReplyMsg();
extern void SetAPen(), SetDrMd(), Move(), Draw();
extern void parse();
extern double evaluate();

extern Formula flist[];
extern int errno;

/*--------------------NewWindow for graphing---------------------------------*/

struct NewWindow GRNW = { 0, 0, 640, 200, 0, 1, VANILLAKEY | MOUSEMOVE,
			  BORDERLESS | ACTIVATE | REPORTMOUSE,
			  NULL, NULL, NULL, NULL, NULL,
			  0, 0, 0, 0, WBENCHSCREEN };

/*--------------------NewWindow for coordinates------------------------------*/

struct NewWindow COORDSNW = { 0, 0, 100, 35, 0, 1, 0, WINDOWDRAG,
			      NULL, NULL, NULL, NULL, NULL,
			      0, 0, 0, 0, WBENCHSCREEN };

/*---------------------------------------------------------------------------*/

/*
	f	- pointer to structures containing formula strings.
	b	- pointer to array defining graph bounds.
	res	- resolution to use when graphing. Currently unused.

	Draw a graph of selected formulas on the screen and wait for a
	mouse button to be pressed. If either x or y bounds are equal, no
	graph is drawn.
	Returns nothing.
*/
void DrawFormula( f, b, res )
Formula *f;
double *b, res;
{
	struct Window *Win, *CWin;
	struct IntuiMessage *msg;
	char buf[15];
	double pcode[80], scalex, scaley, dx, incx, reslt;
	int i, xa, ya, x, y, lx, ly, set, done;

	if ((b[0] == b[1]) || (b[2] == b[3]))
		return;

	if ((Win = OpenWindow(&GRNW)) == NULL)
		return;
	if ((CWin = OpenWindow(&COORDSNW)) == NULL)
	{
		CloseWindow(Win);
		return;
	}

	SetAPen(Win->RPort, 1L);

	/*
		Find resolution, draw axes and labels (later).
	*/
	scaley = 199/(b[0]-b[1]);
	scalex = 639/(b[3]-b[2]);
	incx =  (b[3]-b[2])/639;
	ya = (int)(-b[2]*scalex);
	xa = (int)(b[0]*scaley);

	if (b[0]*b[1] <= 0.0) /* There is an X axis here somewhere. */
	{
		Move(Win->RPort, 0, xa);
		Draw(Win->RPort, 639, xa);
	}
	if (b[2]*b[3] <= 0.0) /* There is an Y axis here somewhere. */
	{
		Move(Win->RPort, ya, 0);
		Draw(Win->RPort, ya, 199);
	}

	for (i = 0; i < MAXFORMULAS; i++)
		if (flist[i].selected & FSELECT)
		{
			set = 0;
			parse(flist[i].form, pcode);
			for (dx = b[2]; dx <= b[3]; dx += incx)
			{
				reslt = evaluate(pcode, dx);
				if (errno != 0)
				/*
					If errno isn't zero, then an exception
					occurred and the result isn't valid.
					The next statement makes sure that the
					next coordinate plotted isn't joined
					to the one that caused the exception.
				*/
					set = 0;
				else
				{
					x = (int)((dx-b[2])*scalex);
					y = (int)((b[0]-reslt)*scaley);
					/*
						Make sure we're within screen
						bounds.
					*/
					if ((x >= 0) && (x < 640) &&
						(y >= 0) && (y < 200))
					{
						Move(Win->RPort, x, y);
						if (set && (flist[i].selected & FJOIN))
							Draw(Win->RPort, lx, ly);
						else
						{
							set = 1;
							Draw(Win->RPort, x, y);
						}
					}
					else	set = 0;
				}
				lx = x;
				ly = y;
			}
		}

	/*
		Wait for a mouse button to be pressed. Draw crosshairs and
		track mouse position in the meantime.
	*/
	SetDrMd(Win->RPort, COMPLEMENT);
	set = done = 0;
	while (!done)
	{
		Wait(1<<Win->UserPort->mp_SigBit);
		while (msg = GetMsg(Win->UserPort))
		{
			if (msg->Class == MOUSEMOVE)
			{
				x = msg->MouseX;
				y = msg->MouseY;
			}
			else	done = 1;
			ReplyMsg(msg);
		}
		/*
			Write coordinates to coordinate window.
		*/
		sprintf(buf, "%3.3e", x/scalex+b[2]);
		Move(CWin->RPort, 5, 15 + CWin->RPort->TxBaseline);
		Text(CWin->RPort, buf, strlen(buf));
		sprintf(buf, "%3.3e", -(y/scaley-b[0]));
		Move(CWin->RPort, 5, 25 + CWin->RPort->TxBaseline);
		Text(CWin->RPort, buf, strlen(buf));

		Move(Win->RPort, x, 0);
		Draw(Win->RPort, x, 199);
		Move(Win->RPort, 0, y);
		Draw(Win->RPort, 639, y);
		if (set)
		{
			Move(Win->RPort, lx, 0);
			Draw(Win->RPort, lx, 199);
			Move(Win->RPort, 0, ly);
			Draw(Win->RPort, 639, ly);
		}
		else	set = 1;
		lx = x;
		ly = y;
	}
	CloseWindow(Win);
	CloseWindow(CWin);
}

