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