#include "lib.h"
#include "gprint.h"
#define MAXVECT 40
#define MAXPOINTS 200
#define LINELENGTH 1
#define PointsPerInterval 64
#define pi 3.14159265358979324
#define twopi (2.0 * pi)
#define len(a, b) groff_hypot((double)(b.x-a.x), (double)(b.y-a.y))
extern int dotshifter;
extern int style[];
extern double thick[];
extern char *tfont[];
extern int tsize[];
extern int stipple_index[];
extern char *stipple;
extern double troffscale;
extern double linethickness;
extern int linmod;
extern int lastx;
extern int lasty;
extern int lastyline;
extern int ytop;
extern int ybottom;
extern int xleft;
extern int xright;
extern enum E {
OUTLINE, FILL, BOTH
} polyfill;
extern double adj1;
extern double adj2;
extern double adj3;
extern double adj4;
extern int res;
void HGSetFont(int font, int size);
void HGPutText(int justify, POINT pnt, register char *string);
void HGSetBrush(int mode);
void tmove2(int px, int py);
void doarc(POINT cp, POINT sp, int angle);
void tmove(POINT * ptr);
void cr();
void drawwig(POINT * ptr, int type);
void HGtline(int x1, int y1);
void deltax(double x);
void deltay(double y);
void HGArc(register int cx, register int cy, int px, int py, int angle);
void picurve(register int *x, register int *y, int npts);
void HGCurve(int *x, int *y, int numpoints);
void Paramaterize(int x[], int y[], double h[], int n);
void PeriodicSpline(double h[], int z[],
double dz[], double d2z[], double d3z[],
int npoints);
void NaturalEndSpline(double h[], int z[],
double dz[], double d2z[], double d3z[],
int npoints);
void
HGPrintElt(ELT *element,
int )
{
register POINT *p1;
register POINT *p2;
register int length;
register int graylevel;
if (!DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) {
if (TEXT(element->type)) {
HGSetFont(element->brushf, element->size);
switch (element->size) {
case 1:
p1->y += adj1;
break;
case 2:
p1->y += adj2;
break;
case 3:
p1->y += adj3;
break;
case 4:
p1->y += adj4;
break;
default:
break;
}
HGPutText(element->type, *p1, element->textpt);
} else {
if (element->brushf)
HGSetBrush(element->brushf);
switch (element->type) {
case ARC:
p2 = PTNextPoint(p1);
tmove(p2);
doarc(*p1, *p2, element->size);
cr();
break;
case CURVE:
length = 0;
drawwig(p1, CURVE);
cr();
break;
case BSPLINE:
length = 0;
drawwig(p1, BSPLINE);
cr();
break;
case VECTOR:
length = 0;
tmove(p1);
while (!Nullpoint((p1 = PTNextPoint(p1)))) {
HGtline((int) (p1->x * troffscale),
(int) (p1->y * troffscale));
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
cr();
break;
case POLYGON:
{
double firstx = p1->x;
double firsty = p1->y;
length = 0;
if (polyfill == FILL || polyfill == BOTH) {
char command = (polyfill == BOTH && element->brushf) ? 'p' : 'P';
switch (element->size) {
case 1:
graylevel = 1;
break;
case 3:
graylevel = 2;
break;
case 12:
graylevel = 3;
break;
case 14:
graylevel = 4;
break;
case 16:
graylevel = 5;
break;
case 19:
graylevel = 6;
break;
case 21:
graylevel = 7;
break;
case 23:
graylevel = 8;
break;
default:
graylevel = NSTIPPLES;
break;
}
if (graylevel < 0)
break;
if (graylevel > NSTIPPLES)
graylevel = NSTIPPLES;
printf("\\D'Fg %.3f'",
double(1000 - stipple_index[graylevel]) / 1000.0);
cr();
tmove(p1);
printf("\\D'%c", command);
while (!Nullpoint((PTNextPoint(p1)))) {
p1 = PTNextPoint(p1);
deltax((double) p1->x);
deltay((double) p1->y);
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
if ((firstx != p1->x) || (firsty != p1->y)) {
deltax((double) firstx);
deltay((double) firsty);
}
putchar('\'');
cr();
break;
}
if (!(element->brushf))
break;
length = 0;
tmove(p1);
while (!Nullpoint((PTNextPoint(p1)))) {
p1 = PTNextPoint(p1);
HGtline((int) (p1->x * troffscale),
(int) (p1->y * troffscale));
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
if ((firstx != p1->x) || (firsty != p1->y)) {
HGtline((int) (firstx * troffscale),
(int) (firsty * troffscale));
}
cr();
break;
}
}
}
}
}
void
HGPutText(int justify,
POINT pnt,
register char *string)
{
int savelasty = lasty;
printf(".nr g8 \\n(.d\n");
printf(".ds g9 \"");
while (*string) {
if (*string == '\\' &&
*(string + 1) == '\\') {
printf("\\\\\\");
string++;
}
printf("%c", *(string++));
}
printf("\n");
tmove(&pnt);
switch (justify) {
case CENTLEFT:
case CENTCENT:
case CENTRIGHT:
printf("\\v'0.85n'");
break;
case TOPLEFT:
case TOPCENT:
case TOPRIGHT:
printf("\\v'1.7n'");
}
switch (justify) {
case BOTCENT:
case CENTCENT:
case TOPCENT:
printf("\\h'-\\w'\\*(g9'u/2u'");
break;
case BOTRIGHT:
case CENTRIGHT:
case TOPRIGHT:
printf("\\h'-\\w'\\*(g9'u'");
}
printf("\\&\\*(g9\n");
printf(".sp |\\n(g8u\n");
lasty = savelasty;
lastx = xleft;
}
void
doarc(POINT cp,
POINT sp,
int angle)
{
if (angle)
HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
(int) (sp.x * troffscale), (int) (sp.y * troffscale), angle);
else
HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
(int) (sp.x * troffscale), (int) (sp.y * troffscale), 0);
}
void
HGSetFont(int font,
int size)
{
printf(".ft %s\n"
".ps %d\n", tfont[font - 1], tsize[size - 1]);
linethickness = DEFTHICK;
}
void
HGSetBrush(int mode)
{
register int printed = 0;
if (linmod != style[--mode]) {
linmod = style[mode];
printed = 1;
}
if (linethickness != thick[mode]) {
linethickness = thick[mode];
printf("\\h'-%.2fp'\\D't %.2fp'", linethickness, linethickness);
printed = 1;
}
if (printed)
cr();
}
void
deltax(double x)
{
register int ix = (int) (x * troffscale);
printf(" %du", ix - lastx);
lastx = ix;
}
void
deltay(double y)
{
register int iy = (int) (y * troffscale);
printf(" %du", iy - lastyline);
lastyline = iy;
}
void
tmove2(int px,
int py)
{
register int dx;
register int dy;
if ((dy = py - lasty)) {
printf("\\v'%du'", dy);
}
lastyline = lasty = py;
if ((dx = px - lastx)) {
printf("\\h'%du'", dx);
lastx = px;
}
}
void
tmove(POINT * ptr)
{
register int ix = (int) (ptr->x * troffscale);
register int iy = (int) (ptr->y * troffscale);
register int dx;
register int dy;
if ((dy = iy - lasty)) {
printf(".sp %du\n", dy);
}
lastyline = lasty = iy;
if ((dx = ix - lastx)) {
printf("\\h'%du'", dx);
lastx = ix;
}
}
void
cr()
{
printf("\n.sp -1\n");
lastx = xleft;
}
void
line(int px,
int py)
{
printf("\\D'l");
printf(" %du", px - lastx);
printf(" %du'", py - lastyline);
lastx = px;
lastyline = lasty = py;
}
void
drawwig(POINT * ptr,
int type)
{
register int npts;
int x[MAXPOINTS], y[MAXPOINTS];
for (npts = 1; !Nullpoint(ptr); ptr = PTNextPoint(ptr), npts++) {
x[npts] = (int) (ptr->x * troffscale);
y[npts] = (int) (ptr->y * troffscale);
}
if (--npts) {
if (type == CURVE)
HGCurve(&x[0], &y[0], npts);
else
picurve(&x[0], &y[0], npts);
}
}
void
HGArc(register int cx,
register int cy,
int px,
int py,
int angle)
{
double xs, ys, resolution, fullcircle;
int m;
register int mask;
register int extent;
register int nx;
register int ny;
register int length;
register double epsilon;
xs = px - cx;
ys = py - cy;
length = 0;
resolution = (1.0 + groff_hypot(xs, ys) / res) * PointsPerInterval;
(void) frexp(resolution, &m);
for (mask = 1; mask < m; mask = mask << 1);
mask -= 1;
epsilon = 1.0 / resolution;
fullcircle = (2.0 * pi) * resolution;
if (angle == 0)
extent = (int) fullcircle;
else
extent = (int) (angle * fullcircle / 360.0);
HGtline(px, py);
while (--extent >= 0) {
xs += epsilon * ys;
nx = cx + (int) (xs + 0.5);
ys -= epsilon * xs;
ny = cy + (int) (ys + 0.5);
if (!(extent & mask)) {
HGtline(nx, ny);
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
}
}
void
picurve(register int *x,
register int *y,
int npts)
{
register int nseg;
register int xp;
register int yp;
int pxp, pyp;
int i;
int length = 0;
double w;
double t1, t2, t3;
if (x[1] == x[npts] && y[1] == y[npts]) {
x[0] = x[npts - 1];
y[0] = y[npts - 1];
x[npts + 1] = x[2];
y[npts + 1] = y[2];
} else {
x[0] = x[1];
y[0] = y[1];
x[npts + 1] = x[npts];
y[npts + 1] = y[npts];
}
pxp = (x[0] + x[1]) / 2;
pyp = (y[0] + y[1]) / 2;
tmove2(pxp, pyp);
for (; npts--; x++, y++) {
xp = x[0] - x[1];
yp = y[0] - y[1];
nseg = (int) groff_hypot((double) xp, (double) yp);
xp = x[1] - x[2];
yp = y[1] - y[2];
nseg = (int) ((double) (nseg + (int) groff_hypot((double) xp, (double) yp)) /
res * PointsPerInterval);
for (i = 1; i < nseg; i++) {
w = (double) i / (double) nseg;
t1 = w * w;
t3 = t1 + 1.0 - (w + w);
t2 = 2.0 - (t3 + t1);
xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2;
yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2;
HGtline(xp, yp);
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
}
}
void
HGCurve(int *x,
int *y,
int numpoints)
{
double h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
double d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
double t, t2, t3;
register int j;
register int k;
register int nx;
register int ny;
int lx, ly;
int length = 0;
lx = x[1];
ly = y[1];
tmove2(lx, ly);
Paramaterize(x, y, h, numpoints);
if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) {
PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
} else {
NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
}
for (j = 1; j < numpoints; ++j) {
if ((x[j] == x[j + 1]) && (y[j] == y[j + 1]))
continue;
for (k = 0; k <= PointsPerInterval; ++k) {
t = (double) k *h[j] / (double) PointsPerInterval;
t2 = t * t;
t3 = t * t * t;
nx = x[j] + (int) (t * dx[j] + t2 * d2x[j] / 2 + t3 * d3x[j] / 6);
ny = y[j] + (int) (t * dy[j] + t2 * d2y[j] / 2 + t3 * d3y[j] / 6);
HGtline(nx, ny);
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
}
}
}
void
Paramaterize(int x[],
int y[],
double h[],
int n)
{
register int dx;
register int dy;
register int i;
register int j;
double u[MAXPOINTS];
for (i = 1; i <= n; ++i) {
u[i] = 0;
for (j = 1; j < i; j++) {
dx = x[j + 1] - x[j];
dy = y[j + 1] - y[j];
u[i] += groff_hypot((double) dx, (double) dy);
}
}
for (i = 1; i < n; ++i)
h[i] = u[i + 1] - u[i];
}
void
PeriodicSpline(double h[],
int z[],
double dz[],
double d2z[],
double d3z[],
int npoints)
{
double d[MAXPOINTS];
double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
double c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
int i;
for (i = 1; i < npoints; ++i) {
deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
}
h[0] = h[npoints - 1];
deltaz[0] = deltaz[npoints - 1];
for (i = 1; i < npoints - 1; ++i) {
d[i] = deltaz[i + 1] - deltaz[i];
}
d[0] = deltaz[1] - deltaz[0];
a[1] = 2 * (h[0] + h[1]);
b[1] = d[0];
c[1] = h[0];
for (i = 2; i < npoints - 1; ++i) {
a[i] = 2 * (h[i - 1] + h[i]) -
pow((double) h[i - 1], (double) 2.0) / a[i - 1];
b[i] = d[i - 1] - h[i - 1] * b[i - 1] / a[i - 1];
c[i] = -h[i - 1] * c[i - 1] / a[i - 1];
}
r[npoints - 1] = 1;
s[npoints - 1] = 0;
for (i = npoints - 2; i > 0; --i) {
r[i] = -(h[i] * r[i + 1] + c[i]) / a[i];
s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
}
d2z[npoints - 1] = (6 * d[npoints - 2] - h[0] * s[1]
- h[npoints - 1] * s[npoints - 2])
/ (h[0] * r[1] + h[npoints - 1] * r[npoints - 2]
+ 2 * (h[npoints - 2] + h[0]));
for (i = 1; i < npoints - 1; ++i) {
d2z[i] = r[i] * d2z[npoints - 1] + s[i];
}
d2z[npoints] = d2z[1];
for (i = 1; i < npoints; ++i) {
dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
}
}
void
NaturalEndSpline(double h[],
int z[],
double dz[],
double d2z[],
double d3z[],
int npoints)
{
double d[MAXPOINTS];
double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
int i;
for (i = 1; i < npoints; ++i) {
deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
}
deltaz[0] = deltaz[npoints - 1];
for (i = 1; i < npoints - 1; ++i) {
d[i] = deltaz[i + 1] - deltaz[i];
}
d[0] = deltaz[1] - deltaz[0];
a[0] = 2 * (h[2] + h[1]);
b[0] = d[1];
for (i = 1; i < npoints - 2; ++i) {
a[i] = 2 * (h[i + 1] + h[i + 2]) -
pow((double) h[i + 1], (double) 2.0) / a[i - 1];
b[i] = d[i + 1] - h[i + 1] * b[i - 1] / a[i - 1];
}
d2z[npoints] = d2z[1] = 0;
for (i = npoints - 1; i > 1; --i) {
d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
}
for (i = 1; i < npoints; ++i) {
dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
}
}
void
change(register int x,
register int y,
register int vis)
{
static int length = 0;
if (vis) {
line(x, y);
if (length++ > LINELENGTH) {
length = 0;
printf("\\\n");
}
} else {
tmove2(x, y);
}
}
void
HGtline(int x_1,
int y_1)
{
register int x_0 = lastx;
register int y_0 = lasty;
register int dx;
register int dy;
register int oldcoord;
register int res1;
register int visible;
register int res2;
register int xinc;
register int yinc;
register int dotcounter;
if (linmod == SOLID) {
line(x_1, y_1);
return;
}
dotcounter = linmod << dotshifter;
xinc = 1;
yinc = 1;
if ((dx = x_1 - x_0) < 0) {
xinc = -xinc;
dx = -dx;
}
if ((dy = y_1 - y_0) < 0) {
yinc = -yinc;
dy = -dy;
}
res1 = 0;
res2 = 0;
visible = 0;
if (dx >= dy) {
oldcoord = y_0;
while (x_0 != x_1) {
if ((x_0 & dotcounter) && !visible) {
change(x_0, y_0, 0);
visible = 1;
} else if (visible && !(x_0 & dotcounter)) {
change(x_0 - xinc, oldcoord, 1);
visible = 0;
}
if (res1 > res2) {
oldcoord = y_0;
res2 += dx - res1;
res1 = 0;
y_0 += yinc;
}
res1 += dy;
x_0 += xinc;
}
} else {
oldcoord = x_0;
while (y_0 != y_1) {
if ((y_0 & dotcounter) && !visible) {
change(x_0, y_0, 0);
visible = 1;
} else if (visible && !(y_0 & dotcounter)) {
change(oldcoord, y_0 - yinc, 1);
visible = 0;
}
if (res1 > res2) {
oldcoord = x_0;
res2 += dy - res1;
res1 = 0;
x_0 += xinc;
}
res1 += dx;
y_0 += yinc;
}
}
if (visible)
change(x_1, y_1, 1);
else
change(x_1, y_1, 0);
}