home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Plot3d -- plot.c, the plotting code
-
- By Adrian Mariano -- adrian@milton.u.washington.edu
-
-
- Copyright (c) 1991 by Adrian Mariano
-
- You may use and distribute this program as much as you like so long as you do
- not charge for this service. I am not liable for failure of this program to
- perform in any way.
-
- */
-
-
- #include "plot3d.h"
-
- /******************************************************************/
- /* */
- /* Parameters to plot3d() */
-
- float xmin=-3; /* Dimensions of display area */
- float xmax=3;
- float ymin=-3;
- float ymax=3;
- float zmin=-3;
- float zmax=3;
-
- float aspect=1.0; /* Aspect ratio */
- float distance=3; /* Perspective distance */
- float tip=-30.0; /* Rotation around y axis */
- float spin=0.0; /* Rotation around z axis */
-
- float var1start;
- float var2start;
- float var1end;
- float var2end;
-
- long var1stepcount=30; /* Number of steps over var 1 */
- long var2stepcount=30; /* Number of steps over var 2 */
-
- /* */
- /******************************************************************/
-
- #define TRUE 1
- #define FRONT 1
- #define FALSE 0
- #define BACK 0
- #define PI 3.14159265
-
-
- /*************************************
- Internal variables
- Global for convenience
- *************************************/
-
- struct sectiontype {
- int x1,y1,x2,y2,x3,y3,x4,y4;
- float x;
- /* char ferr;*/
- };
-
- float xrange,yrange,zrange,sinspin,cosspin,sintip,costip;
- float multx,multy,addx,addy;
-
-
- /* The main function */
- int plot3d(void (*transform)(float *,float *,float *,float,float,float));
-
- /* Takes (x,y,z) and returns (x,y,z) in screen coordinates */
- void realscale(float *xx,float *yy,float *zz);
-
- /* Compare to sections -- used by qsort */
- int sectioncmp(struct sectiontype *a,struct sectiontype *b);
-
- /* plots the data contained the section */
- void plotsections(struct sectiontype *section,int count);
-
- /* Get screen coordinates from float (x,y,z) */
- void scale(int *xint,int *yint,float x,float y,float z);
-
- /* Draw 3d line */
- void line3d(float a,float b,float c,float d,float e,float f);
-
- /* Initialize multx, multy, addx, and addy for use in scaling */
- void calcscale(float xmin,float ymin,float zmin,float xmax,float ymax,float zmax);
-
- /* Draw the axes */
- void drawaxes(char flag);
-
- /* Is this face (of the cube) visible ? */
- int visible(int i);
-
-
-
- /* Function to be plotted */
-
- #define FIX(flag,min,max) ( flag==1 ? max : min )
- #define round(x) floor((x)+0.5)
-
- typedef int(*function)(const void *,const void *);
-
- int plot3d(void (*transform)(float *,float *,float *,float,float,float)) /* transform points to transform to cartesian */
-
- {
- int i,edgecount,steps,steps2; /* Counters */
- float x,y,z; /* Cartesian coordinates */
- float var1step,var2step,var1,var2; /* Values for independent vars */
- struct sectiontype *section; /* Table of sections */
-
-
- /* Get some memory */
- section=farcalloc(var1stepcount+var2stepcount+3+(var1stepcount+1)*(var2stepcount+1),sizeof(struct sectiontype));
- if (!section){
- printf("Insufficient memory\n\n");
- return 0;
- }
- xrange=xmax-xmin; /* Calculate widths for x, y, and z */
- yrange=ymax-ymin;
- zrange=zmax-zmin;
- costip=cos(tip*PI/180); /* Precalculate trig functions for angles */
- sintip=sin(tip*PI/180);
- sinspin=sin(spin*PI/180);
- cosspin=cos(spin*PI/180);
- calcscale(xmin,ymin,zmin,xmax,ymax,zmax); /* Calculate scaling factors */
- var1step=(var1end-var1start)/(var1stepcount);/* Set stepsizes for the */
- var2step=(var2end-var2start)/(var2stepcount);/* independent variables */
- i=0;
- edgecount=0;
- var1=var1start; /* Initialize var1 */
-
- /* First make a partial table of needed boundary values. These are given */
- /* very large x distances so that they will get sorted to the end of the */
- /* section list. A second counter, 'edgecount' is kept. When the */
- /* sections are plotted, the this value will be subtracted from the */
- /* total counter so these edge sections won't be plotted */
-
- /* Create a table of the edge values along the "top" of the function */
- for(var2=var2start,steps=var2stepcount+1; steps ;steps--, i++,edgecount++,var2+=var2step) {
- (*transform)(&x,&y,&z,ff(var1,var2-var2step,0),var1,var2-var2step);
- realscale(&x,&y,&z);
- (section+i)->x4=round(addx+multx*x); /* Bottom left point */
- (section+i)->y4=round(addy+multy*y);
- (section+i)->x=1e37; /* This section will get sorted to the end */
-
- (*transform)(&x,&y,&z,ff(var1,var2,0),var1,var2);
- realscale(&x,&y,&z);
- (section+i)->x3=round(addx+multx*x); /* Bottom right point */
- (section+i)->y3=round(addy+multy*y);
- }
-
- /* Main loop, cycles through var 1 */
- for (var1=var1start+var1step,steps2=var1stepcount; steps2 ;steps2--, var1+=var1step) {
-
- /* Calculate value for left edge of function */
- var2=var2start;
- (*transform)(&x,&y,&z,ff(var1,var2 ,0),var1,var2);
- realscale(&x,&y,&z);
- (section+i)->x3=round(addx+multx*x); /* Bottom right point */
- (section+i)->y3=round(addy+multy*y);
- (section+i)->x=1e37; /* Will get sorted to the end */
- (*transform)(&x,&y,&z,ff(var1-var1step,var2,0),var1-var1step,var2);
- realscale(&x,&y,&z);
- (section+i)->x2=round(addx+multx*x); /* Top right point */
- (section+i)->y2=round(addy+multy*y);
- edgecount++;
- i++;
-
- /* Main loop. Calculate sections for one cycle of var 2 */
- for(var2=var2start+var2step,steps=var2stepcount; steps ; i++ , steps--, var2+=var2step) {
- (*transform)(&x,&y,&z,ff(var1,var2,0),var1,var2);
- realscale(&x,&y,&z);
- (section+i)->x3=round(addx+multx*x); /* Bottom right point */
- (section+i)->y3=round(addy+multy*y);
- (section+i)->x=z;
-
- /* These points have already been calculated */
- (section+i)->x4=(section+i-1)->x3; /* Bottom left point */
- (section+i)->y4=(section+i-1)->y3;
-
- (section+i)->x2=(section+i-var2stepcount-1)->x3; /* Top right */
- (section+i)->y2=(section+i-var2stepcount-1)->y3;
-
- (section+i)->x1=(section+i-var2stepcount-1)->x4; /* Top left */
- (section+i)->y1=(section+i-var2stepcount-1)->y4;
-
- }
- printf("."); /* The it hasn't crashed indicator */
- }
- printf("\nSorting...");
- qsort(section,i,sizeof(struct sectiontype),(function)sectioncmp);
-
- printf("\done");
- entergraphics();
- i-=edgecount; /* Subtract the edges out */
- drawaxes(BACK); /* Draw back part of axes */
- plotsections(section,i);
- drawaxes(FRONT); /* And plot those sections */
- farfree(section);
- return 1;
- }
-
- void realscale(float *xx,float *yy,float *zz) {
- float x,y,z,dist;
-
- x=(*xx/xrange)-xmin/xrange/2-xmax/xrange/2;
- y=(*yy/yrange)-ymin/yrange/2-ymax/yrange/2;
- z=(*zz/zrange)-zmin/zrange/2-zmax/zrange/2;
- *zz=(x*cosspin-y*sinspin)*costip-z*sintip;
- if (distance==0.0) dist=1;
- else dist=distance+0.5-*zz;
- *xx=(y*cosspin+x*sinspin)*aspect/dist;
- *yy=(z*costip+(x*cosspin-y*sinspin)*sintip)/dist;
- }
-
-
- /* Compare to sections for qsort() */
-
- int sectioncmp(struct sectiontype *a,struct sectiontype *b)
- {
- if (a->x < b->x) return(-1);
- if (a->x == b->x) return(0);
- return(1);
- }
-
-
- void plotsections(struct sectiontype *section,int count) /* Plot count sections */
- {
- int i;
- for(i=0;i<count;i++)
- fill((section+i)->x1,(section+i)->y1,(section+i)->x2,(section+i)->y2,
- (section+i)->x3,(section+i)->y3,(section+i)->x4,(section+i)->y4);
-
- }
-
- void scale(int *xint,int *yint,float x,float y,float z) {
- realscale(&x,&y,&z);
- *xint=round(addx+multx*x);
- *yint=round(addy+multy*y);
- }
-
-
- void line3d(float a,float b,float c,float d,float e,float f) {
- int x1,y1,x2,y2;
-
- scale(&x1,&y1,a,b,c);
- scale(&x2,&y2,d,e,f);
- drawline(x1,y1,x2,y2);
- }
-
- /* Determine scaling constants */
-
-
- void calcscale(float xmin,float ymin,float zmin,float xmax,float ymax,float zmax)
- {
- float xs[2],ys[2],zs[2],yb=-1e37,ym=1e37,xm=1e37,xb=-1e37;
- char i,j,k;
-
- multx=1;
- addx=0;
- multy=1;
- addy=0;
- xs[0]=xmin;
- xs[1]=xmax;
- ys[0]=ymin;
- ys[1]=ymax;
- zs[0]=zmin;
- zs[1]=zmax;
- for(i=0;i<2;i++)
- for(j=0;j<2;j++)
- for(k=0;k<2;k++){
- xmin=xs[i];
- ymin=ys[j];
- zmin=zs[k];
- realscale(&xmin,&ymin,&zmin);
- if (xmin>xb) xb=xmin;
- else if (xmin<xm) xm=xmin;
- if (ymin>yb) yb=ymin;
- else if (ymin<ym) ym=ymin;
- }
- multx=((float)maxx)/(xb-xm);
- multy=((float)maxy)/(yb-ym);
- if (multx>multy) multx=multy; else multy=multx;
- multy=-multy;
- addx=-xm*multx+((float)maxx-multx*(xb-xm))/2;
- addy=(float)maxy-ym*multy-((float)maxy+multy*(yb-ym))/2;
- }
-
-
- static int faces[6][3]={{0,0,-1},{-1,0,0},{0,1,0},{1,0,0},{0,-1,0},{0,0,1}};
- static int edges[12][8]={
- {0,1,-1,-1,-1,-1,1,-1},
- {0,2,-1,1,-1,1,1,-1},
- {0,3,1,-1,-1,1,1,-1},
- {0,4,-1,-1,-1,1,-1,-1},
- {4,1,-1,-1,-1,-1,-1,1},
- {1,2,-1,1,-1,-1,1,1},
- {2,3,1,1,-1,1,1,1},
- {3,4,1,-1,-1,1,-1,1},
- {5,1,-1,-1,1,-1, 1,1},
- {5,2,-1, 1,1, 1, 1,1},
- {5,3, 1,-1,1, 1, 1,1},
- {5,4,-1,-1,1, 1,-1,1}};
-
-
- void drawaxes(char flag) /* Draw the axes */
- {
- int i;
- for(i=0;i<12;i++)
- if ((visible(edges[i][0]) && visible(edges[i][1]))==flag)
- line3d(FIX(edges[i][2],xmin,xmax), FIX(edges[i][3],ymin,ymax),
- FIX(edges[i][4],zmin,zmax), FIX(edges[i][5],xmin,xmax),
- FIX(edges[i][6],ymin,ymax), FIX(edges[i][7],zmin,zmax));
- }
-
-
- int visible(int i) /* determine if a face of the coordinate cube is visible */
- {
- return(faces[i][2] * sintip-(faces[i][0]*cosspin-faces[i][1]*sinspin)*costip<0);
- }
-
-
-