Category : C Source Code
Archive   : DRAWFN3S.ZIP
Filename : DRAWFN3D.C

 
Output of file : DRAWFN3D.C contained in archive : DRAWFN3S.ZIP
/*****************************************************************************
* Program to draw a surface function given as (X, Y, Z) = F(u, v). *
* *
* Written by : Gershon Elber Mar. 1989 *
*****************************************************************************/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#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 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 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 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 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 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 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 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);
}


  3 Responses to “Category : C Source Code
Archive   : DRAWFN3S.ZIP
Filename : DRAWFN3D.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/