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