home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
irit
/
drawfuns.arc
/
DRAWFUNC.C
< prev
next >
Wrap
Text File
|
1989-09-10
|
17KB
|
511 lines
/*****************************************************************************
* 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);
}