/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tktrig.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tktrig.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 69 by dashley, Sat Nov 5 10:54:17 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkTrig.c --   * tkTrig.c --
5   *   *
6   *      This file contains a collection of trigonometry utility   *      This file contains a collection of trigonometry utility
7   *      routines that are used by Tk and in particular by the   *      routines that are used by Tk and in particular by the
8   *      canvas code.  It also has miscellaneous geometry functions   *      canvas code.  It also has miscellaneous geometry functions
9   *      used by canvases.   *      used by canvases.
10   *   *
11   * Copyright (c) 1992-1994 The Regents of the University of California.   * Copyright (c) 1992-1994 The Regents of the University of California.
12   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
13   *   *
14   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
15   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16   *   *
17   * RCS: @(#) $Id: tktrig.c,v 1.1.1.1 2001/06/13 05:11:18 dtashley Exp $   * RCS: @(#) $Id: tktrig.c,v 1.1.1.1 2001/06/13 05:11:18 dtashley Exp $
18   */   */
19    
20  #include <stdio.h>  #include <stdio.h>
21  #include "tkInt.h"  #include "tkInt.h"
22  #include "tkPort.h"  #include "tkPort.h"
23  #include "tkCanvas.h"  #include "tkCanvas.h"
24    
25  #undef MIN  #undef MIN
26  #define MIN(a,b) (((a) < (b)) ? (a) : (b))  #define MIN(a,b) (((a) < (b)) ? (a) : (b))
27  #undef MAX  #undef MAX
28  #define MAX(a,b) (((a) > (b)) ? (a) : (b))  #define MAX(a,b) (((a) > (b)) ? (a) : (b))
29  #ifndef PI  #ifndef PI
30  #   define PI 3.14159265358979323846  #   define PI 3.14159265358979323846
31  #endif /* PI */  #endif /* PI */
32    
33  /*  /*
34   *--------------------------------------------------------------   *--------------------------------------------------------------
35   *   *
36   * TkLineToPoint --   * TkLineToPoint --
37   *   *
38   *      Compute the distance from a point to a finite line segment.   *      Compute the distance from a point to a finite line segment.
39   *   *
40   * Results:   * Results:
41   *      The return value is the distance from the line segment   *      The return value is the distance from the line segment
42   *      whose end-points are *end1Ptr and *end2Ptr to the point   *      whose end-points are *end1Ptr and *end2Ptr to the point
43   *      given by *pointPtr.   *      given by *pointPtr.
44   *   *
45   * Side effects:   * Side effects:
46   *      None.   *      None.
47   *   *
48   *--------------------------------------------------------------   *--------------------------------------------------------------
49   */   */
50    
51  double  double
52  TkLineToPoint(end1Ptr, end2Ptr, pointPtr)  TkLineToPoint(end1Ptr, end2Ptr, pointPtr)
53      double end1Ptr[2];          /* Coordinates of first end-point of line. */      double end1Ptr[2];          /* Coordinates of first end-point of line. */
54      double end2Ptr[2];          /* Coordinates of second end-point of line. */      double end2Ptr[2];          /* Coordinates of second end-point of line. */
55      double pointPtr[2];         /* Points to coords for point. */      double pointPtr[2];         /* Points to coords for point. */
56  {  {
57      double x, y;      double x, y;
58    
59      /*      /*
60       * Compute the point on the line that is closest to the       * Compute the point on the line that is closest to the
61       * point.  This must be done separately for vertical edges,       * point.  This must be done separately for vertical edges,
62       * horizontal edges, and other edges.       * horizontal edges, and other edges.
63       */       */
64    
65      if (end1Ptr[0] == end2Ptr[0]) {      if (end1Ptr[0] == end2Ptr[0]) {
66    
67          /*          /*
68           * Vertical edge.           * Vertical edge.
69           */           */
70    
71          x = end1Ptr[0];          x = end1Ptr[0];
72          if (end1Ptr[1] >= end2Ptr[1]) {          if (end1Ptr[1] >= end2Ptr[1]) {
73              y = MIN(end1Ptr[1], pointPtr[1]);              y = MIN(end1Ptr[1], pointPtr[1]);
74              y = MAX(y, end2Ptr[1]);              y = MAX(y, end2Ptr[1]);
75          } else {          } else {
76              y = MIN(end2Ptr[1], pointPtr[1]);              y = MIN(end2Ptr[1], pointPtr[1]);
77              y = MAX(y, end1Ptr[1]);              y = MAX(y, end1Ptr[1]);
78          }          }
79      } else if (end1Ptr[1] == end2Ptr[1]) {      } else if (end1Ptr[1] == end2Ptr[1]) {
80    
81          /*          /*
82           * Horizontal edge.           * Horizontal edge.
83           */           */
84    
85          y = end1Ptr[1];          y = end1Ptr[1];
86          if (end1Ptr[0] >= end2Ptr[0]) {          if (end1Ptr[0] >= end2Ptr[0]) {
87              x = MIN(end1Ptr[0], pointPtr[0]);              x = MIN(end1Ptr[0], pointPtr[0]);
88              x = MAX(x, end2Ptr[0]);              x = MAX(x, end2Ptr[0]);
89          } else {          } else {
90              x = MIN(end2Ptr[0], pointPtr[0]);              x = MIN(end2Ptr[0], pointPtr[0]);
91              x = MAX(x, end1Ptr[0]);              x = MAX(x, end1Ptr[0]);
92          }          }
93      } else {      } else {
94          double m1, b1, m2, b2;          double m1, b1, m2, b2;
95    
96          /*          /*
97           * The edge is neither horizontal nor vertical.  Convert the           * The edge is neither horizontal nor vertical.  Convert the
98           * edge to a line equation of the form y = m1*x + b1.  Then           * edge to a line equation of the form y = m1*x + b1.  Then
99           * compute a line perpendicular to this edge but passing           * compute a line perpendicular to this edge but passing
100           * through the point, also in the form y = m2*x + b2.           * through the point, also in the form y = m2*x + b2.
101           */           */
102    
103          m1 = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);          m1 = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);
104          b1 = end1Ptr[1] - m1*end1Ptr[0];          b1 = end1Ptr[1] - m1*end1Ptr[0];
105          m2 = -1.0/m1;          m2 = -1.0/m1;
106          b2 = pointPtr[1] - m2*pointPtr[0];          b2 = pointPtr[1] - m2*pointPtr[0];
107          x = (b2 - b1)/(m1 - m2);          x = (b2 - b1)/(m1 - m2);
108          y = m1*x + b1;          y = m1*x + b1;
109          if (end1Ptr[0] > end2Ptr[0]) {          if (end1Ptr[0] > end2Ptr[0]) {
110              if (x > end1Ptr[0]) {              if (x > end1Ptr[0]) {
111                  x = end1Ptr[0];                  x = end1Ptr[0];
112                  y = end1Ptr[1];                  y = end1Ptr[1];
113              } else if (x < end2Ptr[0]) {              } else if (x < end2Ptr[0]) {
114                  x = end2Ptr[0];                  x = end2Ptr[0];
115                  y = end2Ptr[1];                  y = end2Ptr[1];
116              }              }
117          } else {          } else {
118              if (x > end2Ptr[0]) {              if (x > end2Ptr[0]) {
119                  x = end2Ptr[0];                  x = end2Ptr[0];
120                  y = end2Ptr[1];                  y = end2Ptr[1];
121              } else if (x < end1Ptr[0]) {              } else if (x < end1Ptr[0]) {
122                  x = end1Ptr[0];                  x = end1Ptr[0];
123                  y = end1Ptr[1];                  y = end1Ptr[1];
124              }              }
125          }          }
126      }      }
127    
128      /*      /*
129       * Compute the distance to the closest point.       * Compute the distance to the closest point.
130       */       */
131    
132      return hypot(pointPtr[0] - x, pointPtr[1] - y);      return hypot(pointPtr[0] - x, pointPtr[1] - y);
133  }  }
134    
135  /*  /*
136   *--------------------------------------------------------------   *--------------------------------------------------------------
137   *   *
138   * TkLineToArea --   * TkLineToArea --
139   *   *
140   *      Determine whether a line lies entirely inside, entirely   *      Determine whether a line lies entirely inside, entirely
141   *      outside, or overlapping a given rectangular area.   *      outside, or overlapping a given rectangular area.
142   *   *
143   * Results:   * Results:
144   *      -1 is returned if the line given by end1Ptr and end2Ptr   *      -1 is returned if the line given by end1Ptr and end2Ptr
145   *      is entirely outside the rectangle given by rectPtr.  0 is   *      is entirely outside the rectangle given by rectPtr.  0 is
146   *      returned if the polygon overlaps the rectangle, and 1 is   *      returned if the polygon overlaps the rectangle, and 1 is
147   *      returned if the polygon is entirely inside the rectangle.   *      returned if the polygon is entirely inside the rectangle.
148   *   *
149   * Side effects:   * Side effects:
150   *      None.   *      None.
151   *   *
152   *--------------------------------------------------------------   *--------------------------------------------------------------
153   */   */
154    
155  int  int
156  TkLineToArea(end1Ptr, end2Ptr, rectPtr)  TkLineToArea(end1Ptr, end2Ptr, rectPtr)
157      double end1Ptr[2];          /* X and y coordinates for one endpoint      double end1Ptr[2];          /* X and y coordinates for one endpoint
158                                   * of line. */                                   * of line. */
159      double end2Ptr[2];          /* X and y coordinates for other endpoint      double end2Ptr[2];          /* X and y coordinates for other endpoint
160                                   * of line. */                                   * of line. */
161      double rectPtr[4];          /* Points to coords for rectangle, in the      double rectPtr[4];          /* Points to coords for rectangle, in the
162                                   * order x1, y1, x2, y2.  X1 must be no                                   * order x1, y1, x2, y2.  X1 must be no
163                                   * larger than x2, and y1 no larger than y2. */                                   * larger than x2, and y1 no larger than y2. */
164  {  {
165      int inside1, inside2;      int inside1, inside2;
166    
167      /*      /*
168       * First check the two points individually to see whether they       * First check the two points individually to see whether they
169       * are inside the rectangle or not.       * are inside the rectangle or not.
170       */       */
171    
172      inside1 = (end1Ptr[0] >= rectPtr[0]) && (end1Ptr[0] <= rectPtr[2])      inside1 = (end1Ptr[0] >= rectPtr[0]) && (end1Ptr[0] <= rectPtr[2])
173              && (end1Ptr[1] >= rectPtr[1]) && (end1Ptr[1] <= rectPtr[3]);              && (end1Ptr[1] >= rectPtr[1]) && (end1Ptr[1] <= rectPtr[3]);
174      inside2 = (end2Ptr[0] >= rectPtr[0]) && (end2Ptr[0] <= rectPtr[2])      inside2 = (end2Ptr[0] >= rectPtr[0]) && (end2Ptr[0] <= rectPtr[2])
175              && (end2Ptr[1] >= rectPtr[1]) && (end2Ptr[1] <= rectPtr[3]);              && (end2Ptr[1] >= rectPtr[1]) && (end2Ptr[1] <= rectPtr[3]);
176      if (inside1 != inside2) {      if (inside1 != inside2) {
177          return 0;          return 0;
178      }      }
179      if (inside1 & inside2) {      if (inside1 & inside2) {
180          return 1;          return 1;
181      }      }
182    
183      /*      /*
184       * Both points are outside the rectangle, but still need to check       * Both points are outside the rectangle, but still need to check
185       * for intersections between the line and the rectangle.  Horizontal       * for intersections between the line and the rectangle.  Horizontal
186       * and vertical lines are particularly easy, so handle them       * and vertical lines are particularly easy, so handle them
187       * separately.       * separately.
188       */       */
189    
190      if (end1Ptr[0] == end2Ptr[0]) {      if (end1Ptr[0] == end2Ptr[0]) {
191          /*          /*
192           * Vertical line.           * Vertical line.
193           */           */
194            
195          if (((end1Ptr[1] >= rectPtr[1]) ^ (end2Ptr[1] >= rectPtr[1]))          if (((end1Ptr[1] >= rectPtr[1]) ^ (end2Ptr[1] >= rectPtr[1]))
196                  && (end1Ptr[0] >= rectPtr[0])                  && (end1Ptr[0] >= rectPtr[0])
197                  && (end1Ptr[0] <= rectPtr[2])) {                  && (end1Ptr[0] <= rectPtr[2])) {
198              return 0;              return 0;
199          }          }
200      } else if (end1Ptr[1] == end2Ptr[1]) {      } else if (end1Ptr[1] == end2Ptr[1]) {
201          /*          /*
202           * Horizontal line.           * Horizontal line.
203           */           */
204            
205          if (((end1Ptr[0] >= rectPtr[0]) ^ (end2Ptr[0] >= rectPtr[0]))          if (((end1Ptr[0] >= rectPtr[0]) ^ (end2Ptr[0] >= rectPtr[0]))
206                  && (end1Ptr[1] >= rectPtr[1])                  && (end1Ptr[1] >= rectPtr[1])
207                  && (end1Ptr[1] <= rectPtr[3])) {                  && (end1Ptr[1] <= rectPtr[3])) {
208              return 0;              return 0;
209          }          }
210      } else {      } else {
211          double m, x, y, low, high;          double m, x, y, low, high;
212            
213          /*          /*
214           * Diagonal line.  Compute slope of line and use           * Diagonal line.  Compute slope of line and use
215           * for intersection checks against each of the           * for intersection checks against each of the
216           * sides of the rectangle: left, right, bottom, top.           * sides of the rectangle: left, right, bottom, top.
217           */           */
218            
219          m = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);          m = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);
220          if (end1Ptr[0] < end2Ptr[0]) {          if (end1Ptr[0] < end2Ptr[0]) {
221              low = end1Ptr[0];  high = end2Ptr[0];              low = end1Ptr[0];  high = end2Ptr[0];
222          } else {          } else {
223              low = end2Ptr[0]; high = end1Ptr[0];              low = end2Ptr[0]; high = end1Ptr[0];
224          }          }
225            
226          /*          /*
227           * Left edge.           * Left edge.
228           */           */
229            
230          y = end1Ptr[1] + (rectPtr[0] - end1Ptr[0])*m;          y = end1Ptr[1] + (rectPtr[0] - end1Ptr[0])*m;
231          if ((rectPtr[0] >= low) && (rectPtr[0] <= high)          if ((rectPtr[0] >= low) && (rectPtr[0] <= high)
232                  && (y >= rectPtr[1]) && (y <= rectPtr[3])) {                  && (y >= rectPtr[1]) && (y <= rectPtr[3])) {
233              return 0;              return 0;
234          }          }
235            
236          /*          /*
237           * Right edge.           * Right edge.
238           */           */
239            
240          y += (rectPtr[2] - rectPtr[0])*m;          y += (rectPtr[2] - rectPtr[0])*m;
241          if ((y >= rectPtr[1]) && (y <= rectPtr[3])          if ((y >= rectPtr[1]) && (y <= rectPtr[3])
242                  && (rectPtr[2] >= low) && (rectPtr[2] <= high)) {                  && (rectPtr[2] >= low) && (rectPtr[2] <= high)) {
243              return 0;              return 0;
244          }          }
245            
246          /*          /*
247           * Bottom edge.           * Bottom edge.
248           */           */
249            
250          if (end1Ptr[1] < end2Ptr[1]) {          if (end1Ptr[1] < end2Ptr[1]) {
251              low = end1Ptr[1];  high = end2Ptr[1];              low = end1Ptr[1];  high = end2Ptr[1];
252          } else {          } else {
253              low = end2Ptr[1]; high = end1Ptr[1];              low = end2Ptr[1]; high = end1Ptr[1];
254          }          }
255          x = end1Ptr[0] + (rectPtr[1] - end1Ptr[1])/m;          x = end1Ptr[0] + (rectPtr[1] - end1Ptr[1])/m;
256          if ((x >= rectPtr[0]) && (x <= rectPtr[2])          if ((x >= rectPtr[0]) && (x <= rectPtr[2])
257                  && (rectPtr[1] >= low) && (rectPtr[1] <= high)) {                  && (rectPtr[1] >= low) && (rectPtr[1] <= high)) {
258              return 0;              return 0;
259          }          }
260            
261          /*          /*
262           * Top edge.           * Top edge.
263           */           */
264            
265          x += (rectPtr[3] - rectPtr[1])/m;          x += (rectPtr[3] - rectPtr[1])/m;
266          if ((x >= rectPtr[0]) && (x <= rectPtr[2])          if ((x >= rectPtr[0]) && (x <= rectPtr[2])
267                  && (rectPtr[3] >= low) && (rectPtr[3] <= high)) {                  && (rectPtr[3] >= low) && (rectPtr[3] <= high)) {
268              return 0;              return 0;
269          }          }
270      }      }
271      return -1;      return -1;
272  }  }
273    
274  /*  /*
275   *--------------------------------------------------------------   *--------------------------------------------------------------
276   *   *
277   * TkThickPolyLineToArea --   * TkThickPolyLineToArea --
278   *   *
279   *      This procedure is called to determine whether a connected   *      This procedure is called to determine whether a connected
280   *      series of line segments lies entirely inside, entirely   *      series of line segments lies entirely inside, entirely
281   *      outside, or overlapping a given rectangular area.   *      outside, or overlapping a given rectangular area.
282   *   *
283   * Results:   * Results:
284   *      -1 is returned if the lines are entirely outside the area,   *      -1 is returned if the lines are entirely outside the area,
285   *      0 if they overlap, and 1 if they are entirely inside the   *      0 if they overlap, and 1 if they are entirely inside the
286   *      given area.   *      given area.
287   *   *
288   * Side effects:   * Side effects:
289   *      None.   *      None.
290   *   *
291   *--------------------------------------------------------------   *--------------------------------------------------------------
292   */   */
293    
294          /* ARGSUSED */          /* ARGSUSED */
295  int  int
296  TkThickPolyLineToArea(coordPtr, numPoints, width, capStyle, joinStyle, rectPtr)  TkThickPolyLineToArea(coordPtr, numPoints, width, capStyle, joinStyle, rectPtr)
297      double *coordPtr;           /* Points to an array of coordinates for      double *coordPtr;           /* Points to an array of coordinates for
298                                   * the polyline:  x0, y0, x1, y1, ... */                                   * the polyline:  x0, y0, x1, y1, ... */
299      int numPoints;              /* Total number of points at *coordPtr. */      int numPoints;              /* Total number of points at *coordPtr. */
300      double width;               /* Width of each line segment. */      double width;               /* Width of each line segment. */
301      int capStyle;               /* How are end-points of polyline drawn?      int capStyle;               /* How are end-points of polyline drawn?
302                                   * CapRound, CapButt, or CapProjecting. */                                   * CapRound, CapButt, or CapProjecting. */
303      int joinStyle;              /* How are joints in polyline drawn?      int joinStyle;              /* How are joints in polyline drawn?
304                                   * JoinMiter, JoinRound, or JoinBevel. */                                   * JoinMiter, JoinRound, or JoinBevel. */
305      double *rectPtr;            /* Rectangular area to check against. */      double *rectPtr;            /* Rectangular area to check against. */
306  {  {
307      double radius, poly[10];      double radius, poly[10];
308      int count;      int count;
309      int changedMiterToBevel;    /* Non-zero means that a mitered corner      int changedMiterToBevel;    /* Non-zero means that a mitered corner
310                                   * had to be treated as beveled after all                                   * had to be treated as beveled after all
311                                   * because the angle was < 11 degrees. */                                   * because the angle was < 11 degrees. */
312      int inside;                 /* Tentative guess about what to return,      int inside;                 /* Tentative guess about what to return,
313                                   * based on all points seen so far:  one                                   * based on all points seen so far:  one
314                                   * means everything seen so far was                                   * means everything seen so far was
315                                   * inside the area;  -1 means everything                                   * inside the area;  -1 means everything
316                                   * was outside the area.  0 means overlap                                   * was outside the area.  0 means overlap
317                                   * has been found. */                                   * has been found. */
318    
319      radius = width/2.0;      radius = width/2.0;
320      inside = -1;      inside = -1;
321    
322      if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2])      if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2])
323              && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) {              && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) {
324          inside = 1;          inside = 1;
325      }      }
326    
327      /*      /*
328       * Iterate through all of the edges of the line, computing a polygon       * Iterate through all of the edges of the line, computing a polygon
329       * for each edge and testing the area against that polygon.  In       * for each edge and testing the area against that polygon.  In
330       * addition, there are additional tests to deal with rounded joints       * addition, there are additional tests to deal with rounded joints
331       * and caps.       * and caps.
332       */       */
333    
334      changedMiterToBevel = 0;      changedMiterToBevel = 0;
335      for (count = numPoints; count >= 2; count--, coordPtr += 2) {      for (count = numPoints; count >= 2; count--, coordPtr += 2) {
336    
337          /*          /*
338           * If rounding is done around the first point of the edge           * If rounding is done around the first point of the edge
339           * then test a circular region around the point with the           * then test a circular region around the point with the
340           * area.           * area.
341           */           */
342    
343          if (((capStyle == CapRound) && (count == numPoints))          if (((capStyle == CapRound) && (count == numPoints))
344                  || ((joinStyle == JoinRound) && (count != numPoints))) {                  || ((joinStyle == JoinRound) && (count != numPoints))) {
345              poly[0] = coordPtr[0] - radius;              poly[0] = coordPtr[0] - radius;
346              poly[1] = coordPtr[1] - radius;              poly[1] = coordPtr[1] - radius;
347              poly[2] = coordPtr[0] + radius;              poly[2] = coordPtr[0] + radius;
348              poly[3] = coordPtr[1] + radius;              poly[3] = coordPtr[1] + radius;
349              if (TkOvalToArea(poly, rectPtr) != inside) {              if (TkOvalToArea(poly, rectPtr) != inside) {
350                  return 0;                  return 0;
351              }              }
352          }          }
353    
354          /*          /*
355           * Compute the polygonal shape corresponding to this edge,           * Compute the polygonal shape corresponding to this edge,
356           * consisting of two points for the first point of the edge           * consisting of two points for the first point of the edge
357           * and two points for the last point of the edge.           * and two points for the last point of the edge.
358           */           */
359    
360          if (count == numPoints) {          if (count == numPoints) {
361              TkGetButtPoints(coordPtr+2, coordPtr, width,              TkGetButtPoints(coordPtr+2, coordPtr, width,
362                      capStyle == CapProjecting, poly, poly+2);                      capStyle == CapProjecting, poly, poly+2);
363          } else if ((joinStyle == JoinMiter) && !changedMiterToBevel) {          } else if ((joinStyle == JoinMiter) && !changedMiterToBevel) {
364              poly[0] = poly[6];              poly[0] = poly[6];
365              poly[1] = poly[7];              poly[1] = poly[7];
366              poly[2] = poly[4];              poly[2] = poly[4];
367              poly[3] = poly[5];              poly[3] = poly[5];
368          } else {          } else {
369              TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2);              TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2);
370    
371              /*              /*
372               * If the last joint was beveled, then also check a               * If the last joint was beveled, then also check a
373               * polygon comprising the last two points of the previous               * polygon comprising the last two points of the previous
374               * polygon and the first two from this polygon;  this checks               * polygon and the first two from this polygon;  this checks
375               * the wedges that fill the beveled joint.               * the wedges that fill the beveled joint.
376               */               */
377    
378              if ((joinStyle == JoinBevel) || changedMiterToBevel) {              if ((joinStyle == JoinBevel) || changedMiterToBevel) {
379                  poly[8] = poly[0];                  poly[8] = poly[0];
380                  poly[9] = poly[1];                  poly[9] = poly[1];
381                  if (TkPolygonToArea(poly, 5, rectPtr) != inside) {                  if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
382                      return 0;                      return 0;
383                  }                  }
384                  changedMiterToBevel = 0;                  changedMiterToBevel = 0;
385              }              }
386          }          }
387          if (count == 2) {          if (count == 2) {
388              TkGetButtPoints(coordPtr, coordPtr+2, width,              TkGetButtPoints(coordPtr, coordPtr+2, width,
389                      capStyle == CapProjecting, poly+4, poly+6);                      capStyle == CapProjecting, poly+4, poly+6);
390          } else if (joinStyle == JoinMiter) {          } else if (joinStyle == JoinMiter) {
391              if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,              if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
392                      (double) width, poly+4, poly+6) == 0) {                      (double) width, poly+4, poly+6) == 0) {
393                  changedMiterToBevel = 1;                  changedMiterToBevel = 1;
394                  TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4,                  TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4,
395                          poly+6);                          poly+6);
396              }              }
397          } else {          } else {
398              TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6);              TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6);
399          }          }
400          poly[8] = poly[0];          poly[8] = poly[0];
401          poly[9] = poly[1];          poly[9] = poly[1];
402          if (TkPolygonToArea(poly, 5, rectPtr) != inside) {          if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
403              return 0;              return 0;
404          }          }
405      }      }
406    
407      /*      /*
408       * If caps are rounded, check the cap around the final point       * If caps are rounded, check the cap around the final point
409       * of the line.       * of the line.
410       */       */
411    
412      if (capStyle == CapRound) {      if (capStyle == CapRound) {
413          poly[0] = coordPtr[0] - radius;          poly[0] = coordPtr[0] - radius;
414          poly[1] = coordPtr[1] - radius;          poly[1] = coordPtr[1] - radius;
415          poly[2] = coordPtr[0] + radius;          poly[2] = coordPtr[0] + radius;
416          poly[3] = coordPtr[1] + radius;          poly[3] = coordPtr[1] + radius;
417          if (TkOvalToArea(poly, rectPtr) != inside) {          if (TkOvalToArea(poly, rectPtr) != inside) {
418              return 0;              return 0;
419          }          }
420      }      }
421    
422      return inside;      return inside;
423  }  }
424    
425  /*  /*
426   *--------------------------------------------------------------   *--------------------------------------------------------------
427   *   *
428   * TkPolygonToPoint --   * TkPolygonToPoint --
429   *   *
430   *      Compute the distance from a point to a polygon.   *      Compute the distance from a point to a polygon.
431   *   *
432   * Results:   * Results:
433   *      The return value is 0.0 if the point referred to by   *      The return value is 0.0 if the point referred to by
434   *      pointPtr is within the polygon referred to by polyPtr   *      pointPtr is within the polygon referred to by polyPtr
435   *      and numPoints.  Otherwise the return value is the   *      and numPoints.  Otherwise the return value is the
436   *      distance of the point from the polygon.   *      distance of the point from the polygon.
437   *   *
438   * Side effects:   * Side effects:
439   *      None.   *      None.
440   *   *
441   *--------------------------------------------------------------   *--------------------------------------------------------------
442   */   */
443    
444  double  double
445  TkPolygonToPoint(polyPtr, numPoints, pointPtr)  TkPolygonToPoint(polyPtr, numPoints, pointPtr)
446      double *polyPtr;            /* Points to an array coordinates for      double *polyPtr;            /* Points to an array coordinates for
447                                   * closed polygon:  x0, y0, x1, y1, ...                                   * closed polygon:  x0, y0, x1, y1, ...
448                                   * The polygon may be self-intersecting. */                                   * The polygon may be self-intersecting. */
449      int numPoints;              /* Total number of points at *polyPtr. */      int numPoints;              /* Total number of points at *polyPtr. */
450      double *pointPtr;           /* Points to coords for point. */      double *pointPtr;           /* Points to coords for point. */
451  {  {
452      double bestDist;            /* Closest distance between point and      double bestDist;            /* Closest distance between point and
453                                   * any edge in polygon. */                                   * any edge in polygon. */
454      int intersections;          /* Number of edges in the polygon that      int intersections;          /* Number of edges in the polygon that
455                                   * intersect a ray extending vertically                                   * intersect a ray extending vertically
456                                   * upwards from the point to infinity. */                                   * upwards from the point to infinity. */
457      int count;      int count;
458      register double *pPtr;      register double *pPtr;
459    
460      /*      /*
461       * Iterate through all of the edges in the polygon, updating       * Iterate through all of the edges in the polygon, updating
462       * bestDist and intersections.       * bestDist and intersections.
463       *       *
464       * TRICKY POINT:  when computing intersections, include left       * TRICKY POINT:  when computing intersections, include left
465       * x-coordinate of line within its range, but not y-coordinate.       * x-coordinate of line within its range, but not y-coordinate.
466       * Otherwise if the point lies exactly below a vertex we'll       * Otherwise if the point lies exactly below a vertex we'll
467       * count it as two intersections.       * count it as two intersections.
468       */       */
469    
470      bestDist = 1.0e36;      bestDist = 1.0e36;
471      intersections = 0;      intersections = 0;
472    
473      for (count = numPoints, pPtr = polyPtr; count > 1; count--, pPtr += 2) {      for (count = numPoints, pPtr = polyPtr; count > 1; count--, pPtr += 2) {
474          double x, y, dist;          double x, y, dist;
475    
476          /*          /*
477           * Compute the point on the current edge closest to the point           * Compute the point on the current edge closest to the point
478           * and update the intersection count.  This must be done           * and update the intersection count.  This must be done
479           * separately for vertical edges, horizontal edges, and           * separately for vertical edges, horizontal edges, and
480           * other edges.           * other edges.
481           */           */
482    
483          if (pPtr[2] == pPtr[0]) {          if (pPtr[2] == pPtr[0]) {
484    
485              /*              /*
486               * Vertical edge.               * Vertical edge.
487               */               */
488    
489              x = pPtr[0];              x = pPtr[0];
490              if (pPtr[1] >= pPtr[3]) {              if (pPtr[1] >= pPtr[3]) {
491                  y = MIN(pPtr[1], pointPtr[1]);                  y = MIN(pPtr[1], pointPtr[1]);
492                  y = MAX(y, pPtr[3]);                  y = MAX(y, pPtr[3]);
493              } else {              } else {
494                  y = MIN(pPtr[3], pointPtr[1]);                  y = MIN(pPtr[3], pointPtr[1]);
495                  y = MAX(y, pPtr[1]);                  y = MAX(y, pPtr[1]);
496              }              }
497          } else if (pPtr[3] == pPtr[1]) {          } else if (pPtr[3] == pPtr[1]) {
498    
499              /*              /*
500               * Horizontal edge.               * Horizontal edge.
501               */               */
502    
503              y = pPtr[1];              y = pPtr[1];
504              if (pPtr[0] >= pPtr[2]) {              if (pPtr[0] >= pPtr[2]) {
505                  x = MIN(pPtr[0], pointPtr[0]);                  x = MIN(pPtr[0], pointPtr[0]);
506                  x = MAX(x, pPtr[2]);                  x = MAX(x, pPtr[2]);
507                  if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[0])                  if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[0])
508                          && (pointPtr[0] >= pPtr[2])) {                          && (pointPtr[0] >= pPtr[2])) {
509                      intersections++;                      intersections++;
510                  }                  }
511              } else {              } else {
512                  x = MIN(pPtr[2], pointPtr[0]);                  x = MIN(pPtr[2], pointPtr[0]);
513                  x = MAX(x, pPtr[0]);                  x = MAX(x, pPtr[0]);
514                  if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[2])                  if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[2])
515                          && (pointPtr[0] >= pPtr[0])) {                          && (pointPtr[0] >= pPtr[0])) {
516                      intersections++;                      intersections++;
517                  }                  }
518              }              }
519          } else {          } else {
520              double m1, b1, m2, b2;              double m1, b1, m2, b2;
521              int lower;                  /* Non-zero means point below line. */              int lower;                  /* Non-zero means point below line. */
522    
523              /*              /*
524               * The edge is neither horizontal nor vertical.  Convert the               * The edge is neither horizontal nor vertical.  Convert the
525               * edge to a line equation of the form y = m1*x + b1.  Then               * edge to a line equation of the form y = m1*x + b1.  Then
526               * compute a line perpendicular to this edge but passing               * compute a line perpendicular to this edge but passing
527               * through the point, also in the form y = m2*x + b2.               * through the point, also in the form y = m2*x + b2.
528               */               */
529    
530              m1 = (pPtr[3] - pPtr[1])/(pPtr[2] - pPtr[0]);              m1 = (pPtr[3] - pPtr[1])/(pPtr[2] - pPtr[0]);
531              b1 = pPtr[1] - m1*pPtr[0];              b1 = pPtr[1] - m1*pPtr[0];
532              m2 = -1.0/m1;              m2 = -1.0/m1;
533              b2 = pointPtr[1] - m2*pointPtr[0];              b2 = pointPtr[1] - m2*pointPtr[0];
534              x = (b2 - b1)/(m1 - m2);              x = (b2 - b1)/(m1 - m2);
535              y = m1*x + b1;              y = m1*x + b1;
536              if (pPtr[0] > pPtr[2]) {              if (pPtr[0] > pPtr[2]) {
537                  if (x > pPtr[0]) {                  if (x > pPtr[0]) {
538                      x = pPtr[0];                      x = pPtr[0];
539                      y = pPtr[1];                      y = pPtr[1];
540                  } else if (x < pPtr[2]) {                  } else if (x < pPtr[2]) {
541                      x = pPtr[2];                      x = pPtr[2];
542                      y = pPtr[3];                      y = pPtr[3];
543                  }                  }
544              } else {              } else {
545                  if (x > pPtr[2]) {                  if (x > pPtr[2]) {
546                      x = pPtr[2];                      x = pPtr[2];
547                      y = pPtr[3];                      y = pPtr[3];
548                  } else if (x < pPtr[0]) {                  } else if (x < pPtr[0]) {
549                      x = pPtr[0];                      x = pPtr[0];
550                      y = pPtr[1];                      y = pPtr[1];
551                  }                  }
552              }              }
553              lower = (m1*pointPtr[0] + b1) > pointPtr[1];              lower = (m1*pointPtr[0] + b1) > pointPtr[1];
554              if (lower && (pointPtr[0] >= MIN(pPtr[0], pPtr[2]))              if (lower && (pointPtr[0] >= MIN(pPtr[0], pPtr[2]))
555                      && (pointPtr[0] < MAX(pPtr[0], pPtr[2]))) {                      && (pointPtr[0] < MAX(pPtr[0], pPtr[2]))) {
556                  intersections++;                  intersections++;
557              }              }
558          }          }
559    
560          /*          /*
561           * Compute the distance to the closest point, and see if that           * Compute the distance to the closest point, and see if that
562           * is the best distance seen so far.           * is the best distance seen so far.
563           */           */
564    
565          dist = hypot(pointPtr[0] - x, pointPtr[1] - y);          dist = hypot(pointPtr[0] - x, pointPtr[1] - y);
566          if (dist < bestDist) {          if (dist < bestDist) {
567              bestDist = dist;              bestDist = dist;
568          }          }
569      }      }
570    
571      /*      /*
572       * We've processed all of the points.  If the number of intersections       * We've processed all of the points.  If the number of intersections
573       * is odd, the point is inside the polygon.       * is odd, the point is inside the polygon.
574       */       */
575    
576      if (intersections & 0x1) {      if (intersections & 0x1) {
577          return 0.0;          return 0.0;
578      }      }
579      return bestDist;      return bestDist;
580  }  }
581    
582  /*  /*
583   *--------------------------------------------------------------   *--------------------------------------------------------------
584   *   *
585   * TkPolygonToArea --   * TkPolygonToArea --
586   *   *
587   *      Determine whether a polygon lies entirely inside, entirely   *      Determine whether a polygon lies entirely inside, entirely
588   *      outside, or overlapping a given rectangular area.   *      outside, or overlapping a given rectangular area.
589   *   *
590   * Results:   * Results:
591   *      -1 is returned if the polygon given by polyPtr and numPoints   *      -1 is returned if the polygon given by polyPtr and numPoints
592   *      is entirely outside the rectangle given by rectPtr.  0 is   *      is entirely outside the rectangle given by rectPtr.  0 is
593   *      returned if the polygon overlaps the rectangle, and 1 is   *      returned if the polygon overlaps the rectangle, and 1 is
594   *      returned if the polygon is entirely inside the rectangle.   *      returned if the polygon is entirely inside the rectangle.
595   *   *
596   * Side effects:   * Side effects:
597   *      None.   *      None.
598   *   *
599   *--------------------------------------------------------------   *--------------------------------------------------------------
600   */   */
601    
602  int  int
603  TkPolygonToArea(polyPtr, numPoints, rectPtr)  TkPolygonToArea(polyPtr, numPoints, rectPtr)
604      double *polyPtr;            /* Points to an array coordinates for      double *polyPtr;            /* Points to an array coordinates for
605                                   * closed polygon:  x0, y0, x1, y1, ...                                   * closed polygon:  x0, y0, x1, y1, ...
606                                   * The polygon may be self-intersecting. */                                   * The polygon may be self-intersecting. */
607      int numPoints;              /* Total number of points at *polyPtr. */      int numPoints;              /* Total number of points at *polyPtr. */
608      register double *rectPtr;   /* Points to coords for rectangle, in the      register double *rectPtr;   /* Points to coords for rectangle, in the
609                                   * order x1, y1, x2, y2.  X1 and y1 must                                   * order x1, y1, x2, y2.  X1 and y1 must
610                                   * be lower-left corner. */                                   * be lower-left corner. */
611  {  {
612      int state;                  /* State of all edges seen so far (-1 means      int state;                  /* State of all edges seen so far (-1 means
613                                   * outside, 1 means inside, won't ever be                                   * outside, 1 means inside, won't ever be
614                                   * 0). */                                   * 0). */
615      int count;      int count;
616      register double *pPtr;      register double *pPtr;
617    
618      /*      /*
619       * Iterate over all of the edges of the polygon and test them       * Iterate over all of the edges of the polygon and test them
620       * against the rectangle.  Can quit as soon as the state becomes       * against the rectangle.  Can quit as soon as the state becomes
621       * "intersecting".       * "intersecting".
622       */       */
623    
624      state = TkLineToArea(polyPtr, polyPtr+2, rectPtr);      state = TkLineToArea(polyPtr, polyPtr+2, rectPtr);
625      if (state == 0) {      if (state == 0) {
626          return 0;          return 0;
627      }      }
628      for (pPtr = polyPtr+2, count = numPoints-1; count >= 2;      for (pPtr = polyPtr+2, count = numPoints-1; count >= 2;
629              pPtr += 2, count--) {              pPtr += 2, count--) {
630          if (TkLineToArea(pPtr, pPtr+2, rectPtr) != state) {          if (TkLineToArea(pPtr, pPtr+2, rectPtr) != state) {
631              return 0;              return 0;
632          }          }
633      }      }
634    
635      /*      /*
636       * If all of the edges were inside the rectangle we're done.       * If all of the edges were inside the rectangle we're done.
637       * If all of the edges were outside, then the rectangle could       * If all of the edges were outside, then the rectangle could
638       * still intersect the polygon (if it's entirely enclosed).       * still intersect the polygon (if it's entirely enclosed).
639       * Call TkPolygonToPoint to figure this out.       * Call TkPolygonToPoint to figure this out.
640       */       */
641    
642      if (state == 1) {      if (state == 1) {
643          return 1;          return 1;
644      }      }
645      if (TkPolygonToPoint(polyPtr, numPoints, rectPtr) == 0.0) {      if (TkPolygonToPoint(polyPtr, numPoints, rectPtr) == 0.0) {
646          return 0;          return 0;
647      }      }
648      return -1;      return -1;
649  }  }
650    
651  /*  /*
652   *--------------------------------------------------------------   *--------------------------------------------------------------
653   *   *
654   * TkOvalToPoint --   * TkOvalToPoint --
655   *   *
656   *      Computes the distance from a given point to a given   *      Computes the distance from a given point to a given
657   *      oval, in canvas units.   *      oval, in canvas units.
658   *   *
659   * Results:   * Results:
660   *      The return value is 0 if the point given by *pointPtr is   *      The return value is 0 if the point given by *pointPtr is
661   *      inside the oval.  If the point isn't inside the   *      inside the oval.  If the point isn't inside the
662   *      oval then the return value is approximately the distance   *      oval then the return value is approximately the distance
663   *      from the point to the oval.  If the oval is filled, then   *      from the point to the oval.  If the oval is filled, then
664   *      anywhere in the interior is considered "inside";  if   *      anywhere in the interior is considered "inside";  if
665   *      the oval isn't filled, then "inside" means only the area   *      the oval isn't filled, then "inside" means only the area
666   *      occupied by the outline.   *      occupied by the outline.
667   *   *
668   * Side effects:   * Side effects:
669   *      None.   *      None.
670   *   *
671   *--------------------------------------------------------------   *--------------------------------------------------------------
672   */   */
673    
674          /* ARGSUSED */          /* ARGSUSED */
675  double  double
676  TkOvalToPoint(ovalPtr, width, filled, pointPtr)  TkOvalToPoint(ovalPtr, width, filled, pointPtr)
677      double ovalPtr[4];          /* Pointer to array of four coordinates      double ovalPtr[4];          /* Pointer to array of four coordinates
678                                   * (x1, y1, x2, y2) defining oval's bounding                                   * (x1, y1, x2, y2) defining oval's bounding
679                                   * box. */                                   * box. */
680      double width;               /* Width of outline for oval. */      double width;               /* Width of outline for oval. */
681      int filled;                 /* Non-zero means oval should be treated as      int filled;                 /* Non-zero means oval should be treated as
682                                   * filled;  zero means only consider outline. */                                   * filled;  zero means only consider outline. */
683      double pointPtr[2];         /* Coordinates of point. */      double pointPtr[2];         /* Coordinates of point. */
684  {  {
685      double xDelta, yDelta, scaledDistance, distToOutline, distToCenter;      double xDelta, yDelta, scaledDistance, distToOutline, distToCenter;
686      double xDiam, yDiam;      double xDiam, yDiam;
687    
688      /*      /*
689       * Compute the distance between the center of the oval and the       * Compute the distance between the center of the oval and the
690       * point in question, using a coordinate system where the oval       * point in question, using a coordinate system where the oval
691       * has been transformed to a circle with unit radius.       * has been transformed to a circle with unit radius.
692       */       */
693    
694      xDelta = (pointPtr[0] - (ovalPtr[0] + ovalPtr[2])/2.0);      xDelta = (pointPtr[0] - (ovalPtr[0] + ovalPtr[2])/2.0);
695      yDelta = (pointPtr[1] - (ovalPtr[1] + ovalPtr[3])/2.0);      yDelta = (pointPtr[1] - (ovalPtr[1] + ovalPtr[3])/2.0);
696      distToCenter = hypot(xDelta, yDelta);      distToCenter = hypot(xDelta, yDelta);
697      scaledDistance = hypot(xDelta / ((ovalPtr[2] + width - ovalPtr[0])/2.0),      scaledDistance = hypot(xDelta / ((ovalPtr[2] + width - ovalPtr[0])/2.0),
698              yDelta / ((ovalPtr[3] + width - ovalPtr[1])/2.0));              yDelta / ((ovalPtr[3] + width - ovalPtr[1])/2.0));
699    
700    
701      /*      /*
702       * If the scaled distance is greater than 1 then it means no       * If the scaled distance is greater than 1 then it means no
703       * hit.  Compute the distance from the point to the edge of       * hit.  Compute the distance from the point to the edge of
704       * the circle, then scale this distance back to the original       * the circle, then scale this distance back to the original
705       * coordinate system.       * coordinate system.
706       *       *
707       * Note: this distance isn't completely accurate.  It's only       * Note: this distance isn't completely accurate.  It's only
708       * an approximation, and it can overestimate the correct       * an approximation, and it can overestimate the correct
709       * distance when the oval is eccentric.       * distance when the oval is eccentric.
710       */       */
711    
712      if (scaledDistance > 1.0) {      if (scaledDistance > 1.0) {
713          return (distToCenter/scaledDistance) * (scaledDistance - 1.0);          return (distToCenter/scaledDistance) * (scaledDistance - 1.0);
714      }      }
715    
716      /*      /*
717       * Scaled distance less than 1 means the point is inside the       * Scaled distance less than 1 means the point is inside the
718       * outer edge of the oval.  If this is a filled oval, then we       * outer edge of the oval.  If this is a filled oval, then we
719       * have a hit.  Otherwise, do the same computation as above       * have a hit.  Otherwise, do the same computation as above
720       * (scale back to original coordinate system), but also check       * (scale back to original coordinate system), but also check
721       * to see if the point is within the width of the outline.       * to see if the point is within the width of the outline.
722       */       */
723    
724      if (filled) {      if (filled) {
725          return 0.0;          return 0.0;
726      }      }
727      if (scaledDistance > 1E-10) {      if (scaledDistance > 1E-10) {
728          distToOutline = (distToCenter/scaledDistance) * (1.0 - scaledDistance)          distToOutline = (distToCenter/scaledDistance) * (1.0 - scaledDistance)
729                  - width;                  - width;
730      } else {      } else {
731          /*          /*
732           * Avoid dividing by a very small number (it could cause an           * Avoid dividing by a very small number (it could cause an
733           * arithmetic overflow).  This problem occurs if the point is           * arithmetic overflow).  This problem occurs if the point is
734           * very close to the center of the oval.           * very close to the center of the oval.
735           */           */
736    
737          xDiam = ovalPtr[2] - ovalPtr[0];          xDiam = ovalPtr[2] - ovalPtr[0];
738          yDiam = ovalPtr[3] - ovalPtr[1];          yDiam = ovalPtr[3] - ovalPtr[1];
739          if (xDiam < yDiam) {          if (xDiam < yDiam) {
740              distToOutline = (xDiam - width)/2;              distToOutline = (xDiam - width)/2;
741          } else {          } else {
742              distToOutline = (yDiam - width)/2;              distToOutline = (yDiam - width)/2;
743          }          }
744      }      }
745    
746      if (distToOutline < 0.0) {      if (distToOutline < 0.0) {
747          return 0.0;          return 0.0;
748      }      }
749      return distToOutline;      return distToOutline;
750  }  }
751    
752  /*  /*
753   *--------------------------------------------------------------   *--------------------------------------------------------------
754   *   *
755   * TkOvalToArea --   * TkOvalToArea --
756   *   *
757   *      Determine whether an oval lies entirely inside, entirely   *      Determine whether an oval lies entirely inside, entirely
758   *      outside, or overlapping a given rectangular area.   *      outside, or overlapping a given rectangular area.
759   *   *
760   * Results:   * Results:
761   *      -1 is returned if the oval described by ovalPtr is entirely   *      -1 is returned if the oval described by ovalPtr is entirely
762   *      outside the rectangle given by rectPtr.  0 is returned if the   *      outside the rectangle given by rectPtr.  0 is returned if the
763   *      oval overlaps the rectangle, and 1 is returned if the oval   *      oval overlaps the rectangle, and 1 is returned if the oval
764   *      is entirely inside the rectangle.   *      is entirely inside the rectangle.
765   *   *
766   * Side effects:   * Side effects:
767   *      None.   *      None.
768   *   *
769   *--------------------------------------------------------------   *--------------------------------------------------------------
770   */   */
771    
772  int  int
773  TkOvalToArea(ovalPtr, rectPtr)  TkOvalToArea(ovalPtr, rectPtr)
774      register double *ovalPtr;   /* Points to coordinates definining the      register double *ovalPtr;   /* Points to coordinates definining the
775                                   * bounding rectangle for the oval: x1, y1,                                   * bounding rectangle for the oval: x1, y1,
776                                   * x2, y2.  X1 must be less than x2 and y1                                   * x2, y2.  X1 must be less than x2 and y1
777                                   * less than y2. */                                   * less than y2. */
778      register double *rectPtr;   /* Points to coords for rectangle, in the      register double *rectPtr;   /* Points to coords for rectangle, in the
779                                   * order x1, y1, x2, y2.  X1 and y1 must                                   * order x1, y1, x2, y2.  X1 and y1 must
780                                   * be lower-left corner. */                                   * be lower-left corner. */
781  {  {
782      double centerX, centerY, radX, radY, deltaX, deltaY;      double centerX, centerY, radX, radY, deltaX, deltaY;
783    
784      /*      /*
785       * First, see if oval is entirely inside rectangle or entirely       * First, see if oval is entirely inside rectangle or entirely
786       * outside rectangle.       * outside rectangle.
787       */       */
788    
789      if ((rectPtr[0] <= ovalPtr[0]) && (rectPtr[2] >= ovalPtr[2])      if ((rectPtr[0] <= ovalPtr[0]) && (rectPtr[2] >= ovalPtr[2])
790              && (rectPtr[1] <= ovalPtr[1]) && (rectPtr[3] >= ovalPtr[3])) {              && (rectPtr[1] <= ovalPtr[1]) && (rectPtr[3] >= ovalPtr[3])) {
791          return 1;          return 1;
792      }      }
793      if ((rectPtr[2] < ovalPtr[0]) || (rectPtr[0] > ovalPtr[2])      if ((rectPtr[2] < ovalPtr[0]) || (rectPtr[0] > ovalPtr[2])
794              || (rectPtr[3] < ovalPtr[1]) || (rectPtr[1] > ovalPtr[3])) {              || (rectPtr[3] < ovalPtr[1]) || (rectPtr[1] > ovalPtr[3])) {
795          return -1;          return -1;
796      }      }
797    
798      /*      /*
799       * Next, go through the rectangle side by side.  For each side       * Next, go through the rectangle side by side.  For each side
800       * of the rectangle, find the point on the side that is closest       * of the rectangle, find the point on the side that is closest
801       * to the oval's center, and see if that point is inside the       * to the oval's center, and see if that point is inside the
802       * oval.  If at least one such point is inside the oval, then       * oval.  If at least one such point is inside the oval, then
803       * the rectangle intersects the oval.       * the rectangle intersects the oval.
804       */       */
805    
806      centerX = (ovalPtr[0] + ovalPtr[2])/2;      centerX = (ovalPtr[0] + ovalPtr[2])/2;
807      centerY = (ovalPtr[1] + ovalPtr[3])/2;      centerY = (ovalPtr[1] + ovalPtr[3])/2;
808      radX = (ovalPtr[2] - ovalPtr[0])/2;      radX = (ovalPtr[2] - ovalPtr[0])/2;
809      radY = (ovalPtr[3] - ovalPtr[1])/2;      radY = (ovalPtr[3] - ovalPtr[1])/2;
810    
811      deltaY = rectPtr[1] - centerY;      deltaY = rectPtr[1] - centerY;
812      if (deltaY < 0.0) {      if (deltaY < 0.0) {
813          deltaY = centerY - rectPtr[3];          deltaY = centerY - rectPtr[3];
814          if (deltaY < 0.0) {          if (deltaY < 0.0) {
815              deltaY = 0;              deltaY = 0;
816          }          }
817      }      }
818      deltaY /= radY;      deltaY /= radY;
819      deltaY *= deltaY;      deltaY *= deltaY;
820    
821      /*      /*
822       * Left side:       * Left side:
823       */       */
824    
825      deltaX = (rectPtr[0] - centerX)/radX;      deltaX = (rectPtr[0] - centerX)/radX;
826      deltaX *= deltaX;      deltaX *= deltaX;
827      if ((deltaX + deltaY) <= 1.0) {      if ((deltaX + deltaY) <= 1.0) {
828          return 0;          return 0;
829      }      }
830    
831      /*      /*
832       * Right side:       * Right side:
833       */       */
834    
835      deltaX = (rectPtr[2] - centerX)/radX;      deltaX = (rectPtr[2] - centerX)/radX;
836      deltaX *= deltaX;      deltaX *= deltaX;
837      if ((deltaX + deltaY) <= 1.0) {      if ((deltaX + deltaY) <= 1.0) {
838          return 0;          return 0;
839      }      }
840    
841      deltaX = rectPtr[0] - centerX;      deltaX = rectPtr[0] - centerX;
842      if (deltaX < 0.0) {      if (deltaX < 0.0) {
843          deltaX = centerX - rectPtr[2];          deltaX = centerX - rectPtr[2];
844          if (deltaX < 0.0) {          if (deltaX < 0.0) {
845              deltaX = 0;              deltaX = 0;
846          }          }
847      }      }
848      deltaX /= radX;      deltaX /= radX;
849      deltaX *= deltaX;      deltaX *= deltaX;
850    
851      /*      /*
852       * Bottom side:       * Bottom side:
853       */       */
854    
855      deltaY = (rectPtr[1] - centerY)/radY;      deltaY = (rectPtr[1] - centerY)/radY;
856      deltaY *= deltaY;      deltaY *= deltaY;
857      if ((deltaX + deltaY) < 1.0) {      if ((deltaX + deltaY) < 1.0) {
858          return 0;          return 0;
859      }      }
860    
861      /*      /*
862       * Top side:       * Top side:
863       */       */
864    
865      deltaY = (rectPtr[3] - centerY)/radY;      deltaY = (rectPtr[3] - centerY)/radY;
866      deltaY *= deltaY;      deltaY *= deltaY;
867      if ((deltaX + deltaY) < 1.0) {      if ((deltaX + deltaY) < 1.0) {
868          return 0;          return 0;
869      }      }
870    
871      return -1;      return -1;
872  }  }
873    
874  /*  /*
875   *--------------------------------------------------------------   *--------------------------------------------------------------
876   *   *
877   * TkIncludePoint --   * TkIncludePoint --
878   *   *
879   *      Given a point and a generic canvas item header, expand   *      Given a point and a generic canvas item header, expand
880   *      the item's bounding box if needed to include the point.   *      the item's bounding box if needed to include the point.
881   *   *
882   * Results:   * Results:
883   *      None.   *      None.
884   *   *
885   * Side effects:   * Side effects:
886   *      The boudn.   *      The boudn.
887   *   *
888   *--------------------------------------------------------------   *--------------------------------------------------------------
889   */   */
890    
891          /* ARGSUSED */          /* ARGSUSED */
892  void  void
893  TkIncludePoint(itemPtr, pointPtr)  TkIncludePoint(itemPtr, pointPtr)
894      register Tk_Item *itemPtr;          /* Item whose bounding box is      register Tk_Item *itemPtr;          /* Item whose bounding box is
895                                           * being calculated. */                                           * being calculated. */
896      double *pointPtr;                   /* Address of two doubles giving      double *pointPtr;                   /* Address of two doubles giving
897                                           * x and y coordinates of point. */                                           * x and y coordinates of point. */
898  {  {
899      int tmp;      int tmp;
900    
901      tmp = (int) (pointPtr[0] + 0.5);      tmp = (int) (pointPtr[0] + 0.5);
902      if (tmp < itemPtr->x1) {      if (tmp < itemPtr->x1) {
903          itemPtr->x1 = tmp;          itemPtr->x1 = tmp;
904      }      }
905      if (tmp > itemPtr->x2) {      if (tmp > itemPtr->x2) {
906          itemPtr->x2 = tmp;          itemPtr->x2 = tmp;
907      }      }
908      tmp = (int) (pointPtr[1] + 0.5);      tmp = (int) (pointPtr[1] + 0.5);
909      if (tmp < itemPtr->y1) {      if (tmp < itemPtr->y1) {
910          itemPtr->y1 = tmp;          itemPtr->y1 = tmp;
911      }      }
912      if (tmp > itemPtr->y2) {      if (tmp > itemPtr->y2) {
913          itemPtr->y2 = tmp;          itemPtr->y2 = tmp;
914      }      }
915  }  }
916    
917  /*  /*
918   *--------------------------------------------------------------   *--------------------------------------------------------------
919   *   *
920   * TkBezierScreenPoints --   * TkBezierScreenPoints --
921   *   *
922   *      Given four control points, create a larger set of XPoints   *      Given four control points, create a larger set of XPoints
923   *      for a Bezier spline based on the points.   *      for a Bezier spline based on the points.
924   *   *
925   * Results:   * Results:
926   *      The array at *xPointPtr gets filled in with numSteps XPoints   *      The array at *xPointPtr gets filled in with numSteps XPoints
927   *      corresponding to the Bezier spline defined by the four   *      corresponding to the Bezier spline defined by the four
928   *      control points.  Note:  no output point is generated for the   *      control points.  Note:  no output point is generated for the
929   *      first input point, but an output point *is* generated for   *      first input point, but an output point *is* generated for
930   *      the last input point.   *      the last input point.
931   *   *
932   * Side effects:   * Side effects:
933   *      None.   *      None.
934   *   *
935   *--------------------------------------------------------------   *--------------------------------------------------------------
936   */   */
937    
938  void  void
939  TkBezierScreenPoints(canvas, control, numSteps, xPointPtr)  TkBezierScreenPoints(canvas, control, numSteps, xPointPtr)
940      Tk_Canvas canvas;                   /* Canvas in which curve is to be      Tk_Canvas canvas;                   /* Canvas in which curve is to be
941                                           * drawn. */                                           * drawn. */
942      double control[];                   /* Array of coordinates for four      double control[];                   /* Array of coordinates for four
943                                           * control points:  x0, y0, x1, y1,                                           * control points:  x0, y0, x1, y1,
944                                           * ... x3 y3. */                                           * ... x3 y3. */
945      int numSteps;                       /* Number of curve points to      int numSteps;                       /* Number of curve points to
946                                           * generate.  */                                           * generate.  */
947      register XPoint *xPointPtr;         /* Where to put new points. */      register XPoint *xPointPtr;         /* Where to put new points. */
948  {  {
949      int i;      int i;
950      double u, u2, u3, t, t2, t3;      double u, u2, u3, t, t2, t3;
951    
952      for (i = 1; i <= numSteps; i++, xPointPtr++) {      for (i = 1; i <= numSteps; i++, xPointPtr++) {
953          t = ((double) i)/((double) numSteps);          t = ((double) i)/((double) numSteps);
954          t2 = t*t;          t2 = t*t;
955          t3 = t2*t;          t3 = t2*t;
956          u = 1.0 - t;          u = 1.0 - t;
957          u2 = u*u;          u2 = u*u;
958          u3 = u2*u;          u3 = u2*u;
959          Tk_CanvasDrawableCoords(canvas,          Tk_CanvasDrawableCoords(canvas,
960                  (control[0]*u3 + 3.0 * (control[2]*t*u2 + control[4]*t2*u)                  (control[0]*u3 + 3.0 * (control[2]*t*u2 + control[4]*t2*u)
961                      + control[6]*t3),                      + control[6]*t3),
962                  (control[1]*u3 + 3.0 * (control[3]*t*u2 + control[5]*t2*u)                  (control[1]*u3 + 3.0 * (control[3]*t*u2 + control[5]*t2*u)
963                      + control[7]*t3),                      + control[7]*t3),
964                  &xPointPtr->x, &xPointPtr->y);                  &xPointPtr->x, &xPointPtr->y);
965      }      }
966  }  }
967    
968  /*  /*
969   *--------------------------------------------------------------   *--------------------------------------------------------------
970   *   *
971   * TkBezierPoints --   * TkBezierPoints --
972   *   *
973   *      Given four control points, create a larger set of points   *      Given four control points, create a larger set of points
974   *      for a Bezier spline based on the points.   *      for a Bezier spline based on the points.
975   *   *
976   * Results:   * Results:
977   *      The array at *coordPtr gets filled in with 2*numSteps   *      The array at *coordPtr gets filled in with 2*numSteps
978   *      coordinates, which correspond to the Bezier spline defined   *      coordinates, which correspond to the Bezier spline defined
979   *      by the four control points.  Note:  no output point is   *      by the four control points.  Note:  no output point is
980   *      generated for the first input point, but an output point   *      generated for the first input point, but an output point
981   *      *is* generated for the last input point.   *      *is* generated for the last input point.
982   *   *
983   * Side effects:   * Side effects:
984   *      None.   *      None.
985   *   *
986   *--------------------------------------------------------------   *--------------------------------------------------------------
987   */   */
988    
989  void  void
990  TkBezierPoints(control, numSteps, coordPtr)  TkBezierPoints(control, numSteps, coordPtr)
991      double control[];                   /* Array of coordinates for four      double control[];                   /* Array of coordinates for four
992                                           * control points:  x0, y0, x1, y1,                                           * control points:  x0, y0, x1, y1,
993                                           * ... x3 y3. */                                           * ... x3 y3. */
994      int numSteps;                       /* Number of curve points to      int numSteps;                       /* Number of curve points to
995                                           * generate.  */                                           * generate.  */
996      register double *coordPtr;          /* Where to put new points. */      register double *coordPtr;          /* Where to put new points. */
997  {  {
998      int i;      int i;
999      double u, u2, u3, t, t2, t3;      double u, u2, u3, t, t2, t3;
1000    
1001      for (i = 1; i <= numSteps; i++, coordPtr += 2) {      for (i = 1; i <= numSteps; i++, coordPtr += 2) {
1002          t = ((double) i)/((double) numSteps);          t = ((double) i)/((double) numSteps);
1003          t2 = t*t;          t2 = t*t;
1004          t3 = t2*t;          t3 = t2*t;
1005          u = 1.0 - t;          u = 1.0 - t;
1006          u2 = u*u;          u2 = u*u;
1007          u3 = u2*u;          u3 = u2*u;
1008          coordPtr[0] = control[0]*u3          coordPtr[0] = control[0]*u3
1009                  + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3;                  + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3;
1010          coordPtr[1] = control[1]*u3          coordPtr[1] = control[1]*u3
1011                  + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3;                  + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3;
1012      }      }
1013  }  }
1014    
1015  /*  /*
1016   *--------------------------------------------------------------   *--------------------------------------------------------------
1017   *   *
1018   * TkMakeBezierCurve --   * TkMakeBezierCurve --
1019   *   *
1020   *      Given a set of points, create a new set of points that fit   *      Given a set of points, create a new set of points that fit
1021   *      parabolic splines to the line segments connecting the original   *      parabolic splines to the line segments connecting the original
1022   *      points.  Produces output points in either of two forms.   *      points.  Produces output points in either of two forms.
1023   *   *
1024   *      Note: in spite of this procedure's name, it does *not* generate   *      Note: in spite of this procedure's name, it does *not* generate
1025   *      Bezier curves.  Since only three control points are used for   *      Bezier curves.  Since only three control points are used for
1026   *      each curve segment, not four, the curves are actually just   *      each curve segment, not four, the curves are actually just
1027   *      parabolic.   *      parabolic.
1028   *   *
1029   * Results:   * Results:
1030   *      Either or both of the xPoints or dblPoints arrays are filled   *      Either or both of the xPoints or dblPoints arrays are filled
1031   *      in.  The return value is the number of points placed in the   *      in.  The return value is the number of points placed in the
1032   *      arrays.  Note:  if the first and last points are the same, then   *      arrays.  Note:  if the first and last points are the same, then
1033   *      a closed curve is generated.   *      a closed curve is generated.
1034   *   *
1035   * Side effects:   * Side effects:
1036   *      None.   *      None.
1037   *   *
1038   *--------------------------------------------------------------   *--------------------------------------------------------------
1039   */   */
1040    
1041  int  int
1042  TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints)  TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints)
1043      Tk_Canvas canvas;                   /* Canvas in which curve is to be      Tk_Canvas canvas;                   /* Canvas in which curve is to be
1044                                           * drawn. */                                           * drawn. */
1045      double *pointPtr;                   /* Array of input coordinates:  x0,      double *pointPtr;                   /* Array of input coordinates:  x0,
1046                                           * y0, x1, y1, etc.. */                                           * y0, x1, y1, etc.. */
1047      int numPoints;                      /* Number of points at pointPtr. */      int numPoints;                      /* Number of points at pointPtr. */
1048      int numSteps;                       /* Number of steps to use for each      int numSteps;                       /* Number of steps to use for each
1049                                           * spline segments (determines                                           * spline segments (determines
1050                                           * smoothness of curve). */                                           * smoothness of curve). */
1051      XPoint xPoints[];                   /* Array of XPoints to fill in (e.g.      XPoint xPoints[];                   /* Array of XPoints to fill in (e.g.
1052                                           * for display.  NULL means don't                                           * for display.  NULL means don't
1053                                           * fill in any XPoints. */                                           * fill in any XPoints. */
1054      double dblPoints[];                 /* Array of points to fill in as      double dblPoints[];                 /* Array of points to fill in as
1055                                           * doubles, in the form x0, y0,                                           * doubles, in the form x0, y0,
1056                                           * x1, y1, ....  NULL means don't                                           * x1, y1, ....  NULL means don't
1057                                           * fill in anything in this form.                                           * fill in anything in this form.
1058                                           * Caller must make sure that this                                           * Caller must make sure that this
1059                                           * array has enough space. */                                           * array has enough space. */
1060  {  {
1061      int closed, outputPoints, i;      int closed, outputPoints, i;
1062      int numCoords = numPoints*2;      int numCoords = numPoints*2;
1063      double control[8];      double control[8];
1064    
1065      /*      /*
1066       * If the curve is a closed one then generate a special spline       * If the curve is a closed one then generate a special spline
1067       * that spans the last points and the first ones.  Otherwise       * that spans the last points and the first ones.  Otherwise
1068       * just put the first point into the output.       * just put the first point into the output.
1069       */       */
1070    
1071      if (!pointPtr) {      if (!pointPtr) {
1072          /* Of pointPtr == NULL, this function returns an upper limit.          /* Of pointPtr == NULL, this function returns an upper limit.
1073           * of the array size to store the coordinates. This can be           * of the array size to store the coordinates. This can be
1074           * used to allocate storage, before the actual coordinates           * used to allocate storage, before the actual coordinates
1075           * are calculated. */           * are calculated. */
1076          return 1 + numPoints * numSteps;          return 1 + numPoints * numSteps;
1077      }      }
1078    
1079      outputPoints = 0;      outputPoints = 0;
1080      if ((pointPtr[0] == pointPtr[numCoords-2])      if ((pointPtr[0] == pointPtr[numCoords-2])
1081              && (pointPtr[1] == pointPtr[numCoords-1])) {              && (pointPtr[1] == pointPtr[numCoords-1])) {
1082          closed = 1;          closed = 1;
1083          control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0];          control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0];
1084          control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1];          control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1];
1085          control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0];          control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0];
1086          control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1];          control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1];
1087          control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2];          control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2];
1088          control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3];          control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3];
1089          control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];          control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
1090          control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];          control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
1091          if (xPoints != NULL) {          if (xPoints != NULL) {
1092              Tk_CanvasDrawableCoords(canvas, control[0], control[1],              Tk_CanvasDrawableCoords(canvas, control[0], control[1],
1093                      &xPoints->x, &xPoints->y);                      &xPoints->x, &xPoints->y);
1094              TkBezierScreenPoints(canvas, control, numSteps, xPoints+1);              TkBezierScreenPoints(canvas, control, numSteps, xPoints+1);
1095              xPoints += numSteps+1;              xPoints += numSteps+1;
1096          }          }
1097          if (dblPoints != NULL) {          if (dblPoints != NULL) {
1098              dblPoints[0] = control[0];              dblPoints[0] = control[0];
1099              dblPoints[1] = control[1];              dblPoints[1] = control[1];
1100              TkBezierPoints(control, numSteps, dblPoints+2);              TkBezierPoints(control, numSteps, dblPoints+2);
1101              dblPoints += 2*(numSteps+1);              dblPoints += 2*(numSteps+1);
1102          }          }
1103          outputPoints += numSteps+1;          outputPoints += numSteps+1;
1104      } else {      } else {
1105          closed = 0;          closed = 0;
1106          if (xPoints != NULL) {          if (xPoints != NULL) {
1107              Tk_CanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1],              Tk_CanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1],
1108                      &xPoints->x, &xPoints->y);                      &xPoints->x, &xPoints->y);
1109              xPoints += 1;              xPoints += 1;
1110          }          }
1111          if (dblPoints != NULL) {          if (dblPoints != NULL) {
1112              dblPoints[0] = pointPtr[0];              dblPoints[0] = pointPtr[0];
1113              dblPoints[1] = pointPtr[1];              dblPoints[1] = pointPtr[1];
1114              dblPoints += 2;              dblPoints += 2;
1115          }          }
1116          outputPoints += 1;          outputPoints += 1;
1117      }      }
1118    
1119      for (i = 2; i < numPoints; i++, pointPtr += 2) {      for (i = 2; i < numPoints; i++, pointPtr += 2) {
1120          /*          /*
1121           * Set up the first two control points.  This is done           * Set up the first two control points.  This is done
1122           * differently for the first spline of an open curve           * differently for the first spline of an open curve
1123           * than for other cases.           * than for other cases.
1124           */           */
1125    
1126          if ((i == 2) && !closed) {          if ((i == 2) && !closed) {
1127              control[0] = pointPtr[0];              control[0] = pointPtr[0];
1128              control[1] = pointPtr[1];              control[1] = pointPtr[1];
1129              control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2];              control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2];
1130              control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3];              control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3];
1131          } else {          } else {
1132              control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2];              control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
1133              control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3];              control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
1134              control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2];              control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2];
1135              control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3];              control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3];
1136          }          }
1137    
1138          /*          /*
1139           * Set up the last two control points.  This is done           * Set up the last two control points.  This is done
1140           * differently for the last spline of an open curve           * differently for the last spline of an open curve
1141           * than for other cases.           * than for other cases.
1142           */           */
1143    
1144          if ((i == (numPoints-1)) && !closed) {          if ((i == (numPoints-1)) && !closed) {
1145              control[4] = .667*pointPtr[2] + .333*pointPtr[4];              control[4] = .667*pointPtr[2] + .333*pointPtr[4];
1146              control[5] = .667*pointPtr[3] + .333*pointPtr[5];              control[5] = .667*pointPtr[3] + .333*pointPtr[5];
1147              control[6] = pointPtr[4];              control[6] = pointPtr[4];
1148              control[7] = pointPtr[5];              control[7] = pointPtr[5];
1149          } else {          } else {
1150              control[4] = .833*pointPtr[2] + .167*pointPtr[4];              control[4] = .833*pointPtr[2] + .167*pointPtr[4];
1151              control[5] = .833*pointPtr[3] + .167*pointPtr[5];              control[5] = .833*pointPtr[3] + .167*pointPtr[5];
1152              control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4];              control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4];
1153              control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5];              control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5];
1154          }          }
1155    
1156          /*          /*
1157           * If the first two points coincide, or if the last           * If the first two points coincide, or if the last
1158           * two points coincide, then generate a single           * two points coincide, then generate a single
1159           * straight-line segment by outputting the last control           * straight-line segment by outputting the last control
1160           * point.           * point.
1161           */           */
1162    
1163          if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3]))          if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3]))
1164                  || ((pointPtr[2] == pointPtr[4])                  || ((pointPtr[2] == pointPtr[4])
1165                  && (pointPtr[3] == pointPtr[5]))) {                  && (pointPtr[3] == pointPtr[5]))) {
1166              if (xPoints != NULL) {              if (xPoints != NULL) {
1167                  Tk_CanvasDrawableCoords(canvas, control[6], control[7],                  Tk_CanvasDrawableCoords(canvas, control[6], control[7],
1168                          &xPoints[0].x, &xPoints[0].y);                          &xPoints[0].x, &xPoints[0].y);
1169                  xPoints++;                  xPoints++;
1170              }              }
1171              if (dblPoints != NULL) {              if (dblPoints != NULL) {
1172                  dblPoints[0] = control[6];                  dblPoints[0] = control[6];
1173                  dblPoints[1] = control[7];                  dblPoints[1] = control[7];
1174                  dblPoints += 2;                  dblPoints += 2;
1175              }              }
1176              outputPoints += 1;              outputPoints += 1;
1177              continue;              continue;
1178          }          }
1179    
1180          /*          /*
1181           * Generate a Bezier spline using the control points.           * Generate a Bezier spline using the control points.
1182           */           */
1183    
1184    
1185          if (xPoints != NULL) {          if (xPoints != NULL) {
1186              TkBezierScreenPoints(canvas, control, numSteps, xPoints);              TkBezierScreenPoints(canvas, control, numSteps, xPoints);
1187              xPoints += numSteps;              xPoints += numSteps;
1188          }          }
1189          if (dblPoints != NULL) {          if (dblPoints != NULL) {
1190              TkBezierPoints(control, numSteps, dblPoints);              TkBezierPoints(control, numSteps, dblPoints);
1191              dblPoints += 2*numSteps;              dblPoints += 2*numSteps;
1192          }          }
1193          outputPoints += numSteps;          outputPoints += numSteps;
1194      }      }
1195      return outputPoints;      return outputPoints;
1196  }  }
1197    
1198  /*  /*
1199   *--------------------------------------------------------------   *--------------------------------------------------------------
1200   *   *
1201   * TkMakeBezierPostscript --   * TkMakeBezierPostscript --
1202   *   *
1203   *      This procedure generates Postscript commands that create   *      This procedure generates Postscript commands that create
1204   *      a path corresponding to a given Bezier curve.   *      a path corresponding to a given Bezier curve.
1205   *   *
1206   * Results:   * Results:
1207   *      None.  Postscript commands to generate the path are appended   *      None.  Postscript commands to generate the path are appended
1208   *      to the interp's result.   *      to the interp's result.
1209   *   *
1210   * Side effects:   * Side effects:
1211   *      None.   *      None.
1212   *   *
1213   *--------------------------------------------------------------   *--------------------------------------------------------------
1214   */   */
1215    
1216  void  void
1217  TkMakeBezierPostscript(interp, canvas, pointPtr, numPoints)  TkMakeBezierPostscript(interp, canvas, pointPtr, numPoints)
1218      Tcl_Interp *interp;                 /* Interpreter in whose result the      Tcl_Interp *interp;                 /* Interpreter in whose result the
1219                                           * Postscript is to be stored. */                                           * Postscript is to be stored. */
1220      Tk_Canvas canvas;                   /* Canvas widget for which the      Tk_Canvas canvas;                   /* Canvas widget for which the
1221                                           * Postscript is being generated. */                                           * Postscript is being generated. */
1222      double *pointPtr;                   /* Array of input coordinates:  x0,      double *pointPtr;                   /* Array of input coordinates:  x0,
1223                                           * y0, x1, y1, etc.. */                                           * y0, x1, y1, etc.. */
1224      int numPoints;                      /* Number of points at pointPtr. */      int numPoints;                      /* Number of points at pointPtr. */
1225  {  {
1226      int closed, i;      int closed, i;
1227      int numCoords = numPoints*2;      int numCoords = numPoints*2;
1228      double control[8];      double control[8];
1229      char buffer[200];      char buffer[200];
1230    
1231      /*      /*
1232       * If the curve is a closed one then generate a special spline       * If the curve is a closed one then generate a special spline
1233       * that spans the last points and the first ones.  Otherwise       * that spans the last points and the first ones.  Otherwise
1234       * just put the first point into the path.       * just put the first point into the path.
1235       */       */
1236    
1237      if ((pointPtr[0] == pointPtr[numCoords-2])      if ((pointPtr[0] == pointPtr[numCoords-2])
1238              && (pointPtr[1] == pointPtr[numCoords-1])) {              && (pointPtr[1] == pointPtr[numCoords-1])) {
1239          closed = 1;          closed = 1;
1240          control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0];          control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0];
1241          control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1];          control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1];
1242          control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0];          control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0];
1243          control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1];          control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1];
1244          control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2];          control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2];
1245          control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3];          control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3];
1246          control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];          control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
1247          control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];          control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
1248          sprintf(buffer, "%.15g %.15g moveto\n%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",          sprintf(buffer, "%.15g %.15g moveto\n%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",
1249                  control[0], Tk_CanvasPsY(canvas, control[1]),                  control[0], Tk_CanvasPsY(canvas, control[1]),
1250                  control[2], Tk_CanvasPsY(canvas, control[3]),                  control[2], Tk_CanvasPsY(canvas, control[3]),
1251                  control[4], Tk_CanvasPsY(canvas, control[5]),                  control[4], Tk_CanvasPsY(canvas, control[5]),
1252                  control[6], Tk_CanvasPsY(canvas, control[7]));                  control[6], Tk_CanvasPsY(canvas, control[7]));
1253      } else {      } else {
1254          closed = 0;          closed = 0;
1255          control[6] = pointPtr[0];          control[6] = pointPtr[0];
1256          control[7] = pointPtr[1];          control[7] = pointPtr[1];
1257          sprintf(buffer, "%.15g %.15g moveto\n",          sprintf(buffer, "%.15g %.15g moveto\n",
1258                  control[6], Tk_CanvasPsY(canvas, control[7]));                  control[6], Tk_CanvasPsY(canvas, control[7]));
1259      }      }
1260      Tcl_AppendResult(interp, buffer, (char *) NULL);      Tcl_AppendResult(interp, buffer, (char *) NULL);
1261    
1262      /*      /*
1263       * Cycle through all the remaining points in the curve, generating       * Cycle through all the remaining points in the curve, generating
1264       * a curve section for each vertex in the linear path.       * a curve section for each vertex in the linear path.
1265       */       */
1266    
1267      for (i = numPoints-2, pointPtr += 2; i > 0; i--, pointPtr += 2) {      for (i = numPoints-2, pointPtr += 2; i > 0; i--, pointPtr += 2) {
1268          control[2] = 0.333*control[6] + 0.667*pointPtr[0];          control[2] = 0.333*control[6] + 0.667*pointPtr[0];
1269          control[3] = 0.333*control[7] + 0.667*pointPtr[1];          control[3] = 0.333*control[7] + 0.667*pointPtr[1];
1270    
1271          /*          /*
1272           * Set up the last two control points.  This is done           * Set up the last two control points.  This is done
1273           * differently for the last spline of an open curve           * differently for the last spline of an open curve
1274           * than for other cases.           * than for other cases.
1275           */           */
1276    
1277          if ((i == 1) && !closed) {          if ((i == 1) && !closed) {
1278              control[6] = pointPtr[2];              control[6] = pointPtr[2];
1279              control[7] = pointPtr[3];              control[7] = pointPtr[3];
1280          } else {          } else {
1281              control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];              control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
1282              control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];              control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
1283          }          }
1284          control[4] = 0.333*control[6] + 0.667*pointPtr[0];          control[4] = 0.333*control[6] + 0.667*pointPtr[0];
1285          control[5] = 0.333*control[7] + 0.667*pointPtr[1];          control[5] = 0.333*control[7] + 0.667*pointPtr[1];
1286    
1287          sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",          sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",
1288                  control[2], Tk_CanvasPsY(canvas, control[3]),                  control[2], Tk_CanvasPsY(canvas, control[3]),
1289                  control[4], Tk_CanvasPsY(canvas, control[5]),                  control[4], Tk_CanvasPsY(canvas, control[5]),
1290                  control[6], Tk_CanvasPsY(canvas, control[7]));                  control[6], Tk_CanvasPsY(canvas, control[7]));
1291          Tcl_AppendResult(interp, buffer, (char *) NULL);          Tcl_AppendResult(interp, buffer, (char *) NULL);
1292      }      }
1293  }  }
1294    
1295  /*  /*
1296   *--------------------------------------------------------------   *--------------------------------------------------------------
1297   *   *
1298   * TkGetMiterPoints --   * TkGetMiterPoints --
1299   *   *
1300   *      Given three points forming an angle, compute the   *      Given three points forming an angle, compute the
1301   *      coordinates of the inside and outside points of   *      coordinates of the inside and outside points of
1302   *      the mitered corner formed by a line of a given   *      the mitered corner formed by a line of a given
1303   *      width at that angle.   *      width at that angle.
1304   *   *
1305   * Results:   * Results:
1306   *      If the angle formed by the three points is less than   *      If the angle formed by the three points is less than
1307   *      11 degrees then 0 is returned and m1 and m2 aren't   *      11 degrees then 0 is returned and m1 and m2 aren't
1308   *      modified.  Otherwise 1 is returned and the points at   *      modified.  Otherwise 1 is returned and the points at
1309   *      m1 and m2 are filled in with the positions of the points   *      m1 and m2 are filled in with the positions of the points
1310   *      of the mitered corner.   *      of the mitered corner.
1311   *   *
1312   * Side effects:   * Side effects:
1313   *      None.   *      None.
1314   *   *
1315   *--------------------------------------------------------------   *--------------------------------------------------------------
1316   */   */
1317    
1318  int  int
1319  TkGetMiterPoints(p1, p2, p3, width, m1, m2)  TkGetMiterPoints(p1, p2, p3, width, m1, m2)
1320      double p1[];                /* Points to x- and y-coordinates of point      double p1[];                /* Points to x- and y-coordinates of point
1321                                   * before vertex. */                                   * before vertex. */
1322      double p2[];                /* Points to x- and y-coordinates of vertex      double p2[];                /* Points to x- and y-coordinates of vertex
1323                                   * for mitered joint. */                                   * for mitered joint. */
1324      double p3[];                /* Points to x- and y-coordinates of point      double p3[];                /* Points to x- and y-coordinates of point
1325                                   * after vertex. */                                   * after vertex. */
1326      double width;               /* Width of line.  */      double width;               /* Width of line.  */
1327      double m1[];                /* Points to place to put "left" vertex      double m1[];                /* Points to place to put "left" vertex
1328                                   * point (see as you face from p1 to p2). */                                   * point (see as you face from p1 to p2). */
1329      double m2[];                /* Points to place to put "right" vertex      double m2[];                /* Points to place to put "right" vertex
1330                                   * point. */                                   * point. */
1331  {  {
1332      double theta1;              /* Angle of segment p2-p1. */      double theta1;              /* Angle of segment p2-p1. */
1333      double theta2;              /* Angle of segment p2-p3. */      double theta2;              /* Angle of segment p2-p3. */
1334      double theta;               /* Angle between line segments (angle      double theta;               /* Angle between line segments (angle
1335                                   * of joint). */                                   * of joint). */
1336      double theta3;              /* Angle that bisects theta1 and      double theta3;              /* Angle that bisects theta1 and
1337                                   * theta2 and points to m1. */                                   * theta2 and points to m1. */
1338      double dist;                /* Distance of miter points from p2. */      double dist;                /* Distance of miter points from p2. */
1339      double deltaX, deltaY;      /* X and y offsets cooresponding to      double deltaX, deltaY;      /* X and y offsets cooresponding to
1340                                   * dist (fudge factors for bounding                                   * dist (fudge factors for bounding
1341                                   * box). */                                   * box). */
1342      double p1x, p1y, p2x, p2y, p3x, p3y;      double p1x, p1y, p2x, p2y, p3x, p3y;
1343      static double elevenDegrees = (11.0*2.0*PI)/360.0;      static double elevenDegrees = (11.0*2.0*PI)/360.0;
1344    
1345      /*      /*
1346       * Round the coordinates to integers to mimic what happens when the       * Round the coordinates to integers to mimic what happens when the
1347       * line segments are displayed; without this code, the bounding box       * line segments are displayed; without this code, the bounding box
1348       * of a mitered line can be miscomputed greatly.       * of a mitered line can be miscomputed greatly.
1349       */       */
1350    
1351      p1x = floor(p1[0]+0.5);      p1x = floor(p1[0]+0.5);
1352      p1y = floor(p1[1]+0.5);      p1y = floor(p1[1]+0.5);
1353      p2x = floor(p2[0]+0.5);      p2x = floor(p2[0]+0.5);
1354      p2y = floor(p2[1]+0.5);      p2y = floor(p2[1]+0.5);
1355      p3x = floor(p3[0]+0.5);      p3x = floor(p3[0]+0.5);
1356      p3y = floor(p3[1]+0.5);      p3y = floor(p3[1]+0.5);
1357    
1358      if (p2y == p1y) {      if (p2y == p1y) {
1359          theta1 = (p2x < p1x) ? 0 : PI;          theta1 = (p2x < p1x) ? 0 : PI;
1360      } else if (p2x == p1x) {      } else if (p2x == p1x) {
1361          theta1 = (p2y < p1y) ? PI/2.0 : -PI/2.0;          theta1 = (p2y < p1y) ? PI/2.0 : -PI/2.0;
1362      } else {      } else {
1363          theta1 = atan2(p1y - p2y, p1x - p2x);          theta1 = atan2(p1y - p2y, p1x - p2x);
1364      }      }
1365      if (p3y == p2y) {      if (p3y == p2y) {
1366          theta2 = (p3x > p2x) ? 0 : PI;          theta2 = (p3x > p2x) ? 0 : PI;
1367      } else if (p3x == p2x) {      } else if (p3x == p2x) {
1368          theta2 = (p3y > p2y) ? PI/2.0 : -PI/2.0;          theta2 = (p3y > p2y) ? PI/2.0 : -PI/2.0;
1369      } else {      } else {
1370          theta2 = atan2(p3y - p2y, p3x - p2x);          theta2 = atan2(p3y - p2y, p3x - p2x);
1371      }      }
1372      theta = theta1 - theta2;      theta = theta1 - theta2;
1373      if (theta > PI) {      if (theta > PI) {
1374          theta -= 2*PI;          theta -= 2*PI;
1375      } else if (theta < -PI) {      } else if (theta < -PI) {
1376          theta += 2*PI;          theta += 2*PI;
1377      }      }
1378      if ((theta < elevenDegrees) && (theta > -elevenDegrees)) {      if ((theta < elevenDegrees) && (theta > -elevenDegrees)) {
1379          return 0;          return 0;
1380      }      }
1381      dist = 0.5*width/sin(0.5*theta);      dist = 0.5*width/sin(0.5*theta);
1382      if (dist < 0.0) {      if (dist < 0.0) {
1383          dist = -dist;          dist = -dist;
1384      }      }
1385    
1386      /*      /*
1387       * Compute theta3 (make sure that it points to the left when       * Compute theta3 (make sure that it points to the left when
1388       * looking from p1 to p2).       * looking from p1 to p2).
1389       */       */
1390    
1391      theta3 = (theta1 + theta2)/2.0;      theta3 = (theta1 + theta2)/2.0;
1392      if (sin(theta3 - (theta1 + PI)) < 0.0) {      if (sin(theta3 - (theta1 + PI)) < 0.0) {
1393          theta3 += PI;          theta3 += PI;
1394      }      }
1395      deltaX = dist*cos(theta3);      deltaX = dist*cos(theta3);
1396      m1[0] = p2x + deltaX;      m1[0] = p2x + deltaX;
1397      m2[0] = p2x - deltaX;      m2[0] = p2x - deltaX;
1398      deltaY = dist*sin(theta3);      deltaY = dist*sin(theta3);
1399      m1[1] = p2y + deltaY;      m1[1] = p2y + deltaY;
1400      m2[1] = p2y - deltaY;      m2[1] = p2y - deltaY;
1401      return 1;      return 1;
1402  }  }
1403    
1404  /*  /*
1405   *--------------------------------------------------------------   *--------------------------------------------------------------
1406   *   *
1407   * TkGetButtPoints --   * TkGetButtPoints --
1408   *   *
1409   *      Given two points forming a line segment, compute the   *      Given two points forming a line segment, compute the
1410   *      coordinates of two endpoints of a rectangle formed by   *      coordinates of two endpoints of a rectangle formed by
1411   *      bloating the line segment until it is width units wide.   *      bloating the line segment until it is width units wide.
1412   *   *
1413   * Results:   * Results:
1414   *      There is no return value.  M1 and m2 are filled in to   *      There is no return value.  M1 and m2 are filled in to
1415   *      correspond to m1 and m2 in the diagram below:   *      correspond to m1 and m2 in the diagram below:
1416   *   *
1417   *                 ----------------* m1   *                 ----------------* m1
1418   *                                 |   *                                 |
1419   *              p1 *---------------* p2   *              p1 *---------------* p2
1420   *                                 |   *                                 |
1421   *                 ----------------* m2   *                 ----------------* m2
1422   *   *
1423   *      M1 and m2 will be W units apart, with p2 centered between   *      M1 and m2 will be W units apart, with p2 centered between
1424   *      them and m1-m2 perpendicular to p1-p2.  However, if   *      them and m1-m2 perpendicular to p1-p2.  However, if
1425   *      "project" is true then m1 and m2 will be as follows:   *      "project" is true then m1 and m2 will be as follows:
1426   *   *
1427   *                 -------------------* m1   *                 -------------------* m1
1428   *                                p2  |   *                                p2  |
1429   *              p1 *---------------*  |   *              p1 *---------------*  |
1430   *                                    |   *                                    |
1431   *                 -------------------* m2   *                 -------------------* m2
1432   *   *
1433   *      In this case p2 will be width/2 units from the segment m1-m2.   *      In this case p2 will be width/2 units from the segment m1-m2.
1434   *   *
1435   * Side effects:   * Side effects:
1436   *      None.   *      None.
1437   *   *
1438   *--------------------------------------------------------------   *--------------------------------------------------------------
1439   */   */
1440    
1441  void  void
1442  TkGetButtPoints(p1, p2, width, project, m1, m2)  TkGetButtPoints(p1, p2, width, project, m1, m2)
1443      double p1[];                /* Points to x- and y-coordinates of point      double p1[];                /* Points to x- and y-coordinates of point
1444                                   * before vertex. */                                   * before vertex. */
1445      double p2[];                /* Points to x- and y-coordinates of vertex      double p2[];                /* Points to x- and y-coordinates of vertex
1446                                   * for mitered joint. */                                   * for mitered joint. */
1447      double width;               /* Width of line.  */      double width;               /* Width of line.  */
1448      int project;                /* Non-zero means project p2 by an additional      int project;                /* Non-zero means project p2 by an additional
1449                                   * width/2 before computing m1 and m2. */                                   * width/2 before computing m1 and m2. */
1450      double m1[];                /* Points to place to put "left" result      double m1[];                /* Points to place to put "left" result
1451                                   * point, as you face from p1 to p2. */                                   * point, as you face from p1 to p2. */
1452      double m2[];                /* Points to place to put "right" result      double m2[];                /* Points to place to put "right" result
1453                                   * point. */                                   * point. */
1454  {  {
1455      double length;              /* Length of p1-p2 segment. */      double length;              /* Length of p1-p2 segment. */
1456      double deltaX, deltaY;      /* Increments in coords. */      double deltaX, deltaY;      /* Increments in coords. */
1457    
1458      width *= 0.5;      width *= 0.5;
1459      length = hypot(p2[0] - p1[0], p2[1] - p1[1]);      length = hypot(p2[0] - p1[0], p2[1] - p1[1]);
1460      if (length == 0.0) {      if (length == 0.0) {
1461          m1[0] = m2[0] = p2[0];          m1[0] = m2[0] = p2[0];
1462          m1[1] = m2[1] = p2[1];          m1[1] = m2[1] = p2[1];
1463      } else {      } else {
1464          deltaX = -width * (p2[1] - p1[1]) / length;          deltaX = -width * (p2[1] - p1[1]) / length;
1465          deltaY = width * (p2[0] - p1[0]) / length;          deltaY = width * (p2[0] - p1[0]) / length;
1466          m1[0] = p2[0] + deltaX;          m1[0] = p2[0] + deltaX;
1467          m2[0] = p2[0] - deltaX;          m2[0] = p2[0] - deltaX;
1468          m1[1] = p2[1] + deltaY;          m1[1] = p2[1] + deltaY;
1469          m2[1] = p2[1] - deltaY;          m2[1] = p2[1] - deltaY;
1470          if (project) {          if (project) {
1471              m1[0] += deltaY;              m1[0] += deltaY;
1472              m2[0] += deltaY;              m2[0] += deltaY;
1473              m1[1] -= deltaX;              m1[1] -= deltaX;
1474              m2[1] -= deltaX;              m2[1] -= deltaX;
1475          }          }
1476      }      }
1477  }  }
1478    
1479  /* End of tktrig.c */  /* End of tktrig.c */

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25