home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Program to draw a function given as Y = f(X) or X = f(t), Y = f(t) . *
- * The function is drawn with its derivatives, up to any level... *
- * *
- * Written be : Gershon Elber Ver 0.2, Apr. 1989 *
- *****************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <graphics.h>
- #include <math.h>
- #include <string.h>
- #include <conio.h>
- #include <dos.h>
- #include <dir.h>
- #include <setjmp.h>
- #include "Program.h"
- #include "Expr2TrG.h"
- #include "GraphGnG.h"
- #include "MouseDrv.h"
- #include "Config.h"
- #include "MathErr.h"
-
- int MouseExists = FALSE, /* Set according to autotest and config enforcment */
- GraphDriver = DETECT; /* " */
- char *VersionStr = "DrawFunc IBMPC version 1.0, Gershon Elber, "
- __DATE__ ", " __TIME__ "\n"
- "(C) Copyright 1989 Gershon Elber, Non commercial use only.";
- static int
- FuncDrawFlags[4] = { TRUE, FALSE, FALSE, FALSE }, /* What Der. to draw */
- AutoScaleFlag = TRUE,
- NumOfSamples = 100; /* Number of samples per function drawing */
- static double
- LocalXmin = 1.0, LocalXmax = -1.0, /* For autoscaling */
- LocalYmax = 1.0;
- static jmp_buf LongJumpBuffer; /* Used in error trapping */
- static char CurrentWorkingDir[LINE_LEN];/* Save start CWD to recover on exit */
-
- extern unsigned int _stklen = 16384;
-
- /* And here is the configuration module data structure: */
- static ConfigStruct SetUp[] =
- { { "NumOfSamples", (void *) &NumOfSamples, SU_INTEGER_TYPE },
- { "GraphDriver", (void *) &GraphDriver, SU_INTEGER_TYPE },
- { "Mouse", (void *) &MouseExists, SU_BOOLEAN_TYPE } };
-
- /* Number of entries in SetUp structure: */
- #define NUM_SET_UP sizeof(SetUp) / sizeof(ConfigStruct)
-
- static void UpdateMainFlags(MenuItem *MainMenu, int *FuncDrawFlags);
- void RedrawScreen(ExprNode *PFuncX[], ExprNode *PFuncY[],
- char SFuncX[][LINE_LEN_LONG], char SFuncY[][LINE_LEN_LONG],
- double *Xmin, double *Xmax, double *Ymax,
- double Tmin, double Tmax, int InputKind);
- static void DrawFunction(ExprNode *PFuncX, ExprNode *PFuncY,
- char *SFuncX, char *SFuncY, int Color, double Tmin, double Tmax,
- double Xmin, double Xmax, double Ymax, double PosX, double PosY,
- int InputKind, char *FuncName);
- static double MapXcoord(double x, double Xmin, double Xmax);
- static double MapYcoord(double y, double Ymax);
- static void DrawAxes(double Xmin, double Xmax, double Ymax);
-
- /*****************************************************************************
- * Main routine of function drawing. *
- *****************************************************************************/
- void main(int argc, char **argv)
- {
- static struct MenuItem MainMenu[] = { /* Main Menu selection */
- YELLOW, "Function Drawing",
- FUNC_COLOR, "Get Function",
- FUNC_DER1, " ", /* Used as F' ON/OFF */
- FUNC_DER2, " ", /* Used as F'' ON/OFF */
- FUNC_DER3, " ", /* Used as F''' ON/OFF */
- CYAN, "Parameters Set",
- CYAN, "Redraw",
- CYAN, "Help",
- MAGENTA, "",
- BLUE, "Exit"
- };
- int i, select, InputKind = 0, color;
- char SFuncX[4][LINE_LEN_LONG], SFuncY[4][LINE_LEN_LONG], *FuncName,
- *ErrorMsg;
- double Xmin = -1.0, Xmax = 1.0, Ymax = 1.0,
- TFuncMin = -1.0, TFuncMax = 1.0;
- /* Used to save input func. as binary tree */
- ExprNode *PFuncX[4], *PFuncY[4];
- /* Used to save func. as string */
-
- /* If math error occurs - long jump to given place: */
- MathErrorSetUp(ME_KILL, NULL);
-
- getcwd(CurrentWorkingDir, LINE_LEN-1);
-
- MouseExists = MouseDetect(); /* Automatic mouse detection routine */
-
- if (_osmajor <= 2) /* No argv[0] is given (prgm name) - allways NULL! */
- Config("DrawFunc", SetUp, NUM_SET_UP);/*Read config. file if exists */
- else Config(*argv, SetUp, NUM_SET_UP); /* Read config. file if exists */
-
- while (argc-- > 1) {
- if (strcmp(*++argv, "-z") == 0) {
- fprintf(stderr, "\n%s\n", VersionStr);
- fprintf(stderr, "\nUsage: drawfunc [-z]\n");
- ConfigPrint(SetUp, NUM_SET_UP);
- MyExit(0);
- }
- }
-
- GGInitGraph();
- GGClearMenuArea();
- GGClearViewArea();
-
- if (MouseExists) /* Must be initialized AFTER graph mode was selected. */
- if ((ErrorMsg = MouseInit()) != NULL) {
- /* Must be called before any usage! */
- fprintf(stderr, "\n%s\n\n\tPress any key to continue:", ErrorMsg);
- MouseExists = FALSE;
- getch();
- }
-
- for (i=0; i<4; i++) {
- PFuncX[i] = PFuncY[i] = NULL; /* Clear data */
- SFuncX[i][0] = SFuncY[i][0] = 0;
- }
-
- while (TRUE) {
- UpdateMainFlags(MainMenu, FuncDrawFlags);
- GGMenuDraw(9, MainMenu, TRUE); /* Draw MainMenu */
- select = GGMenuPick();
-
- switch (select) {
- case 1: /* Get New function to draw */
- GGClearViewArea(); /* New data - clear all */
- DoGetFunc(PFuncX, PFuncY, SFuncX, SFuncY, &InputKind
- , &Xmin, &Xmax, &Ymax, &TFuncMin, &TFuncMax);
- if (InputKind == XY_FUNC_T) {
- LocalXmin = Xmin = -1.0; /* Default as a start */
- LocalXmax = Xmax = 1.0;
- LocalYmax = Ymax = 1.0;
- }
- else LocalYmax = Ymax = 1.0; /* Default as a start */
- RedrawScreen(PFuncX, PFuncY, SFuncX, SFuncY,
- &Xmin, &Xmax, &Ymax,
- TFuncMin, TFuncMax, InputKind);
- break;
- case 2: /* Toggle first derivative drawing */
- case 3: /* Toggle second derivative drawing */
- case 4: /* Toggle third derivative drawing */
- if (FuncDrawFlags[select-1]) {
- FuncDrawFlags[select-1] = !FuncDrawFlags[select-1];
- RedrawScreen(PFuncX, PFuncY, SFuncX, SFuncY,
- &Xmin, &Xmax, &Ymax, TFuncMin,
- TFuncMax, InputKind);
- }
- else {
- switch (select) {
- case 2:
- color = FUNC_DER1;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?'(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y'(x) =";
- break;
- }
- break;
- case 3:
- color = FUNC_DER2;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?''(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y''(x) =";
- break;
- }
- break;
- case 4:
- color = FUNC_DER3;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?'''(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y'''(x) =";
- break;
- }
- break;
- }
- GGViewPortViewArea();
- DrawFunction(PFuncX[select-1], PFuncY[select-1],
- SFuncX[select-1], SFuncY[select-1],
- color, TFuncMin, TFuncMax, Xmin, Xmax, Ymax,
- FUNC_POS_X, FUNC_POS_Y-FUNC_DIF_Y*(select-1),
- InputKind, FuncName);
- PrintMathError(); /* If was error - put error msg */
- FuncDrawFlags[select-1] = !FuncDrawFlags[select-1];
- }
- break;
- case 5: /* Set Scale */
- switch(InputKind) {
- case 0: /* No function yet - put error message */
- GGPutErrorMsg("No Function defined yet");
- break;
- case XY_FUNC_T:
- DoSetScale(&Xmin, &Xmax, &Ymax, &NumOfSamples,
- &AutoScaleFlag, &TFuncMin, &TFuncMax);
- break;
- case Y_FUNC_X:
- DoSetScale(&Xmin, &Xmax, &Ymax, &NumOfSamples,
- &AutoScaleFlag, &Xmin, &Xmax);
- break;
- default:
- break;
- }
- LocalXmin = Xmin; /* Disable local autoscaling */
- LocalXmax = Xmax;
- LocalYmax = Ymax;
- /* break; - redraw the screen after scalings */
- if (!InputKind) break; /* If no function is defined - quit */
-
- case 6: /* Redraw */
- RedrawScreen(PFuncX, PFuncY, SFuncX, SFuncY,
- &Xmin, &Xmax, &Ymax,
- TFuncMin, TFuncMax, InputKind);
- break;
-
- case 7: /* Help */
- GGPrintHelpMenu("DrawFunc.hlp", "MAINMENU");
- break;
-
- case 9: /* Exit */
- if (GGConfirm("Exit Program")) {
- MyExit(0);
- }
- break;
- }
- }
- }
-
- /*****************************************************************************
- * Routine to update the EditMenu status according to flags : *
- *****************************************************************************/
- static void UpdateMainFlags(MenuItem *MainMenu, int *FuncDrawFlags)
- {
- static char *Der1On = "First Der. ON";
- static char *Der1Off = "First Der. OFF";
- static char *Der2On = "Second Der. ON";
- static char *Der2Off = "Second Der. OFF";
- static char *Der3On = "Third Der. ON";
- static char *Der3Off = "Third Der. OFF";
-
- if (FuncDrawFlags[1]) strcpy(MainMenu[2].string, Der1On);
- else strcpy(MainMenu[2].string, Der1Off);
-
- if (FuncDrawFlags[2]) strcpy(MainMenu[3].string, Der2On);
- else strcpy(MainMenu[3].string, Der2Off);
-
- if (FuncDrawFlags[3]) strcpy(MainMenu[4].string, Der3On);
- else strcpy(MainMenu[4].string, Der3Off);
- }
-
- /*****************************************************************************
- * Routines to clear the all screen and redraw axes and functions: *
- *****************************************************************************/
- void RedrawScreen(ExprNode *PFuncX[], ExprNode *PFuncY[],
- char SFuncX[][LINE_LEN_LONG], char SFuncY[][LINE_LEN_LONG],
- double *Xmin, double *Xmax, double *Ymax,
- double Tmin, double Tmax, int InputKind)
- {
- int color, i;
- char *FuncName;
-
- if (AutoScaleFlag) {
- if (InputKind == XY_FUNC_T) {
- *Xmin = LocalXmin;
- *Xmax = LocalXmax;
- }
- *Ymax = LocalYmax; /* might be improved by function drawing itself */
- }
- if (ABS(*Ymax) < EPSILON) *Ymax = EPSILON;
-
- LocalXmin = 1.0;
- LocalXmax = -1.0;
- LocalYmax = 0;
-
- GGClearViewArea(); /* Clear old graphic data */
- DrawAxes(*Xmin, *Xmax, *Ymax);
-
- for (i=0; i<=3; i++) if (FuncDrawFlags[i]) { /* Draw the functions */
- switch (i) {
- case 0:
- color = FUNC_COLOR;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y(x) =";
- break;
- }
- break;
- case 1:
- color = FUNC_DER1;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?'(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y'(x) =";
- break;
- }
- break;
- case 2:
- color = FUNC_DER2;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?''(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y''(x) =";
- break;
- }
- break;
- case 3:
- color = FUNC_DER3;
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName = "?'''(t) =";
- break;
- case Y_FUNC_X:
- FuncName = "Y'''(x) =";
- break;
- }
- break;
- }
- DrawFunction(PFuncX[i], PFuncY[i], SFuncX[i], SFuncY[i], color,
- Tmin, Tmax, *Xmin, *Xmax, *Ymax, FUNC_POS_X,
- FUNC_POS_Y - i * FUNC_DIF_Y, InputKind, FuncName);
- PrintMathError(); /* If was error - put error msg */
- }
- }
-
- /*****************************************************************************
- * Routine to draw the given function pfunc scaled according to max. vals. *
- * Method: Linear interpolation between the sampled points. *
- *****************************************************************************/
- static void DrawFunction(ExprNode *PFuncX, ExprNode *PFuncY,
- char *SFuncX, char *SFuncY, int Color, double Tmin, double Tmax,
- double Xmin, double Xmax, double Ymax, double PosX, double PosY,
- int InputKind, char *FuncName)
- {
- double Dt, t, Dx, x, y;
- int i;
-
- if (setjmp(LongJumpBuffer) != 0) return;
- /* If math error occurs - long jump to given place: */
- MathErrorSetUp(ME_LONGJMP, &LongJumpBuffer);
-
- GGMySetColor(Color);
- GGViewPortViewArea();
-
- switch (InputKind) {
- case XY_FUNC_T:
- SetParamValue(Tmin, PARAMETER_T);
- x = EvalTree(PFuncX);
- y = EvalTree(PFuncY);
- t = Tmin;
- Dt = (Tmax - Tmin) / NumOfSamples;
- break;
- case Y_FUNC_X:
- x = Xmin;
- Dx = (Xmax - Xmin) / NumOfSamples;
- SetParamValue(Xmin, PARAMETER_X);
- y = EvalTree(PFuncY);
- break;
- }
- if (InputKind == XY_FUNC_T) {
- if (x > LocalXmax) LocalXmax = x;
- if (x < LocalXmin) LocalXmin = x;
- }
- if (ABS(y) > LocalYmax) LocalYmax = ABS(y);
-
- GGMyMove(MapXcoord(x, Xmin, Xmax), MapYcoord(y, Ymax));
- for (i=1; i<=NumOfSamples; i++) {
- switch (InputKind) {
- case XY_FUNC_T:
- t = t + Dt;
- SetParamValue(t, PARAMETER_T);
- x = EvalTree(PFuncX);
- y = EvalTree(PFuncY);
- break;
- case Y_FUNC_X:
- x = x + Dx;
- SetParamValue(x, PARAMETER_X);
- y = EvalTree(PFuncY);
- break;
- }
- if (InputKind == XY_FUNC_T) {
- if (x > LocalXmax) LocalXmax = x;
- if (x < LocalXmin) LocalXmin = x;
- }
- if (ABS(y) > LocalYmax) LocalYmax = ABS(y);
- GGMyDraw(MapXcoord(x, Xmin, Xmax), MapYcoord(y, Ymax));
- }
-
- switch (InputKind) {
- case XY_FUNC_T:
- FuncName[0] = 'X';
- GGPutMsgXY(FuncName, PosX , PosY);
- GGPutMsgXY(SFuncX, PosX+0.35, PosY);
- FuncName[0] = 'Y';
- GGPutMsgXY(FuncName, PosX, PosY-FUNC_DIF_Y*0.5);
- GGPutMsgXY(SFuncY, PosX+0.35, PosY-FUNC_DIF_Y*0.5);
- break;
- case Y_FUNC_X:
- GGPutMsgXY(FuncName, PosX, PosY);
- GGPutMsgXY(SFuncY, PosX+0.35, PosY);
- break;
- }
-
- MathErrorSetUp(ME_KILL, NULL);
- }
-
- /*****************************************************************************
- * Routine to map the Xmin..Xmax range into normelizes -1..1 window range: *
- *****************************************************************************/
- static double MapXcoord(double x, double Xmin, double Xmax)
- {
- x = ((x - Xmin) / (Xmax - Xmin) - 0.5) * MAIN_SCALE;
- return BOUND(x, -0.99, 0.99); /* Force it between -1 and 1 */
- }
-
- /*****************************************************************************
- * Routine to map the -Ymax..Ymax range into normelizes -1..1 window range: *
- *****************************************************************************/
- static double MapYcoord(double y, double Ymax)
- {
- y = (y / (2*Ymax)) * MAIN_SCALE;
- return BOUND(y, -0.99, 0.99);
- }
-
- /****************************************************************************
- * Routine to Draw the axes according to given X range: *
- ****************************************************************************/
- static void DrawAxes(double Xmin, double Xmax, double Ymax)
- {
- double Xaxis;
- char s[LINE_LEN];
-
- GGMySetColor(AXES_COLOR);
- GGMyMove(-1.0, 0.0); /* Draw X axis */
- GGMyDraw(1.0, 0.0);
- GGPutMsgXY("X", 0.85, 0.05);
-
- if (((Xaxis=MapXcoord(0.0, Xmin, Xmax)) > -1.0) && (Xaxis < 1.0)) {
- /* Draw Y axis only of in range */
- GGMyMove(Xaxis, -1.0); /* Draw Y axis */
- GGMyDraw(Xaxis, 1.0);
- GGPutMsgXY("Y", Xaxis, 0.95);
- }
-
- sprintf(s, "Xmin = %10lf", Xmin);
- GGPutMsgXY(s, -0.75, 0.93);
- sprintf(s, "Xmax = %10lf", Xmax);
- GGPutMsgXY(s, -0.75, 0.86);
- sprintf(s, "Ymax = %10lf", Ymax);
- GGPutMsgXY(s, -0.75, 0.79);
- }
-
- /****************************************************************************
- * Routine to print math error according MathErr trapping module or *
- * evaluations in extr2tre module - function evaltree(), which might be *
- * retrieved via EvalError() function: *
- ****************************************************************************/
- void PrintMathError(void)
- {
- int EvalErr;
- char *p = NULL;
-
- if ((EvalErr = EvalError()) != 0) switch (EvalErr) {
- case E_ERR_DivByZero:
- p = "Div by zero";
- break;
- default:
- p = "Undef. math error";
- break;
- }
- else p = MathErrorGet();
-
- if (p != NULL) {
- GGPutMsgXY("Math Error:", -0.9, -0.8);
- GGPutMsgXY(p, -0.9, -0.9);
- }
- }
-
- /*****************************************************************************
- * My Routine to exit the program - do some closing staff before calling exit *
- *****************************************************************************/
- void MyExit(int ExitCode)
- {
- GGCloseGraph(); /* Recover text mode */
- MouseClose(); /* Recover mouse interrupts */
-
- chdir(CurrentWorkingDir); /* Recover original directory before exit */
- setdisk(CurrentWorkingDir[0] - 'A'); /* Move to the old disk */
-
- exit(ExitCode);
- }