home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- Alged: Algebra Editor henckel@vnet.ibm.com
-
- Copyright (c) 1994 John Henckel
- Permission to use, copy, modify, distribute and sell this software
- and its documentation for any purpose is hereby granted without fee,
- provided that the above copyright notice appear in all copies.
- */
- #include "alged.h"
- #include <graphics.h>
- #include <dos.h>
- /*
- xs is size
- xo is origin (left edge)
- xz is maxx/xs (number of pixels per unit length)
- np is number of points
- */
- static node* defx; // default fx
- static double xs=0,xo,ys,yo,xz,yz,np,ts,to;
- static double err,step;
- static node ivar[10]; /* independent variables */
- static int gm,polar,nv,rain,fill;
- static int co1,co2,co3; /* colors */
- extern char gdriver[80];
- extern int gmode,psz,pst;
- /*-----------------------------------------------------------------
- Palette variables
- */
- typedef struct { unsigned char r,g,b; } palen;
- static palen pal[480];
- static int v256;
- /*-----------------------------------------------------------------
- 3d variables
- */
- static int in3d,vix=1;
- static double focalen = 5, cont;
- static double cx,cy,cz; // camera location
- static double ax,ay,az; // camera orientation
- static double m[4][4]; // transform matrix
- extern double lightx,lighty,lightz; // see algfile.c
- #define EPS 1E-200
- /* These are the zooming ratios.... rr1 is (1-rr)/2 */
- #define rr 0.7
- #define rr1 0.15
- #define tt (M_PI/72)
-
- typedef struct { // save previous row data for polyfill
- short x2,y2; // screen location
- } point2d;
-
- typedef struct { // save previous row data for polyfill
- double x,y,z; // 3d location
- } point3d;
-
- /*-----------------------------------------------------------------
- find var
- */
- double getvar(char *name) { int i;
- for (i=0; i<nv; ++i)
- if (!strcmp(name,ivar[i].name)) return ivar[i].value;
- return 0.0;
- }
-
- /*-----------------------------------------------------------------
- min and max
- */
- double mind(double x, double y) {
- return min(x,y);
- }
- double maxd(double x, double y) {
- return max(x,y);
- }
-
- /*-----------------------------------------------------------------
- gray_palette
- */
- void gray_palette()
- {
- int i;
- for (i=0; i<120; ++i) pal[i].r = pal[i].g = pal[i].b = i/2+3;
- for (i=120; i<240; ++i) pal[i].r = pal[i].g = pal[i].b = 123-i/2;
- for (i=0; i<240; ++i) pal[i+240] = pal[i];
- }
-
- /*-----------------------------------------------------------------
- wave_palette
- */
- #define cwav(r) 31*(sin((i+r)*M_PI/120)+1)
- // #define cwav(r) max(min(abs((i+r)%240-120)-40,40),0)*63/40
- void wave_palette()
- {
- int i;
- for (i=0; i<240; ++i) {
- pal[i].r = cwav(0);
- pal[i].g = cwav(80);
- pal[i].b = cwav(160);
- }
- for (i=0; i<240; ++i) pal[i+240] = pal[i];
- }
-
- /* positive modulo */
- long pmod(long x,long y) {
- if (y==0) return x;
- if (y<0) y=-y;
- x = x % y;
- if (x < 0) x += y;
- return x;
- }
-
- /*-----------------------------------------------------------------
- set_palette - set the top 240 colors of the vga palette
- */
- void set_palette(int i)
- {
- struct REGPACK r;
- i = pmod(i,240);
- r.r_ax = 0x1012;
- r.r_bx = 0x0010; /* start */
- r.r_cx = 0x00F0; /* length */
- r.r_es = FP_SEG(pal);
- r.r_dx = FP_OFF(pal) + i*sizeof*pal;
- intr(0x10, &r);
- }
-
- /*-----------------------------------------------------------------
- eval - return value of p, using ivar
- */
- double eval(node *p) {
- double u,v;
- if (!p) return 0;
- switch (p->kind) {
- case VAR: return getvar(p->name);
- case NUM: return p->value;
- case ADD: return eval(p->lf) + eval(p->rt);
- case SUB: return eval(p->lf) - eval(p->rt);
- case MUL: return eval(p->lf) * eval(p->rt);
- case DIV:
- v = eval(p->rt);
- if (fabs(v)<err) return 0;
- return eval(p->lf) / v;
- case EXP:
- u = eval(p->lf);
- v = eval(p->rt);
- if (u<err && !whole(v)) modf(v,&v); // result would be imaginary
- if (fabs(v * log10(fabs(u)+1)) > 300) return 0;
- if (!v) return 0;
- return pow(u,v);
- case EQU: return mind(eval(p->lf),eval(p->rt));
- case FUN:
- if (!strcmp(p->name,"sin")) return sin(eval(p->lf));
- if (!strcmp(p->name,"cos")) return cos(eval(p->lf));
- if (!strcmp(p->name,"tan")) return tan(eval(p->lf));
- if (!strcmp(p->name,"asin")) {
- v = eval(p->lf);
- if (v>1 || v<-1) return 0;
- return asin(v);
- }
- if (!strcmp(p->name,"acos")) {
- v = eval(p->lf);
- if (v>1 || v<-1) return 0;
- return acos(v);
- }
- if (!strcmp(p->name,"atan")) return atan(eval(p->lf));
- if (!strcmp(p->name,"sinh")) return sinh(eval(p->lf));
- if (!strcmp(p->name,"cosh")) return cosh(eval(p->lf));
- if (!strcmp(p->name,"tanh")) return tanh(eval(p->lf));
- if (!strcmp(p->name,"rand")) return eval(p->lf)*rand()/RAND_MAX;
- if (!strcmp(p->name,"sign")) {
- v = eval(p->lf);
- return v<0?-1:v>0?1:0;
- }
- if (!strcmp(p->name,"ln")) {
- v = eval(p->lf);
- if (v<=0) return 0;
- return log(v);
- }
- if (!strcmp(p->name,"log")) {
- v = eval(p->lf);
- if (v<=0) return 0;
- return log10(v);
- }
- if (!strcmp(p->name,"abs")) return fabs(eval(p->lf));
- if (!strcmp(p->name,"r") && p->nump==2) return hypot(eval(p->lf),eval(p->rt));
- if (!strcmp(p->name,"min") && p->nump==2) return mind(eval(p->lf),eval(p->rt));
- if (!strcmp(p->name,"max") && p->nump==2) return maxd(eval(p->lf),eval(p->rt));
- if (!strcmp(p->name,"atan2") && p->nump==2) {
- u = eval(p->lf);
- v = eval(p->rt);
- if (v==0 && u==0) return 0;
- return atan2(u,v);
- }
- if (!strcmp(p->name,"mod") && p->nump==2) return fmod(eval(p->lf),eval(p->rt));
- default: return 0;
- }
- }
-
- /*-----------------------------------------------------------------
- reset window, use a weird number for xs to get better safety
- */
- void resetx() { int i;
- xs = 7-M_PI/13; ys = xs*0.75;
- xo=xs/-2; yo=ys/-2; np=25;
- err = pow(10,-sigdig); step=1.0;
- for (i=0; i<10; ++i) ivar[i].value = 0;
- cz=2.5; cy=2.58819; cx=9.33013; // camera location
- ax=.261799; ay=M_PI/2+ax; az=0; // camera orientation
- ts=xs; to=xo; vix=1;
- co1=15; co2=2; co3=1; rain=0;
- focalen=5; fill=0; polar=0; cont=0.2;
- }
- /*-----------------------------------------------------------------
- add a new var
- */
- void addvar(char *name) { int i;
- for (i=0; i<nv; ++i) if (!strcmp(name,ivar[i].name)) break;
- if (i==nv && nv<10) strcpy(ivar[nv++].name,name);
- }
- /*-----------------------------------------------------------------
- look for the first var in p
- */
- void setivar(node *p) { int i;
- if (p->kind==VAR) addvar(p->name);
- for (i=0; i<p->nump; ++i) setivar(p->parm[i]);
- }
-
- /*-----------------------------------------------------------------
- show help file
- */
- void showghelp() {
- FILE *f;
- int i,c=0;
- static char s[85];
-
- strcpy(s,"alged");
- strcat(s,lang);
- strcat(s,".hlq");
- f = fopen(s,"r");
- if (!f) { printf(msg[16],s);
- pause; return;
- }
- restorecrtmode();
- if (ti.screenheight>25) textmode(64); /* ega 43 line mode */
- textattr(norm);
- clrscr();
- i = ti.screenheight-1;
- while (!feof(f)) {
- printf(fgets(s,80,f));
- if (!--i) {
- i = ti.screenheight-4;
- while (!(c=getch()));
- if (c==27) break;
- }
- }
- if (c!=27) getch();
- fclose(f);
- setgraphmode(gmode);
- }
- /*-----------------------------------------------------------------
- rotate vars starting at index i
- */
- void rot_var(int i) {
- node t;
- if (nv < 2) return;
- t = ivar[i];
- t.value = 0;
- for (++i; i<nv; ++i) {
- ivar[i-1] = ivar[i];
- ivar[i-1].value = 0;
- }
- ivar[nv-1] = t;
- strcpy(defx->name,ivar[0].name); // default fx is ivar[0]
- }
- /*-----------------------------------------------------------------
- handle key
- */
- void handlekey(char c) {
- switch (c) {
- case ';': showghelp(); break; /* F1 */
- case 72: yo+=ys/4; break;
- case 75: xo-=xs/4; break;
- case 77: xo+=xs/4; break;
- case 80: yo-=ys/4; break;
- case 82: xo+=xs*rr1; yo+=ys*rr1; xs*=rr; ys*=rr; break;
- case 83: xs/=rr; ys/=rr; xo-=xs*rr1; yo-=ys*rr1; break;
- case 71: np/=rr; break;
- case 79: if (np>6) np*=rr; break;
- case 73: ys/=rr; yo-=ys*rr1; break;
- case 81: yo+=ys*rr1; ys*=rr; break;
- case 'd': resetx(); break;
- case 'a': polar = ++polar%3;
- if (!in3d && polar>1) polar=0; break;
- case 'q': ivar[1].value -= step; break;
- case 'w': ivar[2].value -= step; break;
- case 'e': ivar[3].value -= step; break;
- case 'r': ivar[4].value -= step; break;
- case 't': ivar[5].value -= step; break;
- case 'y': ivar[6].value -= step; break;
- case 'u': ivar[7].value -= step; break;
- case 'i': ivar[8].value -= step; break;
- case 'o': ivar[9].value -= step; break;
- case 'p': step *= sqrt(.1); break;
- case '1': ivar[1].value += step; break;
- case '2': ivar[2].value += step; break;
- case '3': ivar[3].value += step; break;
- case '4': ivar[4].value += step; break;
- case '5': ivar[5].value += step; break;
- case '6': ivar[6].value += step; break;
- case '7': ivar[7].value += step; break;
- case '8': ivar[8].value += step; break;
- case '9': ivar[9].value += step; break;
- case '0': step /= sqrt(.1); break;
- case 'V':
- if (in3d) rot_var(1);
- if (++vix >= nv) vix = 1; // variable index counter
- if (!in3d || vix==1) rot_var(0);
- break;
- }
- }
-
- /*-----------------------------------------------------------------
- MAIN GRAPH ROUTINE
-
- fx is an optional scaling function for the x coordinate, and fy
- is a required function for the y coord. In case of polar coordinates
- the x is theta and the y is radius.
- */
- #define rline(x,y,a,b) line(xz*(x-xo),yz*(ys+yo-(y)),xz*(a-xo),yz*(ys+yo-(b)))
-
- void graph(node *fx,node *fy) {
- int gd=DETECT,c,i;
- double t,x1,y1,x2,y2,z;
- char ss[60];
-
- nv=0;
- strcpy(ivar[1].name,"y");
- setivar(fy);
- if (fx) setivar(fx);
- if (!nv) addvar("x");
- if (!defx) defx = newvar("x");
- if (!fx) {
- fx = defx;
- strcpy(defx->name,ivar[0].name);
- }
- if (!xs) {
- if (*gdriver && *gdriver!='*') { // customized bgi file!
- gd=installuserdriver(gdriver,NULL);
- gm=gmode;
- if (!!(i=graphresult())) {
- printf(msg[17],i,grapherrormsg(i));
- pause;
- return;
- }
- }
- initgraph(&gd,&gm,"");
- if (!!(i=graphresult())) {
- printf(msg[17],i,grapherrormsg(i));
- pause;
- return;
- }
- if (!*gdriver) gmode = gm; // auto detect and auto mode
- if (gm != gmode) setgraphmode(gmode);
- resetx();
- if (psz<2) { psz = getpalettesize()-1; pst=1; }
- v256 = (psz+pst>17 || getpalettesize()>17);
- }
- else setgraphmode(gmode);
- while (1) {
- xz = getmaxx()/xs;
- yz = getmaxy()/ys;
-
- if (in3d && graph3d(fx,fy)) break;
- cleardevice();
-
- // setlinestyle(DOTTED_LINE,0,1);
- setcolor(co2);
- rline(xo,0,xo+xs,0);
- rline(0,yo,0,yo+ys);
- rline(.1,1,-.1,1);
- rline(.1,-1,-.1,-1);
- rline(1,.1,1,-.1);
- rline(-1,.1,-1,-.1);
- rline(.1,2,-.1,2);
- rline(.1,-2,-.1,-2);
- rline(2,.1,2,-.1);
- rline(-2,.1,-2,-.1);
-
- rline(1.1,1,.9,1);
- rline(1,1.1,1,.9);
- rline(-1.1,1,-.9,1);
- rline(-1,1.1,-1,.9);
- rline(1.1,-1,.9,-1);
- rline(1,-1.1,1,-.9);
- rline(-1.1,-1,-.9,-1);
- rline(-1,-1.1,-1,-.9);
-
- // setlinestyle(SOLID_LINE,0,1);
- setcolor(co1);
- sprintf(ss,"%g ",yo+ys); outtextxy(getmaxx()/2,0,ss);
- sprintf(ss,"%g ",yo ); outtextxy(getmaxx()/2,getmaxy()-8,ss);
- sprintf(ss,"%g ",xo+xs); outtextxy(getmaxx()-50,getmaxy()/2,ss);
- sprintf(ss,"%g ",xo ); outtextxy(0,getmaxy()/2,ss);
- sprintf(ss,"%s %g ",msg[18],step);
- if (polar) strcat(ss,msg[19]);
- strcat(ss,msg[36]);
- outtextxy(0,0,ss);
- sprintf(ss,"%s =[%8.4f %8.4f] ",ivar[0].name,xo,xo+xs);
- outtextxy(0,10,ss);
- for (i=1; i<nv; ) {
- sprintf(ss,"%s = %8.4f ",ivar[i].name,ivar[i].value);
- outtextxy(0,++i*10,ss);
- }
- srand(2);
- for (t=xo; t<=xs+xo; t+=xs/np) {
- ivar[0].value = t;
- if (polar) ivar[0].value = (2*(t-xo)/xs-1)*M_PI;
- x2 = eval(fx);
- y2 = eval(fy);
- if (polar) {
- z = x2;
- x2 = y2*cos(z);
- y2 = y2*sin(z);
- }
- x2 = xz*(x2-xo);
- y2 = yz*(ys+yo-y2);
- if (x2>30000) x2=30000;
- if (x2<-30000) x2=-30000;
- if (y2>30000) y2=30000;
- if (y2<-30000) y2=-30000;
- if (t!=xo) line(x1,y1,x2,y2);
- x1=x2; y1=y2;
- if (kbhit()) break;
- }
- c = getch();
- while (kbhit()) c = getch();
- if (c==27) break; /* escape */
- in3d=1;
- if (c=='g' && graph3d(fx,fy)) break; /* 3d graphics */
- in3d=0;
- handlekey(c);
- }
- restorecrtmode();
- if (ti.screenheight>25) textmode(64); /* ega 43 line mode */
- }
-
- /*-----------------------------------------------------------------
- compute matrix
- */
- static void computematrix() {
- double sa,sb,sc,ca,cb,cc; int i;
-
- // Precompute some sines and cosines
- ca=cos(ax); sa=sin(ax);
- cb=cos(ay); sb=sin(ay);
- cc=cos(az); sc=sin(az);
-
- // Compute rotation transformation
- m[0][0]=cb*cc-sb*sa*sc; /* R = Rb.Ra.Rc */
- m[0][1]=ca*sc;
- m[0][2]=sb*cc+cb*sa*sc;
- m[1][0]=-cb*sc-sb*sa*cc;
- m[1][1]=ca*cc;
- m[1][2]=-sb*sc+cb*sa*cc;
- m[2][0]=-sb*ca;
- m[2][1]=-sa;
- m[2][2]=cb*ca;
-
- // Compute translation transformation
- for (i=0; i<3; ++i) m[i][3]=-cx*m[i][0]-cy*m[i][1]-cz*m[i][2];
-
- for (i=0; i<4; ++i) m[3][i]=m[2][i]/focalen;
- }
-
- static void view3d(double dx,double dy,double dz,double *xx,double *yy) {
- double x,y,z,t;
- x = dx*m[0][0] + dy*m[0][1] + dz*m[0][2] + m[0][3];
- y = dx*m[1][0] + dy*m[1][1] + dz*m[1][2] + m[1][3];
- z = dx*m[3][0] + dy*m[3][1] + dz*m[3][2] + m[3][3];
-
- // Check if the point is behind the visual cone.
- t = hypot(x,y)/5; // 5 is slope of the cone
- if (z < t) z=t; // push point to the cone
- if (z < EPS) z=EPS; // don't divide by zero
- *xx = x/z;
- *yy = y/z;
- }
-
- /*-----------------------------------------------------------------
- move camera forward or backward
- */
- void movecam(double spd) {
- double y,d;
- y=sin(ax);
- d=cos(ax);
- cz+=spd*cos(ay)*d;
- cy-=spd*y;
- cx-=spd*sin(ay)*d;
- }
- /*-----------------------------------------------------------------
- rotate camera - with constant radius v=-1,1 vertically or 3,5 horiz
- */
- void spincam(int v) {
- double r,t,a;
- r = hypot(cx,cz);
- if (v<2) { // vertical
- t = atan2(cy,r) + tt*v;
- if (fabs(t)>M_PI/2) return;
- a = hypot(r,cy);
- cy = sin(t)*a;
- a *= cos(t)/r;
- cx *= a; cz *= a;
- ax+=tt*v;
- }
- else { // horizontal
- t = atan2(cz,cx);
- t+=tt*(v-4);
- cx=cos(t)*r;
- cz=sin(t)*r;
- ay+=tt*(v-4);
- }
- }
-
- /*-----------------------------------------------------------------
- These are some macros to ease 3D vector computation
- */
- #define diff3d(A,B,C) { \
- (A##x) = (B##x) - (C##x); \
- (A##y) = (B##y) - (C##y); \
- (A##z) = (B##z) - (C##z); \
- }
- #define cross3d(A,B,C) { \
- (A##x) = (B##y)*(C##z) - (C##y)*(B##z); \
- (A##y) = (B##z)*(C##x) - (C##z)*(B##x); \
- (A##z) = (B##x)*(C##y) - (C##x)*(B##y); \
- }
- #define len3d(A) hypot(A##x,hypot(A##y,A##z))
- /*-----------------------------------------------------------------
- compute brightness of a triangle using light source
- return a positive number less than range/2
- */
- int light_source(double px, double py, double pz,point3d *save,int range)
- {
- static double ax,ay,az,bx,by,bz,cx,cy,cz,t;
- /* get two vectors: a,b in the plane, and compute cross product */
- diff3d(a,p,save[0].);
- diff3d(b,p,save[1].);
- cross3d(c,a,b); /* c = a x b, normal to the plane */
- t = len3d(c);
- if (t<EPS) cy=1;
- else { cx/=t; cy/=t; cz/=t; } /* make unit vector */
-
- t = cx*lightx + cy*lighty + cz*lightz; /* dot product = cos theta */
- if (polar) t=-t; // why?
- if (range>16) range/=2; // if large spectrum, use half
- if (t>0) return range*((1-cont)*t+cont);
- return range*(cont*t+cont);
- }
-
- #define rline3(a,b,c,u,v,w) \
- view3d(a,b,c,&x,&y); \
- view3d(u,v,w,&z,&yy); \
- rline(x,y,z,yy)
- /*------------------------------------------------------------------
- 3D Graphics
-
- This draws a 3d surface function where the altitude is z = fz,
- and x is the first variable found in fx and y is fy (if specified)
- or if fy is NULL then y is the second variable found in fz. If
- there are insufficient variables in fz, then a zero is returned.
-
- Implementation: z is fz, x is ivar[0],y is fy or ivar[1].
-
- P.S. I changed my mind in the middle of doing this. Now y is fz,
- a function of x and z, and fy is unused. I did this because y is the
- vertical axis. Thus the code is confusing at places.
- Actually, I decided to make x=fy, so that I can make a bagel in polar
- mode. So the code is very confusing at places.
- */
- int graph3d(node *fy,node *fz) {
- int c,i,j,mm=0; // mm 0=norm, 1=camera, 2=grid
- static double x,y,z,xx,yy,cc,zz,x2,y2;
- static point2d *save2 = 0;
- static point3d *save3 = 0;
- static struct { int x1,y1,x2,y2,x3,y3,x4,y4; } f; // used by fillpoly
- static char ss[60];
- static int np=0,onp=0;
- static double zmag,uo,us;
- static short fillpat[] = { 10,11,3,8,7,900 };
- int spd=0, palrot=0, palix=0, cmn,cmx;
- double ca=1;
- int pp=0, palst=pst, palsz=psz;
-
- while (1) {
- if (spd) { // speedy mode (cleardevice is very slow)
- delay(50);
- setcolor(0);
- rline3(-2,0,0,2,0,0); // erase axes (draw black)
- rline3(0,-2*zmag,0,0,2*zmag,0);
- rline3(0,0,-2,0,0,2);
- rline3(2.2,0,0,2,0,-0.1); // arrows
- rline3(2.2,0,0,2,0, 0.1);
- rline3(0,0,2.2,-0.1,0,2);
- rline3(0,0,2.2, 0.1,0,2);
- rline3(0,2.2*zmag,0,-0.1,2*zmag,0);
- rline3(0,2.2*zmag,0, 0.1,2*zmag,0);
- }
- // if (polar) { uo=-M_PI; us=-2*uo; to=uo/2; ts=us/2; }
- if (!np) { // reset defaults
- zmag=1; us=ts; uo=to; np=25;
- ca=1.0; palrot=palix=0;
- }
- computematrix();
- xz = getmaxx()/xs;
- yz = getmaxy()/ys;
- if (np<3) np = 3;
- if (np>2000) np = 2000;
-
- if (!spd) cleardevice();
- spd=0;
- // setlinestyle(DOTTED_LINE,0,1);
- setcolor(co2);
- rline3(-2,0,0,2,0,0); // draw axes
- rline3(0,-2*zmag,0,0,2*zmag,0);
- rline3(0,0,-2,0,0,2);
- rline3(2.2,0,0,2,0,-0.1); // arrows
- rline3(2.2,0,0,2,0, 0.1);
- rline3(0,0,2.2,-0.1,0,2);
- rline3(0,0,2.2, 0.1,0,2);
- rline3(0,2.2*zmag,0,-0.1,2*zmag,0);
- rline3(0,2.2*zmag,0, 0.1,2*zmag,0);
-
- if (!kbhit()) {
- setcolor(co1);
- sprintf(ss,"%s %g ",msg[18],step );
- if (polar==1) strcat(ss,msg[19]);
- if (polar==2) strcat(ss,msg[37]);
- strcat(ss,msg[36]);
- outtextxy(0,0,ss); i=0;
- sprintf(ss,"%s =[%8.4f,%8.4f] ",ivar[i].name,to,to+ts);
- outtextxy(0,++i*10,ss);
- sprintf(ss,"%s =[%8.4f,%8.4f] ",ivar[i].name,uo,uo+us);
- outtextxy(0,++i*10,ss);
- while (i<nv) {
- sprintf(ss,"%s = %8.4f ",ivar[i].name,ivar[i].value);
- outtextxy(0,++i*10,ss);
- }
- x = 180/M_PI;
- sprintf(ss," %8.4f %8.4f %d ",zmag,focalen,np); outtextxy(0,++i*10,ss);
- sprintf(ss," %8.4f %8.4f %8.4f ",cx,cy,cz); outtextxy(0,++i*10,ss);
- sprintf(ss," %8.4f %8.4f %8.4f ",ax*x,ay*x,az*x); outtextxy(0,++i*10,ss);
- if (mm) outtextxy(0,++i*10,msg[27]);
- } else spd=1;
- if (!kbhit()) {
- setcolor(co2);
- rline3(2,0,0.1,2,0,-0.1);
- rline3(0.1,2*zmag,0,-0.1,2*zmag,0);
- rline3(0.1,0,2,-0.1,0,2);
- rline3(1,0,0.1,1,0,-0.1); // axis ticks
- rline3(-1,0,0.1,-1,0,-0.1);
- rline3(0.1,zmag,0,-0.1,zmag,0);
- rline3(0.1,-1*zmag,0,-0.1,-1*zmag,0);
- rline3(0.1,0,1,-0.1,0,1);
- rline3(0.1,0,-1,-0.1,0,-1);
- }
- if (!kbhit() && !polar) {
- setcolor(co3);
- rline3(to ,0,uo ,to+ts,0,uo );
- rline3(to+ts,0,uo ,to+ts,0,uo+us);
- rline3(to+ts,0,uo+us,to ,0,uo+us);
- rline3(to ,0,uo+us,to ,0,uo );
-
- rline3(-1,-zmag, 1, 1,-zmag, 1); // draw a unit box
- rline3( 1,-zmag, 1, 1, zmag, 1);
- rline3( 1, zmag, 1,-1, zmag, 1);
- rline3(-1, zmag, 1,-1,-zmag, 1);
- rline3(-1,-zmag,-1,-1,-zmag, 1);
- rline3( 1,-zmag,-1, 1,-zmag, 1);
- rline3(-1, zmag,-1,-1, zmag, 1);
- rline3( 1, zmag,-1, 1, zmag, 1);
- rline3(-1,-zmag,-1, 1,-zmag,-1);
- rline3( 1,-zmag,-1, 1, zmag,-1);
- rline3( 1, zmag,-1,-1, zmag,-1);
- rline3(-1, zmag,-1,-1,-zmag,-1);
- }
- // setlinestyle(SOLID_LINE,0,1);
- setcolor(co1);
- if (onp<np || onp>np*3) { onp = np;
- if (save2) free(save2);
- if (save3) free(save3);
- save2 = malloc((np+1)*sizeof*save2);
- save3 = NULL;
- }
- if (rain==2 && !save3) save3 = malloc((np+1)*sizeof*save3);
- /*-----------------------
- MAIN DRAW LOOP
- */
- srand(2); cmn=32767; cmx=-cmn; // set color min/max
- if (!kbhit())
- for (j=0,x=to; j<=np; ++j,x+=ts/np) {
- ivar[0].value = x;
- for (i=0,y=uo; i<=np; ++i,y+=us/np) {
- ivar[1].value = y;
- xx = eval(fy); /* by default fy = ivar[0] */
- zz = y;
- yy = cc = eval(fz);
- if (polar==1) { /* spherical */
- x2 = xx;
- xx = cos(y)*cos(x2)*yy;
- zz = sin(y)*cos(x2)*yy;
- yy *= sin(x2);
- }
- else if (polar==2) { /* cylindrical */
- x2 = xx;
- xx = yy*cos(y);
- zz = yy*sin(y);
- yy = x2;
- }
- yy *= zmag;
- view3d(xx,yy,zz,&x2,&y2);
- x2 = xz*(x2-xo);
- y2 = yz*(ys+yo-y2);
- c = ca*zmag*cc*np/ts; /* color or fill pattern */
- if (c<cmn) cmn=c;
- if (c>cmx) cmx=c;
- if (rain==1) { /* color by height */
- c = pmod(c,palsz)+palst;
- setcolor(c);
- }
- else if (rain==2 && i && j) { /* color by derivative */
- c = light_source(xx,yy,zz,save3+i-1,palsz) + palst;
- setcolor(c);
- }
- if (fill) {
- f.x3=save2[i].x2; f.y3=save2[i].y2;
- f.x2=x2; f.y2=y2;
- if (i && j) {
- if (rain && fill>2) setcolor(7);
- if (rain) setfillstyle(1,c);
- else setfillstyle(fillpat[pmod(c,6)],co1);
- if (fill&1) fillpoly(4,&f.x1);
- else fillpoly(3,&f.x2);
- }
- f.x1=f.x2; f.y1=f.y2;
- f.x4=f.x3; f.y4=f.y3;
- }
- else {
- if (i) line(save2[i-1].x2,save2[i-1].y2,x2,y2);
- if (j) line(save2[i].x2,save2[i].y2,x2,y2);
- }
- save2[i].x2 = x2;
- save2[i].y2 = y2;
- if (rain==2 && save3) {
- save3[i].x = xx;
- save3[i].y = yy;
- save3[i].z = zz;
- }
- if (kbhit()) break;
- }
- if (kbhit()) break;
- }
- /* Draw a color legend at the bottom of the screen. */
- if (rain && palsz>16 && !kbhit()) {
- c = getmaxy();
- for (i=0; i<256; ++i) { putpixel(i,c,i); putpixel(i,c-1,i); }
- }
- next_key:
- if (rain && palrot && v256) while (!kbhit()) {
- palix += palrot;
- if (palst!=16 || palsz!=240) wave_palette();
- palst=16; palsz=240;
- c = clock();
- set_palette(palix);
- while (c <= clock() && c+2 > clock());
- }
- c = getch(); if (!c) c=getch(); // get ONE keystroke
- while(kbhit()) c=getch(); // flush kbd buffer
- if (c==27) return 1; /* escape */
- if (c=='g') return 0; /* 2d graphics */
- if (c=='d') np=0; // force reset above
- if (c<84 && c>70) c+=mm;
- switch (c) {
- case 'c': rain=(rain+1)%3; break; // color mode
- case 'x': // palette mode
- if (!v256) break;
- pp = 1-pp;
- if (pp) wave_palette();
- else gray_palette();
- set_palette(palix);
- if (palst==16 && palsz==240 && j>np) goto next_key;
- palst=16; palsz=240;
- break;
- case '=': palrot -= (palrot>-10); goto next_key;
- case '-': palrot += (palrot<10); goto next_key;
- case 'z': if (cmx==cmn) ca=1.0; else ca*=1.0*palsz/(cmx-cmn); break;
- case 'f': fill=(fill+1)%(5-!rain*2); break;
- case 13: mm=200-mm; break;
- case 75: spincam(3); break; // l,r,u,d
- case 77: spincam(5); break;
- case 72: spincam(1); break;
- case 80: spincam(-1); break;
- case ',': focalen*=rr;
- case 82: cx*=rr; cy*=rr; cz*=rr; break; // ins,del
- case '.': focalen/=rr;
- case 83: cx/=rr; cy/=rr; cz/=rr; break;
- case 71: np/=rr; break; // home end
- case 79: if (np>3) np*=rr; break;
- case 73: zmag/=rr; break; // pgup dn
- case 81: zmag*=rr; break;
- case 275: ay+=tt; break; // mm l,r,u,d
- case 277: ay-=tt; break;
- case 272: ax+=tt; break;
- case 280: ax-=tt; break;
- case 282: movecam(3); break; // mm ins,del
- case 283: movecam(-3); break;
- case 273: az+=tt; break; // mm pgup dn
- case 281: az-=tt; break;
- case 115: to-=ts/4; break; // ctrl l r u d
- case 116: to+=ts/4; break;
- case 141: uo+=us/4; break;
- case 145: uo-=us/4; break;
- case 146: ts/=rr; us/=rr;
- to-=ts*rr1; uo-=us*rr1; break; // ctrl ins del
- case 147: to+=ts*rr1; uo+=us*rr1;
- ts*=rr; us*=rr; break;
- case 132: us/=rr; uo-=us*rr1; break; // ctrl pgup dn
- case 118: uo+=us*rr1; us*=rr; break;
- case '?': cont-=.1; if (cont<0) cont=0; break; // f5
- case '@': cont+=.1; if (cont>1) cont=1; break; // f6
- case 'T': c='t';
- default: handlekey(c);
- if (c=='a')
- if (polar) {
- to=uo=-M_PI; ts=us=-2*uo;
- if (polar==1) { to=uo/2; ts=us/2; }
- }
- }
- }
- /* never here */
- }
-