2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
5 * This file is part of the Gnome Library.
7 * The Gnome Library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * The Gnome Library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 /* Miscellaneous utility functions for the FooCanvas widget
27 * FooCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
28 * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
31 * Author: Federico Mena <federico@nuclecu.unam.mx>
36 #include <sys/types.h>
39 #include "foo-canvas.h"
40 #include "foo-canvas-util.h"
43 * Ok, so some systems require magic incantations for M_PI to be defined.
44 * It's not important enough to worry about.
47 #define M_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117
51 * foo_canvas_points_new:
52 * @num_points: The number of points to allocate space for in the array.
54 * Creates a structure that should be used to pass an array of points to
57 * Return value: A newly-created array of points. It should be filled in
61 foo_canvas_points_new (int num_points
)
63 FooCanvasPoints
*points
;
65 g_return_val_if_fail (num_points
> 1, NULL
);
67 points
= g_new (FooCanvasPoints
, 1);
68 points
->num_points
= num_points
;
69 points
->coords
= g_new (double, 2 * num_points
);
70 points
->ref_count
= 1;
76 * foo_canvas_points_ref:
77 * @points: A canvas points structure.
79 * Increases the reference count of the specified points structure.
81 * Return value: The canvas points structure itself.
84 foo_canvas_points_ref (FooCanvasPoints
*points
)
86 g_return_val_if_fail (points
!= NULL
, NULL
);
88 points
->ref_count
+= 1;
93 * foo_canvas_points_free:
94 * @points: A canvas points structure.
96 * Decreases the reference count of the specified points structure. If it
97 * reaches zero, then the structure is freed.
100 foo_canvas_points_free (FooCanvasPoints
*points
)
102 g_return_if_fail (points
!= NULL
);
104 points
->ref_count
-= 1;
105 if (points
->ref_count
== 0) {
106 g_free (points
->coords
);
112 * foo_canvas_get_miter_points:
113 * @x1: X coordinate of the first point
114 * @y1: Y coordinate of the first point
115 * @x2: X coordinate of the second (angle) point
116 * @y2: Y coordinate of the second (angle) point
117 * @x3: X coordinate of the third point
118 * @y3: Y coordinate of the third point
119 * @width: Width of the line
120 * @mx1: The X coordinate of the first miter point is returned here.
121 * @my1: The Y coordinate of the first miter point is returned here.
122 * @mx2: The X coordinate of the second miter point is returned here.
123 * @my2: The Y coordinate of the second miter point is returned here.
125 * Given three points forming an angle, computes the coordinates of the inside
126 * and outside points of the mitered corner formed by a line of a given width at
129 * Return value: FALSE if the angle is less than 11 degrees (this is the same
130 * threshold as X uses. If this occurs, the return points are not modified.
131 * Otherwise, returns TRUE.
134 foo_canvas_get_miter_points (double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
136 double *mx1
, double *my1
, double *mx2
, double *my2
)
138 double theta1
; /* angle of segment p2-p1 */
139 double theta2
; /* angle of segment p2-p3 */
140 double theta
; /* angle between line segments */
141 double theta3
; /* angle that bisects theta1 and theta2 and points to p1 */
142 double dist
; /* distance of miter points from p2 */
143 double dx
, dy
; /* x and y offsets corresponding to dist */
145 double ELEVEN_DEGREES
= 11.0 * M_PI
/ 180.0;
147 /* Degenerate cases. */
148 if ((x1
== x2
&& y1
== y2
) || (x2
== x3
&& y2
== y3
))
151 theta1
= atan2 (y1
- y2
, x1
- x2
);
152 theta2
= atan2 (y3
- y2
, x3
- x2
);
153 theta
= theta1
- theta2
;
155 /* Normalize to (-pi; pi]. */
158 else if (theta
<= -M_PI
)
161 if (fabs (theta
) < ELEVEN_DEGREES
)
164 dist
= fabs (0.5 * width
/ sin (0.5 * theta
));
166 theta3
= (theta1
+ theta2
) / 2.0;
167 if (sin (theta3
- theta1
) > 0.0)
170 dx
= dist
* cos (theta3
);
171 dy
= dist
* sin (theta3
);
182 * foo_canvas_get_butt_points:
183 * @x1: X coordinate of first point in the line
184 * @y1: Y cooordinate of first point in the line
185 * @x2: X coordinate of second point (endpoint) of the line
186 * @y2: Y coordinate of second point (endpoint) of the line
187 * @width: Width of the line
188 * @project: Whether the butt points should project out by width/2 distance
189 * @bx1: X coordinate of first butt point is returned here
190 * @by1: Y coordinate of first butt point is returned here
191 * @bx2: X coordinate of second butt point is returned here
192 * @by2: Y coordinate of second butt point is returned here
194 * Computes the butt points of a line segment.
197 foo_canvas_get_butt_points (double x1
, double y1
, double x2
, double y2
,
198 double width
, int project
,
199 double *bx1
, double *by1
, double *bx2
, double *by2
)
207 length
= sqrt (dx
* dx
+ dy
* dy
);
209 if (length
< FOO_CANVAS_EPSILON
) {
213 dx
= -width
* (y2
- y1
) / length
;
214 dy
= width
* (x2
- x1
) / length
;
231 * foo_canvas_polygon_to_point:
232 * @poly: Vertices of the polygon. X coordinates are in the even indices, and Y
233 * coordinates are in the odd indices
234 * @num_points: Number of points in the polygon
235 * @x: X coordinate of the point
236 * @y: Y coordinate of the point
238 * Computes the distance between a point and a polygon.
240 * Return value: The distance from the point to the polygon, or zero if the
241 * point is inside the polygon.
244 foo_canvas_polygon_to_point (double *poly
, int num_points
, double x
, double y
)
252 /* Iterate through all the edges in the polygon, updating best and intersections.
254 * When computing intersections, include left X coordinate of line within its range, but not
255 * Y coordinate. Otherwise if the point lies exactly below a vertex we'll count it as two
265 for (i
= num_points
, p
= poly
; i
> 1; i
--, p
+= 2) {
268 /* Compute the point on the current edge closest to the point and update the
269 * intersection count. This must be done separately for vertical edges, horizontal
285 } else if (p
[3] == p
[1]) {
286 /* Horizontal edge */
294 if ((y
< py
) && (x
< p
[0]) && (x
>= p
[2]))
300 if ((y
< py
) && (x
< p
[2]) && (x
>= p
[0]))
304 double m1
, b1
, m2
, b2
;
307 /* Diagonal edge. Convert the edge to a line equation (y = m1*x + b1), then
308 * compute a line perpendicular to this edge but passing through the point,
312 m1
= (p
[3] - p
[1]) / (p
[2] - p
[0]);
313 b1
= p
[1] - m1
* p
[0];
318 px
= (b2
- b1
) / (m1
- m2
);
325 } else if (px
< p
[2]) {
333 } else if (px
< p
[0]) {
339 lower
= (m1
* x
+ b1
) > y
;
341 if (lower
&& (x
>= MIN (p
[0], p
[2])) && (x
< MAX (p
[0], p
[2])))
345 /* Compute the distance to the closest point, and see if that is the best so far */
349 dist
= sqrt (dx
* dx
+ dy
* dy
);
354 /* We've processed all the points. If the number of intersections is odd, the point is
355 * inside the polygon.
358 if (intersections
& 0x1)
365 * foo_canvas_item_reset_bounds:
366 * @item: A canvas item
368 * Resets the bounding box of a canvas item to an empty rectangle.
371 foo_canvas_item_reset_bounds (FooCanvasItem
*item
)
380 * foo_canvas_update_bbox:
381 * @canvas: the canvas needing update
382 * @x1: Left coordinate of the new bounding box
383 * @y1: Top coordinate of the new bounding box
384 * @x2: Right coordinate of the new bounding box
385 * @y2: Bottom coordinate of the new bounding box
387 * Sets the bbox to the new value, requesting full repaint.
390 foo_canvas_update_bbox (FooCanvasItem
*item
, int x1
, int y1
, int x2
, int y2
)
392 foo_canvas_item_request_redraw (item
);
397 foo_canvas_item_request_redraw (item
);