draw.c revision c166fba9
1f80a6dcdSmrg/*
2f80a6dcdSmrg *
3f80a6dcdSmrgCopyright (c) 1991  X Consortium
4f80a6dcdSmrg
5f80a6dcdSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
6f80a6dcdSmrgof this software and associated documentation files (the "Software"), to deal
7f80a6dcdSmrgin the Software without restriction, including without limitation the rights
8f80a6dcdSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9f80a6dcdSmrgcopies of the Software, and to permit persons to whom the Software is
10f80a6dcdSmrgfurnished to do so, subject to the following conditions:
11f80a6dcdSmrg
12f80a6dcdSmrgThe above copyright notice and this permission notice shall be included in
13f80a6dcdSmrgall copies or substantial portions of the Software.
14f80a6dcdSmrg
15f80a6dcdSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16f80a6dcdSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17f80a6dcdSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18f80a6dcdSmrgX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19f80a6dcdSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20f80a6dcdSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21f80a6dcdSmrg
22f80a6dcdSmrgExcept as contained in this notice, the name of the X Consortium shall not be
23f80a6dcdSmrgused in advertising or otherwise to promote the sale, use or other dealings
24f80a6dcdSmrgin this Software without prior written authorization from the X Consortium.
25f80a6dcdSmrg *
26f80a6dcdSmrg */
27f80a6dcdSmrg
28f80a6dcdSmrg/*
29f80a6dcdSmrg * draw.c
30f80a6dcdSmrg *
31f80a6dcdSmrg * accept dvi function calls and translate to X
32f80a6dcdSmrg */
33f80a6dcdSmrg
34f80a6dcdSmrg/*
35f80a6dcdSmrg  Support for ditroff drawing commands added: lines, circles, ellipses,
36f80a6dcdSmrg  arcs and splines.  Splines are approximated as short lines by iterating
37f80a6dcdSmrg  a simple approximation algorithm.  This seems good enough for previewing.
38f80a6dcdSmrg
39f80a6dcdSmrg  David Evans <dre@cs.nott.ac.uk>, 14th March, 1990
40f80a6dcdSmrg*/
41f80a6dcdSmrg
42f80a6dcdSmrg#include <X11/Xos.h>
43f80a6dcdSmrg#include <X11/IntrinsicP.h>
44f80a6dcdSmrg#include <X11/StringDefs.h>
45f80a6dcdSmrg#include <stdio.h>
46f80a6dcdSmrg#include <ctype.h>
47f80a6dcdSmrg#include <math.h>
48f80a6dcdSmrg#include "DviP.h"
49f80a6dcdSmrg#include <stdlib.h>
50f80a6dcdSmrg
51f80a6dcdSmrg#ifndef M_PI
52f80a6dcdSmrg#define M_PI 3.14159265358979323846264338327950
53f80a6dcdSmrg#endif
54f80a6dcdSmrg
55f80a6dcdSmrg/*	the following are for use in the spline approximation algorithm */
56f80a6dcdSmrg
57f80a6dcdSmrgtypedef struct	Point {
58f80a6dcdSmrg    double	x;
59f80a6dcdSmrg    double	y;
60f80a6dcdSmrg    struct Point	*next;
61f80a6dcdSmrg} Point;
62f80a6dcdSmrg
63f80a6dcdSmrg#define	ITERATIONS	10	/* iterations to approximate spline */
64f80a6dcdSmrg
65f80a6dcdSmrg#define	midx(p,q)	((p->x + q->x) / 2)	/* mid x point on pq */
66f80a6dcdSmrg#define	midy(p,q)	((p->y + q->y) / 2)	/* mid y point on pq */
67f80a6dcdSmrg
68f80a6dcdSmrg#define	length(p,q)	sqrt(((q->x - p->x)*(q->x - p->x)) \
69f80a6dcdSmrg			     + ((q->y - p->y)*(q->y - p->y))) /* length of pq */
70f80a6dcdSmrg
7165912f00Smrgstatic Point *spline = (Point *)NULL;	/* head of spline linked list */
72f80a6dcdSmrg
73f80a6dcdSmrgstatic void	ApproxSpline(int n);
74f80a6dcdSmrgstatic void	DeletePoint(Point *p);
75f80a6dcdSmrgstatic void	DrawSplineSegments(DviWidget dw);
76c166fba9Smrgstatic int	GetSpline(const char *s);
77f80a6dcdSmrgstatic void	InsertPoint(Point *p, Point *q);
78f80a6dcdSmrgstatic void	LineApprox(Point *p1, Point *p2, Point *p3);
79f80a6dcdSmrgstatic Point *	MakePoint(double x, double y);
80f80a6dcdSmrg
81f80a6dcdSmrgvoid
8265912f00SmrgHorizontalMove(DviWidget dw, int delta)
83f80a6dcdSmrg{
84f80a6dcdSmrg    dw->dvi.state->x += delta;
85f80a6dcdSmrg}
86f80a6dcdSmrg
87f80a6dcdSmrgvoid
8865912f00SmrgHorizontalGoto(DviWidget dw, int NewPosition)
89f80a6dcdSmrg{
90f80a6dcdSmrg    dw->dvi.state->x = NewPosition;
91f80a6dcdSmrg}
92f80a6dcdSmrg
93f80a6dcdSmrgvoid
9465912f00SmrgVerticalMove(DviWidget dw, int delta)
95f80a6dcdSmrg{
96f80a6dcdSmrg    dw->dvi.state->y += delta;
97f80a6dcdSmrg}
98f80a6dcdSmrg
99f80a6dcdSmrgvoid
10065912f00SmrgVerticalGoto(DviWidget dw, int NewPosition)
101f80a6dcdSmrg{
102f80a6dcdSmrg    dw->dvi.state->y = NewPosition;
103f80a6dcdSmrg}
104f80a6dcdSmrg
105f80a6dcdSmrg#ifdef USE_XFT
106f80a6dcdSmrgstatic void
107f80a6dcdSmrgDrawText (DviWidget dw)
108f80a6dcdSmrg{
109f80a6dcdSmrg    int	    i;
110f80a6dcdSmrg    XftFont *font;
111f80a6dcdSmrg
112f80a6dcdSmrg    font = dw->dvi.cache.font;
113f80a6dcdSmrg    for (i = 0; i <= dw->dvi.cache.index; i++)
114f80a6dcdSmrg    {
115f80a6dcdSmrg	if (dw->dvi.cache.cache[i].font)
116f80a6dcdSmrg	    font = dw->dvi.cache.cache[i].font;
117f80a6dcdSmrg	XftDrawString8 (dw->dvi.draw, &dw->dvi.black,
118f80a6dcdSmrg			font,
119f80a6dcdSmrg			dw->dvi.cache.cache[i].x,
120f80a6dcdSmrg			dw->dvi.cache.start_y,
121f80a6dcdSmrg			(unsigned char *) dw->dvi.cache.cache[i].chars,
122f80a6dcdSmrg			dw->dvi.cache.cache[i].nchars);
123f80a6dcdSmrg    }
124f80a6dcdSmrg}
125f80a6dcdSmrg#endif
126f80a6dcdSmrg
127f80a6dcdSmrgvoid
12865912f00SmrgFlushCharCache (DviWidget dw)
129f80a6dcdSmrg{
130f80a6dcdSmrg    int	    xx, yx;
131f80a6dcdSmrg
132f80a6dcdSmrg    xx = ToX(dw, dw->dvi.state->x);
133f80a6dcdSmrg    yx = ToX(dw, dw->dvi.state->y);
134f80a6dcdSmrg    if (dw->dvi.cache.char_index != 0)
135f80a6dcdSmrg    {
136f80a6dcdSmrg#ifdef USE_XFT
137f80a6dcdSmrg	DrawText (dw);
138f80a6dcdSmrg#else
139f80a6dcdSmrg	XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
140f80a6dcdSmrg		    dw->dvi.cache.start_x, dw->dvi.cache.start_y,
141f80a6dcdSmrg		    dw->dvi.cache.cache, dw->dvi.cache.index + 1);
142f80a6dcdSmrg#endif
143f80a6dcdSmrg    }
144f80a6dcdSmrg    dw->dvi.cache.index = 0;
145f80a6dcdSmrg    dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
146f80a6dcdSmrg    if (dw->dvi.noPolyText)
147f80a6dcdSmrg	dw->dvi.cache.max = 1;
148f80a6dcdSmrg    dw->dvi.cache.char_index = 0;
149f80a6dcdSmrg    dw->dvi.cache.cache[0].nchars = 0;
150f80a6dcdSmrg    dw->dvi.cache.start_x = dw->dvi.cache.x = xx;
151f80a6dcdSmrg    dw->dvi.cache.start_y = dw->dvi.cache.y = yx;
152f80a6dcdSmrg}
153f80a6dcdSmrg
154f80a6dcdSmrgvoid
15565912f00SmrgSetGCForDraw (DviWidget dw)
156f80a6dcdSmrg{
157f80a6dcdSmrg    int	lw;
158f80a6dcdSmrg    if (dw->dvi.state->line_style != dw->dvi.line_style ||
159f80a6dcdSmrg	dw->dvi.state->line_width != dw->dvi.line_width)
160f80a6dcdSmrg    {
161f80a6dcdSmrg	lw = ToX(dw, dw->dvi.state->line_width);
162f80a6dcdSmrg	if (lw <= 1)
163f80a6dcdSmrg	    lw = 0;
164f80a6dcdSmrg	XSetLineAttributes (XtDisplay (dw), dw->dvi.normal_GC,
165f80a6dcdSmrg			    lw, LineSolid, CapButt, JoinMiter);
166f80a6dcdSmrg	dw->dvi.line_style = dw->dvi.state->line_style;
167f80a6dcdSmrg	dw->dvi.line_width = dw->dvi.state->line_width;
168f80a6dcdSmrg    }
169f80a6dcdSmrg}
170f80a6dcdSmrg
171f80a6dcdSmrgvoid
17265912f00SmrgDrawLine (DviWidget dw, int x, int y)
173f80a6dcdSmrg{
174f80a6dcdSmrg    if (dw->dvi.display_enable)
175f80a6dcdSmrg	XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
176f80a6dcdSmrg		   ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y),
177f80a6dcdSmrg		   ToX(dw, dw->dvi.state->x + x), ToX(dw,dw->dvi.state->y + y));
178f80a6dcdSmrg    dw->dvi.state->x += x;
179f80a6dcdSmrg    dw->dvi.state->y += y;
180f80a6dcdSmrg}
181f80a6dcdSmrg
182f80a6dcdSmrgvoid
18365912f00SmrgDrawCircle (DviWidget dw, int diameter)
184f80a6dcdSmrg{
185f80a6dcdSmrg    if (dw->dvi.display_enable)
186f80a6dcdSmrg    	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
187f80a6dcdSmrg	      	  ToX(dw, dw->dvi.state->x),
188f80a6dcdSmrg	      	  ToX(dw, dw->dvi.state->y - (diameter / 2)),
189f80a6dcdSmrg	      	  ToX(dw, diameter), ToX(dw, diameter), 0, 360 * 64);
190f80a6dcdSmrg    dw->dvi.state->x += diameter;
191f80a6dcdSmrg}
192f80a6dcdSmrg
193f80a6dcdSmrgvoid
19465912f00SmrgDrawEllipse (DviWidget dw, int a, int b)
195f80a6dcdSmrg{
196f80a6dcdSmrg    if (dw->dvi.display_enable)
197f80a6dcdSmrg	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
198f80a6dcdSmrg		  ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y - (b / 2)),
199f80a6dcdSmrg		  ToX(dw,a), ToX(dw,b), 0, 360 * 64);
200f80a6dcdSmrg    dw->dvi.state->x += a;
201f80a6dcdSmrg}
202f80a6dcdSmrg
203f80a6dcdSmrg
204f80a6dcdSmrg/*	Convert angle in degrees to 64ths of a degree */
205f80a6dcdSmrg
206f80a6dcdSmrgstatic int
207f80a6dcdSmrgConvertAngle(int theta)
208f80a6dcdSmrg{
209f80a6dcdSmrg    return(theta * 64);
210f80a6dcdSmrg}
211f80a6dcdSmrg
212f80a6dcdSmrgvoid
21365912f00SmrgDrawArc (DviWidget dw, int x0, int y0, int x1, int y1)
214f80a6dcdSmrg{
215f80a6dcdSmrg    int	xc, yc, x2, y2, r;
216f80a6dcdSmrg    int	angle1, angle2;
217f80a6dcdSmrg
218f80a6dcdSmrg    /* centre */
219f80a6dcdSmrg    xc = dw->dvi.state->x + x0;
220f80a6dcdSmrg    yc = dw->dvi.state->y + y0;
221f80a6dcdSmrg
222f80a6dcdSmrg    /* to */
223f80a6dcdSmrg    x2 = xc + x1;
224f80a6dcdSmrg    y2 = yc + y1;
225f80a6dcdSmrg
226f80a6dcdSmrg    dw->dvi.state->x = x2;
227f80a6dcdSmrg    dw->dvi.state->y = y2;
228f80a6dcdSmrg
229f80a6dcdSmrg    if (dw->dvi.display_enable) {
230f80a6dcdSmrg
231f80a6dcdSmrg	/* radius */
232f80a6dcdSmrg	r = (int)sqrt((float) x1 * x1 + (float) y1 * y1);
233f80a6dcdSmrg
234f80a6dcdSmrg	/* start and finish angles */
235f80a6dcdSmrg	if (x0 == 0) {
236f80a6dcdSmrg		if (y0 >= 0)
237f80a6dcdSmrg			angle1 = 90;
238f80a6dcdSmrg		else
239f80a6dcdSmrg			angle1 = 270;
240f80a6dcdSmrg	}
241f80a6dcdSmrg	else {
242f80a6dcdSmrg		angle1 = (int) (atan((double)(y0) / (double)(x0)) * 180 / M_PI);
243f80a6dcdSmrg		if (x0 > 0)
244f80a6dcdSmrg			angle1 = 180 - angle1;
245f80a6dcdSmrg		else
246f80a6dcdSmrg			angle1 = -angle1;
247f80a6dcdSmrg	}
248f80a6dcdSmrg
249f80a6dcdSmrg	if (x1 == 0) {
250f80a6dcdSmrg		if (y1 <= 0)
251f80a6dcdSmrg			angle2 = 90;
252f80a6dcdSmrg		else
253f80a6dcdSmrg			angle2 = 270;
254f80a6dcdSmrg	}
255f80a6dcdSmrg	else {
256f80a6dcdSmrg		angle2 = (int) (atan((double)(y1) / (double)(x1)) * 180 / M_PI);
257f80a6dcdSmrg		if (x1 < 0)
258f80a6dcdSmrg			angle2 = 180 - angle2;
259f80a6dcdSmrg		else
260f80a6dcdSmrg			angle2 = -angle2;
261f80a6dcdSmrg	}
262f80a6dcdSmrg
263f80a6dcdSmrg	if (angle1 < 0)
264f80a6dcdSmrg		angle1 += 360;
265f80a6dcdSmrg	if (angle2 < 0)
266f80a6dcdSmrg		angle2 += 360;
267f80a6dcdSmrg
268f80a6dcdSmrg	if (angle2 < angle1)
269f80a6dcdSmrg		angle1 -= 360;
270f80a6dcdSmrg	angle2 = angle2 - angle1;
271f80a6dcdSmrg
272f80a6dcdSmrg	angle1 = ConvertAngle(angle1);
273f80a6dcdSmrg	angle2 = ConvertAngle(angle2);
274f80a6dcdSmrg
275f80a6dcdSmrg	XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
276f80a6dcdSmrg		  ToX(dw, xc - r), ToX(dw, yc - r),
277f80a6dcdSmrg		  ToX(dw, 2 * r), ToX(dw, 2 * r),
278f80a6dcdSmrg		  angle1, angle2);
279f80a6dcdSmrg    }
280f80a6dcdSmrg}
281f80a6dcdSmrg
282f80a6dcdSmrg/* copy next non-blank string from p to temp, update p */
283f80a6dcdSmrg
284c166fba9Smrgstatic const char *
285c166fba9Smrggetstr(const char *p, char *temp)
286f80a6dcdSmrg{
287f80a6dcdSmrg    while (*p == ' ' || *p == '\t' || *p == '\n')
288f80a6dcdSmrg	p++;
289f80a6dcdSmrg    if (*p == '\0') {
290f80a6dcdSmrg	temp[0] = 0;
291f80a6dcdSmrg	return((char *)NULL);
292f80a6dcdSmrg    }
293f80a6dcdSmrg    while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
294f80a6dcdSmrg	*temp++ = *p++;
295f80a6dcdSmrg    *temp = '\0';
296f80a6dcdSmrg    return(p);
297f80a6dcdSmrg}
298f80a6dcdSmrg
299f80a6dcdSmrg
300f80a6dcdSmrg/*	Draw a spline by approximating with short lines.      */
301f80a6dcdSmrg
302f80a6dcdSmrg/*ARGSUSED*/
303f80a6dcdSmrgvoid
304c166fba9SmrgDrawSpline (DviWidget dw, const char *s, int len)
305f80a6dcdSmrg{
306f80a6dcdSmrg    int		n;
307f80a6dcdSmrg
308f80a6dcdSmrg    /* get coordinate pairs into spline linked list */
309f80a6dcdSmrg    if ((n = GetSpline(s)) <= 0)
310f80a6dcdSmrg	return;
311f80a6dcdSmrg
312f80a6dcdSmrg    ApproxSpline(n);
313f80a6dcdSmrg
314f80a6dcdSmrg    DrawSplineSegments(dw);
315f80a6dcdSmrg}
316f80a6dcdSmrg
317f80a6dcdSmrg
318f80a6dcdSmrg/*	Parse string s to create a linked list of Point's with spline */
319f80a6dcdSmrg/*	as its head.  Return the number of coordinate pairs found.    */
320f80a6dcdSmrg
321f80a6dcdSmrgstatic int
322c166fba9SmrgGetSpline(const char *s)
323f80a6dcdSmrg{
324f80a6dcdSmrg    double	x, y, x1, y1;
325f80a6dcdSmrg    int		n = 0;
326f80a6dcdSmrg    Point	*pt;
327c166fba9Smrg    const char	*p = s;
328c166fba9Smrg    char        d[10];
329f80a6dcdSmrg
330f80a6dcdSmrg    if (!*p)
331f80a6dcdSmrg	return(n);
332f80a6dcdSmrg
333f80a6dcdSmrg    pt = spline = MakePoint(0.0, 0.0);
334f80a6dcdSmrg    n = 1;
335f80a6dcdSmrg    x = y = 0.0;
336f80a6dcdSmrg    p = s;
337f80a6dcdSmrg    while (p && *p) {
338c166fba9Smrg	if ((p = getstr(p, d)) == (const char *)NULL)
339f80a6dcdSmrg	    break;
340f80a6dcdSmrg	x1 = x + atof(d);
341c166fba9Smrg	if ((p = getstr(p, d)) == (const char *)NULL)
342f80a6dcdSmrg	    break;
343f80a6dcdSmrg	y1 = y + atof(d);
344f80a6dcdSmrg	pt->next = MakePoint(x1, y1);
345f80a6dcdSmrg	pt = pt->next;
346f80a6dcdSmrg	x = pt->x;
347f80a6dcdSmrg	y = pt->y;
348f80a6dcdSmrg	n++;
349f80a6dcdSmrg    }
350f80a6dcdSmrg
351f80a6dcdSmrg    /* number of pairs of points */
352f80a6dcdSmrg
353f80a6dcdSmrg    return(n);
354f80a6dcdSmrg}
355f80a6dcdSmrg
356f80a6dcdSmrg/*	Approximate a spline by lines generated by iterations of the	  */
357f80a6dcdSmrg/*	approximation algorithm from the original n points in the spline. */
358f80a6dcdSmrg
359f80a6dcdSmrgstatic void
36065912f00SmrgApproxSpline(int n)
361f80a6dcdSmrg{
362f80a6dcdSmrg    int		mid, j;
363f80a6dcdSmrg    Point	*p1, *p2, *p3, *p;
364f80a6dcdSmrg
365f80a6dcdSmrg    if (n < 3)
366f80a6dcdSmrg	return;
367f80a6dcdSmrg
368f80a6dcdSmrg    /* number of mid-points to calculate */
369f80a6dcdSmrg    mid = n - 3;
370f80a6dcdSmrg
371f80a6dcdSmrg    /* remember original points are stored as an array of n points */
372f80a6dcdSmrg    /* so I can index it directly to calculate mid-points only.	   */
373f80a6dcdSmrg    if (mid > 0) {
374f80a6dcdSmrg	p = spline->next;
375f80a6dcdSmrg	j = 1;
376f80a6dcdSmrg	while (j < n-2) {
377f80a6dcdSmrg	    p1 = p;
378f80a6dcdSmrg	    p = p->next;
379f80a6dcdSmrg	    p2 = p;
380f80a6dcdSmrg	    InsertPoint(p1, MakePoint(midx(p1, p2), midy(p1, p2)));
381f80a6dcdSmrg	    j++;
382f80a6dcdSmrg	}
383f80a6dcdSmrg    }
384f80a6dcdSmrg
385f80a6dcdSmrg    /* Now approximate curve by line segments.		   */
386f80a6dcdSmrg    /* There *should* be the correct number of points now! */
387f80a6dcdSmrg
388f80a6dcdSmrg    p = spline;
389f80a6dcdSmrg    while (p != (Point *)NULL) {
390f80a6dcdSmrg	p1 = p;
391f80a6dcdSmrg	if ((p = p->next) == (Point *)NULL)
392f80a6dcdSmrg	    break;
393f80a6dcdSmrg	p2 = p;
394f80a6dcdSmrg	if ((p = p->next) == (Point *)NULL)
395f80a6dcdSmrg	    break;
396f80a6dcdSmrg	p3 = p;		/* This point becomes first point of next curve */
397f80a6dcdSmrg
398f80a6dcdSmrg	LineApprox(p1, p2, p3);
399f80a6dcdSmrg    }
400f80a6dcdSmrg}
401f80a6dcdSmrg
402f80a6dcdSmrg
403f80a6dcdSmrg/*	p1, p2, and p3 are initially 3 *consecutive* points on the curve. */
404f80a6dcdSmrg/*	For each adjacent pair of points find the mid-point, insert this  */
405f80a6dcdSmrg/*	in the linked list, delete the first of the two used (unless it   */
406f80a6dcdSmrg/*	is the first for this curve).  Repeat this ITERATIONS times.	  */
407f80a6dcdSmrg
408f80a6dcdSmrg/*ARGSUSED*/
409f80a6dcdSmrgstatic void
41065912f00SmrgLineApprox(Point *p1, Point *p2, Point *p3)
411f80a6dcdSmrg{
412f80a6dcdSmrg    Point	*p4, *p;
413f80a6dcdSmrg    int		reps = ITERATIONS;
414f80a6dcdSmrg
415f80a6dcdSmrg    while (reps) {
416f80a6dcdSmrg	for (p = p1; p != (Point *)NULL && p != p3; ) {
417f80a6dcdSmrg	    InsertPoint(p, p4 = MakePoint( midx(p,p->next), midy(p,p->next) ));
418f80a6dcdSmrg	    if (p != p1)
419f80a6dcdSmrg		DeletePoint(p);
420f80a6dcdSmrg	    p = p4->next;		/* skip inserted point! */
421f80a6dcdSmrg	}
422f80a6dcdSmrg	reps--;
423f80a6dcdSmrg    }
424f80a6dcdSmrg}
425f80a6dcdSmrg
426f80a6dcdSmrg
427f80a6dcdSmrg/*	Traverse the linked list, calling DrawLine to approximate the */
428f80a6dcdSmrg/*	spline curve.  Rounding errors are taken into account so that */
429f80a6dcdSmrg/*	the "curve" is continuous, and ends up where expected.	      */
430f80a6dcdSmrg
431f80a6dcdSmrgstatic void
43265912f00SmrgDrawSplineSegments(DviWidget dw)
433f80a6dcdSmrg{
434f80a6dcdSmrg    Point	*p, *q;
435f80a6dcdSmrg    double	x1, y1;
436f80a6dcdSmrg    int		dx, dy;
437f80a6dcdSmrg    double	xpos, ypos;
438f80a6dcdSmrg
439f80a6dcdSmrg    p = spline;
440f80a6dcdSmrg    dx = dy = 0;
441f80a6dcdSmrg
442f80a6dcdSmrg    /* save the start position */
443f80a6dcdSmrg
444f80a6dcdSmrg    xpos = dw->dvi.state->x;
445f80a6dcdSmrg    ypos = dw->dvi.state->y;
446f80a6dcdSmrg
447f80a6dcdSmrg    x1 = y1 = 0.0;
448f80a6dcdSmrg
449f80a6dcdSmrg    while (p != (Point *)NULL) {
450f80a6dcdSmrg	dx = p->x - x1 + 0.5;
451f80a6dcdSmrg	dy = p->y - y1 + 0.5;
452f80a6dcdSmrg	DrawLine (dw, dx, dy);
453f80a6dcdSmrg
454f80a6dcdSmrg	x1 = p->x;
455f80a6dcdSmrg	y1 = p->y;
456f80a6dcdSmrg	dw->dvi.state->x = xpos + x1;
457f80a6dcdSmrg	dw->dvi.state->y = ypos + y1;
458f80a6dcdSmrg
459f80a6dcdSmrg	q = p;
460f80a6dcdSmrg	p = p->next;
461f80a6dcdSmrg	XtFree((char *)q);
462f80a6dcdSmrg    }
463f80a6dcdSmrg    spline = (Point *)NULL;
464f80a6dcdSmrg}
465f80a6dcdSmrg
466f80a6dcdSmrg
467f80a6dcdSmrg/*	Malloc memory for a Point, and initialise the elements to x, y, NULL */
468f80a6dcdSmrg/*	Return a pointer to the new Point.				     */
469f80a6dcdSmrg
470f80a6dcdSmrgstatic Point *
47165912f00SmrgMakePoint(double x, double y)
472f80a6dcdSmrg{
473f80a6dcdSmrg    Point	*p;
474f80a6dcdSmrg
475f80a6dcdSmrg    p = (Point *) XtMalloc (sizeof (Point));
476f80a6dcdSmrg    p->x = x;
477f80a6dcdSmrg    p->y = y;
478f80a6dcdSmrg    p->next = (Point *)NULL;
479f80a6dcdSmrg
480f80a6dcdSmrg    return(p);
481f80a6dcdSmrg}
482f80a6dcdSmrg
483f80a6dcdSmrg
484f80a6dcdSmrg/*	Insert point q in linked list after point p. */
485f80a6dcdSmrg
486f80a6dcdSmrgstatic void
48765912f00SmrgInsertPoint(Point *p, Point *q)
488f80a6dcdSmrg{
489f80a6dcdSmrg    /* point q to the next point */
490f80a6dcdSmrg    q->next = p->next;
491f80a6dcdSmrg
492f80a6dcdSmrg    /* point p to new inserted one */
493f80a6dcdSmrg    p->next = q;
494f80a6dcdSmrg}
495f80a6dcdSmrg
496f80a6dcdSmrg/*	Delete point p from the linked list. */
497f80a6dcdSmrg
498f80a6dcdSmrgstatic void
49965912f00SmrgDeletePoint(Point *p)
500f80a6dcdSmrg{
501f80a6dcdSmrg    Point	*tmp;
502f80a6dcdSmrg
503f80a6dcdSmrg    tmp = p->next;
504f80a6dcdSmrg    p->x = p->next->x;
505f80a6dcdSmrg    p->y = p->next->y;
506f80a6dcdSmrg    p->next = p->next->next;
507f80a6dcdSmrg    XtFree((char *)tmp);
508f80a6dcdSmrg}
509