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*/
4100994698Smrg#ifdef HAVE_CONFIG_H
4200994698Smrg# include "config.h"
4300994698Smrg#endif
44f80a6dcdSmrg
45f80a6dcdSmrg#include <X11/Xos.h>
46f80a6dcdSmrg#include <X11/IntrinsicP.h>
47f80a6dcdSmrg#include <X11/StringDefs.h>
48f80a6dcdSmrg#include <stdio.h>
49f80a6dcdSmrg#include <ctype.h>
50f80a6dcdSmrg#include <math.h>
51f80a6dcdSmrg#include "DviP.h"
52f80a6dcdSmrg#include <stdlib.h>
53f80a6dcdSmrg
54f80a6dcdSmrg#ifndef M_PI
55f80a6dcdSmrg#define M_PI 3.14159265358979323846264338327950
56f80a6dcdSmrg#endif
57f80a6dcdSmrg
58f80a6dcdSmrg/*	the following are for use in the spline approximation algorithm */
59f80a6dcdSmrg
6000994698Smrgtypedef struct Point {
6100994698Smrg    double x;
6200994698Smrg    double y;
6300994698Smrg    struct Point *next;
64f80a6dcdSmrg} Point;
65f80a6dcdSmrg
6600994698Smrg#define	ITERATIONS	10      /* iterations to approximate spline */
67f80a6dcdSmrg
6800994698Smrg#define	midx(p,q)	((p->x + q->x) / 2)     /* mid x point on pq */
6900994698Smrg#define	midy(p,q)	((p->y + q->y) / 2)     /* mid y point on pq */
70f80a6dcdSmrg
71f80a6dcdSmrg#define	length(p,q)	sqrt(((q->x - p->x)*(q->x - p->x)) \
72f80a6dcdSmrg			     + ((q->y - p->y)*(q->y - p->y))) /* length of pq */
73f80a6dcdSmrg
7400994698Smrgstatic Point *spline = (Point *) NULL;  /* head of spline linked list */
75f80a6dcdSmrg
7600994698Smrgstatic void     ApproxSpline(int n);
7700994698Smrgstatic void     DeletePoint(Point *p);
7800994698Smrgstatic void     DrawSplineSegments(DviWidget dw);
7900994698Smrgstatic int      GetSpline(const char *s);
8000994698Smrgstatic void     InsertPoint(Point *p, Point *q);
8100994698Smrgstatic void     LineApprox(Point *p1, Point *p2, Point *p3);
8200994698Smrgstatic Point *  MakePoint(double x, double y);
83f80a6dcdSmrg
84f80a6dcdSmrg#ifdef USE_XFT
85f80a6dcdSmrgstatic void
8600994698SmrgDrawText(DviWidget dw)
87f80a6dcdSmrg{
8800994698Smrg    XftFont *font = dw->dvi.cache.font;
8900994698Smrg
9000994698Smrg    for (int i = 0; i <= dw->dvi.cache.index; i++) {
9100994698Smrg        if (dw->dvi.cache.cache[i].font)
9200994698Smrg            font = dw->dvi.cache.cache[i].font;
9300994698Smrg        XftDrawString8(dw->dvi.draw, &dw->dvi.black,
9400994698Smrg                       font,
9500994698Smrg                       dw->dvi.cache.cache[i].x,
9600994698Smrg                       dw->dvi.cache.start_y,
9700994698Smrg                       (unsigned char *) dw->dvi.cache.cache[i].chars,
9800994698Smrg                       dw->dvi.cache.cache[i].nchars);
99f80a6dcdSmrg    }
100f80a6dcdSmrg}
101f80a6dcdSmrg#endif
102f80a6dcdSmrg
103f80a6dcdSmrgvoid
10400994698SmrgFlushCharCache(DviWidget dw)
105f80a6dcdSmrg{
10600994698Smrg    int xx = ToX(dw, dw->dvi.state->x);
10700994698Smrg    int yx = ToX(dw, dw->dvi.state->y);
108f80a6dcdSmrg
10900994698Smrg    if (dw->dvi.cache.char_index != 0) {
110f80a6dcdSmrg#ifdef USE_XFT
11100994698Smrg        DrawText(dw);
112f80a6dcdSmrg#else
11300994698Smrg        XDrawText(XtDisplay(dw), XtWindow(dw), dw->dvi.normal_GC,
11400994698Smrg                  dw->dvi.cache.start_x, dw->dvi.cache.start_y,
11500994698Smrg                  dw->dvi.cache.cache, dw->dvi.cache.index + 1);
116f80a6dcdSmrg#endif
117f80a6dcdSmrg    }
118f80a6dcdSmrg    dw->dvi.cache.index = 0;
119f80a6dcdSmrg    dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
120f80a6dcdSmrg    if (dw->dvi.noPolyText)
12100994698Smrg        dw->dvi.cache.max = 1;
122f80a6dcdSmrg    dw->dvi.cache.char_index = 0;
123f80a6dcdSmrg    dw->dvi.cache.cache[0].nchars = 0;
124f80a6dcdSmrg    dw->dvi.cache.start_x = dw->dvi.cache.x = xx;
125f80a6dcdSmrg    dw->dvi.cache.start_y = dw->dvi.cache.y = yx;
126f80a6dcdSmrg}
127f80a6dcdSmrg
128f80a6dcdSmrgvoid
12900994698SmrgSetGCForDraw(DviWidget dw)
130f80a6dcdSmrg{
131f80a6dcdSmrg    if (dw->dvi.state->line_style != dw->dvi.line_style ||
13200994698Smrg        dw->dvi.state->line_width != dw->dvi.line_width) {
13300994698Smrg        int lw = ToX(dw, dw->dvi.state->line_width);
13400994698Smrg
13500994698Smrg        if (lw <= 1)
13600994698Smrg            lw = 0;
13700994698Smrg        XSetLineAttributes(XtDisplay(dw), dw->dvi.normal_GC,
13800994698Smrg                           lw, LineSolid, CapButt, JoinMiter);
13900994698Smrg        dw->dvi.line_style = dw->dvi.state->line_style;
14000994698Smrg        dw->dvi.line_width = dw->dvi.state->line_width;
141f80a6dcdSmrg    }
142f80a6dcdSmrg}
143f80a6dcdSmrg
144f80a6dcdSmrgvoid
14500994698SmrgDrawLine(DviWidget dw, int x, int y)
146f80a6dcdSmrg{
147f80a6dcdSmrg    if (dw->dvi.display_enable)
14800994698Smrg        XDrawLine(XtDisplay(dw), XtWindow(dw), dw->dvi.normal_GC,
14900994698Smrg                  ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y),
15000994698Smrg                  ToX(dw, dw->dvi.state->x + x), ToX(dw, dw->dvi.state->y + y));
151f80a6dcdSmrg    dw->dvi.state->x += x;
152f80a6dcdSmrg    dw->dvi.state->y += y;
153f80a6dcdSmrg}
154f80a6dcdSmrg
155f80a6dcdSmrgvoid
15600994698SmrgDrawCircle(DviWidget dw, int diameter)
157f80a6dcdSmrg{
158f80a6dcdSmrg    if (dw->dvi.display_enable)
15900994698Smrg        XDrawArc(XtDisplay(dw), XtWindow(dw), dw->dvi.normal_GC,
16000994698Smrg                 ToX(dw, dw->dvi.state->x),
16100994698Smrg                 ToX(dw, dw->dvi.state->y - (diameter / 2)),
16200994698Smrg                 ToX(dw, diameter), ToX(dw, diameter), 0, 360 * 64);
163f80a6dcdSmrg    dw->dvi.state->x += diameter;
164f80a6dcdSmrg}
165f80a6dcdSmrg
166f80a6dcdSmrgvoid
16700994698SmrgDrawEllipse(DviWidget dw, int a, int b)
168f80a6dcdSmrg{
169f80a6dcdSmrg    if (dw->dvi.display_enable)
17000994698Smrg        XDrawArc(XtDisplay(dw), XtWindow(dw), dw->dvi.normal_GC,
17100994698Smrg                 ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y - (b / 2)),
17200994698Smrg                 ToX(dw, a), ToX(dw, b), 0, 360 * 64);
173f80a6dcdSmrg    dw->dvi.state->x += a;
174f80a6dcdSmrg}
175f80a6dcdSmrg
176f80a6dcdSmrg/*	Convert angle in degrees to 64ths of a degree */
177f80a6dcdSmrg
178f80a6dcdSmrgstatic int
179f80a6dcdSmrgConvertAngle(int theta)
180f80a6dcdSmrg{
18100994698Smrg    return (theta * 64);
182f80a6dcdSmrg}
183f80a6dcdSmrg
184f80a6dcdSmrgvoid
18500994698SmrgDrawArc(DviWidget dw, int x0, int y0, int x1, int y1)
186f80a6dcdSmrg{
187f80a6dcdSmrg    /* centre */
18800994698Smrg    int xc = dw->dvi.state->x + x0;
18900994698Smrg    int yc = dw->dvi.state->y + y0;
190f80a6dcdSmrg
191f80a6dcdSmrg    /* to */
19200994698Smrg    int x2 = xc + x1;
19300994698Smrg    int y2 = yc + y1;
194f80a6dcdSmrg
195f80a6dcdSmrg    dw->dvi.state->x = x2;
196f80a6dcdSmrg    dw->dvi.state->y = y2;
197f80a6dcdSmrg
198f80a6dcdSmrg    if (dw->dvi.display_enable) {
19900994698Smrg        int angle1, angle2;
20000994698Smrg
20100994698Smrg        /* radius */
20200994698Smrg        int r = (int) sqrt((float) x1 * x1 + (float) y1 * y1);
20300994698Smrg
20400994698Smrg        /* start and finish angles */
20500994698Smrg        if (x0 == 0) {
20600994698Smrg            if (y0 >= 0)
20700994698Smrg                angle1 = 90;
20800994698Smrg            else
20900994698Smrg                angle1 = 270;
21000994698Smrg        }
21100994698Smrg        else {
21200994698Smrg            angle1 = (int) (atan((double) (y0) / (double) (x0)) * 180 / M_PI);
21300994698Smrg            if (x0 > 0)
21400994698Smrg                angle1 = 180 - angle1;
21500994698Smrg            else
21600994698Smrg                angle1 = -angle1;
21700994698Smrg        }
21800994698Smrg
21900994698Smrg        if (x1 == 0) {
22000994698Smrg            if (y1 <= 0)
22100994698Smrg                angle2 = 90;
22200994698Smrg            else
22300994698Smrg                angle2 = 270;
22400994698Smrg        }
22500994698Smrg        else {
22600994698Smrg            angle2 = (int) (atan((double) (y1) / (double) (x1)) * 180 / M_PI);
22700994698Smrg            if (x1 < 0)
22800994698Smrg                angle2 = 180 - angle2;
22900994698Smrg            else
23000994698Smrg                angle2 = -angle2;
23100994698Smrg        }
23200994698Smrg
23300994698Smrg        if (angle1 < 0)
23400994698Smrg            angle1 += 360;
23500994698Smrg        if (angle2 < 0)
23600994698Smrg            angle2 += 360;
23700994698Smrg
23800994698Smrg        if (angle2 < angle1)
23900994698Smrg            angle1 -= 360;
24000994698Smrg        angle2 = angle2 - angle1;
24100994698Smrg
24200994698Smrg        angle1 = ConvertAngle(angle1);
24300994698Smrg        angle2 = ConvertAngle(angle2);
24400994698Smrg
24500994698Smrg        XDrawArc(XtDisplay(dw), XtWindow(dw), dw->dvi.normal_GC,
24600994698Smrg                 ToX(dw, xc - r), ToX(dw, yc - r),
24700994698Smrg                 ToX(dw, 2 * r), ToX(dw, 2 * r), angle1, angle2);
248f80a6dcdSmrg    }
249f80a6dcdSmrg}
250f80a6dcdSmrg
251f80a6dcdSmrg/* copy next non-blank string from p to temp, update p */
252f80a6dcdSmrg
253c166fba9Smrgstatic const char *
25400994698Smrggetstr(const char *p, char *temp, size_t temp_size)
255f80a6dcdSmrg{
256f80a6dcdSmrg    while (*p == ' ' || *p == '\t' || *p == '\n')
25700994698Smrg        p++;
258f80a6dcdSmrg    if (*p == '\0') {
25900994698Smrg        temp[0] = 0;
26000994698Smrg        return ((char *) NULL);
26100994698Smrg    }
26200994698Smrg    while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') {
26300994698Smrg        /* leave room for trailing NIL byte */
26400994698Smrg        if (temp_size > 1) {
26500994698Smrg            *temp++ = *p++;
26600994698Smrg            temp_size--;
26700994698Smrg        }
268f80a6dcdSmrg    }
269f80a6dcdSmrg    *temp = '\0';
27000994698Smrg    return (p);
271f80a6dcdSmrg}
272f80a6dcdSmrg
273f80a6dcdSmrg/*	Draw a spline by approximating with short lines.      */
274f80a6dcdSmrg
275f80a6dcdSmrg/*ARGSUSED*/
276f80a6dcdSmrgvoid
27700994698SmrgDrawSpline(DviWidget dw, const char *s, int len)
278f80a6dcdSmrg{
27900994698Smrg    int n;
280f80a6dcdSmrg
281f80a6dcdSmrg    /* get coordinate pairs into spline linked list */
282f80a6dcdSmrg    if ((n = GetSpline(s)) <= 0)
28300994698Smrg        return;
284f80a6dcdSmrg
285f80a6dcdSmrg    ApproxSpline(n);
286f80a6dcdSmrg
287f80a6dcdSmrg    DrawSplineSegments(dw);
288f80a6dcdSmrg}
289f80a6dcdSmrg
290f80a6dcdSmrg
291f80a6dcdSmrg/*	Parse string s to create a linked list of Point's with spline */
292f80a6dcdSmrg/*	as its head.  Return the number of coordinate pairs found.    */
293f80a6dcdSmrg
294f80a6dcdSmrgstatic int
295c166fba9SmrgGetSpline(const char *s)
296f80a6dcdSmrg{
29700994698Smrg    double x, y;
29800994698Smrg    int n = 0;
29900994698Smrg    Point *pt;
30000994698Smrg    const char *p = s;
30100994698Smrg    char d[10];
302f80a6dcdSmrg
303f80a6dcdSmrg    if (!*p)
30400994698Smrg        return (n);
305f80a6dcdSmrg
306f80a6dcdSmrg    pt = spline = MakePoint(0.0, 0.0);
307f80a6dcdSmrg    n = 1;
308f80a6dcdSmrg    x = y = 0.0;
309f80a6dcdSmrg    p = s;
310f80a6dcdSmrg    while (p && *p) {
31100994698Smrg        double x1, y1;
31200994698Smrg
31300994698Smrg        if ((p = getstr(p, d, sizeof(d))) == (const char *) NULL)
31400994698Smrg            break;
31500994698Smrg        x1 = x + atof(d);
31600994698Smrg        if ((p = getstr(p, d, sizeof(d))) == (const char *) NULL)
31700994698Smrg            break;
31800994698Smrg        y1 = y + atof(d);
31900994698Smrg        pt->next = MakePoint(x1, y1);
32000994698Smrg        pt = pt->next;
32100994698Smrg        x = pt->x;
32200994698Smrg        y = pt->y;
32300994698Smrg        n++;
324f80a6dcdSmrg    }
325f80a6dcdSmrg
326f80a6dcdSmrg    /* number of pairs of points */
327f80a6dcdSmrg
32800994698Smrg    return (n);
329f80a6dcdSmrg}
330f80a6dcdSmrg
331f80a6dcdSmrg/*	Approximate a spline by lines generated by iterations of the	  */
332f80a6dcdSmrg/*	approximation algorithm from the original n points in the spline. */
333f80a6dcdSmrg
334f80a6dcdSmrgstatic void
33565912f00SmrgApproxSpline(int n)
336f80a6dcdSmrg{
33700994698Smrg    int mid;
33800994698Smrg    Point *p1, *p2, *p3, *p;
339f80a6dcdSmrg
340f80a6dcdSmrg    if (n < 3)
34100994698Smrg        return;
342f80a6dcdSmrg
343f80a6dcdSmrg    /* number of mid-points to calculate */
344f80a6dcdSmrg    mid = n - 3;
345f80a6dcdSmrg
346f80a6dcdSmrg    /* remember original points are stored as an array of n points */
34700994698Smrg    /* so I can index it directly to calculate mid-points only.    */
348f80a6dcdSmrg    if (mid > 0) {
34900994698Smrg        int j;
35000994698Smrg
35100994698Smrg        p = spline->next;
35200994698Smrg        j = 1;
35300994698Smrg        while (j < n - 2) {
35400994698Smrg            p1 = p;
35500994698Smrg            p = p->next;
35600994698Smrg            p2 = p;
35700994698Smrg            InsertPoint(p1, MakePoint(midx(p1, p2), midy(p1, p2)));
35800994698Smrg            j++;
35900994698Smrg        }
360f80a6dcdSmrg    }
361f80a6dcdSmrg
36200994698Smrg    /* Now approximate curve by line segments.             */
363f80a6dcdSmrg    /* There *should* be the correct number of points now! */
364f80a6dcdSmrg
365f80a6dcdSmrg    p = spline;
36600994698Smrg    while (p != (Point *) NULL) {
36700994698Smrg        p1 = p;
36800994698Smrg        if ((p = p->next) == (Point *) NULL)
36900994698Smrg            break;
37000994698Smrg        p2 = p;
37100994698Smrg        if ((p = p->next) == (Point *) NULL)
37200994698Smrg            break;
37300994698Smrg        p3 = p;         /* This point becomes first point of next curve */
37400994698Smrg
37500994698Smrg        LineApprox(p1, p2, p3);
376f80a6dcdSmrg    }
377f80a6dcdSmrg}
378f80a6dcdSmrg
379f80a6dcdSmrg/*	p1, p2, and p3 are initially 3 *consecutive* points on the curve. */
380f80a6dcdSmrg/*	For each adjacent pair of points find the mid-point, insert this  */
381f80a6dcdSmrg/*	in the linked list, delete the first of the two used (unless it   */
382f80a6dcdSmrg/*	is the first for this curve).  Repeat this ITERATIONS times.	  */
383f80a6dcdSmrg
384f80a6dcdSmrg/*ARGSUSED*/
385f80a6dcdSmrgstatic void
38665912f00SmrgLineApprox(Point *p1, Point *p2, Point *p3)
387f80a6dcdSmrg{
38800994698Smrg    int reps = ITERATIONS;
389f80a6dcdSmrg
390f80a6dcdSmrg    while (reps) {
39100994698Smrg        for (Point *p = p1; p != (Point *) NULL && p != p3;) {
39200994698Smrg            Point *p4 = MakePoint(midx(p, p->next), midy(p, p->next));
39300994698Smrg
39400994698Smrg            InsertPoint(p, p4);
39500994698Smrg            if (p != p1)
39600994698Smrg                DeletePoint(p);
39700994698Smrg            p = p4->next;       /* skip inserted point! */
39800994698Smrg        }
39900994698Smrg        reps--;
400f80a6dcdSmrg    }
401f80a6dcdSmrg}
402f80a6dcdSmrg
403f80a6dcdSmrg
404f80a6dcdSmrg/*	Traverse the linked list, calling DrawLine to approximate the */
405f80a6dcdSmrg/*	spline curve.  Rounding errors are taken into account so that */
406f80a6dcdSmrg/*	the "curve" is continuous, and ends up where expected.	      */
407f80a6dcdSmrg
408f80a6dcdSmrgstatic void
40965912f00SmrgDrawSplineSegments(DviWidget dw)
410f80a6dcdSmrg{
41100994698Smrg    Point *p = spline;
412f80a6dcdSmrg
413f80a6dcdSmrg    /* save the start position */
41400994698Smrg    double xpos = dw->dvi.state->x;
41500994698Smrg    double ypos = dw->dvi.state->y;
41600994698Smrg
41700994698Smrg    double x1 = 0.0, y1 = 0.0;
418f80a6dcdSmrg
41900994698Smrg    while (p != (Point *) NULL) {
42000994698Smrg        int dx = p->x - x1 + 0.5;
42100994698Smrg        int dy = p->y - y1 + 0.5;
422f80a6dcdSmrg
42300994698Smrg        DrawLine(dw, dx, dy);
424f80a6dcdSmrg
42500994698Smrg        x1 = p->x;
42600994698Smrg        y1 = p->y;
42700994698Smrg        dw->dvi.state->x = xpos + x1;
42800994698Smrg        dw->dvi.state->y = ypos + y1;
429f80a6dcdSmrg
43000994698Smrg        Point *q = p;
431f80a6dcdSmrg
43200994698Smrg        p = p->next;
43300994698Smrg        XtFree((char *) q);
434f80a6dcdSmrg    }
43500994698Smrg    spline = (Point *) NULL;
436f80a6dcdSmrg}
437f80a6dcdSmrg
438f80a6dcdSmrg/*	Malloc memory for a Point, and initialise the elements to x, y, NULL */
439f80a6dcdSmrg/*	Return a pointer to the new Point.				     */
440f80a6dcdSmrg
441f80a6dcdSmrgstatic Point *
44265912f00SmrgMakePoint(double x, double y)
443f80a6dcdSmrg{
44400994698Smrg    Point *p = (Point *) XtMalloc(sizeof(Point));
445f80a6dcdSmrg
446f80a6dcdSmrg    p->x = x;
447f80a6dcdSmrg    p->y = y;
44800994698Smrg    p->next = (Point *) NULL;
449f80a6dcdSmrg
45000994698Smrg    return (p);
451f80a6dcdSmrg}
452f80a6dcdSmrg
453f80a6dcdSmrg/*	Insert point q in linked list after point p. */
454f80a6dcdSmrg
455f80a6dcdSmrgstatic void
45665912f00SmrgInsertPoint(Point *p, Point *q)
457f80a6dcdSmrg{
458f80a6dcdSmrg    /* point q to the next point */
459f80a6dcdSmrg    q->next = p->next;
460f80a6dcdSmrg
461f80a6dcdSmrg    /* point p to new inserted one */
462f80a6dcdSmrg    p->next = q;
463f80a6dcdSmrg}
464f80a6dcdSmrg
465f80a6dcdSmrg/*	Delete point p from the linked list. */
466f80a6dcdSmrg
467f80a6dcdSmrgstatic void
46865912f00SmrgDeletePoint(Point *p)
469f80a6dcdSmrg{
47000994698Smrg    Point *tmp = p->next;
471f80a6dcdSmrg
472f80a6dcdSmrg    p->x = p->next->x;
473f80a6dcdSmrg    p->y = p->next->y;
474f80a6dcdSmrg    p->next = p->next->next;
47500994698Smrg    XtFree((char *) tmp);
476f80a6dcdSmrg}
477