home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
amiga
/
print
/
post16.lzh
/
postgraph.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-17
|
54KB
|
1,706 lines
/* PostScript interpreter file "postgraph.c" - graphics routines */
/* (C) Adrian Aylward 1989, 1991 */
# include "post.h"
/* Routines */
extern void checkclipsize(int size, int end);
extern void setlinesize(int len);
extern void flattencurve(struct point *ppoint, int depth);
extern void strokeparm(struct point *ppoint, float *len);
extern void strokeline(struct point *ppoint, int bjoin, int ejoin,int first);
extern void strokecap(int type, int cap);
extern void clipline(struct clip *pclip);
extern void clipswap(struct clip *pclip);
extern void swappath(int beg, int end);
/* Initialise the graphics state */
void initgstate(void)
{ struct object token, *aptr;
vmref aref;
if (page.xsize > 30000 || page.ysize > 30000 || page.yheight > 30000)
error(errlimitcheck);
gstate.dev = page;
pathsize = linesize = clipsize = 0;
halfbeg = memhbeg;
halfsize = memhlen;
halfok = gstacksize + 1;
screenok = 0;
token.type = 0;
token.flags = 0;
token.length = 0;
token.value.ival = 0;
gstate.font = token;
gstate.clipbeg = 0;
aref = arrayalloc(9);
aptr = vmaptr(aref);
nametoken(&aptr[0], "dup", -1, flagexec);
nametoken(&aptr[1], "mul", -1, flagexec);
nametoken(&aptr[2], "exch", -1, flagexec);
aptr[3] = aptr[0];
aptr[4] = aptr[1];
nametoken(&aptr[5], "add", -1, flagexec);
token.type = typereal;
token.flags = 0;
token.length = 0;
token.value.rval = 1.0;
aptr[6] = token;
aptr[7] = aptr[2];
nametoken(&aptr[8], "sub", -1, flagexec);
token.type = typearray;
token.flags = flagexec;
token.length = 9;
token.value.vref = aref;
bind(&token, 0);
if (gstate.dev.depth == 4)
{ gstate.screendepth = 4;
gstate.screenangle[0] = 105.0;
gstate.screenangle[1] = 75.0;
gstate.screenangle[2] = 95.0;
gstate.screenangle[3] = 45.0;
gstate.screenfreq[0] = gstate.screenfreq[1] =
gstate.screenfreq[2] = gstate.screenfreq[3] = 60.0;
gstate.screenfunc[0] = gstate.screenfunc[1] =
gstate.screenfunc[2] = gstate.screenfunc[3] = token;
}
else
{ gstate.screendepth = 1;
gstate.screenangle[0] = 45.0;
gstate.screenfreq[0] = 60.0;
gstate.screenfunc[0] = token;
}
gstate.transdepth = 1;
token.length = 0;
gstate.transfer[0] = token;
gstate.ucr = token;
gstate.gcr = token;
gstate.flatness = 1.0;
gstate.cacheflag = 0;
gstate.nullflag = 0;
gnest = 0;
gstack = vmallocv(sizeof (struct gstate) * (gstacksize + 1));
setuphalf();
initgraphics();
gsave();
vmstack[0].gnest = 1;
}
/* Initialise the graphics */
void initgraphics(void)
{ struct object token;
initctm(gstate.ctm);
gstate.pathbeg = gstate.pathend = gstate.clipbeg;
cliplength(0);
gstate.clipflag = 0;
gstate.linewidth = 1.0;
gstate.linecap = 0;
gstate.linejoin = 0;
gstate.mitrelimit = 10.0;
gstate.mitresin = 0.198997;
gstate.dashoffset = 0.0;
token.type = typearray;
token.flags = 0;
token.length = 0;
token.value.vref = 0;
gstate.dasharray = token;
gstate.gray = 0.0;
gstate.rgb[0] = gstate.rgb[1] = gstate.rgb[2] = 0.0;
gstate.rgbw[0] = gstate.rgbw[1] =
gstate.rgbw[2] = gstate.rgbw[3] = 0.0;
gstate.shadeok = 0;
}
/* Initialise a matrix to the default ctm */
void initctm(float newctm[])
{ newctm[0] = gstate.dev.xden / 72.0;
newctm[1] = 0.0;
newctm[2] = 0.0;
newctm[3] = gstate.dev.yden / 72.0;
newctm[4] = -gstate.dev.xoff;
newctm[5] = -gstate.dev.yoff;
if (gstate.dev.ydir < 0)
{ newctm[3] = -newctm[3];
newctm[5] = (gstate.dev.yheight + gstate.dev.yoff);
}
}
/* Change device page */
void setdevice(struct device *ppage)
{ struct gstate *pgstate;
int i;
/* Check whether the densities or depth have changed; install the page */
if (ppage->depth != page.depth ||
ppage->xden != page.xden ||
ppage->yden != page.yden ||
ppage->ydir != page.ydir)
{ halfok = gstacksize + 1;
screenok = 0;
}
page = *ppage;
/* Update all the page devices on the gstate stack */
i = gnest;
pgstate = &gstack[0];
for (;;)
{ if (i == 0) pgstate = &gstate;
if (!pgstate->cacheflag && !pgstate->nullflag)
{ if (page.depth != pgstate->dev.depth) pgstate->shadeok = 0;
pgstate->dev = page;
}
if (i == 0) break;
i--;
pgstate++;
}
/* Reinitialise the CTM of the bottommost graphics state */
initctm(gstack[0].ctm);
}
/* Check the image memory size */
void checkimagesize(int len)
{ if (len > memilen)
{ memfree(memibeg, memilen);
memilen = 0;
memibeg = memalloc(len);
if (memibeg == NULL) error(errmemoryallocation);
memilen = len;
}
}
/* Check the line array size */
void checklinesize(int size)
{ int len, segs;
if (size > linesize)
{ len = (sizeof (struct line) +
sizeof (struct line *) +
sizeof (struct lineseg) * 2) * size;
segs = (len + memlmin - 1) / memlmin;
if (segs > memlsegmax) error(errlimitcheck);
setlinesize(memlmin * segs);
}
}
/* Check the clip array size, relocating the clip pointers */
void checkclipsize(int size, int end)
{ struct clip *pclip, **pcptr;
int len, segs, oldsize;
if (size > clipsize)
{ oldsize = clipsize;
len = (sizeof (struct clip) +
sizeof (struct clip *)) * size;
segs = (len + memlmin - 1) / memlmin;
if (segs > memlsegmax) error(errlimitcheck);
pclip = cliparray;
setlinesize(memlmin * segs);
pcptr = (void *) (cliparray + oldsize);
while (end--)
clipptr[end] = cliparray + (pcptr[end] - pclip);
}
}
/* Set the line and clip array memory size */
void setlinesize(int len)
{ void *beg;
beg = memalloc(len);
if (beg == NULL) error(errmemoryallocation);
memcpy((char *) beg, (char *) memlbeg, memllen);
memfree(memlbeg, memllen);
memlbeg = beg;
memllen = len;
linesize = memllen / (sizeof (struct line) +
sizeof (struct line *) +
sizeof (struct lineseg) * 2);
linearray = memlbeg;
lineptr = (void *) (linearray + linesize);
linesegarray = (void *) (lineptr + linesize);
clipsize = memllen / (sizeof (struct clip) +
sizeof (struct clip *));
cliparray = memlbeg;
clipptr = (void *) (cliparray + clipsize);
}
/* Check the path array size */
void checkpathsize(int size)
{ void *beg;
int len, segs;
if (size > pathsize)
{ len = sizeof (struct point) * size;
segs = (len + mempmin - 1) / mempmin;
if (segs > mempsegmax) error(errlimitcheck);
len = mempmin * segs;
beg = memalloc(len);
if (beg == NULL) error(errmemoryallocation);
memcpy((char *) beg, (char *) mempbeg, memplen);
memfree(mempbeg, memplen);
mempbeg = beg;
memplen = len;
pathsize = len / sizeof (struct point);
patharray = mempbeg;
}
}
/* Shuffle the path up or down to change the clip path length */
void cliplength(int cliplen)
{ struct point *ppoint1, *ppoint2;
int pathlen, len;
len = pathlen = gstate.pathend - gstate.pathbeg;
checkpathsize(gstate.clipbeg + cliplen + pathlen);
ppoint1 = &patharray[gstate.clipbeg + cliplen];
ppoint2 = &patharray[gstate.pathbeg];
if (ppoint1 > ppoint2)
{ ppoint1 += pathlen;
ppoint2 += pathlen;
while (len--) *--ppoint1 = *--ppoint2;
}
else if (ppoint1 < ppoint2)
while (len--) *ppoint1++ = *ppoint2++;
gstate.pathbeg = gstate.clipbeg + cliplen;
gstate.pathend = gstate.pathbeg + pathlen;
}
/* Get the clipping path */
void clippath(void)
{ struct point point, *ppoint1, *ppoint2;
int len, l;
if (gstate.clipflag)
len = gstate.pathbeg - gstate.clipbeg;
else
len = 5;
checkpathsize(gstate.pathbeg + len);
ppoint1 = &patharray[gstate.pathbeg];
if (gstate.clipflag)
{ ppoint2 = &patharray[gstate.clipbeg];
l = len;
while (l--) *ppoint1++ = *ppoint2++;
}
else
{ point.type = ptmove;
point.x = 0.0;
point.y = 0.0;
ppoint1[0] = point;
point.type = ptclosex;
ppoint1[4] = point;
point.type = ptline;
point.x = gstate.dev.xsize;
ppoint1[1] = point;
point.y = gstate.dev.yheight;
ppoint1[2] = point;
point.x = 0.0;
ppoint1[3] = point;
}
gstate.pathend = gstate.pathbeg + len;
}
/* Save the graphics state */
void gsave(void)
{ struct point *ppoint1, *ppoint2;
int i;
if (istate.flags & intgraph) error(errundefined);
if (gnest == gstacksize) error(errlimitcheck);
i = gstate.pathend - gstate.clipbeg;
checkpathsize(gstate.pathend + i);
gstack[gnest++] = gstate;
if (i != 0)
{ ppoint1 = &patharray[gstate.clipbeg];
ppoint2 = &patharray[gstate.pathend];
gstate.clipbeg += i;
gstate.pathbeg += i;
gstate.pathend += i;
while (i--) *ppoint2++ = *ppoint1++;
}
}
/* Restore the graphics state */
void grest(void)
{ if (istate.flags & intgraph) error(errundefined);
if (gnest > istate.gbase &&
gnest > vmstack[vmnest].gnest)
{ gstate = gstack[--gnest];
if (gnest <= halfok)
{ halfok = gstacksize + 1;
setuphalf();
}
}
screenok = 0;
}
/* Restore the graphics state to the previous save */
void grestall(void)
{ int nest;
if (istate.flags & intgraph) error(errundefined);
nest = vmstack[vmnest].gnest;
if (nest > istate.gbase)
{ gnest = nest;
gstate = gstack[--gnest];
gsave();
if (gnest <= halfok)
{ halfok = gstacksize + 1;
setuphalf();
}
screenok = 0;
}
}
/* Get a matrix */
void getmatrix(vmref aref, float *matrix)
{ struct object *aptr;
int i;
i = 6;
aptr = vmaptr(aref);
while (i--)
{ if (aptr->type == typeint)
*matrix = aptr->value.ival;
else if (aptr->type == typereal)
*matrix = aptr->value.rval;
else
error(errtypecheck);
aptr++;
matrix++;
}
}
/* Put a matrix */
void putmatrix(vmref aref, float *matrix)
{ struct object token, *aptr;
int i;
token.type = typereal;
token.flags = 0;
token.length = 0;
i = 6;
aptr = vmaptr(aref);
while (i--)
{ token.value.rval = *matrix++;
*aptr++ = token;
}
}
/* Multiply two matrices */
void multiplymatrix(float *mat1, float *mat2, float *mat3)
{ mat1[0] = mat2[0] * mat3[0] + mat2[1] * mat3[2];
mat1[1] = mat2[0] * mat3[1] + mat2[1] * mat3[3];
mat1[2] = mat2[2] * mat3[0] + mat2[3] * mat3[2];
mat1[3] = mat2[2] * mat3[1] + mat2[3] * mat3[3];
mat1[4] = mat2[4] * mat3[0] + mat2[5] * mat3[2] + mat3[4];
mat1[5] = mat2[4] * mat3[1] + mat2[5] * mat3[3] + mat3[5];
}
/* Invert a matrix */
void invertmatrix(float *mat1, float *mat2)
{ float d = mat2[0] * mat2[3] - mat2[1] * mat2[2];
mat1[0] = mat2[3] / d;
mat1[1] = -mat2[1] / d;
mat1[2] = -mat2[2] / d;
mat1[3] = mat2[0] / d;
mat1[4] = (mat2[2] * mat2[5] - mat2[3] * mat2[4]) / d;
mat1[5] = (mat2[1] * mat2[4] - mat2[0] * mat2[5]) / d;
}
/* Transform a point by a matrix */
void transform(struct point *ppoint, float *matrix)
{ float x, y;
x = ppoint->x;
y = ppoint->y;
ppoint->x = x * matrix[0] + y * matrix[2] + matrix[4];
ppoint->y = x * matrix[1] + y * matrix[3] + matrix[5];
}
/* Delta transform a point by a matrix */
void dtransform(struct point *ppoint, float *matrix)
{ float x, y;
x = ppoint->x;
y = ppoint->y;
ppoint->x = x * matrix[0] + y * matrix[2];
ppoint->y = x * matrix[1] + y * matrix[3];
}
/* Inverse transform a point by a matrix */
void itransform(struct point *ppoint, float *matrix)
{ float x, y, d;
x = ppoint->x;
y = ppoint->y;
d = matrix[0] * matrix[3] - matrix[1] * matrix[2];
ppoint->x = (x * matrix[3] - y * matrix[2] +
matrix[5] * matrix[2] - matrix[4] * matrix[3]) / d;
ppoint->y = (y * matrix[0] - x * matrix[1] +
matrix[4] * matrix[1] - matrix[5] * matrix[0]) / d;
}
/* Inverse delta transform a point by a matrix */
void idtransform(struct point *ppoint, float *matrix)
{ float x, y, d;
x = ppoint->x;
y = ppoint->y;
d = matrix[0] * matrix[3] - matrix[1] * matrix[2];
ppoint->x = (x * matrix[3] - y * matrix[2]) / d;
ppoint->y = (y * matrix[0] - x * matrix[1]) / d;
}
/* Generate a circular arc */
void arc(int dir, float radaa[3],
struct point *centre, struct point *beg, struct point *end)
{ struct point point[3], *ppoint;
float ang1, ang2, angd, angm, radius, radm, rh, cos1, cos2, sin1, sin2;
int num;
/* Find out which direction, and the angle of the arc */
radius = radaa[0];
ang1 = fmod(radaa[1], twopi);
ang2 = fmod(radaa[2], twopi);
if (dir == 0)
{ if (fabs(ang2 - ang1) > pi)
if (ang2 > ang1)
ang1 += twopi;
else
ang2 += twopi;
}
else if (dir > 0)
{ if (ang2 < ang1 + pdelta) ang2 += twopi;
}
else
if (ang2 > ang1 + pdelta) ang1 += twopi;
angd = ang2 - ang1;
/* Determine (a rough upper bound of) the radius, in pixels */
radm = gstate.ctm[0];
if (gstate.ctm[1] > radm) radm = gstate.ctm[1];
if (gstate.ctm[2] > radm) radm = gstate.ctm[2];
if (gstate.ctm[3] > radm) radm = gstate.ctm[3];
radm *= radaa[0];
/* Determine the number of Bezier curves needed to approximate the arc */
if (radm <= 27.0)
angm = pi + .0001;
else if (radm <= 1834.0)
angm = pi / 2.0 + .0001;
else if (radm <= 20953.0)
angm = pi / 3.0 + .0001;
else if (radm <= 117778.0)
angm = pi / 4.0 + .0001;
else
angm = pi / 8.0 + .0001;
num = (int) ceil(fabs(angd) / angm);
angd = angd / num;
/* Generate a move or line from the current point */
cos2 = cos(ang1);
sin2 = sin(ang1);
point[2].type = ptmove;
point[2].x = centre->x + radius * cos2;
point[2].y = centre->y + radius * sin2;
if (dir == 0) *beg = point[2];
transform(&point[2], gstate.ctm);
pathend = gstate.pathend;
ppoint = &patharray[pathend];
if (gstate.pathbeg == pathend ||
fabs(point[2].x - (ppoint - 1)->x) >= 0.2 ||
fabs(point[2].y - (ppoint - 1)->y) >= 0.2)
{ if (gstate.pathbeg != pathend) point[2].type = ptline;
checkpathsize(pathend + 1);
patharray[pathend++] = point[2];
}
point[0].type = ptcurve;
point[1].type = ptcurve;
point[2].type = ptcurve;
/* Loop to generate the curves */
while (num--)
{ ang2 = ang1 + angd;
cos1 = cos2;
sin1 = sin2;
cos2 = cos(ang2);
sin2 = sin(ang2);
/* We place the intermediate control points on the tangents at the
* endpoints (so the gradient is correct) and at a height 4/3 the
* height of the midpoint of the arc (so the midpoint of the curve
* is the same as the midpoint of the arc) */
rh = radius * f43 * tan(angd / 4.0);
point[0].x = -rh * sin1;
point[0].y = rh * cos1;
point[1].x = rh * sin2;
point[1].y = -rh * cos2;
dtransform(&point[0], gstate.ctm);
dtransform(&point[1], gstate.ctm);
point[0].x += point[2].x;
point[0].y += point[2].y;
point[2].x = centre->x + radius * cos2;
point[2].y = centre->y + radius * sin2;
if (dir == 0) *end = point[2];
transform(&point[2], gstate.ctm);
point[1].x += point[2].x;
point[1].y += point[2].y;
checkpathsize(pathend + 3);
ppoint = &patharray[pathend];
ppoint[0] = point[0];
ppoint[1] = point[1];
ppoint[2] = point[2];
pathend += 3;
ang1 = ang2;
}
gstate.pathend = pathend;
}
/* Close the current path */
void closepath(int type)
{ struct point point, *ppoint;
if (gstate.pathbeg == gstate.pathend) return;
ppoint = &patharray[gstate.pathend - 1];
/* If it is closed already, make the close explicit if necessary */
if (ppoint->type == ptclosex)
return;
if (ppoint->type == ptclosei)
{ ppoint->type = type;
return;
}
if (ppoint->type == ptmove)
return;
/* Scan back to the beginning of the sub path to find the coordinates to
* close it to */
for (;;)
{ point = *ppoint;
if (point.type == ptclosex ||
point.type == ptclosei ||
point.type == ptmove)
break;
ppoint--;
}
/* Append a close */
point.type = type;
checkpathsize(gstate.pathend + 1);
patharray[gstate.pathend++] = point;
return;
}
/* Flatten the current path */
void flattenpath(void)
{ struct point point[4], *ppoint1, *ppoint2;
int len, num;
len = gstate.pathend - gstate.pathbeg;
/* Skip all elements before the first curve */
ppoint1 = &patharray[gstate.pathbeg];
for (;;)
{ if (len == 0) return;
if (ppoint1->type == ptcurve) break;
ppoint1++;
len--;
}
num = len;
pathbeg = pathend = gstate.pathend;
/* Flatten curves, copying all points into workspace at the end of the
* path array */
for (;;)
{ if (len == 0) break;
ppoint1 = &patharray[pathbeg - len];
point[1] = ppoint1[0];
if (point[1].type == ptcurve)
{ point[0] = ppoint1[-1];
point[2] = ppoint1[1];
point[3] = ppoint1[2];
flattencurve(point, 0);
len -= 3;
}
else
{ checkpathsize(pathend + 1);
patharray[pathend++] = point[1];
len--;
}
}
/* Copy the workspace back to the path */
ppoint1 = &patharray[gstate.pathend - num];
ppoint2 = &patharray[pathbeg];
len = pathend - pathbeg;
gstate.pathend += len - num;
while (len--) *ppoint1++ = *ppoint2++;
}
/* Flatten a curve */
void flattencurve(struct point *ppoint, int depth)
{ struct point point, curves[7];
float f, g, h, a, b, c;
/* Find the flatness of the curve. As it lies within the convex hull
* of its control points we just find the maximum distance of the
* intermediate control points from the straight line joining the ends */
a = ppoint[3].y - ppoint[0].y;
b = ppoint[0].x - ppoint[3].x;
c = ppoint[3].x * ppoint[0].y - ppoint[0].x * ppoint[3].y;
f = a * ppoint[1].x + b * ppoint[1].y + c;
f = f * f;
g = a * ppoint[2].x + b * ppoint[2].y + c;
g = g * g;
h = gstate.flatness * gstate.flatness * (a * a + b * b);
/* If the curve is not flat enough bisect it and flatten the halves */
if (f > h || g > h)
{ point.type = ptcurve;
curves[0] = ppoint[0];
point.x = ppoint[0].x * f12 + ppoint[1].x * f12;
point.y = ppoint[0].y * f12 + ppoint[1].y * f12;
curves[1] = point;
point.x = ppoint[0].x * f14 + ppoint[1].x * f12 + ppoint[2].x * f14;
point.y = ppoint[0].y * f14 + ppoint[1].y * f12 + ppoint[2].y * f14;
curves[2] = point;
point.x = ppoint[0].x * f18 + ppoint[1].x * f38 + ppoint[2].x * f38
+ ppoint[3].x * f18;
point.y = ppoint[0].y * f18 + ppoint[1].y * f38 + ppoint[2].y * f38
+ ppoint[3].y * f18;
curves[3] = point;
point.x = ppoint[1].x * f14 + ppoint[2].x * f12 + ppoint[3].x * f14;
point.y = ppoint[1].y * f14 + ppoint[2].y * f12 + ppoint[3].y * f14;
curves[4] = point;
point.x = ppoint[2].x * f12 + ppoint[3].x * f12;
point.y = ppoint[2].y * f12 + ppoint[3].y * f12;
curves[5] = point;
curves[6] = ppoint[3];
if (depth == maxdepth) error(errlimitcheck);
flattencurve(&curves[0], depth + 1);
flattencurve(&curves[3], depth + 1);
}
/* Otherwise make it a straight line */
else
{ point = ppoint[3];
point.type = ptline;
checkpathsize(pathend + 1);
patharray[pathend++] = point;
}
}
/* Create a stroke path; return it or fill it */
void strokepath(int fillflag)
{ struct point *ppoint1, *ppoint2;
float length;
int pti, len, ln2, bjoin, ejoin, sjoin, first, next, lev;
lev = flushlevel(-1);
/* Loop through the path ... */
pathbeg = pathend = gstate.pathend;
len = gstate.pathend - gstate.pathbeg;
pti = gstate.pathbeg;
sjoin = bjoin = -1;
first = 1;
while (len--)
{ ppoint1 = &patharray[pti];
/* If it is a line or an explicit close we stroke it ... */
if (ppoint1->type == ptline || ppoint1->type == ptclosex)
{
/* If it is a line we scan the subpath to see if its end is
* joined to a line or explicit close following; if it is the
* first line we scan to the end of the subpath to see if there
* is an explicit close that is joined to its beginning, setting
* up its parameters, and saving the joint for use we get to the
* close. */
if (ppoint1->type == ptline)
{ ln2 = len;
ppoint2 = ppoint1;
ejoin = -1;
while (ln2--)
{ ppoint2++;
if (ppoint2->type == ptline || ppoint2->type == ptclosex)
{ if (ppoint2 == (ppoint1 + 1))
ejoin = gstate.linejoin;
}
else
break;
if (first)
{ if (ppoint2->type == ptclosex)
{ strokeparm(ppoint2, &length);
sjoin = bjoin = gstate.linejoin;
break;
}
}
else
break;
}
next = 0;
}
/* If it is a close we use the end join we saved. */
else
{ ejoin = sjoin;
sjoin = -1;
next = 1;
}
/* Stroke the line or close. The end joint begins the next
* line */
strokeline(ppoint1, bjoin, ejoin, first);
bjoin = ejoin;
first = next;
/* If we are filling, do it now and discard the path */
if (fillflag)
{ fill(pathbeg, pathend, -1);
pathend = pathbeg;
}
}
/* Moves and implicit closes are not stroked */
else
{ sjoin = bjoin = -1;
first = 1;
}
pti++;
}
/* If we are not filling, copy the stroke path to the current path */
if (!fillflag)
{ len = pathend - pathbeg;
gstate.pathend = gstate.pathbeg + len;
ppoint1 = &patharray[gstate.pathbeg];
ppoint2 = &patharray[pathbeg];
while (len--) *ppoint1++ = *ppoint2++;
}
flushlevel(lev);
}
/* Static variables for line parameters */
static struct point cvpt; /* line Vector, device space */
static struct point cupt; /* line Unit vector, user space */
static struct point crpt; /* line Right half width vector, device space */
static struct point cfpt; /* line Forward half width vector, device space */
static struct point pvpt; /* values of the above for the previous line */
static struct point pupt; /* .. */
static struct point prpt; /* .. */
static struct point cppt; /* current point */
static struct point eppt; /* end point */
/* Stroke set up line parameters */
void strokeparm(struct point *ppoint, float *len)
{ float length, d;
/* Save the values for the previous line */
pvpt = cvpt;
pupt = cupt;
prpt = crpt;
/* Inverse delta transform the line to user space. Determine its
* length */
cupt.x = cvpt.x = ppoint[0].x - ppoint[-1].x;
cupt.y = cvpt.y = ppoint[0].y - ppoint[-1].y;
idtransform(&cupt, gstate.ctm);
*len = length = sqrt(cupt.x * cupt.x + cupt.y * cupt.y);
/* If the length is zero the direction is arbitrary, so we choose the x
* direction (used for round line caps only. We then return, as we
* cannot meaningly set up the remaining parameters */
if (length == 0.0)
{ cupt.x = 1.0;
cupt.y = 0.0;
return;
}
/* Construct a unit vector along the line */
cupt.x /= length;
cupt.y /= length;
/* Construct vectors along the line (forward) and across the line (right)
* of length equal to half the line width. Then transform them back to
* device space. */
d = gstate.linewidth / 2.0;
cfpt.x = cupt.x * d;
cfpt.y = cupt.y * d;
crpt.x = cfpt.y;
crpt.y = -cfpt.x;
dtransform(&cfpt, gstate.ctm);
dtransform(&crpt, gstate.ctm);
}
/* Static variables for dash lengths */
static int dashcnt, dashsub;
static float dashlength;
/* Stroke a line */
void strokeline(struct point *ppoint, int bjoin, int ejoin, int first)
{ struct point point;
float x, y, xx, yy, h, s, c, d;
float linelen, length, segment;
int join;
/* If this is the first line in the subpath initialise our location in
* the dash array */
if (first)
{ dashcnt = 0;
if (gstate.dasharray.length != 0)
{ length = gstate.dashoffset;
dashsub = 0;
for (;;)
{ dashlength = gstate.dashlength[dashsub];
if (dashlength > length)
{ dashlength -= length;
break;
}
length -= dashlength;
dashcnt++;
dashsub++;
if (dashsub == gstate.dasharray.length) dashsub = 0;
}
}
}
/* Set up the parameters. Lines of zero length are ignored - unless
they have round caps, in which case we just make two caps */
strokeparm(ppoint, &length);
linelen = length;
if (length == 0.0)
{ if (gstate.linecap != 1) return;
bjoin = -1;
ejoin = -1;
}
/* Start at the beginning of the line */
join = bjoin;
cppt = ppoint[-1];
eppt = ppoint[0];
/* Loop stroking segments according to the dash pattern */
for (;;)
{
/* Find the length remaining in the current dash */
segment = length;
if (gstate.dasharray.length != 0)
{ if (dashlength == 0.0)
{ dashcnt++;
dashsub++;
if (dashsub == gstate.dasharray.length) dashsub = 0;
dashlength = gstate.dashlength[dashsub];
}
if (dashlength >= length)
{ segment = length;
dashlength -= length;
}
else
{ segment = dashlength;
dashlength = 0.0;
}
}
/* Only draw the segment if we are in a dash */
if ((dashcnt & 1) == 0)
{ pathseg = pathend;
/* If the line begins with a mitred or beveled join calculate the
* cross product of the previous and current line vectors; this
* is the sine of the angle between them, and tells us which side
* to make the joint on. If we have a mitred join we must check
* the mitre limit; first we check the dot product of the unit
* vectors to see if the angle is less than a right angle; then
* we check the cross product (sine of the angle) against the
* mitre limit. We don't make mitred joins is the angle is very
* small, as we would divide by zero. */
if (join == 0 || join == 2)
{ s = pupt.x * cupt.y - pupt.y * cupt.x;
if (join == 0)
{ c = pupt.x * cupt.x + pupt.y * cupt.y;
d = pvpt.x * cvpt.y - cvpt.x * pvpt.y;
if ((gstate.mitrelimit > sqrt2) ?
(c < 0.0 && fabs(s) < gstate.mitresin) :
(c < 0.0 || fabs(s) > gstate.mitresin))
join = 2;
if (fabs(d) < 0.0001)
join = 2;
}
/* Make a mitred join. We make the mitre on one side if
* the angle is less than a right angle, on both if it is
* greater */
if (join == 0)
{ d = pvpt.x * cvpt.y - cvpt.x * pvpt.y;
h = (prpt.x * pvpt.y - prpt.y * pvpt.x) / d;
if (s > 0.0) h = -h;
x = cppt.x + cvpt.x * h;
y = cppt.y + cvpt.y * h;
h = (crpt.y * cvpt.x - crpt.x * cvpt.y) / d;
xx = pvpt.x * h;
yy = pvpt.y * h;
point.type = ptmove;
if (c < 0.0)
{ checkpathsize(pathend + 2);
point.x = x - xx;
point.y = y - yy;
patharray[pathend++] = point;
point.type = ptline;
point.x = x + xx;
point.y = y + yy;
patharray[pathend++] = point;
}
else
{ checkpathsize(pathend + 3);
if (s < 0.0)
{ point.x = cppt.x + crpt.x;
point.y = cppt.y + crpt.y;
patharray[pathend++] = point;
point.type = ptline;
point.x = cppt.x - prpt.x;
point.y = cppt.y - prpt.y;
patharray[pathend++] = point;
point.x = x + xx;
point.y = y + yy;
patharray[pathend++] = point;
}
else
{ point.x = x - xx;
point.y = y - yy;
patharray[pathend++] = point;
point.type = ptline;
point.x = cppt.x + prpt.x;
point.y = cppt.y + prpt.y;
patharray[pathend++] = point;
point.x = cppt.x - crpt.x;
point.y = cppt.y - crpt.y;
patharray[pathend++] = point;
}
}
}
/* Make a beveled join */
else
{ checkpathsize(pathend + 3);
point.type = ptmove;
point.x = cppt.x + crpt.x;
point.y = cppt.y + crpt.y;
patharray[pathend++] = point;
point.type = ptline;
if (s != 0.0)
{ point.x = cppt.x;
point.y = cppt.y;
if (s < 0.0)
{ point.x -= prpt.x;
point.y -= prpt.y;
}
else
{ point.x += prpt.x;
point.y += prpt.y;
}
patharray[pathend++] = point;
}
point.x = cppt.x - crpt.x;
point.y = cppt.y - crpt.y;
patharray[pathend++] = point;
}
}
else
/* Make a round join (like a round cap) or a cap */
strokecap(ptmove, (join == 1) ? 1 : gstate.linecap);
}
/* The end of the line */
if (segment == length)
{ join = ejoin;
cppt = eppt;
}
else
{ join = -1;
s = segment / linelen;
cppt.x += cvpt.x * s;
cppt.y += cvpt.y * s;
}
if ((dashcnt & 1) == 0)
{
/* If the line ends with a join make a butt cap, otherwise end
* with the line cap */
strokecap(ptline, (join >= 0) ? 0 : gstate.linecap);
/* Close the path */
point = patharray[pathseg];
point.type = ptclosex;
checkpathsize(pathend + 1);
patharray[pathend++] = point;
}
join = -1;
length -= segment;
if (length == 0.0) break;
}
}
/* Stroke a line cap */
void strokecap(int type, int cap)
{ struct point points[7];
float fx, fy, rx, ry;
/* At the beginning caps face the opposite way to the end */
if (type == ptmove)
{ fx = -cfpt.x;
fy = -cfpt.y;
rx = -crpt.x;
ry = -crpt.y;
}
else
{ fx = cfpt.x;
fy = cfpt.y;
rx = crpt.x;
ry = crpt.y;
}
points[0].type = type;
points[0].x = cppt.x - rx;
points[0].y = cppt.y - ry;
points[6].type = ptline;
points[6].x = cppt.x + rx;
points[6].y = cppt.y + ry;
/* Butt cap */
if (cap == 0)
{ checkpathsize(pathend + 2);
patharray[pathend++] = points[0];
patharray[pathend++] = points[6];
}
/* Projecting square cap */
else if (cap == 2)
{ points[0].x += fx;
points[0].y += fy;
points[6].x += fx;
points[6].y += fy;
checkpathsize(pathend + 2);
patharray[pathend++] = points[0];
patharray[pathend++] = points[6];
}
/* Round cap. Construct a Bezier curve approximation (in 2 sections) and
* flatten it. We always use two sections because they are faster to
* construct than to flatten */
else
{ points[3].type = ptcurve;
points[3].x = cppt.x + fx;
points[3].y = cppt.y + fy;
fx *= f43rt2;
fy *= f43rt2;
rx *= f43rt2;
ry *= f43rt2;
points[1] = points[0];
points[1].x += fx;
points[1].y += fy;
points[2] = points[3];
points[2].x -= rx;
points[2].y -= ry;
points[4] = points[3];
points[4].x += rx;
points[4].y += ry;
points[5] = points[6];
points[5].x += fx;
points[5].y += fy;
checkpathsize(pathend + 1);
patharray[pathend++] = points[0];
flattencurve(&points[0], 0);
flattencurve(&points[3], 0);
}
}
/* Make a new clipping path by intersecting it with the current path */
void clip(int rule)
{ struct point point, *ppoint;
struct clip clip1, clip2, *pclip1, *pclip2, *pclipx;
double a1, b1, c1, a2, b2, c2;
double l1, l2, l3;
double h11, h12, h21, h22, hh;
int xx, yy, x1, y1;
int count, count1, count2, step;
int clipold, clipnew, clipmax, clipflg;
int cdir1, cdir2, fdir1, fdir2;
/* Set up the default clip path */
if (!gstate.clipflag)
{ cliplength(5);
gstate.pathbeg = gstate.clipbeg;
count = gstate.pathend;
clippath();
gstate.pathbeg = gstate.pathend;
gstate.pathend = count;
}
/* Set up the clip array. We convert the coordinates to fixed point,
* with a scale factor of 256. Then when we come to multiplying the
* values to calculate the intersections it will fit into 48 bits or
* so, a reasonable minimum accuracy for double precision floating
* point */
clipend = 0;
for (count1 = gstate.clipbeg; count1 < gstate.pathend; count1++)
{ ppoint = &patharray[count1];
if (ppoint->type != ptmove)
{ if (count1 < gstate.pathbeg)
{ clip1.cdir = 1;
clip1.fdir = 0;
}
else
{ clip1.cdir = 0;
clip1.fdir = 1;
}
clip1.flag = 0;
clip1.swap = 0;
clip1.x1 = floor(ppoint[-1].x * 256.0f + 0.5);
clip1.y1 = floor(ppoint[-1].y * 256.0f + 0.5);
clip1.x2 = floor(ppoint[0].x * 256.0f + 0.5);
clip1.y2 = floor(ppoint[0].y * 256.0f + 0.5);
clipline(&clip1);
}
}
/* Split the lines whenever they intersect. Owing to rounding errors
* The resulting new lines are not in exactly the same place as before,
* so we loop checking for intersections until we don't find any more
*/
clipnew = 0;
for (;;)
{
/* Shell sort the array in order of y1 */
count = clipend;
for (;;)
{ count = count / 3 + 1;
for (count1 = count; count1 < clipend; count1++)
for (count2 = count1 - count;
count2 >= 0 &&
clipptr[count2]->y1 > clipptr[count2 + count]->y1;
count2 -= count)
{ pclip1 = clipptr[count2];
clipptr[count2] = clipptr[count2 + count];
clipptr[count2 + count] = pclip1;
}
if (count == 1) break;
}
/* Exit (with the array sorted) if we have no new lines */
if (clipnew == clipend) break;
/* Locate all the intersections for each line */
count1 = 0;
clipnew = clipend;
while (count1 < clipend - 1)
{ count2 = count1;
/* We don't need to check for intersections with the new lines
* we created by intersecting with ours */
clipmax = clipend - 1;
while (count2 < clipmax)
{ count2++;
pclip1 = clipptr[count1];
pclip2 = clipptr[count2];
/* When we get to the first line whose y1 is greater than
* our y2 we can skip all the way to the beginning of the
* new lines */
if (pclip2->y1 > pclip1->y2)
{ if (count2 < clipnew) count2 = clipnew;
continue;
}
/* Skip lines whose bounding boxes do not intersect ours */
if (pclip2->y2 < pclip1->y1)
continue;
if (min(pclip1->x1,pclip1->x2) > max(pclip2->x1,pclip2->x2))
continue;
if (max(pclip1->x1,pclip1->x2) < min(pclip2->x1,pclip2->x2))
continue;
/* If the two endpoints of each line are on opposite sides
* of the other line, the lines must intersect. If one is
* on the line but not the other, they intersect at the end.
* If both are on the line they are colinear. The distance
* from a point (x,y) to a line (a*X +b*Y + c = 0) is given
* by (a*x + b*y *c) / sqrt(a**2 + b**2). We don't bother
* with the square root as we only want to know the
* relative distances. The test is exact as long as the
* numbers (integer values) we are using are not too big to
* be represented exactly in double precision floating point
*/
clip1 = *pclip1;
clip2 = *pclip2;
a1 = clip1.y2 - clip1.y1;
b1 = clip1.x2 - clip1.x1;
c1 = (double) clip1.x2 * (double) clip1.y1 -
(double) clip1.x1 * (double) clip1.y2;
h11 = a1 * clip2.x1 - b1 * clip2.y1 + c1;
h12 = a1 * clip2.x2 - b1 * clip2.y2 + c1;
if (h11 > 0.0 && h12 > 0.0) continue;
if (h11 < 0.0 && h12 < 0.0) continue;
a2 = clip2.y2 - clip2.y1;
b2 = clip2.x2 - clip2.x1;
c2 = (double) clip2.x2 * (double) clip2.y1 -
(double) clip2.x1 * (double) clip2.y2;
h21 = a2 * clip1.x1 - b2 * clip1.y1 + c2;
h22 = a2 * clip1.x2 - b2 * clip1.y2 + c2;
if (h21 > 0.0 && h22 > 0.0) continue;
if (h21 < 0.0 && h22 < 0.0) continue;
/* If the lines are colinear we treat them as intersecting
* at the endpoints. To find out what order the endpoints
* lie in, we take the beginning of line 1 as our origin
* and calculate the dot products of the displacements of
* the other endpoints with line 1 itself. We then split
* the lines, knowing that the two lines must be in the
* same direction, as we made sure y1 < y2 or x1 < x2
*/
if (h11 == 0.0 && h12 == 0.0)
{ l1 = b1 * b1 + a1 * a1;
l2 = (clip2.x1 - clip1.x1) * b1 +
(clip2.y1 - clip1.y1) * a1;
l3 = (clip2.x2 - clip1.x1) * b1 +
(clip2.y2 - clip1.y1) * a1;
if (l2 < 0 && l3 < l1)
{ clip1.x2 = pclip1->x1 = clip2.x2;
clip1.y2 = pclip1->y1 = clip2.y2;
clip2.x1 = pclip2->x2 = clip1.x1;
clip2.y1 = pclip2->y2 = clip1.y1;
}
else if (l2 <= 0 && l3 >= l1)
{ clip1 = clip2;
clip1.x2 = pclip2->x1 = pclip1->x1;
clip1.y2 = pclip2->y1 = pclip1->y1;
clip2.x1 = pclip2->x2 = pclip1->x2;
clip2.y1 = pclip2->y2 = pclip1->y2;
}
else if (l2 >= 0 && l3 <= l1)
{ clip2 = clip1;
clip1.x2 = pclip1->x1 = pclip2->x1;
clip1.y2 = pclip1->y1 = pclip2->y1;
clip2.x1 = pclip1->x2 = pclip2->x2;
clip2.y1 = pclip1->y2 = pclip2->y2;
}
else if (l2 > 0 && l3 > l1)
{ clip1.x1 = pclip1->x2 = clip2.x1;
clip1.y1 = pclip1->y2 = clip2.y1;
clip2.x2 = pclip2->x1 = clip1.x2;
clip2.y2 = pclip2->y1 = clip1.y2;
}
clipline(&clip1);
clipline(&clip2);
}
/* Otherwise calculate the intersection */
else
{ hh = h22 - h21;
xx = floor((clip1.x1 * h22 - clip1.x2 * h21) / hh + 0.5);
yy = floor((clip1.y1 * h22 - clip1.y2 * h21) / hh + 0.5);
if (xx != clip1.x1 || yy != clip1.y1)
{ pclip1->x2 = clip1.x1 = xx;
pclip1->y2 = clip1.y1 = yy;
clipline(&clip1);
}
pclip2 = clipptr[count2];
if (xx != clip2.x1 || yy != clip2.y1)
{ pclip2->x2 = clip2.x1 = xx;
pclip2->y2 = clip2.y1 = yy;
clipline(&clip2);
}
}
/* We must check the directions in case of rounding error */
clipswap(clipptr[count1]);
clipswap(clipptr[count2]);
}
count1++;
}
}
/* Count the winding number for each line. We construct a test line
* running horizontally from the left, at a height just greater than y1.
* (If the line is horizontal, we regard the test line as being bent at
* the end so it meets the line just to the right of x1.) If we find
* any lines colinear with ours we chain them together */
count1 = 0;
clipold = 0;
clipflg = 0;
while (count1 < clipend)
{ pclip1 = clipptr[count1++];
if (pclip1->flag != 0) continue;
count2 = clipold;
cdir1 = fdir1 = 0;
cdir2 = pclip1->cdir;
fdir2 = pclip1->fdir;
pclipx = NULL;
/* Scan the other lines for intersections with the test line */
while (count2 < clipend)
{ pclip2 = clipptr[count2];
count2++;
if (pclip2 == pclip1) continue;
/* If y2 is less than our y1 we won't need to scan the line
* again. Swap it to the beginning and step past it next time */
if (pclip2->y2 < pclip1->y1)
{ clipptr[count2 - 1] = clipptr[clipold];
clipptr[clipold] = pclip2;
clipold++;
continue;
}
/* Stop scanning when y1 is greater than ours */
if (pclip2->y1 > pclip1->y1) break;
/* If its y2 is greater than our y1, then if it passes to the
* left of our x1 it must intersect the test line */
if (pclip2->y2 > pclip1->y1)
{ a1 = pclip2->x1 * (double) (pclip2->y2 - pclip1->y1) +
pclip2->x2 * (double) (pclip1->y1 - pclip2->y1);
a2 = pclip1->x1 * (double) (pclip2->y2 - pclip2->y1);
if (a1 < a2)
{ cdir1 += pclip2->cdir;
fdir1 += pclip2->fdir;
}
/* If it passes through our x1 we have to compare the slopes.
* The cross procuct is the sine of the angle between them. If
* its slope is greater than ours it must intersect the test
* line. If the slopes are the same they must be colinar;
* calculate the winding number for the far side of the line
* and chain it */
else if (a1 == a2)
{ hh = (double) (pclip1->x2 - pclip1->x1) *
(double) (pclip2->y2 - pclip2->y1) -
(double) (pclip2->x2 - pclip2->x1) *
(double) (pclip1->y2 - pclip1->y1);
if (hh > 0.0)
{ cdir1 += pclip2->cdir;
fdir1 += pclip2->fdir;
}
else if (hh == 0.0)
{ cdir2 += pclip2->cdir;
fdir2 += pclip2->fdir;
if (pclip2->flag == 0)
{ pclip2->chain = pclipx;
pclipx = pclip2;
}
}
}
}
/* Horizontal lines only intersect the test line if they are
* colinear with ours */
else
if (pclip1->y1 == pclip1->y2 &&
pclip2->y1 == pclip2->y2 &&
pclip2->x1 == pclip1->x1)
{ cdir2 += pclip2->cdir;
fdir2 += pclip2->fdir;
if (pclip2->flag == 0)
{ pclip2->chain = pclipx;
pclipx = pclip2;
}
}
}
/* If the line is on the boundary of the intersection of the paths,
* we keep it. If it is interior to or on the boundary of the path
* it does not belong to, or exterior to or on the boundary of the
* other, we must have two or more coincident lines; we keep it and
* its pair to preserve the degenerate path, discarding any others
* that are also coincident. Otherwise we discard it. (We don't
* preserve paths where both the clip and fill paths are
* degenerate.) Flag the lines for their ends to be swapped if they
* are right or bottom edges */
cdir2 = (((cdir1 + cdir2) & rule) != 0);
fdir2 = (((fdir1 + fdir2) & rule) != 0);
cdir1 = (( cdir1 & rule) != 0);
fdir1 = (( fdir1 & rule) != 0);
if ((cdir1 & fdir1) == (cdir2 & fdir2))
if ((pclip1->fdir != 0 && (cdir1 | cdir2) && !(fdir1 & fdir2)) ||
(pclip1->cdir != 0 && (fdir1 | fdir2) && !(cdir1 & fdir2)))
{ pclipx->flag = 2; /* Keep its pair */
pclipx->swap = 1; /* Swap one line */
pclipx = pclipx->chain; /* Discard the rest */
}
else
{ pclip1->flag = 1; /* Discard the line */
clipflg++;
pclipx = NULL; /* Leave the rest */
}
else
if ((cdir1 & fdir1) != 0)
pclip1->swap = 1; /* Swap right and bottom edges */
while (pclipx) /* Discard the rest */
{ pclipx->flag = 1;
clipflg++;
pclipx = pclipx->chain;
}
}
/* Swap the lines so they are pointing in their proper directions */
count1 = clipend;
pclip1 = &cliparray[0];
while (count1--)
{ if (pclip1->swap) clipswap(pclip1);
pclip1++;
}
/* Now join the lines back up to make the path. The lines are in
* approximate order of y2, so we optimise our search on that basis.
* We start by picking any line; then we find the one that joins it */
cliplength(0);
point.type = ptmove;
count = 0;
step = 0;
pathend = gstate.pathend;
while (clipflg < clipend)
{
/* We step alternately backwards and forwards */
count = count + step;
if (step > 0)
step = -step - 1;
else
step = -step + 1;
/* When the array is half empty we compact it */
if (clipflg + clipflg > clipend)
{ count1 = 0;
count2 = 0;
while (count2 < clipend)
{ if (count2 == count) count = count1;
pclip2 = clipptr[count2++];
if (pclip2->flag != 1) clipptr[count1++] = pclip2;
}
clipend -= clipflg;
clipflg = 0;
if (count >= clipend) count = clipend - 1;
step = 1;
}
/* Search for a line that joins the current point */
if (count >= 0 && count < clipend)
{ pclip1 = clipptr[count];
if (pclip1->flag != 1)
{
/* At the beginning of a subpath add a move */
if (point.type == ptmove)
{ x1 = pclip1->x1;
y1 = pclip1->y1;
point.x = x1 / 256.0f;
point.y = y1 / 256.0f;
checkpathsize(pathend + 1);
patharray[pathend++] = point;
point.type = ptline;
xx = pclip1->x2;
yy = pclip1->y2;
step = 0;
}
/* Otherwise look for a line that joins the current point */
else if (pclip1->y1 == yy && pclip1->x1 == xx)
{ xx = pclip1->x2;
yy = pclip1->y2;
step = 0;
}
/* Found a line; if it returns to the beginning close the
* subpath */
if (step == 0)
{ pclip1->flag = 1;
clipflg++;
checkpathsize(pathend + 1);
point.x = xx / 256.0f;
point.y = yy / 256.0f;
if (yy == y1 && xx == x1)
{ point.type = ptclosex;
patharray[pathend++] = point;
point.type = ptmove;
}
else
patharray[pathend++] = point;
step = 1;
}
}
}
}
/* We now have the new clip path, at the end of the path. To put the
* clip path first, we first swap the order of the contents of the two
* paths individually, then swap them both together */
swappath(gstate.pathbeg, gstate.pathend);
swappath(gstate.pathend, pathend);
swappath(gstate.pathbeg, pathend);
gstate.pathbeg = gstate.clipbeg + pathend - gstate.pathend;
gstate.pathend = pathend;
gstate.clipflag = 1;
}
/* Add a clip line to the array */
void clipline(struct clip *pclip)
{ struct clip *pc;
if (pclip->x1 != pclip->x2 || pclip->y1 != pclip->y2)
{ clipswap(pclip);
checkclipsize(clipend + 1, clipend);
pc = &cliparray[clipend];
*pc = *pclip;
clipptr[clipend++] = pc;
}
}
/* Swap a clip line if necessary so y2 > y1 (or x2 > x1) */
void clipswap(struct clip *pclip)
{ int sw;
if (pclip->swap ||
pclip->y1 > pclip->y2 ||
(pclip->y1 == pclip->y2 && pclip->x1 > pclip->x2))
{ pclip->cdir = -pclip->cdir;
pclip->fdir = -pclip->fdir;
sw = pclip->x1;
pclip->x1 = pclip->x2;
pclip->x2 = sw;
sw = pclip->y1;
pclip->y1 = pclip->y2;
pclip->y2 = sw;
}
}
/* Swap the order of the points in a path */
void swappath(int beg, int end)
{ struct point point, *ppoint1, *ppoint2;
ppoint1 = &patharray[beg];
ppoint2 = &patharray[end];
for (;;)
{ ppoint2--;
if (ppoint1 >= ppoint2) break;
point = *ppoint1;
*ppoint1 = *ppoint2;
*ppoint2 = point;
ppoint1++;
}
}
/* End of file "postgraph.c" */