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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25