Subject: v18i064: GL Graphics Library for AT-clone Unix, Part06/07 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: umix!m-net!dtlewis!lewis Posting-number: Volume 18, Issue 64 Archive-name: gl_plot/part06 # To recover, type "sh archive" echo restoring config.h sed 's/^X//' > config.h < BEGIN USER MODIFIABLE PARAMETERS <=== */ X X/* Select one of the following to specify your target system (Xenix */ X/* cross compile to MS_DOS should select MS_DOS). */ X X#define SVAT 1 X#define XENIX_286 0 X#define MS_DOS 0 X#define UNIX_386 0 /* (not yet supported) */ X#define XENIX_386 0 /* (not yet supported) */ X X/* If you defined MS_DOS 1, then specify your compiler here. */ X X#if MS_DOS X#define XEN2DOS 1 /* Compile on Xenix 286 for DOS target system */ X#define USOFT 0 /* Microsoft C under DOS */ X#define TCC 0 /* Borland Turbo-C */ X#define MIX_C 0 /* The old CP/M derived MIX-C compiler */ X#endif /* MS_DOS */ X X/* The following should be defined if you do NOT have a numeric */ X/* coprocessor. It will cause some trig functions to be done with */ X/* integer math (see trig.c). */ X X#define NOFLOAT 1 X X/* The following should be defined if you want the gl library to handle */ X/* interrupt signals. This will clear the screen and return to text */ X/* mode when the interrupt key (or ^C, for MS-DOS) is pressed. If you */ X/* need to do your own signal routine (to close files, for example), */ X/* you may prefer not to have this defined. */ X X#define DO_CLEANUP 1 X X/* VIDEO stuff: */ X X/* Define the name of the program or shell script which will be used */ X/* to switch video modes (UNIX only). This will be made from either */ X/* the mode.c program, or the mode.sh shell script, or some equivalent */ X/* program that works with your system and video adapter. */ X X#define MODEPROG "mode" X/* Another possible choice: */ X/* #define MODEPROG "/usr/local/bin/mode" */ X X/* Define the name of the environment variable that you wish to use to */ X/* indicate your default graphics mode. If we call g_init(ENV_MODE), */ X/* then we will use this environment variable to set the graphics mode. */ X X#define GL_ENV_MODE "GLMODE" X X/* If the environment variable is not set, then fall back to */ X/* DEFAULT_MODE as a last resort. Mode 4 is CGA color mode, a safe */ X/* choice for most systems. */ X X#define DEFAULT_MODE 4 X X/* PRINTER stuff: */ X X/* Define name of the environment variable that you wish to set to */ X/* indicate your default print device. */ X X#define GL_PLOT_DEV "PLOTDEV" X X/* For MS-DOS, define your printer device name (and ignore the rest */ X/* of the printer stuff that follows). Note: Microsoft compilers will */ X/* send output to "stdprn" regardless of how you define this; other */ X/* compilers will use the device you define below. See code in */ X/* g_finish.c if you need to change this. */ X X#define DOSPRINTER "PRN:" X X/* Define the standard print spooler program for your system (UNIX). */ X X#define PRINTPROG "/usr/bin/lp" X#define LP_DEV_FLAG "-d" X X/* Define the device to use if GL_PLOT_DEV is not set. */ X/* Note: Use "lp" only if you plan to manually put the printer */ X/* driver in transparency mode (see lpset(1M)). */ X/* On Microport, your printer devices might look something like the */ X/* following, where /dev/lp is the standard printer driver, and */ X/* /dev/lpt is the transparency mode printer driver. See the "Readme" */ X/* file for more information. */ X/* */ X/* \$ ls -li /dev/lp* */ X/* 82 crw-rw-rw- 2 root sys 7, 0 Oct 9 18:03 /dev/lp */ X/* 82 crw-rw-rw- 2 root sys 7, 0 Oct 9 18:03 /dev/lp0 */ X/* 83 crw-rw-rw- 1 root sys 7, 1 Feb 11 1988 /dev/lp1 */ X/* 295 crw-rw-rw- 2 root sys 7,128 Oct 9 18:08 /dev/lpt */ X/* 295 crw-rw-rw- 2 root sys 7,128 Oct 9 18:08 /dev/lpt0 */ X/* 291 crw-rw-rw- 1 root sys 7,129 May 22 18:42 /dev/lpt1 */ X X#define PRINTDEV "lpt" X X/* You may need to tweak the following in order to get round circles. */ X X#define HERC_ASPECT_RATIO 0.7 X#define CGA_ASPECT_RATIO 0.85 X#define EGA_ASPECT_RATIO 0.6 X#define IBM_PR_ASPECT_RATIO 0.7 X#define LJ_PR_ASPECT_RATIO 0.81 X X/* For Xenix System V 286, you must indicate the video adapter you */ X/* are using. Microport users can ignore this (they must, however, */ X/* create a shared memory key with shmcreate(1). MS-DOS users may */ X/* also ignore this. */ X X#define GL_CGA 0 X#define GL_EGA 1 X#define GL_HERC 0 X#define GL_PGA 0 /* (not implemented) */ X#define GL_VGA 0 /* (easy to do, but not implemented) */ X X/* The following definitions specify the shared memory key identifiers */ X/* which are used by Microport System V/AT. You are free to use any */ X/* identifiers you want to map to video memory with shmcreate(1). */ X/* The following are the recommended values. If you use these, the */ X/* key values will be the same as the physical memory addresses. */ X/* Change these definitions only if you are using different shared */ X/* memory keys for your system. Xenix users may ignore this. */ X X#define MCA_KEY 0xB0000L X#define CGA_KEY 0xB8000L X#define HERC_P0KEY 0xB0000L X#define HERC_P1KEY 0xB8000L X#define EGA_KEY 0xA0000L X X/* ===> END USER MODIFIABLE PARAMETERS <=== */ X X/* The following definitions specify the physical memory locations of */ X/* video memory, for use with MS-DOS. */ X X#define DOS_MCA 0xB0000000L X#define DOS_CGA 0xB8000000L X#define DOS_H_P0 0xB0000000L X#define DOS_H_P1 0xB8000000L X#define DOS_EGA 0xA0000000L X X/* Some specific system dependent characteristics. */ X X#if MIX_C X#define HAS_SIG 0 /* System does not have ^C interrupt handling */ X#else X#if USOFT X#define HAS_SIG 0 /* System does not have ^C interrupt handling */ X#else X#if XEN2DOS X#define HAS_SIG 0 /* System does not have ^C interrupt handling */ X#else X#define HAS_SIG 1 /* System has ^C interrupt handling */ X#endif /* XEN2DOS */ X#endif /* USOFT */ X#endif /* MIX_C */ X X#if MIX_C X#define HAS_ENV 0 /* System does not have getenv() call */ X#else X#define HAS_ENV 1 /* System has getenv() call */ X#endif /* MIX_C */ X X#if MS_DOS X#define HAS_PIPES 0 /* System does not have popen() call */ X#else X#define HAS_PIPES 1 /* System has popen() call */ X#endif /* MS_DOS */ X X#if USOFT X#define HAS_SLEEP 0 /* System does not have sleep() call */ X#else X#if XEN2DOS X#define HAS_SLEEP 0 /* System does not have sleep() call */ X#else X#if MIX_C X#define HAS_SLEEP 0 /* System does not have sleep() call */ X#else X#define HAS_SLEEP 1 /* System has sleep() call */ X#endif /* MIX_C */ X#endif /* XEN2DOS */ X#endif /* USOFT */ X X#if MIX_C X#define HAS_FMOD 0 /* System does not have fmod() call */ X#else X#define HAS_FMOD 1 /* System has fmod() call */ X#endif /* MIX_C */ X X#if MIX_C X#define HAS_ATAN2 0 /* System does not have atan2() call */ X#else X#define HAS_ATAN2 1 /* System has atan2() call */ X#endif /* MIX_C */ X X/* Some MS-DOS compilers have "stdprn" predefined for stream output to */ X/* the printer. */ X X#if USOFT X#define HAS_STDPRN 1 X#else X#if XEN2DOS X#define HAS_STDPRN 1 X#else X#if TCC X#define HAS_STDPRN 1 X#else /* "stdprn" is not predefined */ X#define HAS_STDPRN 0 X#endif /* TCC */ X#endif /* XEN2DOS */ X#endif /* USOFT */ X X/* The following should be defined for 286 versions, in which an */ X/* integer is 16 bits. Other machines must do extra work to check */ X/* for out of range on the normalized 2-D screen space (0 through */ X/* 32767). */ X X#if MS_DOS X#else X#if XENIX_286 X#else X#if SVAT X#define INT16 1 X#else /* Not a 16 bit integer machine */ X#define INT16 0 X#endif /* SVAT */ X#endif /* XENIX_286 */ X#endif /* MS_DOS */ X X/* Parameter to signal call is system dependent. Define a macro to */ X/* handle the difference between pointer to void and pointer to int. */ X X#if TCC X#define SIG_TYPE void X#else X#define SIG_TYPE int X#endif /* TCC */ X X/* Some compilers can use a macro for the calculation for transform */ X/* from normalized 2-D to screen coordinates. If yours can't, then */ X/* define N_TO_P_MACRO as 0. */ X/* (All the compilers I've tried are working now with the macro. Leave */ X/* this here just in case...) */ X X#define N_TO_P_MACRO 1 X X/* Compiler specific stuff for MS-DOS. */ X X/* For MS-DOS, use the DO_BIOS macro to point to the library routine */ X/* that invokes a BIOS call. Int is the interrupt number, and reg */ X/* is a pointer to a structure representing machine registers. */ X/* Define REGISTERS as the name of the data structure for machine */ X/* registers (probably declared in ). */ X/* The remaining macros (AL, AH ...) specify individual registers */ X/* within the REGISTERS data structure, as they would be referenced */ X/* in a REGISTERS structure (e.g. "inreg.AH"). */ X X#if MIX_C X#define DO_BIOS(int,inreg,outreg) bios(int,inreg) X#define REGISTERS REGS X#define AL byte.al X#define AH byte.ah X#define BL byte.bl X#define BH byte.bh X#define CL byte.cl X#define CH byte.ch X#define DL byte.dl X#define DH byte.dh X#endif /* MIX_C */ X X#if USOFT X#define DO_BIOS(int,inreg,outreg) int86(int,inreg,outreg) X#define REGISTERS union REGS X#define AL h.al X#define AH h.ah X#define BL h.bl X#define BH h.bh X#define CL h.cl X#define CH h.ch X#define DL h.dl X#define DH h.dh X#endif /* USOFT */ X X#if XEN2DOS X#define DO_BIOS(int,inreg,outreg) int86(int,inreg,outreg) X#define REGISTERS union REGS X#define AL h.al X#define AH h.ah X#define BL h.bl X#define BH h.bh X#define CL h.cl X#define CH h.ch X#define DL h.dl X#define DH h.dh X#endif /* XEN2DOS */ X X#if TCC X#define DO_BIOS(int,inreg,outreg) int86(int,inreg,outreg) X#define REGISTERS union REGS X#define AL h.al X#define AH h.ah X#define BL h.bl X#define BH h.bh X#define CL h.cl X#define CH h.ch X#define DL h.dl X#define DH h.dh X#endif /* TCC */ X XxX--EOF--XxX echo restoring g_fntctl.c sed 's/^X//' > g_fntctl.c < gf_types.h < gl.h < modes.h < n_curves.c <aspect_ratio in the graphics.h file). X** X** The basic idea is: X** X** Equation of an ellipse: X** X** x^2 / a^2 + y^2 / b^2 = 1 X** X** Therefore the X and Y values are: X** X** X = a * cos(theta) X** Y = b * sin(theta) X** X** For some angle theta. X** X** By stepping through values of theta, we can generate a list of X** line segment endpoints on the ellipse. Then call n_movepen() and X** n_draw() to display the ellipse. X** X** Note: The macros PTS_PER_QUADRANT and TRIG_SCALE are defined X** in graphics.h. X*/ X X#include "config.h" X#if MIX_C X#else X#include X#endif /* MIX_C */ X#include "bitmaps.h" X#include "graphics.h" X X#ifndef M_PI X#define M_PI 3.1415926536 X#endif /* M_PI */ X#ifndef M_PI_2 X#define M_PI_2 1.5707963268 X#endif /* M_PI_2 */ X X#define XINDEX 0 /* For specifying array indices. */ X#define YINDEX 1 X X/* The following two arrays are tables of values for cos and sin */ X/* for one quadrant of a circle, divided into PTS_PER_QUADRANT slices. */ X/* They are found in source file trig.c. */ X Xextern long cos_table[PTS_PER_QUADRANT]; Xextern long sin_table[PTS_PER_QUADRANT]; Xextern long longsin(), longcos(); Xextern int n_movepen(), n_draw(); X Xstatic void make_endpoints(x,y,a,b,endpoints,step) Xint x,y,a,b,step; Xint endpoints[4][PTS_PER_QUADRANT][2]; X{ X int idx; /* Loop index. */ X int value; /* Temporary storage of values */ X X /* Set the values for points on the ellipse. While we're */ X /* at it, scale the values back down using TRIG_SCALE, and do */ X /* the x and y translation to the center point of the ellipse. */ X /* Calculations are done with long ints to preserve precision, */ X /* then cast back to short ints in the endpoints array. */ X /* Use the value of step to skip unnecessary points (for small */ X /* ellipes and arcs). */ X X for(idx=step-1; idx cir_size) X angle1 = fmod((double)angle1,(double)cir_size); X if (fabs(angle2) > cir_size) X angle2 = fmod((double)angle2,(double)cir_size); X X /* Make the angles positive. */ X while (angle1 < 0) angle1 += cir_size; X while (angle2 < 0) angle2 += cir_size; X X /* Calculate a value for step, so we can use fewer endpoints */ X /* for small arcs. */ X step = make_step(a,b); X X#ifdef DEBUG X printf("step is %d\n",step); X#endif /* DEBUG */ X X /* Calculate the end points. */ X X#if NOFLOAT X x_1 = x + (int)((longcos(angle1) * a) / TRIG_SCALE); X y_1 = y + (int)((longsin(angle1) * b) / TRIG_SCALE); X x_2 = x + (int)((longcos(angle2) * a) / TRIG_SCALE); X y_2 = y + (int)((longsin(angle2) * b) / TRIG_SCALE); X#else X x_1 = x + (int)(a * cos((double)angle1)); X y_1 = y + (int)(b * sin((double)angle1)); X x_2 = x + (int)(a * cos((double)angle2)); X y_2 = y + (int)(b * sin((double)angle2)); X#endif /* NOFLOAT */ X X /* Generate the array of arc endpoints. */ X make_endpoints(x,y,a,b,endpoints,step); X X /* Deduce the first and last element of interest in the */ X /* endpoint array. */ X X /* First calculate the initial index value. */ X index = (int)(angle1 / M_PI_2 * (float)PTS_PER_QUADRANT); X /* Now figure the quadrant. */ X quadrant = (index / PTS_PER_QUADRANT) % 4; X /* Wrap around so we point at the array. */ X index = (index % PTS_PER_QUADRANT); X index = index + step - (index % step) - 1; X X#ifdef DEBUG X printf("In n_arc(), index is %d\n",index); X#endif /* DEBUG */ X X /* Calculate the final index value. */ X endindex = (int)(angle2 / M_PI_2 * (float)PTS_PER_QUADRANT); X /* Now figure the quadrant. */ X endquadrant = (endindex / PTS_PER_QUADRANT) % 4; X /* Wrap around so we point at the array. */ X endindex = (endindex % PTS_PER_QUADRANT); X endindex = endindex + step - (endindex % step) - 1; X X#ifdef DEBUG X printf("In n_arc(), endindex is %d\n",endindex); X#endif /* DEBUG */ X X /* Move pen to start point. */ X X#ifdef DEBUG X printf("Move pen to %d %d\n",x_1,y_1); X#endif /* DEBUG */ X X if(n_movepen(x_1,y_1)) istat = 1; X X /* Start drawing, beginning with the first point of interest. */ X /* Wrap around the array if needed. */ X X while ((index != endindex) || (quadrant != endquadrant)) { X X#ifdef DEBUG X printf("Draw to %d %d -- quadrant %d index %d\n", X endpoints[quadrant][index][XINDEX], X endpoints[quadrant][index][YINDEX],quadrant,index); X#endif /* DEBUG */ X X if(n_draw(endpoints[quadrant][index][XINDEX], X endpoints[quadrant][index][YINDEX])) { X istat = 1; X /* This is just for cleaner error recovery: */ X n_movepen(endpoints[quadrant][index][XINDEX], X endpoints[quadrant][index][YINDEX]); X } X /* Increment the indices. */ X if ((index+=step) >= PTS_PER_QUADRANT) { X index = step - 1; X if ((++quadrant) >= 4) { X quadrant = 0; X } X } X }; X X /* Finish at last point of interest. */ X X#ifdef DEBUG X printf("Finish by drawing to %d %d\n",x_2,y_2); X#endif /* DEBUG */ X X if(n_draw(x_2,y_2)) { X istat = 1; X /* This is just for cleaner error recovery: */ X n_movepen(x_2,y_2); X } X return(istat); X} X Xint n_ellipse(x,y,a,b) Xint x,y,a,b; X{ X /* The endpoints array will hold line segment (x,y) end points. */ X /* There are four quadrants, each with PTS_PER_QUADRANT points, */ X /* with two values (X and Y) each. */ X int endpoints[4][PTS_PER_QUADRANT][2]; X int pointindex, quadrant; /* Loop index. */ X int istat = 0; /* Function call return status. */ X int step; /* Amount by which to step through array. */ X X /* Calculate a value for step, so we can use fewer endpoints */ X /* for small ellipses. */ X step = make_step(a,b); X X /* Build the array of endpoints. */ X make_endpoints(x,y,a,b,endpoints,step); X X /* Display the result, drawing all four quadrants. */ X X /* Start the pen at the location of the last endpoint. This */ X /* is the point we want to end up on. */ X if(n_movepen(endpoints[3][PTS_PER_QUADRANT-1][XINDEX], X endpoints[3][PTS_PER_QUADRANT-1][YINDEX])) X istat = 1; X X for (quadrant=0; quadrant<=3; quadrant++) { X X for (pointindex = step -1; pointindex < PTS_PER_QUADRANT; X pointindex += step) { X if(n_draw(endpoints[quadrant][pointindex][XINDEX], X endpoints[quadrant][pointindex][YINDEX])) { X istat = 1; X /* This is just for cleaner error recovery: */ X n_movepen(endpoints[quadrant][pointindex] X [XINDEX], X endpoints[quadrant][pointindex] X [YINDEX]); X } X } X } X return(istat); X} X XxX--EOF--XxX echo restoring plot.c sed 's/^X//' > plot.c < X#if MIX_C X#else X#include X#endif /* MIX_C */ X#include "modes.h" X#include "bitmaps.h" X#include "graphics.h" X X/* The following declarations copied from gl.h. */ Xextern int g_clear(); Xextern int g_init(); Xextern int g_finish(); Xextern long g_style(); Xextern int c_cellstr(); Xextern int n_movepen(); Xextern int n_line(); Xextern int n_draw(); Xextern int n_arc(); Xextern int n_ellipse(); Xextern int n_point(); X Xextern struct GL_graphics graphics; X X/* These routines emulate the BSD plot(3) library. X * X * The arc() routine may vary slightly from the BSD version, X * in that it calculates start and end angles with trig X * functions, rather than with simple integer approximations X * used in the BSD routine. X * X * plot: openpl, erase, label, line, circle, arc, move, cont, X * point, linemod, space, closepl - graphics interface X * X * Coordinate transformations, using X0, X1, Y0, Y1 set in space(): X * X: X * x' = x * (NRM_X_RANGE)/(X1-X0) - (X0*NRM_X_RANGE)/(X1-X0) X * x' = (X0*NRM_X_RANGE + x*NRM_X_RANGE) / (X1-X0) X * X * xconst = X0*NRM_X_RANGE; X * xdiv = X1-X0; X * x' = (xconst+x*NRM_X_RANGE)/xdiv; X * X * Y: X * y' = y * (-NRM_Y_RANGE)/(Y1-Y0) + (Y1*NRM_Y_RANGE)/(Y1-Y0) X * y' = (Y1*NRM_Y_RANGE - y*NRM_Y_RANGE) / (Y1-Y0) X * X * yconst = Y1*NRM_Y_RANGE; X * ydiv = Y1-Y0; X * y' = (yconst-y*NRM_Y_RANGE)/ydiv; X */ X X/* X_TO_NORM(x) and Y_TO_NORM(y) are used to translate from the plot() */ X/* coordinate system, as defined by scale(), to the normalized 2-D */ X/* coordinate system of the screen. */ X X#define X_TO_NORM(x) ((int)((xconst+x*NRM_X_RANGE)/xdiv)) X#define Y_TO_NORM(y) ((int)((yconst-y*NRM_Y_RANGE)/ydiv)) X X/* X_SCALE_NORM() and Y_SCALE_NORM() are used for scaling magnitudes. */ X X#define X_SCALE_NORM(x) (((x)*(NRM_X_RANGE))/(xdiv)) X#define Y_SCALE_NORM(y) (((y)*(NRM_Y_RANGE))/(ydiv)) X Xstatic long xconst,xdiv,yconst,ydiv; /* Used in space() transforms. */ X Xint openpl() X{ X /* Try to get the mode from the environment. */ X /* If no environment variable, use a default. */ X if((g_init(ENV_MODE)) == 0) return(0); X else { X /* Put warning message to standard error, then */ X /* continue. */ X fprintf(stderr,"Use environment variable %s to control mode.\n", X GL_ENV_MODE); X fprintf(stderr,"Continuing with default mode %d\n", X DEFAULT_MODE); X sleep(2); X return(g_init(DEFAULT_MODE)); X } X} X Xint erase() X{ X return(g_clear()); X} X Xint label(s) Xchar s[]; X{ X return(c_cellstr(s)); X} X Xint line(x_1, y_1, x_2, y_2) Xint x_1,y_1,x_2,y_2; X{ X return(n_line( X X_TO_NORM(x_1),Y_TO_NORM(y_1),X_TO_NORM(x_2),Y_TO_NORM(y_2))); X} X Xint circle(x, y, r) X{ X int x_axis=X_SCALE_NORM(r); X int y_axis=Y_SCALE_NORM(r); X return(n_ellipse(X_TO_NORM(x), Y_TO_NORM(y), x_axis, y_axis)); X} X Xint arc(x, y, x_0, y_0, x_1, y_1) X{ X int x_axis, y_axis; /* Major and minor axes. */ X float angle1, angle2; /* Start and end angles. */ X int radius; /* Radius, as calculated from sqrt(x**2+y**2). */ X long dx_0 = x_0 - x; X long dy_0 = y_0 - y; X long dx_1 = x_1 - x; X long dy_1 = y_1 - y; X X /* We will draw a section of elliptical arc with major and */ X /* minor axes such that it appears as a circle on the screen. */ X /* We know the center of the arc (x and y), and the ratio of */ X /* the major and minor axes (b/a equals graphics.aspect_ratio). */ X /* Given the start and end points of the arc, we need to solve */ X /* for the first and second angle, and then for major and minor */ X /* axes. */ X /* These values can be used to call the n_arc() routine. */ X X /* WARNING: The value of angle2 is calculated directly as the */ X /* angle of the vector from (x,y) to (x_1,y_1). The original */ X /* versions of plot(3) from the BSD code apparently use */ X /* a simplistic approximation to this, which may lead to */ X /* different screen displays for arcs drawn with the BSD */ X /* code. The basic idea for the user, however, should be to */ X /* specify x_1 and y_1 such that they fall very close to the */ X /* intended angle. */ X X angle1 = (float)(-atan2((double)dy_0,(double)dx_0)); X angle2 = (float)(-atan2((double)dy_1,(double)dx_1)); X X radius = ((int)(sqrt(fabs((double)(dx_0*dx_0+dy_0*dy_0))))); X x_axis = X_SCALE_NORM(radius); X y_axis = Y_SCALE_NORM(radius); X X return(n_arc(X_TO_NORM(x),Y_TO_NORM(y),x_axis,y_axis,angle2,angle1)); X} X Xint move(x, y) Xint x,y; X{ X return(n_movepen(X_TO_NORM(x),Y_TO_NORM(y))); X} X Xint cont(x, y) Xint x,y; X{ X return(n_draw(X_TO_NORM(x),Y_TO_NORM(y))); X} X Xint point(x, y) Xint x, y; X{ X return(n_point(X_TO_NORM(x),Y_TO_NORM(y))); X} X Xint linemod(s) Xchar s[]; X{ X if (strncmp(s, "dotted", 6) == 0) { X g_style(DOTTED); X } X else if (strncmp(s, "dotdashed", 9) == 0) { X g_style(DOTDASHED); X } X else if (strncmp(s, "longdashed", 10) == 0) { X g_style(LONGDASHED); X } X else if (strncmp(s, "shortdashed", 11) == 0) { X g_style(SHORTDASHED); X } X else if (strncmp(s, "solid", 5) == 0) { X g_style(SOLID); X } X else { X g_style(SOLID); X } X return(0); X} X Xint space(x_0, y_0, x_1, y_1) X{ X /* Set constants for coordinate transformations. */ X /* Adjust x axis for aspect ratio so that output is square. */ X X xconst = (long)(x_0) * NRM_X_RANGE; X xdiv = (long)((float)(x_1-x_0) / graphics.aspect_ratio); X yconst = y_1*NRM_Y_RANGE; X ydiv = y_1-y_0; X} X Xint closepl() X{ X return(g_finish()); X} X XxX--EOF--XxX echo restoring trig.c sed 's/^X//' > trig.c < X#endif /* MIX_C */ X#include "bitmaps.h" X#include "graphics.h" X X#define L_PI 102944L /* Value of pi times TRIG_SCALE. */ X#define L_PI_2 51472L /* Value of pi/2 times TRIG_SCALE. */ X#define L_PI_4 25736L /* Value of pi/4 times TRIG_SCALE. */ X X#define CIRCLE_SIZE 205887L /* Value of pi * 2 * TRIG_SCALE. */ X X#define TABLESLICE 804L /* (L_PI_2 / PTS_PER_QUADRANT) */ X X#define XINDEX 0 /* For specifying array indices. */ X#define YINDEX 1 X X/* The following two arrays are tables of values for cos and sin */ X/* for one quadrant of a circle, divided into PTS_PER_QUADRANT slices. */ X Xlong cos_table[PTS_PER_QUADRANT] = { X 32758L, 32729L, 32679L, 32610L, 32522L, 32413L, 32286L, 32138L, X 31972L, 31786L, 31581L, 31357L, 31114L, 30853L, 30572L, 30274L, X 29957L, 29622L, 29269L, 28899L, 28511L, 28106L, 27684L, 27246L, X 26791L, 26320L, 25833L, 25330L, 24812L, 24279L, 23732L, 23170L, X 22595L, 22006L, 21403L, 20788L, 20160L, 19520L, 18868L, 18205L, X 17531L, 16846L, 16151L, 15447L, 14733L, 14010L, 13279L, 12540L, X 11793L, 11039L, 10279L, 9512L, 8740L, 7962L, 7180L, 6393L, X 5602L, 4808L, 4011L, 3212L, 2411L, 1608L, 804L, 0L X}; X Xlong sin_table[PTS_PER_QUADRANT] = { X 804L, 1608L, 2411L, 3212L, 4011L, 4808L, 5602L, 6393L, X 7180L, 7962L, 8740L, 9512L, 10279L, 11039L, 11793L, 12540L, X 13279L, 14010L, 14733L, 15447L, 16151L, 16846L, 17531L, 18205L, X 18868L, 19520L, 20160L, 20788L, 21403L, 22006L, 22595L, 23170L, X 23732L, 24279L, 24812L, 25330L, 25833L, 26320L, 26791L, 27246L, X 27684L, 28106L, 28511L, 28899L, 29269L, 29622L, 29957L, 30274L, X 30572L, 30853L, 31114L, 31357L, 31581L, 31786L, 31972L, 32138L, X 32286L, 32413L, 32522L, 32610L, 32679L, 32729L, 32758L, 32768L X}; X X/* Estimate sin by interpolation. Return long integer value. */ X Xlong longsin(theta) Xfloat theta; X{ X long longtheta; X int quadrant; X long value1, value2; X long value; X long intpart; X long fractionpart; X X /* We have a floating point value for theta. Put theta */ X /* into a long integer for the rest of the processing. */ X /* Keep everything scaled by a factor of TRIG_SCALE. */ X X longtheta = (long)(theta * F_TRIG_SCALE); X X /* Make angle positive. */ X X while (longtheta < 0) longtheta += CIRCLE_SIZE; X X /* Figure quadrant while making it less than PI/2. */ X X quadrant = 1; X X while (longtheta > L_PI_2) { X longtheta -= L_PI_2; X quadrant++; X if (quadrant > 4) quadrant = 1; X } X X /* If Quadrant 2 or 4 we need to use the reverse of the */ X /* interpolation table. */ X X if (quadrant == 2 || quadrant == 4) longtheta = L_PI_2 - longtheta; X X /* Express angle in terms of number of table increments. */ X X intpart = longtheta / TABLESLICE; X X fractionpart = longtheta % TABLESLICE; X X /* This looks like a kludge, but it isn't. When TABLESLICE is */ X /* set to TABLESLICE, we have the smallest error in the result. */ X /* This just rounds back down when we overshoot the table. */ X X if (intpart >= PTS_PER_QUADRANT) { X intpart = PTS_PER_QUADRANT - 1; X fractionpart = TABLESLICE; X } X X /* Interpolate. */ X X if (intpart <= 0) { X value1 = 0; X value2 = sin_table[0]; X } X else { X value2 = sin_table[(int)(intpart--)]; X value1 = sin_table[(int)intpart]; X } X X value = value1 + (fractionpart * (value2 - value1)) / TABLESLICE; X X /* If Quadrant 3 or 4 the result should be negative. */ X X if (quadrant == 3 || quadrant == 4) return(-value); X else return(value); X} X X X/* Estimate cos by interpolation. Return long integer value. */ X Xlong longcos(theta) Xfloat theta; X{ X long longtheta; X int quadrant; X long value1, value2; X long value; X long intpart; X long fractionpart; X X /* We have a floating point value for theta. Put theta */ X /* into a long integer for the rest of the processing. */ X /* Keep everything scaled by a factor of TRIG_SCALE. */ X X longtheta = (long)(theta * F_TRIG_SCALE); X X /* Make angle positive. */ X X while (longtheta < 0) longtheta += CIRCLE_SIZE; X X /* Figure quadrant while making it less than PI/2. */ X X quadrant = 1; X X while (longtheta > L_PI_2) { X longtheta -= L_PI_2; X quadrant++; X if (quadrant > 4) quadrant = 1; X } X X /* If Quadrant 2 or 4 we need to use the reverse of the */ X /* interpolation table. */ X X if (quadrant == 2 || quadrant == 4) longtheta = L_PI_2 - longtheta; X X /* Express angle in terms of number of table increments. */ X X intpart = longtheta / TABLESLICE; X X fractionpart = longtheta % TABLESLICE; X X /* This looks like a kludge, but it isn't. When TABLESLICE is */ X /* set to TABLESLICE, we have the smallest error in the result. */ X /* This just rounds back down when we overshoot the table. */ X X if (intpart >= PTS_PER_QUADRANT) { X intpart = PTS_PER_QUADRANT - 1; X fractionpart = TABLESLICE; X } X X /* Interpolate. */ X X if (intpart <= 0) { X value1 = 32768L; X value2 = cos_table[0]; X } X else { X value2 = cos_table[(int)(intpart--)]; X value1 = cos_table[(int)intpart]; X } X X value = value1 + (fractionpart * (value2 - value1)) / TABLESLICE; X X /* If Quadrant 2 or 3 the result should be negative. */ X X if (quadrant == 2 || quadrant == 3) return(-value); X else return(value); X} X X/* Test program: Xmain() { X float theta; X Xfloat sinval; Xfloat lsinval; Xfloat cosval; Xfloat lcosval; X X for (theta = -8.3; theta < 100.0; theta += 0.1) { X X sinval = sin((double)theta); X lsinval = longsin(theta) / F_TRIG_SCALE; X cosval = cos((double)theta); X lcosval = longcos(theta) / F_TRIG_SCALE; X X printf("SIN: angle %g %lg %g err %g\n",theta,sinval, X lsinval,sinval-lsinval); X printf("COS: angle %g %lg %g err %g\n",theta,cosval, X lcosval,cosval-lcosval); X } X} X*/ X XxX--EOF--XxX