221 lines
4.0 KiB
C
221 lines
4.0 KiB
C
/*
|
|
* see COPYRIGHT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "bzscreen.h"
|
|
|
|
/*
|
|
* functions to draw the bezier curves in text mode
|
|
*/
|
|
|
|
double
|
|
fmin(a,b)
|
|
double a, b;
|
|
{
|
|
if(a<b)
|
|
return a;
|
|
else
|
|
return b;
|
|
}
|
|
|
|
int
|
|
abs(x)
|
|
int x;
|
|
{
|
|
if(x<0)
|
|
return -x;
|
|
else
|
|
return x;
|
|
}
|
|
|
|
void
|
|
initscreen(physx, physy, cols, rows, xoff, yoff, minx, miny, maxx, maxy)
|
|
unsigned physx, physy, cols, rows, xoff, yoff, minx, miny, maxx, maxy;
|
|
{
|
|
int i,j;
|
|
double yxscale;
|
|
|
|
if(screen.dots != NULL)
|
|
free(screen.dots);
|
|
|
|
if(physx==0 || physy==0 || rows==0 || cols==0) {
|
|
fprintf(stderr, "*** negative or zero screen size\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(physx+xoff > cols || physy+yoff > rows) {
|
|
fprintf(stderr, "*** drawable area out of screen\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(minx>maxx || miny>maxy) {
|
|
fprintf(stderr, "*** empty drawable area\n");
|
|
exit(1);
|
|
}
|
|
|
|
screen.physx = physx;
|
|
screen.physy = physy;
|
|
screen.rows = rows;
|
|
screen.cols = cols+2; /* for '\n\0' */
|
|
screen.xoff = xoff;
|
|
screen.yoff = yoff;
|
|
screen.minx = minx;
|
|
screen.miny = miny;
|
|
|
|
if(( screen.dots=malloc(screen.rows*screen.cols) )==NULL) {
|
|
perror("*** no memory for screen: ");
|
|
exit(1);
|
|
}
|
|
|
|
j=screen.rows*screen.cols;
|
|
for(i=0; i<j; i++)
|
|
screen.dots[i]=' ';
|
|
|
|
/* scale of Y to X on the screen, i.e. x=YXSCALE*y */
|
|
/* 3/4 is the approx. ratio of Y/X sizes of the physical screen */
|
|
yxscale = ((double)physx/(double)physy*3.0/4.0);
|
|
|
|
/* scale of "logical" to "physical", i.e. physical=PHYSSCALE*logical */
|
|
screen.yscale = fmin( ((double)physy-0.51)/(maxy+1-miny),
|
|
((double)physx-0.51)/yxscale/(maxx+1-minx) );
|
|
screen.xscale = yxscale * screen.yscale;
|
|
}
|
|
|
|
void
|
|
drawcurve(mark, ax,ay, bx,by, cx,cy, dx,dy)
|
|
int mark, ax,ay, bx,by, cx,cy, dx,dy;
|
|
{
|
|
int i,j,n,c;
|
|
int maxn=(screen.physx + screen.physy)*2;
|
|
|
|
ax-=screen.minx; bx-=screen.minx; cx-=screen.minx; dx-=screen.minx;
|
|
ay-=screen.miny; by-=screen.miny; cy-=screen.miny; dy-=screen.miny;
|
|
|
|
for(i=0; i<=maxn; i++) {
|
|
double t, t2, t3, nt, nt2, nt3;
|
|
|
|
t=(double)i/(double)maxn; t2=t*t; t3=t2*t;
|
|
nt=1-t; nt2=nt*nt; nt3=nt2*nt;
|
|
|
|
setfdot(
|
|
mark,
|
|
( ax*t3 + bx*3*t2*nt + cx*3*t*nt2 + dx*nt3 ),
|
|
( ay*t3 + by*3*t2*nt + cy*3*t*nt2 + dy*nt3 )
|
|
);
|
|
}
|
|
}
|
|
|
|
/* draw curve and mark direction at the ends */
|
|
|
|
void
|
|
drawcurvedir(mark, ax,ay, bx,by, cx,cy, dx,dy)
|
|
int mark, ax,ay, bx,by, cx,cy, dx,dy;
|
|
{
|
|
int i,j,n,c;
|
|
int maxn=(screen.physx + screen.physy)*2;
|
|
double t, t2, t3, nt, nt2, nt3;
|
|
int markb, marke;
|
|
|
|
ax-=screen.minx; bx-=screen.minx; cx-=screen.minx; dx-=screen.minx;
|
|
ay-=screen.miny; by-=screen.miny; cy-=screen.miny; dy-=screen.miny;
|
|
|
|
if(bx==ax && by==ay) {
|
|
markb=mark;
|
|
} else if( abs(by-ay) > abs(bx-ax) ) {
|
|
if(by>ay)
|
|
markb='^';
|
|
else
|
|
markb='v';
|
|
} else {
|
|
if(bx>ax)
|
|
markb='>';
|
|
else
|
|
markb='<';
|
|
}
|
|
|
|
if(dx==cx && dy==cy) {
|
|
marke=mark;
|
|
} else if( abs(dy-cy) > abs(dx-cx) ) {
|
|
if(dy>cy)
|
|
marke='^';
|
|
else
|
|
marke='v';
|
|
} else {
|
|
if(dx>cx)
|
|
marke='>';
|
|
else
|
|
marke='<';
|
|
}
|
|
|
|
for(i=1; i<maxn; i++) {
|
|
t=(double)i/(double)maxn; t2=t*t; t3=t2*t;
|
|
nt=1-t; nt2=nt*nt; nt3=nt2*nt;
|
|
|
|
setfdot(
|
|
mark,
|
|
( ax*t3 + bx*3*t2*nt + cx*3*t*nt2 + dx*nt3 ),
|
|
( ay*t3 + by*3*t2*nt + cy*3*t*nt2 + dy*nt3 )
|
|
);
|
|
}
|
|
/* mark the ends */
|
|
setfdot( markb, (double)ax, (double)ay );
|
|
setfdot( marke, (double)dx, (double)dy );
|
|
}
|
|
|
|
void
|
|
drawdot(mark, x, y)
|
|
int mark;
|
|
int x, y;
|
|
{
|
|
x=(int)((x-screen.minx)*screen.xscale+0.5);
|
|
y=(int)((y-screen.miny)*screen.yscale+0.5);
|
|
|
|
if(y<0 || y>=screen.physy || x<0 || x>=screen.physx)
|
|
return;
|
|
screendot(x,y)=mark;
|
|
}
|
|
|
|
void
|
|
setabsdot(mark, x, y)
|
|
int x, y, mark;
|
|
{
|
|
if(y<0 || y>=screen.rows || x<0 || x>=screen.cols-2)
|
|
return;
|
|
screenabsdot(x,y)=mark;
|
|
}
|
|
|
|
void
|
|
setfdot(mark, fx, fy)
|
|
int mark;
|
|
double fx, fy;
|
|
{
|
|
int x, y;
|
|
|
|
x=(int)(fx*screen.xscale+0.5);
|
|
y=(int)(fy*screen.yscale+0.5);
|
|
|
|
if(y<0 || y>=screen.physy || x<0 || x>=screen.physx)
|
|
return;
|
|
screendot(x,y)=mark;
|
|
}
|
|
|
|
/* destructive */
|
|
void
|
|
printscreen(f)
|
|
FILE *f;
|
|
{
|
|
int r;
|
|
char *pi, *pc;
|
|
|
|
for(r=screen.rows-1; r>=0; r--) {
|
|
pc=&screenabsdot(0,r);
|
|
for(pi=&screenabsdot(-2,r+1); pi>=pc && *pi == ' '; pi--)
|
|
{}
|
|
pi[1]='\n';
|
|
pi[2]=0;
|
|
fputs(pc, f);
|
|
}
|
|
}
|