home *** CD-ROM | disk | FTP | other *** search
- /*
- * The following code is designed to be used in conjunction with the UNIX *
- * plot facilities, but may be used on its own to produce output to any *
- * sixels printing system. *
- * *
- * If any modification are made to this code, while I am still employed by *
- * the Columbia University Center for Computing Activities, please notify *
- * me, nwc@cunixc.columbia.edu. *
- * */
-
- #include "lno.h"
- #include <stdio.h>
- #include <math.h>
-
- openpl()
- /* nothing really needed here */
- {
- }
-
-
- move(x,y)
- /* set cx,cy memory of last points, scale them, and clear pattern counter. */
- int x,y;
- {
- extern int cx,cy;
-
- newcount();
- ln03scale(&x,&y);
- cx = x;
- cy = y;
- }
-
-
-
- cont(x,y)
- /* scaled coordinates and then pass them to extend */
- {
- ln03scale(&x,&y);
- ln03extend(x,y);
- }
-
-
-
- point(x,y)
- /* scale coordinates and pass them to spot */
- {
- ln03scale(&x,&y);
- ln03spot(x,y);
- }
-
-
-
- line(x1,y1,x2,y2)
- /* mark a starting point and then simply use continue to go to second point */
- int x1,y1,x2,y2;
- {
-
- move(x1,y1);
- ln03scale(&x2,&y2);
- ln03extend(x2,y2);
- }
-
-
-
- label(m)
- /* place ascii text or math font in graph page. This is done by direct *
- * decipoint location addressing. The escape codes and text if placed in *
- * the output file before the sixels output. */
- char *m;
- {
- extern int cy,cx; /* coordinates to place label */
- double xx,yy,tempx,tempy;
-
- tempx = cx;
- tempy = cy;
-
- /*next two lines convert unscaled pixel coordinates to scaled decipoints, *
- *the unit the LN03 positions text by. */
-
- xx =(Xdec * (tempx/Xaxis)) + 0.07 * tempx;
- yy =Ydec - (Ydec * (tempy/Yaxis) - 0.8 * tempy);
-
- /* If a label starts in a "~" then tell the LN03 to use its math font. *
- * A non math font label can begin with a tilda, just prefix it by a space. */
-
- if(*m == '~'){
- printf("\033*>\033n\033[2 I\033[11h");
- printf("\033[%d`\033[%dd%s",ln03round(xx),ln03round(yy),++m);
- }
- else printf("\017\033[2 I\033[11h\033[%d`\033[%dd%s",ln03round(xx),ln03round(yy),m);
-
- cx += (strlen(m)*15);
- }
-
-
-
- arc(x,y,x1,y1,x2,y2)
- /* This arc generation routine is pretty bad... I do not use it for *
- * generating circles for this reason. Much of it depends on floating point *
- * which, depending on the machine may not be that accurate. */
- int x,y,x1,y1,x2,y2;
- {
- double sqrt(),temp;
- register int dx,dy,radsqr;
- register int plotx,ploty,quad,rad,reps = 0;
-
- ln03scale(&x,&y);
- ln03scale(&x1,&y1);
- ln03scale(&x2,&y2);
- dx = abs(x1-x);
- dy = abs(y1-y);
- radsqr = dx*dx + dy*dy;
- temp = radsqr;
- rad = sqrt(temp);
- plotx = x1-x; /* x coord of first point in arc */
- ploty = y1-y; /* y " " " " " " */
- if(x1 > x+rad/2) quad = 1; /* what quadrant are we in ? */
- else if(x1 > x) quad = 2;
- else quad = 3;
- if(y1 < y && quad == 2 ) quad = 4; /* under horizon of y is 4 not 2 */
- ln03filterP(x1,y1);
- while(ln03aprox(plotx+x,x2,ploty+y,y2) != 1){ /* until final coord hit, go */
- if(quad == 2){ /* quadrants not standard, my are by the compass. */
- plotx--; /* we are in North quadrant so inc x and calculate y */
- temp = radsqr - plotx*plotx;
- ploty = ln03round(sqrt(temp));
- ln03extend(plotx+x,ploty+y);
- if(plotx+x < x-rad/2){
- quad = 3;
- reps++;
- }
- }
- else if(quad == 3){ /* in west quad, inc y and calc x */
- ploty--;
- temp = radsqr - ploty*ploty;
- plotx =0-ln03round(sqrt(temp));
- ln03extend(plotx+x,ploty+y);
- if(plotx+x >= x-rad/2){
- quad = 4;
- reps++;
- }
- }
- else if(quad == 4){ /* we are in south quad, mirror north*/
- plotx++;
- temp = radsqr - plotx*plotx;
- ploty =0-ln03round(sqrt(temp));
- ln03extend(plotx+x,ploty+y);
- if(plotx+x > x+rad/2){
- quad = 1;
- reps++;
- }
- }
- else{ /* east quad, mirror west */
- ploty++;
- temp = radsqr - ploty*ploty;
- plotx = ln03round(sqrt(temp));
- ln03extend(plotx+x,ploty+y);
- if(plotx+x <= x+rad/2){
- quad = 2;
- reps++;
- }
- }
- if(reps > 4) /* We have been around the circle more than once...oops! */
- {
- fprintf(stderr,"Second point is not in arc of center and first point.\n");
- fprintf(stderr,"Bad arc is %d, %d, %d, %d, %d, %d.\n",x,y,x1,y1,x2,y2);
- fprintf(stderr," Converting sparse matrix built to date and exiting.\n");
- ln03conv();
- exit(1);
- }
- }
- }
-
-
-
- circle(x,y,r)
- /* this generates 45 degrees of a circle, passing each point to circpoint *
- * which distributes the point to all eight 45 degree segments. */
- int x,y,r;
- {
- register int xx,yy,d;
- extern int cx,cy;
- extern float xscale,yscale;
- int dummy = 1;
-
- newcount();
-
- ln03scale(&x,&y);
- r = ln03round(r * xscale);
- xx = 0;
- yy = r;
- d = 3-2*r;
- while( xx < yy){
- ln03circpoint(xx,yy,x,y);
- if(d < 0) d = d+4*xx+6;
- else{
- d = d+4*(xx-yy) + 10;
- yy--;
- }
- xx++;
- }
- if(xx == yy) ln03circpoint(xx,yy,x,y);
- cx = xx+x;
- cy = yy+y;
- }
-
-
-
- erase()
- /* Just convert what we have, and start fresh. */
- {
- ln03conv();
- }
-
-
-
- linemod(s)
- /* set varible "mode" to reflect pattern chosen. */
- char *s;
- {
- extern int mode;
-
- switch(s[0]){
- case 'l':
- mode = 4;
- break;
- case 'd':
- if(s[3] == 'd') mode = 5;
- else mode = 2;
- break;
- case 's':
- if(s[5] != '\0') mode = 1;
- else mode = 3;
- }
- }
-
-
- space(x1,y1,x2,y2)
- /* set a scaling factor at users request. scale is defaulted to 1 */
- int x1,y1,x2,y2;
- {
- extern float xscale,yscale;
- float temp;
- extern int xoffset,yoffset;
-
- if (x1 < 0) xoffset = -x1;
- if (y1 < 0) yoffset = -y1;
-
- temp = (float)Xaxis/(x2-x1);
- xscale = floor(temp * 100.0)/100.0;
- temp = (float)Xaxis/(y2-y1);
- yscale = floor(temp * 100.0) / 100.0;
- }
-
-
- closepl()
- {
- ln03conv();
- }
-
- /*---------------------------------------------------------------------------*/
- /* BEGIN SUPPORT ROUTINES */
- /*---------------------------------------------------------------------------*/
-
- ln03extend(x1,y1)
- /* Don't ask, I got this from a book, it forms a line by increment to a *
- * point in the area nearest the line. negative slopes are achived by *
- * mirroring a positive slope. */
- register int x1,y1;
- {
- extern int cx,cy;
- register int dx,dy,yincr1,mid,yincr2,yd,xincr1,xincr2,xd,x,y,xend,yend;
- register int xx,yy;
- register int neg=0;
-
-
- dx = abs(x1-cx);
- dy = abs(y1-cy);
- yd = 2*dy-dx;
- yincr1 = 2*dy;
- yincr2 = 2*(dy-dx);
- xd = 2*dx-dy;
- xincr1 = 2*dx;
- xincr2 = 2*(dx-dy);
- if (cx > x1){ /* set up initial variables */
- x = x1;
- y = y1;
- xend = cx;
- yend = cy;
- if(cy < y1 && cx != x1){ /* BELLS AND WISTLES negative slope */
- neg = 1;
- mid = y1;
- yend = cy+(2*dy); /*set y to its + slope equivalent */
- }
- }
- else
- {
- x = cx;
- y = cy;
- xend = x1;
- yend = y1;
- if(y1 < cy && cx != x1){ /* BELLS AND WISTLES negative slope */
- neg = 1;
- mid = cy;
- yend = y1+(2*dy);
- }
- }
- ln03filterP(x,y);
- xx = x;
- yy = y;
- if (x == xend) /* we have a totally verticle line. */
- while (y != yend){
- if (y < yend) y++;
- else y--;
- ln03filterP(x,y);
- }
- while (x < xend){
- if (yd < 0) yd += yincr1;
- else{
- if (y < yend) y++;
- else if (y > yend) y--;
- yd += yincr2;
- }
- if (xd < 0) xd += xincr1;
- else{
- x++;
- xd += xincr2;
- }
- if (xx != x || yy != y){
- if(neg) ln03filterP(x,2*mid-y);
- else ln03filterP(x,y);
- xx = x;
- yy = y;
- }
- }
- cx = x1; /* remember last points */
- cy = y1;
- }
-
-
-
- int ln03round(num)
- /* float number rounding */
- double num;
- {
- int inum;
- double rnum;
-
- inum = num;
- rnum = num - inum;
- return((rnum < .5)?inum:inum+1);
- }
-
- int ln03power(z)
- /* this rountine accepts an integer 0-5 and first takes its five compliment *
- * then it returns 2 to the power of the result. exmp 3 = (5-3)^2 = 4 */
- int z;
- {
- register int inc,final = 2;
-
- z = 5-z;
- if(z ==0) final = 1;
- else if(z==1) final = 2;
- else for(inc = 2;z >= inc; inc++) final *= 2;
- return(final);
- }
-
-
-
- int ln03aprox(a,b,c,d)
- /* check to see if a is aprox equal to b and if c is aprox equal to d *
- * this is done because I don't trust arc's floating point to generate *
- * the circumference points exactly. */
- int a,b,c,d;
- {
- if( a <= b+1 && a >= b-1 && c <= d+1 && c >= d-1) return(1);
- else return(-1);
- }
-
-
-
- death()
- /* Something, some where has created an error, or we are out of RAM, *
- * convert the graph as it stands. */
- {
- fprintf(stderr,"We have ran out of memory for sparse matrix nodes.\n");
- fprintf(stderr," We will convert what has been done to date and leave.\n");
- ln03conv();
- exit(1);
- }
-
-
- ln03spot(x,y)
- /* place a point given by coordinates in sparse matrix. */
- int x,y;
- {
- extern struct sixel *vert[MAXVERT]; /* this is the plotting grid */
- struct sixel *temp,*mark,*malloc();
- extern int cy,cx;
- register int Vval; /* verticle coordinate to the nearest sixel */
- register int Svval; /* verticle coordinate, pixel remainder of sixels*/
-
- if(x >= 0 && x <= Xaxis && y >= 0 && y <= Yaxis){
- cy = y; cx = x;
- Vval =(Yaxis-(y-2))/6; /* div 6 to obtain sixels */
- Svval = y%6; /* modulo to obtain pixels remainder */
- if(vert[Vval] == NULL){ /* this row is new, start it */
- if((temp = malloc(sizeof(struct sixel)))==NULL) death();
- temp->pixels = 0|(ln03power(Svval));/* calc sixels' pixel value */
- temp->horiz = x;
- temp->next = NULL;
- vert[Vval] = temp;
- }
- else{ /* row already has member(s) */
- mark = vert[Vval]; /* set a marker to move along list */
- while(mark->next != NULL && mark->horiz < x) mark = mark->next;
-
- /* we are now a) at row's end, b) an equal horiz, *
- * c) a greater horiz. */
-
- if(mark->next == NULL && mark->horiz < x ){
-
- /* time to add a node because horiz is too big and no next node. */
-
- if((temp = malloc(sizeof(struct sixel)))==NULL) death();
- temp->pixels = 0|(ln03power(Svval));
- temp->horiz = x;
- temp->next = NULL; /* Better safe...... */
- mark->next = temp; /* Add new node to vert structure. */
- }
- else if(mark->horiz == x) mark->pixels |= ln03power(Svval);
-
- /* just modify this node */
-
- else if(mark->horiz > x){
-
- /* insert new node between two present cause we have passed its spot */
-
- if((temp = malloc(sizeof(struct sixel)))==NULL) death();
- temp->pixels = mark->pixels;
- temp->horiz = mark->horiz;
- temp->next = mark->next;
- mark->pixels = 0|(ln03power(Svval));
- mark->horiz = x;
- mark->next = temp;
- }
- }
- }
- }
-
-
- ln03conv()
- /* This routine coverts a sparce matrix to LN03 format of sixels. The *
- * size of the output is minimized by using the LN03's repeat format: *
- * !10? performs ? (a space) 10 times. */
- {
- register int count,rep;
- register int Hplace; /* horizontal displacement */
- register int lastc = 0; /* sixel pixel pattern holder */
- int x;
- struct sixel *temp;
- extern struct sixel *vert[MAXVERT]; /* sparse matrix of sixels */
-
- /* ESC codes to get ln03 sixels mode */
- printf("\033[2 I\033[1`\033[1d\033P000;0000;000q\"1;1");
- for(count = 0; count < MAXVERT; count++)
- if(vert[count] == NULL) printf("?-"); /* LF for a blank row */
- else{
- temp = vert[count];
- if(temp->horiz>0) printf("!%d?",temp->horiz-1);/*tab to 1st char */
- printf("%c",temp->pixels+63);
- Hplace = temp->horiz;
- lastc = temp->pixels;
- rep = 0;
- while(temp->next != NULL){
- temp = temp->next; /* move one node horizontally */
- if(temp->horiz == Hplace+1 && temp->pixels == lastc){
- rep++;
- Hplace++;
- }
- else{
- if(rep > 0) printf("!%d%c",rep,lastc+63);
- if(temp->horiz != Hplace+1 && temp->horiz <= Xaxis)
- printf("!%d?",temp->horiz - Hplace - 1);
- printf("%c",temp->pixels+63);
- Hplace = temp->horiz;
- lastc = temp->pixels;
- rep = 0;
- }
- }
- if(rep > 0) printf("!%d%c-",rep,lastc+63);
- else printf("-");
- }
- printf("\033\\"); /* Tell ln03 we are done with sixels */
-
- for(x = 0; x < MAXVERT; x++)
- vert[x] = (struct sixel *)NULL;
-
- }
-
-
- box(x0,y0,x1,y1)
- /* box drawing routine */
- int x0,y0,x1,y1;
- {
- int xhold,yhold;
-
- xhold = x0;
- yhold = y0;
-
- ln03scale(&x0,&y0);
- ln03scale(&x1,&y1);
-
- move(xhold,yhold);
- ln03extend(x1,y0);
- ln03extend(x1,y1);
-
- move(xhold,yhold);
- ln03extend(x0,y1);
- ln03extend(x1,y1);
- }
-
-
-
- ln03circpoint(xx,yy,x,y)
- /* circle() only calculates 45 degrees of a circle, this distributes the *
- * coordinates given into an entire circle. The decrementing of count is so *
- * that the position in a pattern, i.e. point or space in "dot dash" is *
- * not lost. */
-
- int xx,yy,x,y;
- {
- extern int cx,cy,count;
-
- ln03filterP(xx+x,yy+y);
- count--;
- ln03filterP(yy+x,xx+y);
- count--;
- ln03filterP(yy+x,-xx+y);
- count--;
- ln03filterP(xx+x,-yy+y);
- count--;
- ln03filterP(-xx+x,-yy+y);
- count--;
- ln03filterP(-yy+x,-xx+y);
- count--;
- ln03filterP(-yy+x,xx+y);
- count--;
- ln03filterP(-xx+x,yy+y);
- }
-
-
- ln03filterP(x,y)
- /* filter() acts as a middle man between a caller and spot(), i.e. if our *
- * position in the line pattern (example: dotted line) is a blank space *
- * then spot should not be called. */
- int x,y;
- {
- extern int mode,count;
-
- switch(mode){
- case 1: ln03spot(x,y); /* solid line */
- break;
- case 2: if(count <= 3 ) ln03spot(x,y); /* dotted line */
- if(count == 6) count = 0;
- break;
- case 3: if(count <= 6 ) ln03spot(x,y); /* short dash */
- if(count == 9) count =0;
- break;
- case 4: if(count <= 9 ) ln03spot(x,y); /* long dash */
- if(count == 12) count =0;
- break;
- /* dot dash */
- case 5: if((count <= 6)||((count ==11)||(count==12))) ln03spot(x,y);
- if(count == 17) count = 0;
- break;
- }
- count++; /* increment pattern position. */
- }
-
- ln03scale(x,y)
- int *x,*y;
- {
- extern float xscale,yscale;
- extern int xoffset,yoffset;
- int tempx,tempy;
-
-
- tempx = *x;
- tempy = *y;
-
- tempx += xoffset;
- tempy += yoffset;
-
- tempx = ln03round(tempx*xscale);
- tempy = ln03round(tempy*yscale);
-
- *x = tempx;
- *y = tempy;
- }
-
-
-
-
-
-
-
-