home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Program to draw a surface function given as (X, Y, Z) = F(u, v). *
- * *
- * Written by : Gershon Elber Mar. 1989 *
- *****************************************************************************/
-
- #include <graphics.h>
- #include <stdlib.h>
- #include <math.h>
- #include <string.h>
- #include <setjmp.h>
- #include <conio.h>
- #include <stdio.h>
- #include <dos.h>
- #include <dir.h>
- #include "Program.h"
- #include "Expr2TrG.h"
- #include "GenMat.h"
- #include "MouseDrv.h"
- #include "GraphGnG.h"
- #include "ViewObj.h"
- #include "Config.h"
- #include "MathErr.h"
-
- char *VersionStr = "DrawFn3d IBMPC version 1.2, Gershon Elber, "
- __DATE__ ", " __TIME__ "\n"
- "(C) Copyright 1989 Gershon Elber, Non commercial use only.";
-
- extern unsigned int _stklen = 32767;
-
- int MouseExists = FALSE; /* Set according to autotest and config enforcment. */
- int GraphDriver = DETECT; /* " */
-
- static jmp_buf LongJumpBuffer; /* Used in control C trapping. */
- static char CurrentWorkingDir[LINE_LEN];/* Save start CWD to recover on exit.*/
-
- /* The foolowings are setable (via configuration file drawfn3d.cfg): */
- static double UMin = -1.0, UMax = 1.0, VMin = -1.0, VMax = 1.0;
- static int NumOfSamples = DEFAULT_SAMPLES, NumOfIsoLines = DEFAULT_ISO_LINES,
- ValidUIsoLines, ValidVIsoLines, DblBuffer = FALSE;
-
- /* And here is the configuration module data structure: */
- static ConfigStruct SetUp[] =
- { { "UMin", (void *) &UMin, SU_REAL_TYPE },
- { "UMax", (void *) &UMax, SU_REAL_TYPE },
- { "VMin", (void *) &VMin, SU_REAL_TYPE },
- { "VMax", (void *) &VMax, SU_REAL_TYPE },
- { "NumOfSamples", (void *) &NumOfSamples, SU_INTEGER_TYPE },
- { "NumOfIsoLines", (void *) &NumOfIsoLines, SU_INTEGER_TYPE },
- { "GraphDriver", (void *) &GraphDriver, SU_INTEGER_TYPE },
- { "DblBuffer", (void *) &DblBuffer, SU_BOOLEAN_TYPE },
- { "Mouse", (void *) &MouseExists, SU_BOOLEAN_TYPE } };
-
- /* Number of entries in SetUp structure: */
- #define NUM_SET_UP sizeof(SetUp) / sizeof(ConfigStruct)
-
- static void DrawFunction(ExprNode *PFunc[3], char SFunc[3][LINE_LEN_LONG],
- int Color, double UMin, double UMax, double VMin, double VMax,
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES]);
- static void Draw3DAxes(MatrixType TransMat);
- static void DoTransformFunction(char SFunc[3][LINE_LEN_LONG],
- MatrixType TransMat, int NumOfSamples,
- int NumOfIsoLines, int DblBuffer,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES]);
- static void DrawTransFunction(char SFunc[3][LINE_LEN_LONG], int Color,
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES]);
- static void TestQuitView(void);
- static void PrintMathError(void);
-
- /*****************************************************************************
- * 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",
- CYAN, "Parameters set",
- CYAN, "Redraw",
- CYAN, "Transform Func",
- MAGENTA, "Save Function",
- MAGENTA, "",
- CYAN, "Help",
- MAGENTA, "",
- BLUE, "Quit"
- };
- /* Used to save the 3 input functions (X, Y, Z) as binary tree. */
- ExprNode *PFunc[3];
- /* Used to save the 3 input functions (X, Y, Z) as string. */
- char SFunc[3][LINE_LEN_LONG],
- *ErrorMsg;
- /* Num. of samples per One Iso line, & num. of iso lines in u & v axes. */
- int i, select, InputExists = FALSE;
- MatrixType TransMat; /* Current 3D transformation will be stored here. */
- struct IsoLine *IsoLinesU[MAX_ISO_LINES], *IsoLinesV[MAX_ISO_LINES];
-
- getcwd(CurrentWorkingDir, LINE_LEN-1);
-
- MouseExists = MouseDetect(); /* Automatic mouse detection routine. */
-
- if (_osmajor <= 2) /* No argv[0] is given (prgm name) - allways NULL! */
- Config("DrawFn3d", SetUp, NUM_SET_UP);/*Read config. file if exists.*/
- else Config(*argv, SetUp, NUM_SET_UP); /* Read config. file if exists. */
-
- SFunc[0][0] = SFunc[1][0] = SFunc[2][0] = 0; /* Make sure strings empty. */
-
- while (argc-- > 1) {
- if (strcmp(*++argv, "-z") == 0) {
- fprintf(stderr, "\n%s\n", VersionStr);
- fprintf(stderr, "\nUsage: drawfn3d [-z]\n");
- ConfigPrint(SetUp, NUM_SET_UP);
- MyExit(0);
- }
- }
-
- /* If math error occurs - long jump to given place: */
- MathErrorSetUp(ME_LONGJMP, &LongJumpBuffer);
-
- SetUpHardErr(); /* Set up hardware error, int 24 trap routine. */
-
- for (i=0; i<NumOfIsoLines; i++) {/* Allocate the starting data structure.*/
- IsoLinesU[i] = (IsoLine *) malloc(3*sizeof(float)*NumOfSamples);
- IsoLinesV[i] = (IsoLine *) malloc(3*sizeof(float)*NumOfSamples);
- if (IsoLinesV[i] == (IsoLine *) NULL) {
- printf("Not enough memory: needed %ld, found only %ld.",
- 3L * sizeof(float) * NumOfSamples * NumOfIsoLines * 2L,
- 3L * sizeof(float) * NumOfSamples * i * 2L);
- getch();
- MyExit(1);
- }
- }
-
- GGInitGraph();
- GGClearMenuArea();
- GGClearViewArea();
-
- if (MouseExists) /* Must be initialized AFTER graph mode was selected. */
- if ((ErrorMsg = MouseInit()) != 0) {
- /* Must be called before any usage! */
- fprintf(stderr, "\n%s\n\n\tPress any key to continue:", ErrorMsg);
- MouseExists = FALSE;
- getch();
- }
-
- while (TRUE) {
- GGMenuDraw(9, MainMenu, TRUE); /* Draw MainMenu. */
- select = GGMenuPick();
-
- setjmp(LongJumpBuffer);
- PrintMathError(); /* If was error - put error msg. */
-
- switch (select) {
- case 1: /* Get New function to draw. */
- DoGetFunc(PFunc, SFunc, &InputExists,
- &UMin, &UMax, &VMin, &VMax, &NumOfIsoLines, &NumOfSamples,
- IsoLinesU, IsoLinesV, TransMat);
- break;
-
- case 2: /* Set Parameters. */
- if (InputExists)
- DoSetParam(&NumOfSamples, &NumOfIsoLines,
- &UMin, &UMax, &VMin, &VMax,
- &DblBuffer, IsoLinesU, IsoLinesV);
- else {
- GGPutErrorMsg("Load Surf. first");
- break;
- }
-
- case 3: /* Redraw. */
- if (InputExists)
- RedrawScreen(PFunc, SFunc, UMin, UMax, VMin, VMax,
- TransMat, NumOfSamples, NumOfIsoLines,
- IsoLinesU, IsoLinesV);
- else GGPutErrorMsg("Load Surf. first");
- break;
-
- case 4: /* Transform Function. */
- if (InputExists)
- DoTransformFunction(SFunc, TransMat, NumOfSamples,
- NumOfIsoLines, DblBuffer, IsoLinesU, IsoLinesV);
- else GGPutErrorMsg("Load Surf. first");
- break;
-
- case 5: /* Save Function. */
- if (InputExists)
- DoSaveFunc(PFunc, SFunc, UMin, UMax, VMin, VMax,
- NumOfIsoLines, NumOfSamples, TransMat);
- else GGPutErrorMsg("Load Surf. first");
- break;
-
- case 7: /* Help. */
- GGPrintHelpMenu("DrawFn3d.hlp", "MAINMENU");
- break;
-
- case 9: /* Quit. */
- if (GGConfirm("Quit Program")) MyExit(0);
- break;
- }
- }
- }
-
- /*****************************************************************************
- * Routines to clear the data area and redraw axes and functions: *
- *****************************************************************************/
- void RedrawScreen(ExprNode *PFunc[3], char SFunc[3][LINE_LEN_LONG],
- double UMin, double UMax, double VMin, double VMax,
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES])
- {
- struct viewporttype view;
-
- getviewsettings(&view);
- GGClearViewArea();
-
- Draw3DAxes(TransMat);
-
- if (setjmp(LongJumpBuffer) == 0)
- DrawFunction(PFunc, SFunc, FUNC_COLOR, UMin, UMax, VMin, VMax,
- TransMat, NumOfSamples, NumOfIsoLines, IsoLinesU, IsoLinesV);
-
- PrintMathError(); /* If was error - put error msg. */
-
- setviewport(view.left, view.top, view.right, view.bottom, view.clip);
- }
-
- /*****************************************************************************
- * Routine to draw the given function PFunc. This routine does not only *
- * calculate the function, but also updates IsoLinesU/V. *
- * As control break may interrupt the drawing the data in IsoLinesU/V arrays *
- * might not be fully updated. ValidU/VIsoLines are therefore updated to the *
- * current updated iso line. The DoTransFunction uses there validations. *
- *****************************************************************************/
- static void DrawFunction(ExprNode *PFunc[3], char SFunc[3][LINE_LEN_LONG],
- int Color, double UMin, double UMax, double VMin, double VMax,
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES])
- {
- double Du, u, Dv, v, Vec[3];
- char Line[LINE_LEN_LONG];
- int i, j, k;
-
- GGMySetColor(Color);
- setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
- EvalError();
-
- ValidVIsoLines = ValidUIsoLines = -1; /* In case of ^C break. */
-
- /* Generate and draw the U isolines: */
- u = UMin;
- Du = (UMax - UMin) / (NumOfIsoLines-1);
- for (i=0; i<NumOfIsoLines; i++) {
- TestQuitView();
- v = VMin;
- Dv = (VMax - VMin) / (NumOfSamples-1);
- SetParamValue(u, PARAMETER_U);
- SetParamValue(v, PARAMETER_V);
- for (j=0; j<3; j++) {
- Vec[j] = EvalTree(PFunc[j]);
- IsoLinesU[i] -> Samples[0][j] = (float) Vec[j];
- }
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyMove(Vec[0], Vec[1]);
-
- for (j=1; j<NumOfSamples; j++) {
- v += Dv;
- SetParamValue(v, PARAMETER_V);
- for (k=0; k<3; k++) {
- Vec[k] = EvalTree(PFunc[k]);
- IsoLinesU[i] -> Samples[j][k] = (float) Vec[k];
- }
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- }
- u += Du;
- ValidUIsoLines = i;
- }
-
- /* Generate and draw the V isolines: */
- v = VMin;
- Dv = (VMax - VMin) / (NumOfIsoLines-1);
- for (i=0; i<NumOfIsoLines; i++) {
- TestQuitView();
- u = UMin;
- Du = (UMax - UMin) / (NumOfSamples-1);
- SetParamValue(u, PARAMETER_U);
- SetParamValue(v, PARAMETER_V);
- for (j=0; j<3; j++) {
- Vec[j] = EvalTree(PFunc[j]);
- IsoLinesV[i] -> Samples[0][j] = (float) Vec[j];
- }
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyMove(Vec[0], Vec[1]);
-
- for (j=1; j<NumOfSamples; j++) {
- u += Du;
- SetParamValue(u, PARAMETER_U);
- for (k=0; k<3; k++) {
- Vec[k] = EvalTree(PFunc[k]);
- IsoLinesV[i] -> Samples[j][k] = (float) Vec[k];
- }
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- }
- v += Dv;
- ValidVIsoLines = i;
- }
-
- for (i=0; i<3; i++) {
- sprintf(Line, "%c(u, v) = %s", 'X' + i, SFunc[i]);
- GGPutMsgXY(Line, FUNC_POS_X, FUNC_POS_Y + FUNC_DIF_Y * i);
- }
-
- }
-
- /****************************************************************************
- * Routine to Draw3D axes (X, Y, Z) : *
- ****************************************************************************/
- static void Draw3DAxes(MatrixType TransMat)
- {
- double Vec[3], Orig[3];
-
- GGMySetColor(AXES_COLOR);
-
- setlinestyle(SOLID_LINE, 0, THICK_WIDTH);
-
- Orig[0] = 0.0; Orig[1] = 0.0; Orig[2] = 0.0;
- MultVecby4by4(Orig, Orig, TransMat);
- GGMyMove(Orig[0], Orig[1]);
-
- Vec[0] = 1.0; Vec[1] = 0.0; Vec[2] = 0.0;
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- GGPutMsgXY("X", Vec[0], Vec[1]);
-
- GGMyMove(Orig[0], Orig[1]);
-
- Vec[0] = 0.0; Vec[1] = 1.0; Vec[2] = 0.0;
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- GGPutMsgXY("Y", Vec[0], Vec[1]);
-
- GGMyMove(Orig[0], Orig[1]);
-
- Vec[0] = 0.0; Vec[1] = 0.0; Vec[2] = 1.0;
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- GGPutMsgXY("Z", Vec[0], Vec[1]);
- }
-
- /****************************************************************************
- * Routine to handle the view matrix transformation: *
- * If GlobalDblBuffer is active then double buffering is used. In that case *
- * the exit page will allways be page 0. *
- ****************************************************************************/
- static void DoTransformFunction(char SFunc[3][LINE_LEN_LONG],
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines, int DblBuffer,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES])
- {
- int i, j, ViewPage = 0, DrawPage, UpPage; /* Used for double buffering. */
- MatrixType OrigMat;
- struct viewporttype view;
-
- for (i=0; i<4; i++) for (j=0; j<4; j++) OrigMat[i][j] = TransMat[i][j];
-
- if (DblBuffer) UpPage = 1;
- else UpPage = 0; /* Practically deactivate double buffering. */
-
- if (GGScreenMaxPages < 2) UpPage = 0; /* Only one page in hardware. */
-
- DrawPage = UpPage;
-
- getviewsettings(&view);
- setviewport(0, 0, (int) (GGScreenMaxY/GGAspectRatio), GGScreenMaxY, TRUE);
-
- setactivepage(0);
- InteractDrawMenu();
- if (UpPage != 0) {
- setactivepage(UpPage);
- InteractDrawMenu();
- }
- setvisualpage(ViewPage);
- setactivepage(ViewPage); /* So the DoSetMatrix can print... */
- while (!InteractHandleInput(TransMat, OrigMat)) {
- setactivepage(DrawPage);
- GGClearViewArea();
-
- Draw3DAxes(TransMat);
-
- if (setjmp(LongJumpBuffer) == 0)
- DrawTransFunction(SFunc, FUNC_COLOR, TransMat,
- NumOfSamples, NumOfIsoLines, IsoLinesU, IsoLinesV);
-
- PrintMathError(); /* If was error - put error msg. */
-
- if (DrawPage) {
- DrawPage = 0;
- ViewPage = UpPage;
- }
- else {
- DrawPage = UpPage;
- ViewPage = 0;
- }
- setvisualpage(ViewPage);
- setactivepage(ViewPage); /* So the DoSetMatrix can print... */
- }
-
- if (ViewPage) { /* In case the last page was page 1... */
- setactivepage(0);
- setvisualpage(0);
- GGClearViewArea();
-
- Draw3DAxes(TransMat);
-
- if (setjmp(LongJumpBuffer) == 0)
- DrawTransFunction(SFunc, FUNC_COLOR, TransMat,
- NumOfSamples, NumOfIsoLines, IsoLinesU, IsoLinesV);
-
- PrintMathError(); /* If was error - put error msg. */
- }
-
- GGClearMenuArea();
- setviewport(view.left, view.top, view.right, view.bottom, view.clip);
- }
-
- /*****************************************************************************
- * Routine to draw the given function pfunc *
- * This routine does not calculate the function , but uses IsoLinesU/V instead*
- * Therefore ValidU/VIsoLines is used instead of NumOfIsoLines! *
- *****************************************************************************/
- static void DrawTransFunction(char SFunc[3][LINE_LEN_LONG], int Color,
- MatrixType TransMat, int NumOfSamples, int NumOfIsoLines,
- struct IsoLine *IsoLinesU[MAX_ISO_LINES],
- struct IsoLine *IsoLinesV[MAX_ISO_LINES])
- {
- double Vec[3];
- char Line[LINE_LEN_LONG];
- int i, j, k;
-
- GGMySetColor(Color);
- setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
-
- /* Generate and draw the U isolines: */
- for (i=0; i<=ValidUIsoLines; i++) {
- TestQuitView();
- for (j=0; j<3; j++) Vec[j] = (double) IsoLinesU[i] -> Samples[0][j];
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyMove(Vec[0], Vec[1]);
-
- for (j=1; j<NumOfSamples; j++) {
- for (k=0; k<3; k++) Vec[k] =
- (double) IsoLinesU[i] -> Samples[j][k];
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- }
- }
-
- /* Generate and draw the V isolines: */
- for (i=0; i<=ValidVIsoLines; i++) {
- TestQuitView();
- for (j=0; j<3; j++) Vec[j] = (double) IsoLinesV[i] -> Samples[0][j];
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyMove(Vec[0], Vec[1]);
-
- for (j=1; j<NumOfSamples; j++) {
- for (k=0; k<3; k++) Vec[k] =
- (double) IsoLinesV[i] -> Samples[j][k];
- MultVecby4by4(Vec, Vec, TransMat);
- GGMyDraw(Vec[0], Vec[1]);
- }
- }
-
- for (i=0; i<3; i++) {
- sprintf(Line, "%c(u, v) = %s", 'X'+i, SFunc[i]);
- GGPutMsgXY(Line, FUNC_POS_X, FUNC_POS_Y + FUNC_DIF_Y * i);
- }
- }
-
- /*****************************************************************************
- * Routine to test if quit display event - occured - SPACE was hit on *
- * keyboard or right button was clicked on mouse. *
- *****************************************************************************/
- static void TestQuitView(void)
- {
- int x, y, Buttons;
-
- if (kbhit() && getch() == ' ')
- longjmp(LongJumpBuffer, 1); /* Jump to... */
-
- if (MouseExists && MouseQueryBuffer()) {
- MouseGetBuffer(&x, &y, &Buttons);
- if (Buttons & 0x02) longjmp(LongJumpBuffer, 1); /* Jump to... */
- }
- }
-
- /****************************************************************************
- * Routine to print math error according MathErr trapping module or *
- * evaluations in extr2tre module - function evaltree(), which might be *
- * retrieved via EvalError() function: *
- ****************************************************************************/
- static 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();
-
- GGMySetColor(RED);
-
- if (p != NULL) GGPutErrorMsg(p);
- }
-
- /*****************************************************************************
- * 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);
- }