]>
cvs.zerfleddert.de Git - micropolis/blob - src/tk/tktrig.c
4 * This file contains a collection of trigonometry utility
5 * routines that are used by Tk and in particular by the
6 * canvas code. It also has miscellaneous geometry functions
9 * Copyright 1992 Regents of the University of California.
10 * Permission to use, copy, modify, and distribute this
11 * software and its documentation for any purpose and without
12 * fee is hereby granted, provided that the above copyright
13 * notice appear in all copies. The University of California
14 * makes no representations about the suitability of this
15 * software for any purpose. It is provided "as is" without
16 * express or implied warranty.
20 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkTrig.c,v 1.8 92/08/24 09:24:14 ouster Exp $ SPRITE (Berkeley)";
29 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
31 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
32 #define PI 3.14159265358979323846
35 *--------------------------------------------------------------
39 * Compute the distance from a point to a finite line segment.
42 * The return value is the distance from the line segment
43 * whose end-points are *end1Ptr and *end2Ptr to the point
49 *--------------------------------------------------------------
54 double end1Ptr
[2], /* Coordinates of first end-point of line. */
55 double end2Ptr
[2], /* Coordinates of second end-point of line. */
56 double pointPtr
[2] /* Points to coords for point. */
62 * Compute the point on the line that is closest to the
63 * point. This must be done separately for vertical edges,
64 * horizontal edges, and other edges.
67 if (end1Ptr
[0] == end2Ptr
[0]) {
74 if (end1Ptr
[1] >= end2Ptr
[1]) {
75 y
= MIN(end1Ptr
[1], pointPtr
[1]);
76 y
= MAX(y
, end2Ptr
[1]);
78 y
= MIN(end2Ptr
[1], pointPtr
[1]);
79 y
= MAX(y
, end1Ptr
[1]);
81 } else if (end1Ptr
[1] == end2Ptr
[1]) {
88 if (end1Ptr
[0] >= end2Ptr
[0]) {
89 x
= MIN(end1Ptr
[0], pointPtr
[0]);
90 x
= MAX(x
, end2Ptr
[0]);
92 x
= MIN(end2Ptr
[0], pointPtr
[0]);
93 x
= MAX(x
, end1Ptr
[0]);
96 double m1
, b1
, m2
, b2
;
99 * The edge is neither horizontal nor vertical. Convert the
100 * edge to a line equation of the form y = m1*x + b1. Then
101 * compute a line perpendicular to this edge but passing
102 * through the point, also in the form y = m2*x + b2.
105 m1
= (end2Ptr
[1] - end1Ptr
[1])/(end2Ptr
[0] - end1Ptr
[0]);
106 b1
= end1Ptr
[1] - m1
*end1Ptr
[0];
108 b2
= pointPtr
[1] - m2
*pointPtr
[0];
109 x
= (b2
- b1
)/(m1
- m2
);
111 if (end1Ptr
[0] > end2Ptr
[0]) {
112 if (x
> end1Ptr
[0]) {
115 } else if (x
< end2Ptr
[0]) {
120 if (x
> end2Ptr
[0]) {
123 } else if (x
< end1Ptr
[0]) {
131 * Compute the distance to the closest point.
134 return hypot(pointPtr
[0] - x
, pointPtr
[1] - y
);
138 *--------------------------------------------------------------
142 * Determine whether a line lies entirely inside, entirely
143 * outside, or overlapping a given rectangular area.
146 * -1 is returned if the line given by end1Ptr and end2Ptr
147 * is entirely outside the rectangle given by rectPtr. 0 is
148 * returned if the polygon overlaps the rectangle, and 1 is
149 * returned if the polygon is entirely inside the rectangle.
154 *--------------------------------------------------------------
159 double end1Ptr
[2], /* X and y coordinates for one endpoint
161 double end2Ptr
[2], /* X and y coordinates for other endpoint
163 double rectPtr
[4] /* Points to coords for rectangle, in the
164 * order x1, y1, x2, y2. X1 must be no
165 * larger than x2, and y1 no larger than y2. */
168 int inside1
, inside2
;
171 * First check the two points individually to see whether they
172 * are inside the rectangle or not.
175 inside1
= (end1Ptr
[0] >= rectPtr
[0]) && (end1Ptr
[0] <= rectPtr
[2])
176 && (end1Ptr
[1] >= rectPtr
[1]) && (end1Ptr
[1] <= rectPtr
[3]);
177 inside2
= (end2Ptr
[0] >= rectPtr
[0]) && (end2Ptr
[0] <= rectPtr
[2])
178 && (end2Ptr
[1] >= rectPtr
[1]) && (end2Ptr
[1] <= rectPtr
[3]);
179 if (inside1
!= inside2
) {
182 if (inside1
& inside2
) {
187 * Both points are outside the rectangle, but still need to check
188 * for intersections between the line and the rectangle. Horizontal
189 * and vertical lines are particularly easy, so handle them
193 if (end1Ptr
[0] == end2Ptr
[0]) {
198 if (((end1Ptr
[1] >= rectPtr
[1]) ^ (end2Ptr
[1] >= rectPtr
[1]))
199 && (end1Ptr
[0] >= rectPtr
[0])
200 && (end1Ptr
[0] <= rectPtr
[2])) {
203 } else if (end1Ptr
[1] == end2Ptr
[1]) {
208 if (((end1Ptr
[0] >= rectPtr
[0]) ^ (end2Ptr
[0] >= rectPtr
[0]))
209 && (end1Ptr
[1] >= rectPtr
[1])
210 && (end1Ptr
[1] <= rectPtr
[3])) {
214 double m
, x
, y
, low
, high
;
217 * Diagonal line. Compute slope of line and use
218 * for intersection checks against each of the
219 * sides of the rectangle: left, right, bottom, top.
222 m
= (end2Ptr
[1] - end1Ptr
[1])/(end2Ptr
[0] - end1Ptr
[0]);
223 if (end1Ptr
[0] < end2Ptr
[0]) {
224 low
= end1Ptr
[0]; high
= end2Ptr
[0];
226 low
= end2Ptr
[0]; high
= end1Ptr
[0];
233 y
= end1Ptr
[1] + (rectPtr
[0] - end1Ptr
[0])*m
;
234 if ((rectPtr
[0] >= low
) && (rectPtr
[0] <= high
)
235 && (y
>= rectPtr
[1]) && (y
<= rectPtr
[3])) {
243 y
+= (rectPtr
[2] - rectPtr
[0])*m
;
244 if ((y
>= rectPtr
[1]) && (y
<= rectPtr
[3])
245 && (rectPtr
[2] >= low
) && (rectPtr
[2] <= high
)) {
253 if (end1Ptr
[1] < end2Ptr
[1]) {
254 low
= end1Ptr
[1]; high
= end2Ptr
[1];
256 low
= end2Ptr
[1]; high
= end1Ptr
[1];
258 x
= end1Ptr
[0] + (rectPtr
[1] - end1Ptr
[1])/m
;
259 if ((x
>= rectPtr
[0]) && (x
<= rectPtr
[2])
260 && (rectPtr
[1] >= low
) && (rectPtr
[1] <= high
)) {
268 x
+= (rectPtr
[3] - rectPtr
[1])/m
;
269 if ((x
>= rectPtr
[0]) && (x
<= rectPtr
[2])
270 && (rectPtr
[3] >= low
) && (rectPtr
[3] <= high
)) {
278 *--------------------------------------------------------------
280 * TkPolygonToPoint --
282 * Compute the distance from a point to a polygon.
285 * The return value is 0.0 if the point referred to by
286 * pointPtr is within the polygon referred to by polyPtr
287 * and numPoints. Otherwise the return value is the
288 * distance of the point from the polygon.
293 *--------------------------------------------------------------
298 double *polyPtr
, /* Points to an array coordinates for
299 * closed polygon: x0, y0, x1, y1, ...
300 * The polygon may be self-intersecting. */
301 int numPoints
, /* Total number of points at *polyPtr. */
302 double *pointPtr
/* Points to coords for point. */
305 double bestDist
; /* Closest distance between point and
306 * any edge in polygon. */
307 int intersections
; /* Number of edges in the polygon that
308 * intersect a ray extending vertically
309 * upwards from the point to infinity. */
311 register double *pPtr
;
314 * Iterate through all of the edges in the polygon, updating
315 * bestDist and intersections.
317 * TRICKY POINT: when computing intersections, include left
318 * x-coordinate of line within its range, but not y-coordinate.
319 * Otherwise if the point lies exactly below a vertex we'll
320 * count it as two intersections.
326 for (count
= numPoints
, pPtr
= polyPtr
; count
> 1; count
--, pPtr
+= 2) {
330 * Compute the point on the current edge closest to the point
331 * and update the intersection count. This must be done
332 * separately for vertical edges, horizontal edges, and
336 if (pPtr
[2] == pPtr
[0]) {
343 if (pPtr
[1] >= pPtr
[3]) {
344 y
= MIN(pPtr
[1], pointPtr
[1]);
347 y
= MIN(pPtr
[3], pointPtr
[1]);
350 } else if (pPtr
[3] == pPtr
[1]) {
357 if (pPtr
[0] >= pPtr
[2]) {
358 x
= MIN(pPtr
[0], pointPtr
[0]);
360 if ((pointPtr
[1] < y
) && (pointPtr
[0] < pPtr
[0])
361 && (pointPtr
[0] >= pPtr
[2])) {
365 x
= MIN(pPtr
[2], pointPtr
[0]);
367 if ((pointPtr
[1] < y
) && (pointPtr
[0] < pPtr
[2])
368 && (pointPtr
[0] >= pPtr
[0])) {
373 double m1
, b1
, m2
, b2
;
374 int lower
; /* Non-zero means point below line. */
377 * The edge is neither horizontal nor vertical. Convert the
378 * edge to a line equation of the form y = m1*x + b1. Then
379 * compute a line perpendicular to this edge but passing
380 * through the point, also in the form y = m2*x + b2.
383 m1
= (pPtr
[3] - pPtr
[1])/(pPtr
[2] - pPtr
[0]);
384 b1
= pPtr
[1] - m1
*pPtr
[0];
386 b2
= pointPtr
[1] - m2
*pointPtr
[0];
387 x
= (b2
- b1
)/(m1
- m2
);
389 if (pPtr
[0] > pPtr
[2]) {
393 } else if (x
< pPtr
[2]) {
401 } else if (x
< pPtr
[0]) {
406 lower
= (m1
*pointPtr
[0] + b1
) > pointPtr
[1];
407 if (lower
&& (pointPtr
[0] >= MIN(pPtr
[0], pPtr
[2]))
408 && (pointPtr
[0] < MAX(pPtr
[0], pPtr
[2]))) {
414 * Compute the distance to the closest point, and see if that
415 * is the best distance seen so far.
418 dist
= hypot(pointPtr
[0] - x
, pointPtr
[1] - y
);
419 if (dist
< bestDist
) {
425 * We've processed all of the points. If the number of intersections
426 * is odd, the point is inside the polygon.
429 if (intersections
& 0x1) {
436 *--------------------------------------------------------------
440 * Determine whether a polygon lies entirely inside, entirely
441 * outside, or overlapping a given rectangular area.
444 * -1 is returned if the polygon given by polyPtr and numPoints
445 * is entirely outside the rectangle given by rectPtr. 0 is
446 * returned if the polygon overlaps the rectangle, and 1 is
447 * returned if the polygon is entirely inside the rectangle.
452 *--------------------------------------------------------------
457 double *polyPtr
, /* Points to an array coordinates for
458 * closed polygon: x0, y0, x1, y1, ...
459 * The polygon may be self-intersecting. */
460 int numPoints
, /* Total number of points at *polyPtr. */
461 register double *rectPtr
/* Points to coords for rectangle, in the
462 * order x1, y1, x2, y2. X1 and y1 must
463 * be lower-left corner. */
466 int state
; /* State of all edges seen so far (-1 means
467 * outside, 1 means inside, won't ever be
470 register double *pPtr
;
473 * Iterate over all of the edges of the polygon and test them
474 * against the rectangle. Can quit as soon as the state becomes
478 state
= TkLineToArea(polyPtr
, polyPtr
+2, rectPtr
);
482 for (pPtr
= polyPtr
+2, count
= numPoints
-1; count
>= 2;
483 pPtr
+= 2, count
--) {
484 if (TkLineToArea(pPtr
, pPtr
+2, rectPtr
) != state
) {
490 * If all of the edges were inside the rectangle we're done.
491 * If all of the edges were outside, then the rectangle could
492 * still intersect the polygon (if it's entirely enclosed).
493 * Call TkPolygonToPoint to figure this out.
499 if (TkPolygonToPoint(polyPtr
, numPoints
, rectPtr
) == 0.0) {
506 *--------------------------------------------------------------
510 * Computes the distance from a given point to a given
511 * oval, in canvas units.
514 * The return value is 0 if the point given by *pointPtr is
515 * inside the oval. If the point isn't inside the
516 * oval then the return value is approximately the distance
517 * from the point to the oval. If the oval is filled, then
518 * anywhere in the interior is considered "inside"; if
519 * the oval isn't filled, then "inside" means only the area
520 * occupied by the outline.
525 *--------------------------------------------------------------
531 double ovalPtr
[4], /* Pointer to array of four coordinates
532 * (x1, y1, x2, y2) defining oval's bounding
534 double width
, /* Width of outline for oval. */
535 int filled
, /* Non-zero means oval should be treated as
536 * filled; zero means only consider outline. */
537 double pointPtr
[2] /* Coordinates of point. */
540 double xDelta
, yDelta
, scaledDistance
, distToOutline
, distToCenter
;
543 * Compute the distance between the center of the oval and the
544 * point in question, using a coordinate system where the oval
545 * has been transformed to a circle with unit radius.
548 xDelta
= (pointPtr
[0] - (ovalPtr
[0] + ovalPtr
[2])/2.0);
549 yDelta
= (pointPtr
[1] - (ovalPtr
[1] + ovalPtr
[3])/2.0);
550 distToCenter
= hypot(xDelta
, yDelta
);
551 scaledDistance
= hypot(xDelta
/ ((ovalPtr
[2] + width
- ovalPtr
[0])/2.0),
552 yDelta
/ ((ovalPtr
[3] + width
- ovalPtr
[1])/2.0));
556 * If the scaled distance is greater than 1 then it means no
557 * hit. Compute the distance from the point to the edge of
558 * the circle, then scale this distance back to the original
561 * Note: this distance isn't completely accurate. It's only
562 * an approximation, and it can overestimate the correct
563 * distance when the oval is eccentric.
566 if (scaledDistance
> 1.0) {
567 return (distToCenter
/scaledDistance
) * (scaledDistance
- 1.0);
571 * Scaled distance less than 1 means the point is inside the
572 * outer edge of the oval. If this is a filled oval, then we
573 * have a hit. Otherwise, do the same computation as above
574 * (scale back to original coordinate system), but also check
575 * to see if the point is within the width of the outline.
581 distToOutline
= (distToCenter
/scaledDistance
) * (1.0 - scaledDistance
)
583 if (distToOutline
< 0.0) {
586 return distToOutline
;
590 *--------------------------------------------------------------
594 * Determine whether an oval lies entirely inside, entirely
595 * outside, or overlapping a given rectangular area.
598 * -1 is returned if the oval described by ovalPtr is entirely
599 * outside the rectangle given by rectPtr. 0 is returned if the
600 * oval overlaps the rectangle, and 1 is returned if the oval
601 * is entirely inside the rectangle.
606 *--------------------------------------------------------------
611 register double *ovalPtr
, /* Points to coordinates definining the
612 * bounding rectangle for the oval: x1, y1,
613 * x2, y2. X1 must be less than x2 and y1
615 register double *rectPtr
/* Points to coords for rectangle, in the
616 * order x1, y1, x2, y2. X1 and y1 must
617 * be lower-left corner. */
620 double centerX
, centerY
, radX
, radY
, deltaX
, deltaY
;
623 * First, see if oval is entirely inside rectangle or entirely
627 if ((rectPtr
[0] <= ovalPtr
[0]) && (rectPtr
[2] >= ovalPtr
[2])
628 && (rectPtr
[1] <= ovalPtr
[1]) && (rectPtr
[3] >= ovalPtr
[3])) {
631 if ((rectPtr
[2] < ovalPtr
[0]) || (rectPtr
[0] > ovalPtr
[2])
632 || (rectPtr
[3] < ovalPtr
[1]) || (rectPtr
[1] > ovalPtr
[3])) {
637 * Next, go through the rectangle side by side. For each side
638 * of the rectangle, find the point on the side that is closest
639 * to the oval's center, and see if that point is inside the
640 * oval. If at least one such point is inside the oval, then
641 * the rectangle intersects the oval.
644 centerX
= (ovalPtr
[0] + ovalPtr
[2])/2;
645 centerY
= (ovalPtr
[1] + ovalPtr
[3])/2;
646 radX
= (ovalPtr
[2] - ovalPtr
[0])/2;
647 radY
= (ovalPtr
[3] - ovalPtr
[1])/2;
649 deltaY
= rectPtr
[1] - centerY
;
651 deltaY
= centerY
- rectPtr
[3];
663 deltaX
= (rectPtr
[0] - centerX
)/radX
;
665 if ((deltaX
+ deltaY
) <= 1.0) {
673 deltaX
= (rectPtr
[2] - centerX
)/radX
;
675 if ((deltaX
+ deltaY
) <= 1.0) {
679 deltaX
= rectPtr
[0] - centerX
;
681 deltaX
= centerX
- rectPtr
[2];
693 deltaY
= (rectPtr
[1] - centerY
)/radY
;
695 if ((deltaX
+ deltaY
) < 1.0) {
703 deltaY
= (rectPtr
[3] - centerY
)/radY
;
705 if ((deltaX
+ deltaY
) < 1.0) {
713 *--------------------------------------------------------------
717 * Given a point and a generic canvas item header, expand
718 * the item's bounding box if needed to include the point.
726 *--------------------------------------------------------------
732 Tk_Canvas
*canvasPtr
, /* Canvas containing item. */
733 register Tk_Item
*itemPtr
, /* Item whose bounding box is
734 * being calculated. */
735 double *pointPtr
/* Address of two doubles giving
736 * x and y coordinates of point. */
741 tmp
= pointPtr
[0] + 0.5;
742 if (tmp
< itemPtr
->x1
) {
745 if (tmp
> itemPtr
->x2
) {
748 tmp
= pointPtr
[1] + 0.5;
749 if (tmp
< itemPtr
->y1
) {
752 if (tmp
> itemPtr
->y2
) {
758 *--------------------------------------------------------------
760 * TkBezierScreenPoints --
762 * Given four control points, create a larger set of XPoints
763 * for a Bezier spline based on the points.
766 * The array at *xPointPtr gets filled in with numSteps XPoints
767 * corresponding to the Bezier spline defined by the four
768 * control points. Note: no output point is generated for the
769 * first input point, but an output point *is* generated for
770 * the last input point.
775 *--------------------------------------------------------------
779 TkBezierScreenPoints (
780 Tk_Canvas
*canvasPtr
, /* Canvas in which curve is to be
782 double control
[], /* Array of coordinates for four
783 * control points: x0, y0, x1, y1,
785 int numSteps
, /* Number of curve points to
787 register XPoint
*xPointPtr
/* Where to put new points. */
791 double u
, u2
, u3
, t
, t2
, t3
;
793 for (i
= 1; i
<= numSteps
; i
++, xPointPtr
++) {
794 t
= ((double) i
)/((double) numSteps
);
800 xPointPtr
->x
= SCREEN_X(canvasPtr
, (control
[0]*u3
801 + 3.0 * (control
[2]*t
*u2
+ control
[4]*t2
*u
) + control
[6]*t3
));
802 xPointPtr
->y
= SCREEN_Y(canvasPtr
, (control
[1]*u3
803 + 3.0 * (control
[3]*t
*u2
+ control
[5]*t2
*u
) + control
[7]*t3
));
808 *--------------------------------------------------------------
812 * Given four control points, create a larger set of points
813 * for a Bezier spline based on the points.
816 * The array at *coordPtr gets filled in with 2*numSteps
817 * coordinates, which correspond to the Bezier spline defined
818 * by the four control points. Note: no output point is
819 * generated for the first input point, but an output point
820 * *is* generated for the last input point.
825 *--------------------------------------------------------------
830 double control
[], /* Array of coordinates for four
831 * control points: x0, y0, x1, y1,
833 int numSteps
, /* Number of curve points to
835 register double *coordPtr
/* Where to put new points. */
839 double u
, u2
, u3
, t
, t2
, t3
;
841 for (i
= 1; i
<= numSteps
; i
++, coordPtr
+= 2) {
842 t
= ((double) i
)/((double) numSteps
);
848 coordPtr
[0] = control
[0]*u3
849 + 3.0 * (control
[2]*t
*u2
+ control
[4]*t2
*u
) + control
[6]*t3
;
850 coordPtr
[1] = control
[1]*u3
851 + 3.0 * (control
[3]*t
*u2
+ control
[5]*t2
*u
) + control
[7]*t3
;
856 *--------------------------------------------------------------
858 * TkMakeBezierCurve --
860 * Given a set of points, create a new set of points that
861 * fit Bezier splines to the line segments connecting the
862 * original points. Produces output points in either of two
866 * Either or both of the xPoints or dblPoints arrays are filled
867 * in. The return value is the number of points placed in the
868 * arrays. Note: if the first and last points are the same, then
869 * a closed curve is generated.
874 *--------------------------------------------------------------
879 Tk_Canvas
*canvasPtr
, /* Canvas in which curve is to be
881 double *pointPtr
, /* Array of input coordinates: x0,
882 * y0, x1, y1, etc.. */
883 int numPoints
, /* Number of points at pointPtr. */
884 int numSteps
, /* Number of steps to use for each
885 * spline segments (determines
886 * smoothness of curve). */
887 XPoint xPoints
[], /* Array of XPoints to fill in (e.g.
888 * for display. NULL means don't
889 * fill in any XPoints. */
890 double dblPoints
[] /* Array of points to fill in as
891 * doubles, in the form x0, y0,
892 * x1, y1, .... NULL means don't
893 * fill in anything in this form.
894 * Caller must make sure that this
895 * array has enough space. */
898 int closed
, outputPoints
, i
;
899 int numCoords
= numPoints
*2;
903 * If the curve is a closed one then generate a special spline
904 * that spans the last points and the first ones. Otherwise
905 * just put the first point into the output.
909 if ((pointPtr
[0] == pointPtr
[numCoords
-2])
910 && (pointPtr
[1] == pointPtr
[numCoords
-1])) {
912 control
[0] = 0.5*pointPtr
[numCoords
-4] + 0.5*pointPtr
[0];
913 control
[1] = 0.5*pointPtr
[numCoords
-3] + 0.5*pointPtr
[1];
914 control
[2] = 0.167*pointPtr
[numCoords
-4] + 0.833*pointPtr
[0];
915 control
[3] = 0.167*pointPtr
[numCoords
-3] + 0.833*pointPtr
[1];
916 control
[4] = 0.833*pointPtr
[0] + 0.167*pointPtr
[2];
917 control
[5] = 0.833*pointPtr
[1] + 0.167*pointPtr
[3];
918 control
[6] = 0.5*pointPtr
[0] + 0.5*pointPtr
[2];
919 control
[7] = 0.5*pointPtr
[1] + 0.5*pointPtr
[3];
920 if (xPoints
!= NULL
) {
921 xPoints
->x
= SCREEN_X(canvasPtr
, control
[0]);
922 xPoints
->y
= SCREEN_Y(canvasPtr
, control
[1]);
923 TkBezierScreenPoints(canvasPtr
, control
, numSteps
, xPoints
+1);
924 xPoints
+= numSteps
+1;
926 if (dblPoints
!= NULL
) {
927 dblPoints
[0] = control
[0];
928 dblPoints
[1] = control
[1];
929 TkBezierPoints(control
, numSteps
, dblPoints
+2);
930 dblPoints
+= 2*(numSteps
+1);
932 outputPoints
+= numSteps
+1;
935 if (xPoints
!= NULL
) {
936 xPoints
->x
= SCREEN_X(canvasPtr
, pointPtr
[0]);
937 xPoints
->y
= SCREEN_Y(canvasPtr
, pointPtr
[1]);
940 if (dblPoints
!= NULL
) {
941 dblPoints
[0] = pointPtr
[0];
942 dblPoints
[1] = pointPtr
[1];
948 for (i
= 2; i
< numPoints
; i
++, pointPtr
+= 2) {
950 * Set up the first two control points. This is done
951 * differently for the first spline of an open curve
952 * than for other cases.
955 if ((i
== 2) && !closed
) {
956 control
[0] = pointPtr
[0];
957 control
[1] = pointPtr
[1];
958 control
[2] = 0.333*pointPtr
[0] + 0.667*pointPtr
[2];
959 control
[3] = 0.333*pointPtr
[1] + 0.667*pointPtr
[3];
961 control
[0] = 0.5*pointPtr
[0] + 0.5*pointPtr
[2];
962 control
[1] = 0.5*pointPtr
[1] + 0.5*pointPtr
[3];
963 control
[2] = 0.167*pointPtr
[0] + 0.833*pointPtr
[2];
964 control
[3] = 0.167*pointPtr
[1] + 0.833*pointPtr
[3];
968 * Set up the last two control points. This is done
969 * differently for the last spline of an open curve
970 * than for other cases.
973 if ((i
== (numPoints
-1)) && !closed
) {
974 control
[4] = .667*pointPtr
[2] + .333*pointPtr
[4];
975 control
[5] = .667*pointPtr
[3] + .333*pointPtr
[5];
976 control
[6] = pointPtr
[4];
977 control
[7] = pointPtr
[5];
979 control
[4] = .833*pointPtr
[2] + .167*pointPtr
[4];
980 control
[5] = .833*pointPtr
[3] + .167*pointPtr
[5];
981 control
[6] = 0.5*pointPtr
[2] + 0.5*pointPtr
[4];
982 control
[7] = 0.5*pointPtr
[3] + 0.5*pointPtr
[5];
986 * If the first two points coincide, or if the last
987 * two points coincide, then generate a single
988 * straight-line segment by outputting the last control
992 if (((pointPtr
[0] == pointPtr
[2]) && (pointPtr
[1] == pointPtr
[3]))
993 || ((pointPtr
[2] == pointPtr
[4])
994 && (pointPtr
[3] == pointPtr
[5]))) {
995 if (xPoints
!= NULL
) {
996 xPoints
[0].x
= SCREEN_X(canvasPtr
, control
[6]);
997 xPoints
[0].y
= SCREEN_Y(canvasPtr
, control
[7]);
1000 if (dblPoints
!= NULL
) {
1001 dblPoints
[0] = control
[6];
1002 dblPoints
[1] = control
[7];
1010 * Generate a Bezier spline using the control points.
1014 if (xPoints
!= NULL
) {
1015 TkBezierScreenPoints(canvasPtr
, control
, numSteps
, xPoints
);
1016 xPoints
+= numSteps
;
1018 if (dblPoints
!= NULL
) {
1019 TkBezierPoints(control
, numSteps
, dblPoints
);
1020 dblPoints
+= 2*numSteps
;
1022 outputPoints
+= numSteps
;
1024 return outputPoints
;
1028 *--------------------------------------------------------------
1030 * TkGetMiterPoints --
1032 * Given three points forming an angle, compute the
1033 * coordinates of the inside and outside points of
1034 * the mitered corner formed by a line of a given
1035 * width at that angle.
1038 * If the angle formed by the three points is less than
1039 * 11 degrees then 0 is returned and m1 and m2 aren't
1040 * modified. Otherwise 1 is returned and the points at
1041 * m1 and m2 are filled in with the positions of the points
1042 * of the mitered corner.
1047 *--------------------------------------------------------------
1052 double p1
[], /* Points to x- and y-coordinates of point
1054 double p2
[], /* Points to x- and y-coordinates of vertex
1055 * for mitered joint. */
1056 double p3
[], /* Points to x- and y-coordinates of point
1058 double width
, /* Width of line. */
1059 double m1
[], /* Points to place to put "left" vertex
1060 * point (see as you face from p1 to p2). */
1061 double m2
[] /* Points to place to put "right" vertex
1065 double theta1
; /* Angle of segment p2-p1. */
1066 double theta2
; /* Angle of segment p2-p3. */
1067 double theta
; /* Angle between line segments (angle
1069 double theta3
; /* Angle that bisects theta1 and
1070 * theta2 and points to m1. */
1071 double dist
; /* Distance of miter points from p2. */
1072 double deltaX
, deltaY
; /* X and y offsets cooresponding to
1073 * dist (fudge factors for bounding
1075 static float elevenDegrees
= (11.0*2.0*PI
)/360.0;
1077 if (p2
[1] == p1
[1]) {
1078 theta1
= (p2
[0] < p1
[0]) ? 0 : PI
;
1079 } else if (p2
[0] == p1
[0]) {
1080 theta1
= (p2
[1] < p1
[1]) ? PI
/2.0 : -PI
/2.0;
1082 theta1
= atan2(p1
[1] - p2
[1], p1
[0] - p2
[0]);
1084 if (p3
[1] == p2
[1]) {
1085 theta2
= (p3
[0] > p2
[0]) ? 0 : PI
;
1086 } else if (p3
[0] == p2
[0]) {
1087 theta2
= (p3
[1] > p2
[1]) ? PI
/2.0 : -PI
/2.0;
1089 theta2
= atan2(p3
[1] - p2
[1], p3
[0] - p2
[0]);
1091 theta
= theta1
- theta2
;
1094 } else if (theta
< -PI
) {
1097 if ((theta
< elevenDegrees
) && (theta
> -elevenDegrees
)) {
1100 dist
= 0.5*width
/sin(0.5*theta
);
1106 * Compute theta3 (make sure that it points to the left when
1107 * looking from p1 to p2).
1110 theta3
= (theta1
+ theta2
)/2.0;
1111 if (sin(theta3
- (theta1
+ PI
)) < 0.0) {
1114 deltaX
= dist
*cos(theta3
);
1115 m1
[0] = p2
[0] + deltaX
;
1116 m2
[0] = p2
[0] - deltaX
;
1117 deltaY
= dist
*sin(theta3
);
1118 m1
[1] = p2
[1] + deltaY
;
1119 m2
[1] = p2
[1] - deltaY
;
1124 *--------------------------------------------------------------
1126 * TkGetButtPoints --
1128 * Given two points forming a line segment, compute the
1129 * coordinates of two endpoints of a rectangle formed by
1130 * bloating the line segment until it is width units wide.
1133 * There is no return value. M1 and m2 are filled in to
1134 * correspond to m1 and m2 in the diagram below:
1136 * ----------------* m1
1138 * p1 *---------------* p2
1140 * ----------------* m2
1142 * M1 and m2 will be W units apart, with p2 centered between
1143 * them and m1-m2 perpendicular to p1-p2. However, if
1144 * "project" is true then m1 and m2 will be as follows:
1146 * -------------------* m1
1148 * p1 *---------------* |
1150 * -------------------* m2
1152 * In this case p2 will be width/2 units from the segment m1-m2.
1157 *--------------------------------------------------------------
1162 double p1
[], /* Points to x- and y-coordinates of point
1164 double p2
[], /* Points to x- and y-coordinates of vertex
1165 * for mitered joint. */
1166 double width
, /* Width of line. */
1167 int project
, /* Non-zero means project p2 by an additional
1168 * width/2 before computing m1 and m2. */
1169 double m1
[], /* Points to place to put "left" result
1170 * point, as you face from p1 to p2. */
1171 double m2
[] /* Points to place to put "right" result
1175 double length
; /* Length of p1-p2 segment. */
1176 double deltaX
, deltaY
; /* Increments in coords. */
1179 length
= hypot(p2
[0] - p1
[0], p2
[1] - p1
[1]);
1180 if (length
== 0.0) {
1181 m1
[0] = m2
[0] = p2
[0];
1182 m1
[1] = m2
[1] = p2
[1];
1184 deltaX
= -width
* (p2
[1] - p1
[1]) / length
;
1185 deltaY
= width
* (p2
[0] - p1
[0]) / length
;
1186 m1
[0] = p2
[0] + deltaX
;
1187 m2
[0] = p2
[0] - deltaX
;
1188 m1
[1] = p2
[1] + deltaY
;
1189 m2
[1] = p2
[1] - deltaY
;