4 * This module provides procedures to draw borders in
5 * the three-dimensional Motif style.
7 * Copyright 1990 Regents of the University of California.
8 * Permission to use, copy, modify, and distribute this
9 * software and its documentation for any purpose and without
10 * fee is hereby granted, provided that the above copyright
11 * notice appear in all copies. The University of California
12 * makes no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without
14 * express or implied warranty.
18 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tk3d.c,v 1.30 92/06/15 14:28:18 ouster Exp $ SPRITE (Berkeley)";
25 * One of the following data structures is allocated for
26 * each 3-D border currently in use. Structures of this
27 * type are indexed by borderTable, so that a single
28 * structure can be shared for several uses.
32 Display
*display
; /* Display for which the resources
33 * below are allocated. */
34 int refCount
; /* Number of different users of
36 XColor
*bgColorPtr
; /* Background color (intensity
37 * between lightColorPtr and
39 XColor
*lightColorPtr
; /* Color used for lighter areas of
40 * border (must free this when
41 * deleting structure). */
42 XColor
*darkColorPtr
; /* Color for darker areas (must
43 * free when deleting structure). */
44 Pixmap shadow
; /* Stipple pattern to use for drawing
45 * lighter-shadow-ed areas. Only used on
46 * monochrome displays; on color displays
48 GC lightGC
; /* Used to draw lighter parts of
50 GC darkGC
; /* Used to draw darker parts of the
52 GC bgGC
; /* Used (if necessary) to draw areas in
53 * the background color. */
54 Tcl_HashEntry
*hashPtr
; /* Entry in borderTable (needed in
55 * order to delete structure). */
59 * Hash table to map from a border's values (color, etc.) to a
60 * Border structure for those values.
63 static Tcl_HashTable borderTable
;
65 Tk_Uid colorName
; /* Color for border. */
66 Colormap colormap
; /* Colormap used for allocating border
68 Screen
*screen
; /* Screen on which border will be drawn. */
72 * Maximum intensity for a color:
75 #define MAX_INTENSITY 65535
78 static int initialized
= 0; /* 0 means static structures haven't
79 * been initialized yet. */
82 * Forward declarations for procedures defined in this file:
85 static void BorderInit
_ANSI_ARGS_((void));
86 static int Intersect
_ANSI_ARGS_((XPoint
*a1Ptr
, XPoint
*a2Ptr
,
87 XPoint
*b1Ptr
, XPoint
*b2Ptr
, XPoint
*iPtr
));
88 static void ShiftLine
_ANSI_ARGS_((XPoint
*p1Ptr
, XPoint
*p2Ptr
,
89 int distance
, XPoint
*p3Ptr
));
92 *--------------------------------------------------------------
96 * Create a data structure for displaying a 3-D border.
99 * The return value is a token for a data structure
100 * describing a 3-D border. This token may be passed
101 * to Tk_Draw3DRectangle and Tk_Free3DBorder. If an
102 * error prevented the border from being created then
103 * NULL is returned and an error message will be left
107 * Data structures, graphics contexts, etc. are allocated.
108 * It is the caller's responsibility to eventually call
109 * Tk_Free3DBorder to release the resources.
111 *--------------------------------------------------------------
116 Tcl_Interp
*interp
, /* Place to store an error message. */
117 Tk_Window tkwin
, /* Token for window in which
118 * border will be drawn. */
119 Colormap colormap
, /* Colormap to use for allocating border
120 * colors. None means use default colormap
122 Tk_Uid colorName
/* String giving name of color
123 * for window background. */
127 Tcl_HashEntry
*hashPtr
;
128 register Border
*borderPtr
;
130 unsigned long light
, dark
;
139 * First, check to see if there's already a border that will work
143 key
.colorName
= colorName
;
144 if (colormap
== None
) {
145 colormap
= Tk_DefaultColormap(Tk_Screen(tkwin
));
147 key
.colormap
= colormap
;
148 key
.screen
= Tk_Screen(tkwin
);
150 hashPtr
= Tcl_CreateHashEntry(&borderTable
, (char *) &key
, &new);
152 borderPtr
= (Border
*) Tcl_GetHashValue(hashPtr
);
153 borderPtr
->refCount
++;
157 * No satisfactory border exists yet. Initialize a new one.
160 borderPtr
= (Border
*) ckalloc(sizeof(Border
));
161 borderPtr
->display
= Tk_Display(tkwin
);
162 borderPtr
->refCount
= 1;
163 borderPtr
->bgColorPtr
= NULL
;
164 borderPtr
->lightColorPtr
= NULL
;
165 borderPtr
->darkColorPtr
= NULL
;
166 borderPtr
->shadow
= None
;
167 borderPtr
->lightGC
= None
;
168 borderPtr
->darkGC
= None
;
169 borderPtr
->bgGC
= None
;
170 borderPtr
->hashPtr
= hashPtr
;
171 Tcl_SetHashValue(hashPtr
, borderPtr
);
174 * Figure out what colors and GC's to use for the light
175 * and dark areas and set up the graphics contexts.
176 * Monochrome displays get handled differently than
180 borderPtr
->bgColorPtr
= Tk_GetColor(interp
, tkwin
,
181 key
.colormap
, colorName
);
182 if (borderPtr
->bgColorPtr
== NULL
) {
185 if (Tk_DefaultDepth(Tk_Screen(tkwin
)) == 1) {
187 * Monochrome display.
190 light
= borderPtr
->bgColorPtr
->pixel
;
191 if (light
== WhitePixelOfScreen(Tk_Screen(tkwin
))) {
192 dark
= BlackPixelOfScreen(Tk_Screen(tkwin
));
194 dark
= WhitePixelOfScreen(Tk_Screen(tkwin
));
196 borderPtr
->shadow
= Tk_GetBitmap(interp
, tkwin
,
197 Tk_GetUid("gray50"));
198 if (borderPtr
->shadow
== None
) {
202 XColor lightColor
, darkColor
;
206 * Color display. Compute the colors for the illuminated
207 * and shaded portions of the border.
210 tmp
= (14*(int)borderPtr
->bgColorPtr
->red
)/10;
211 if (tmp
> MAX_INTENSITY
) {
214 lightColor
.red
= tmp
;
215 tmp
= (14*(int)borderPtr
->bgColorPtr
->green
)/10;
216 if (tmp
> MAX_INTENSITY
) {
219 lightColor
.green
= tmp
;
220 tmp
= (14*(int)borderPtr
->bgColorPtr
->blue
)/10;
221 if (tmp
> MAX_INTENSITY
) {
224 lightColor
.blue
= tmp
;
225 darkColor
.red
= (60*(int)borderPtr
->bgColorPtr
->red
)/100;
226 darkColor
.green
= (60*(int)borderPtr
->bgColorPtr
->green
)/100;
227 darkColor
.blue
= (60*(int)borderPtr
->bgColorPtr
->blue
)/100;
228 borderPtr
->lightColorPtr
= Tk_GetColorByValue(interp
, tkwin
,
229 key
.colormap
, &lightColor
);
230 if (borderPtr
->lightColorPtr
== NULL
) {
233 borderPtr
->darkColorPtr
= Tk_GetColorByValue(interp
, tkwin
,
234 key
.colormap
, &darkColor
);
235 if (borderPtr
->darkColorPtr
== NULL
) {
238 light
= borderPtr
->lightColorPtr
->pixel
;
239 dark
= borderPtr
->darkColorPtr
->pixel
;
241 gcValues
.foreground
= light
;
242 gcValues
.background
= dark
;
243 mask
= GCForeground
|GCBackground
;
244 if (borderPtr
->shadow
!= None
) {
245 gcValues
.stipple
= borderPtr
->shadow
;
246 gcValues
.fill_style
= FillOpaqueStippled
;
247 mask
|= GCStipple
|GCFillStyle
;
249 borderPtr
->lightGC
= Tk_GetGC(tkwin
, mask
, &gcValues
);
250 gcValues
.foreground
= dark
;
251 gcValues
.background
= light
;
252 borderPtr
->darkGC
= Tk_GetGC(tkwin
, GCForeground
|GCBackground
,
254 gcValues
.foreground
= borderPtr
->bgColorPtr
->pixel
;
255 borderPtr
->bgGC
= Tk_GetGC(tkwin
, GCForeground
, &gcValues
);
257 return (Tk_3DBorder
) borderPtr
;
260 Tk_Free3DBorder((Tk_3DBorder
) borderPtr
);
265 *--------------------------------------------------------------
267 * Tk_Draw3DRectangle --
269 * Draw a 3-D border at a given place in a given window.
275 * A 3-D border will be drawn in the indicated drawable.
276 * The outside edges of the border will be determined by x,
277 * y, width, and height. The inside edges of the border
278 * will be determined by the borderWidth argument.
280 *--------------------------------------------------------------
285 Display
*display
, /* X display in which to draw. */
286 Drawable drawable
, /* X window or pixmap in which to draw. */
287 Tk_3DBorder border
, /* Token for border to draw. */
291 int height
, /* Outside area of region in
292 * which border will be drawn. */
293 int borderWidth
, /* Desired width for border, in
295 int relief
/* Should be either TK_RELIEF_RAISED
296 * or TK_RELIEF_SUNKEN; indicates
297 * position of interior of window relative
301 register Border
*borderPtr
= (Border
*) border
;
305 if ((width
< 2*borderWidth
) || (height
< 2*borderWidth
)) {
309 if (relief
== TK_RELIEF_RAISED
) {
310 top
= borderPtr
->lightGC
;
311 bottom
= borderPtr
->darkGC
;
312 } else if (relief
== TK_RELIEF_SUNKEN
) {
313 top
= borderPtr
->darkGC
;
314 bottom
= borderPtr
->lightGC
;
316 top
= bottom
= borderPtr
->bgGC
;
318 XFillRectangle(display
, drawable
, bottom
, x
, y
+height
-borderWidth
,
320 (unsigned int) width
, (unsigned int) borderWidth
);
321 XFillRectangle(display
, drawable
, bottom
, x
+width
-borderWidth
, y
,
322 (unsigned int) borderWidth
, (unsigned int) height
);
323 points
[0].x
= points
[1].x
= points
[6].x
= x
;
324 points
[0].y
= points
[6].y
= y
+ height
;
325 points
[1].y
= points
[2].y
= y
;
326 points
[2].x
= x
+ width
;
327 points
[3].x
= x
+ width
- borderWidth
;
328 points
[3].y
= points
[4].y
= y
+ borderWidth
;
329 points
[4].x
= points
[5].x
= x
+ borderWidth
;
330 points
[5].y
= y
+ height
- borderWidth
;
331 XFillPolygon(display
, drawable
, top
, points
, 7, Nonconvex
,
336 *--------------------------------------------------------------
338 * Tk_NameOf3DBorder --
340 * Given a border, return a textual string identifying the
344 * The return value is the string that was used to create
350 *--------------------------------------------------------------
355 Tk_3DBorder border
/* Token for border. */
358 Border
*borderPtr
= (Border
*) border
;
360 return ((BorderKey
*) borderPtr
->hashPtr
->key
.words
)->colorName
;
364 *--------------------------------------------------------------------
366 * Tk_3DBorderColor --
368 * Given a 3D border, return the X color used for the "flat"
372 * Returns the color used drawing flat surfaces with the border.
377 *--------------------------------------------------------------------
380 Tk_3DBorderColor (Tk_3DBorder border
)
382 return(((Border
*) border
)->bgColorPtr
);
386 *--------------------------------------------------------------
390 * This procedure is called when a 3D border is no longer
391 * needed. It frees the resources associated with the
392 * border. After this call, the caller should never again
393 * use the "border" token.
399 * Resources are freed.
401 *--------------------------------------------------------------
406 Tk_3DBorder border
/* Token for border to be released. */
409 register Border
*borderPtr
= (Border
*) border
;
411 borderPtr
->refCount
--;
412 if (borderPtr
->refCount
== 0) {
413 if (borderPtr
->bgColorPtr
!= NULL
) {
414 Tk_FreeColor(borderPtr
->bgColorPtr
);
416 if (borderPtr
->lightColorPtr
!= NULL
) {
417 Tk_FreeColor(borderPtr
->lightColorPtr
);
419 if (borderPtr
->darkColorPtr
!= NULL
) {
420 Tk_FreeColor(borderPtr
->darkColorPtr
);
422 if (borderPtr
->shadow
!= None
) {
423 Tk_FreeBitmap(borderPtr
->shadow
);
425 if (borderPtr
->lightGC
!= None
) {
426 Tk_FreeGC(borderPtr
->lightGC
);
428 if (borderPtr
->darkGC
!= None
) {
429 Tk_FreeGC(borderPtr
->darkGC
);
431 if (borderPtr
->bgGC
!= None
) {
432 Tk_FreeGC(borderPtr
->bgGC
);
434 Tcl_DeleteHashEntry(borderPtr
->hashPtr
);
435 ckfree((char *) borderPtr
);
440 *----------------------------------------------------------------------
442 * Tk_SetBackgroundFromBorder --
444 * Change the background of a window to one appropriate for a given
451 * Tkwin's background gets modified.
453 *----------------------------------------------------------------------
457 Tk_SetBackgroundFromBorder (
458 Tk_Window tkwin
, /* Window whose background is to be set. */
459 Tk_3DBorder border
/* Token for border. */
462 register Border
*borderPtr
= (Border
*) border
;
464 Tk_SetWindowBackground(tkwin
, borderPtr
->bgColorPtr
->pixel
);
468 *----------------------------------------------------------------------
472 * Parse a relief description and return the corresponding
473 * relief value, or an error.
476 * A standard Tcl return value. If all goes well then
477 * *reliefPtr is filled in with one of the values
478 * TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN.
483 *----------------------------------------------------------------------
488 Tcl_Interp
*interp
, /* For error messages. */
489 char *name
, /* Name of a relief type. */
490 int *reliefPtr
/* Where to store converted relief. */
497 length
= strlen(name
);
498 if ((c
== 'f') && (strncmp(name
, "flat", length
) == 0)) {
499 *reliefPtr
= TK_RELIEF_FLAT
;
500 } else if ((c
== 'r') && (strncmp(name
, "raised", length
) == 0)) {
501 *reliefPtr
= TK_RELIEF_RAISED
;
502 } else if ((c
== 's') && (strncmp(name
, "sunken", length
) == 0)) {
503 *reliefPtr
= TK_RELIEF_SUNKEN
;
505 sprintf(interp
->result
, "bad relief type \"%.50s\": must be %s",
506 name
, "flat, raised, or sunken");
513 *--------------------------------------------------------------
517 * Given a relief value, produce a string describing that
521 * The return value is a static string that is equivalent
527 *--------------------------------------------------------------
532 int relief
/* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED,
533 * or TK_RELIEF_SUNKEN. */
536 if (relief
== TK_RELIEF_FLAT
) {
538 } else if (relief
== TK_RELIEF_SUNKEN
) {
540 } else if (relief
== TK_RELIEF_RAISED
) {
543 return "unknown relief";
548 *--------------------------------------------------------------
550 * Tk_Draw3DPolygon --
552 * Draw a border with 3-D appearance around the edge of a
559 * Information is drawn in "drawable" in the form of a
560 * 3-D border borderWidth units width wide on the left
561 * of the trajectory given by pointPtr and numPoints (or
562 * -borderWidth units wide on the right side, if borderWidth
565 *--------------------------------------------------------------
570 Display
*display
, /* X display in which to draw polygon. */
571 Drawable drawable
, /* X window or pixmap in which to draw. */
572 Tk_3DBorder border
, /* Token for border to draw. */
573 XPoint
*pointPtr
, /* Array of points describing
574 * polygon. All points must be
575 * absolute (CoordModeOrigin). */
576 int numPoints
, /* Number of points at *pointPtr. */
577 int borderWidth
, /* Width of border, measured in
578 * pixels to the left of the polygon's
579 * trajectory. May be negative. */
580 int leftRelief
/* TK_RELIEF_RAISED or
581 * TK_RELIEF_SUNKEN: indicates how
582 * stuff to left of trajectory looks
583 * relative to stuff on right. */
586 XPoint poly
[4], b1
, b2
, newB1
, newB2
;
587 XPoint perp
, c
, shift1
, shift2
; /* Used for handling parallel lines. */
588 register XPoint
*p1Ptr
, *p2Ptr
;
589 Border
*borderPtr
= (Border
*) border
;
591 int i
, lightOnLeft
, dx
, dy
, parallel
, pointsSeen
;
594 * If the polygon is already closed, drop the last point from it
595 * (we'll close it automatically).
598 p1Ptr
= &pointPtr
[numPoints
-1];
599 p2Ptr
= &pointPtr
[0];
600 if ((p1Ptr
->x
== p2Ptr
->x
) && (p1Ptr
->y
== p2Ptr
->y
)) {
605 * The loop below is executed once for each vertex in the polgon.
606 * At the beginning of each iteration things look like this:
611 * b1 * poly[0] (pointPtr[i-1])
618 * b2 *--------------------*
621 * x-------------------------
623 * The job of this iteration is to do the following:
624 * (a) Compute x (the border corner corresponding to
625 * pointPtr[i]) and put it in poly[2]. As part of
626 * this, compute a new b1 and b2 value for the next
627 * side of the polygon.
628 * (b) Put pointPtr[i] into poly[3].
629 * (c) Draw the polygon given by poly[0..3].
630 * (d) Advance poly[0], poly[1], b1, and b2 for the
631 * next side of the polygon.
635 * The above situation doesn't first come into existence until
636 * two points have been processed; the first two points are
637 * used to "prime the pump", so some parts of the processing
638 * are ommitted for these points. The variable "pointsSeen"
639 * keeps track of the priming process; it has to be separate
640 * from i in order to be able to ignore duplicate points in the
645 for (i
= -2, p1Ptr
= &pointPtr
[numPoints
-2], p2Ptr
= p1Ptr
+1;
646 i
< numPoints
; i
++, p1Ptr
= p2Ptr
, p2Ptr
++) {
647 if ((i
== -1) || (i
== numPoints
-1)) {
650 if ((p2Ptr
->x
== p1Ptr
->x
) && (p2Ptr
->y
== p1Ptr
->y
)) {
652 * Ignore duplicate points (they'd cause core dumps in
653 * ShiftLine calls below).
657 ShiftLine(p1Ptr
, p2Ptr
, borderWidth
, &newB1
);
658 newB2
.x
= newB1
.x
+ (p2Ptr
->x
- p1Ptr
->x
);
659 newB2
.y
= newB1
.y
+ (p2Ptr
->y
- p1Ptr
->y
);
662 if (pointsSeen
>= 1) {
663 parallel
= Intersect(&newB1
, &newB2
, &b1
, &b2
, &poly
[2]);
666 * If two consecutive segments of the polygon are parallel,
667 * then things get more complex. Consider the following
671 * *----b1-----------b2------a
674 * *---------*----------* b
675 * poly[0] *p2Ptr *p1Ptr /
680 * Instead of using x and *p1Ptr for poly[2] and poly[3], as
681 * in the original diagram, use a and b as above. Then instead
682 * of using x and *p1Ptr for the new poly[0] and poly[1], use
685 * Do the computation in three stages:
686 * 1. Compute a point "perp" such that the line p1Ptr-perp
687 * is perpendicular to p1Ptr-p2Ptr.
688 * 2. Compute the points a and c by intersecting the lines
689 * b1-b2 and newB1-newB2 with p1Ptr-perp.
690 * 3. Compute b by shifting p1Ptr-perp to the right and
691 * intersecting it with p1Ptr-p2Ptr.
695 perp
.x
= p1Ptr
->x
+ (p2Ptr
->y
- p1Ptr
->y
);
696 perp
.y
= p1Ptr
->y
- (p2Ptr
->x
- p1Ptr
->x
);
697 (void) Intersect(p1Ptr
, &perp
, &b1
, &b2
, &poly
[2]);
698 (void) Intersect(p1Ptr
, &perp
, &newB1
, &newB2
, &c
);
699 ShiftLine(p1Ptr
, &perp
, borderWidth
, &shift1
);
700 shift2
.x
= shift1
.x
+ (perp
.x
- p1Ptr
->x
);
701 shift2
.y
= shift1
.y
+ (perp
.y
- p1Ptr
->y
);
702 (void) Intersect(p1Ptr
, p2Ptr
, &shift1
, &shift2
, &poly
[3]);
705 if (pointsSeen
>= 2) {
706 dx
= poly
[3].x
- poly
[0].x
;
707 dy
= poly
[3].y
- poly
[0].y
;
709 lightOnLeft
= (dy
<= dx
);
711 lightOnLeft
= (dy
< dx
);
713 if (lightOnLeft
^ (leftRelief
== TK_RELIEF_RAISED
)) {
714 gc
= borderPtr
->lightGC
;
716 gc
= borderPtr
->darkGC
;
718 XFillPolygon(display
, drawable
, gc
, poly
, 4, Convex
,
725 poly
[0].x
= poly
[3].x
;
726 poly
[0].y
= poly
[3].y
;
730 } else if (pointsSeen
>= 1) {
731 poly
[1].x
= poly
[2].x
;
732 poly
[1].y
= poly
[2].y
;
739 *----------------------------------------------------------------------
741 * Tk_Fill3DRectangle --
743 * Fill a rectangular area, supplying a 3D border if desired.
749 * Information gets drawn on the screen.
751 *----------------------------------------------------------------------
756 Display
*display
, /* X display in which to draw rectangle. */
757 Drawable drawable
, /* X window or pixmap in which to draw. */
758 Tk_3DBorder border
, /* Token for border to draw. */
762 int height
, /* Outside area of rectangular region. */
763 int borderWidth
, /* Desired width for border, in
764 * pixels. Border will be *inside* region. */
765 int relief
/* Indicates 3D effect: TK_RELIEF_FLAT,
766 * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */
769 register Border
*borderPtr
= (Border
*) border
;
771 XFillRectangle(display
, drawable
, borderPtr
->bgGC
,
772 x
, y
, (unsigned int) width
, (unsigned int) height
);
773 if (relief
!= TK_RELIEF_FLAT
) {
774 Tk_Draw3DRectangle(display
, drawable
, border
, x
, y
, width
,
775 height
, borderWidth
, relief
);
780 *----------------------------------------------------------------------
782 * Tk_Fill3DPolygon --
784 * Fill a polygonal area, supplying a 3D border if desired.
790 * Information gets drawn on the screen.
792 *----------------------------------------------------------------------
797 Display
*display
, /* X display in which to draw polygon. */
798 Drawable drawable
, /* X window or pixmap in which to draw. */
799 Tk_3DBorder border
, /* Token for border to draw. */
800 XPoint
*pointPtr
, /* Array of points describing
801 * polygon. All points must be
802 * absolute (CoordModeOrigin). */
803 int numPoints
, /* Number of points at *pointPtr. */
804 int borderWidth
, /* Width of border, measured in
805 * pixels to the left of the polygon's
806 * trajectory. May be negative. */
807 int leftRelief
/* Indicates 3D effect of left side of
808 * trajectory relative to right:
809 * TK_RELIEF_FLAT, TK_RELIEF_RAISED,
810 * or TK_RELIEF_SUNKEN. */
813 register Border
*borderPtr
= (Border
*) border
;
815 XFillPolygon(display
, drawable
, borderPtr
->bgGC
,
816 pointPtr
, numPoints
, Complex
, CoordModeOrigin
);
817 if (leftRelief
!= TK_RELIEF_FLAT
) {
818 Tk_Draw3DPolygon(display
, drawable
, border
, pointPtr
, numPoints
,
819 borderWidth
, leftRelief
);
824 *--------------------------------------------------------------
828 * Initialize the structures used for border management.
836 *-------------------------------------------------------------
843 Tcl_InitHashTable(&borderTable
, sizeof(BorderKey
)/sizeof(int));
847 *--------------------------------------------------------------
851 * Given two points on a line, compute a point on a
852 * new line that is parallel to the given line and
853 * a given distance away from it.
861 *--------------------------------------------------------------
866 XPoint
*p1Ptr
, /* First point on line. */
867 XPoint
*p2Ptr
, /* Second point on line. */
868 int distance
, /* New line is to be this many
869 * units to the left of original
870 * line, when looking from p1 to
871 * p2. May be negative. */
872 XPoint
*p3Ptr
/* Store coords of point on new
876 int dx
, dy
, dxNeg
, dyNeg
;
879 * The table below is used for a quick approximation in
880 * computing the new point. An index into the table
881 * is 128 times the slope of the original line (the slope
882 * must always be between 0 and 1). The value of the table
883 * entry is 128 times the amount to displace the new line
884 * in y for each unit of perpendicular distance. In other
885 * words, the table maps from the tangent of an angle to
886 * the inverse of its cosine. If the slope of the original
887 * line is greater than 1, then the displacement is done in
888 * x rather than in y.
891 static int shiftTable
[129];
894 * Initialize the table if this is the first time it is
898 if (shiftTable
[0] == 0) {
900 double tangent
, cosine
;
902 for (i
= 0; i
<= 128; i
++) {
904 cosine
= 128/cos(atan(tangent
)) + .5;
905 shiftTable
[i
] = cosine
;
910 dx
= p2Ptr
->x
- p1Ptr
->x
;
911 dy
= p2Ptr
->y
- p1Ptr
->y
;
925 dy
= ((distance
* shiftTable
[(dy
<<7)/dx
]) + 64) >> 7;
931 dx
= ((distance
* shiftTable
[(dx
<<7)/dy
]) + 64) >> 7;
940 *--------------------------------------------------------------
944 * Find the intersection point between two lines.
947 * Under normal conditions 0 is returned and the point
948 * at *iPtr is filled in with the intersection between
949 * the two lines. If the two lines are parallel, then
950 * -1 is returned and *iPtr isn't modified.
955 *--------------------------------------------------------------
960 XPoint
*a1Ptr
, /* First point of first line. */
961 XPoint
*a2Ptr
, /* Second point of first line. */
962 XPoint
*b1Ptr
, /* First point of second line. */
963 XPoint
*b2Ptr
, /* Second point of second line. */
964 XPoint
*iPtr
/* Filled in with intersection point. */
967 int dxadyb
, dxbdya
, dxadxb
, dyadyb
, p
, q
;
970 * The code below is just a straightforward manipulation of two
971 * equations of the form y = (x-x1)*(y2-y1)/(x2-x1) + y1 to solve
972 * for the x-coordinate of intersection, then the y-coordinate.
975 dxadyb
= (a2Ptr
->x
- a1Ptr
->x
)*(b2Ptr
->y
- b1Ptr
->y
);
976 dxbdya
= (b2Ptr
->x
- b1Ptr
->x
)*(a2Ptr
->y
- a1Ptr
->y
);
977 dxadxb
= (a2Ptr
->x
- a1Ptr
->x
)*(b2Ptr
->x
- b1Ptr
->x
);
978 dyadyb
= (a2Ptr
->y
- a1Ptr
->y
)*(b2Ptr
->y
- b1Ptr
->y
);
980 if (dxadyb
== dxbdya
) {
983 p
= (a1Ptr
->x
*dxbdya
- b1Ptr
->x
*dxadyb
+ (b1Ptr
->y
- a1Ptr
->y
)*dxadxb
);
990 iPtr
->x
= - ((-p
+ q
/2)/q
);
992 iPtr
->x
= (p
+ q
/2)/q
;
994 p
= (a1Ptr
->y
*dxadyb
- b1Ptr
->y
*dxbdya
+ (b1Ptr
->x
- a1Ptr
->x
)*dyadyb
);
1001 iPtr
->y
= - ((-p
+ q
/2)/q
);
1003 iPtr
->y
= (p
+ q
/2)/q
;