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 GnomeCanvas widget
27
* GnomeCanvas 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
/* needed for M_PI_2 under 'gcc -ansi -predantic' on GNU/Linux */
38
# define _BSD_SOURCE 1
40
#include <sys/types.h>
44
#include "gnome-canvas.h"
45
#include "gnome-canvas-util.h"
46
#include <libart_lgpl/art_uta.h>
47
#include <libart_lgpl/art_svp.h>
48
#include <libart_lgpl/art_svp_ops.h>
49
#include <libart_lgpl/art_rgb.h>
50
#include <libart_lgpl/art_rgb_svp.h>
51
#include <libart_lgpl/art_uta_svp.h>
52
#include <libart_lgpl/art_rect_svp.h>
55
* gnome_canvas_points_new:
56
* @num_points: The number of points to allocate space for in the array.
58
* Creates a structure that should be used to pass an array of points to
61
* Return value: A newly-created array of points. It should be filled in
65
gnome_canvas_points_new (int num_points)
67
GnomeCanvasPoints *points;
69
g_return_val_if_fail (num_points > 1, NULL);
71
points = g_new (GnomeCanvasPoints, 1);
72
points->num_points = num_points;
73
points->coords = g_new (double, 2 * num_points);
74
points->ref_count = 1;
80
* gnome_canvas_points_ref:
81
* @points: A canvas points structure.
83
* Increases the reference count of the specified points structure.
85
* Return value: The canvas points structure itself.
88
gnome_canvas_points_ref (GnomeCanvasPoints *points)
90
g_return_val_if_fail (points != NULL, NULL);
92
points->ref_count += 1;
97
* gnome_canvas_points_free:
98
* @points: A canvas points structure.
100
* Decreases the reference count of the specified points structure. If it
101
* reaches zero, then the structure is freed.
104
gnome_canvas_points_free (GnomeCanvasPoints *points)
106
g_return_if_fail (points != NULL);
108
points->ref_count -= 1;
109
if (points->ref_count == 0) {
110
g_free (points->coords);
116
* gnome_canvas_get_miter_points:
117
* @x1: X coordinate of the first point
118
* @y1: Y coordinate of the first point
119
* @x2: X coordinate of the second (angle) point
120
* @y2: Y coordinate of the second (angle) point
121
* @x3: X coordinate of the third point
122
* @y3: Y coordinate of the third point
123
* @width: Width of the line
124
* @mx1: The X coordinate of the first miter point is returned here.
125
* @my1: The Y coordinate of the first miter point is returned here.
126
* @mx2: The X coordinate of the second miter point is returned here.
127
* @my2: The Y coordinate of the second miter point is returned here.
129
* Given three points forming an angle, computes the coordinates of the inside
130
* and outside points of the mitered corner formed by a line of a given width at
133
* Return value: FALSE if the angle is less than 11 degrees (this is the same
134
* threshold as X uses. If this occurs, the return points are not modified.
135
* Otherwise, returns TRUE.
138
gnome_canvas_get_miter_points (double x1, double y1, double x2, double y2, double x3, double y3,
140
double *mx1, double *my1, double *mx2, double *my2)
142
double theta1; /* angle of segment p2-p1 */
143
double theta2; /* angle of segment p2-p3 */
144
double theta; /* angle between line segments */
145
double theta3; /* angle that bisects theta1 and theta2 and points to p1 */
146
double dist; /* distance of miter points from p2 */
147
double dx, dy; /* x and y offsets corresponding to dist */
149
#define ELEVEN_DEGREES (11.0 * G_PI / 180.0)
152
theta1 = (x2 < x1) ? 0.0 : G_PI;
154
theta1 = (y2 < y1) ? G_PI_2 : -G_PI_2;
156
theta1 = atan2 (y1 - y2, x1 - x2);
159
theta2 = (x3 > x2) ? 0 : G_PI;
161
theta2 = (y3 > y2) ? G_PI_2 : -G_PI_2;
163
theta2 = atan2 (y3 - y2, x3 - x2);
165
theta = theta1 - theta2;
169
else if (theta < -G_PI)
172
if ((theta < ELEVEN_DEGREES) && (theta > -ELEVEN_DEGREES))
175
dist = 0.5 * width / sin (0.5 * theta);
179
theta3 = (theta1 + theta2) / 2.0;
180
if (sin (theta3 - (theta1 + G_PI)) < 0.0)
183
dx = dist * cos (theta3);
184
dy = dist * sin (theta3);
195
* gnome_canvas_get_butt_points:
196
* @x1: X coordinate of first point in the line
197
* @y1: Y cooordinate of first point in the line
198
* @x2: X coordinate of second point (endpoint) of the line
199
* @y2: Y coordinate of second point (endpoint) of the line
200
* @width: Width of the line
201
* @project: Whether the butt points should project out by width/2 distance
202
* @bx1: X coordinate of first butt point is returned here
203
* @by1: Y coordinate of first butt point is returned here
204
* @bx2: X coordinate of second butt point is returned here
205
* @by2: Y coordinate of second butt point is returned here
207
* Computes the butt points of a line segment.
210
gnome_canvas_get_butt_points (double x1, double y1, double x2, double y2,
211
double width, int project,
212
double *bx1, double *by1, double *bx2, double *by2)
220
length = sqrt (dx * dx + dy * dy);
222
if (length < GNOME_CANVAS_EPSILON) {
226
dx = -width * (y2 - y1) / length;
227
dy = width * (x2 - x1) / length;
244
* gnome_canvas_polygon_to_point:
245
* @poly: Vertices of the polygon. X coordinates are in the even indices, and Y
246
* coordinates are in the odd indices
247
* @num_points: Number of points in the polygon
248
* @x: X coordinate of the point
249
* @y: Y coordinate of the point
251
* Computes the distance between a point and a polygon.
253
* Return value: The distance from the point to the polygon, or zero if the
254
* point is inside the polygon.
257
gnome_canvas_polygon_to_point (double *poly, int num_points, double x, double y)
265
/* Iterate through all the edges in the polygon, updating best and intersections.
267
* When computing intersections, include left X coordinate of line within its range, but not
268
* Y coordinate. Otherwise if the point lies exactly below a vertex we'll count it as two
275
for (i = num_points, p = poly; i > 1; i--, p += 2) {
278
/* Compute the point on the current edge closest to the point and update the
279
* intersection count. This must be done separately for vertical edges, horizontal
295
} else if (p[3] == p[1]) {
296
/* Horizontal edge */
304
if ((y < py) && (x < p[0]) && (x >= p[2]))
310
if ((y < py) && (x < p[2]) && (x >= p[0]))
314
double m1, b1, m2, b2;
317
/* Diagonal edge. Convert the edge to a line equation (y = m1*x + b1), then
318
* compute a line perpendicular to this edge but passing through the point,
322
m1 = (p[3] - p[1]) / (p[2] - p[0]);
323
b1 = p[1] - m1 * p[0];
328
px = (b2 - b1) / (m1 - m2);
335
} else if (px < p[2]) {
343
} else if (px < p[0]) {
349
lower = (m1 * x + b1) > y;
351
if (lower && (x >= MIN (p[0], p[2])) && (x < MAX (p[0], p[2])))
355
/* Compute the distance to the closest point, and see if that is the best so far */
359
dist = sqrt (dx * dx + dy * dy);
364
/* We've processed all the points. If the number of intersections is odd, the point is
365
* inside the polygon.
368
if (intersections & 0x1)
374
/* Here are some helper functions for aa rendering: */
377
* gnome_canvas_render_svp:
378
* @buf: the canvas buffer to render over
379
* @svp: the vector path to render
380
* @rgba: the rgba color to render
382
* Render the svp over the buf.
385
gnome_canvas_render_svp (GnomeCanvasBuf *buf, ArtSVP *svp, guint32 rgba)
387
guint32 fg_color, bg_color;
391
bg_color = buf->bg_color;
394
fg_color = rgba >> 8;
396
/* composite over background color */
397
int bg_r, bg_g, bg_b;
398
int fg_r, fg_g, fg_b;
401
bg_r = (bg_color >> 16) & 0xff;
402
fg_r = (rgba >> 24) & 0xff;
403
tmp = (fg_r - bg_r) * alpha;
404
fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
406
bg_g = (bg_color >> 8) & 0xff;
407
fg_g = (rgba >> 16) & 0xff;
408
tmp = (fg_g - bg_g) * alpha;
409
fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
411
bg_b = bg_color & 0xff;
412
fg_b = (rgba >> 8) & 0xff;
413
tmp = (fg_b - bg_b) * alpha;
414
fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
416
fg_color = (fg_r << 16) | (fg_g << 8) | fg_b;
419
buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
421
buf->buf, buf->buf_rowstride,
426
art_rgb_svp_alpha (svp,
427
buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
429
buf->buf, buf->buf_rowstride,
435
* gnome_canvas_update_svp:
436
* @canvas: the canvas containing the svp that needs updating.
437
* @p_svp: a pointer to the existing svp
438
* @new_svp: the new svp
440
* Sets the svp to the new value, requesting repaint on what's changed. This
441
* function takes responsibility for freeing new_svp.
444
gnome_canvas_update_svp (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp)
447
ArtSVP *diff G_GNUC_UNUSED;
452
if (old_svp != NULL) {
454
art_drect_svp (&bb, old_svp);
455
if ((bb.x1 - bb.x0) * (bb.y1 - bb.y0) > (64 * 64)) {
456
repaint_uta = art_uta_from_svp (old_svp);
457
gnome_canvas_request_redraw_uta (canvas, repaint_uta);
460
art_drect_to_irect (&ib, &bb);
461
gnome_canvas_request_redraw (canvas, ib.x0, ib.y0, ib.x1, ib.y1);
463
art_svp_free (old_svp);
466
if (new_svp != NULL) {
468
art_drect_svp (&bb, new_svp);
469
if ((bb.x1 - bb.x0) * (bb.y1 - bb.y0) > (64 * 64)) {
470
repaint_uta = art_uta_from_svp (new_svp);
471
gnome_canvas_request_redraw_uta (canvas, repaint_uta);
474
art_drect_to_irect (&ib, &bb);
475
gnome_canvas_request_redraw (canvas, ib.x0, ib.y0, ib.x1, ib.y1);
483
* gnome_canvas_update_svp_clip:
484
* @canvas: the canvas containing the svp that needs updating.
485
* @p_svp: a pointer to the existing svp
486
* @new_svp: the new svp
487
* @clip_svp: a clip path, if non-null
489
* Sets the svp to the new value, clipping if necessary, and requesting repaint
490
* on what's changed. This function takes responsibility for freeing new_svp.
493
gnome_canvas_update_svp_clip (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp, ArtSVP *clip_svp)
497
if (clip_svp != NULL) {
498
clipped_svp = art_svp_intersect (new_svp, clip_svp);
499
art_svp_free (new_svp);
501
clipped_svp = new_svp;
503
gnome_canvas_update_svp (canvas, p_svp, clipped_svp);
507
* gnome_canvas_item_reset_bounds:
508
* @item: A canvas item
510
* Resets the bounding box of a canvas item to an empty rectangle.
513
gnome_canvas_item_reset_bounds (GnomeCanvasItem *item)
522
* gnome_canvas_item_update_svp:
523
* @item: the canvas item containing the svp that needs updating.
524
* @p_svp: a pointer to the existing svp
525
* @new_svp: the new svp
527
* Sets the svp to the new value, requesting repaint on what's changed. This
528
* function takes responsibility for freeing new_svp. This routine also adds the
529
* svp's bbox to the item's.
532
gnome_canvas_item_update_svp (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp)
536
gnome_canvas_update_svp (item->canvas, p_svp, new_svp);
542
art_drect_svp_union (&bbox, new_svp);
551
* gnome_canvas_item_update_svp_clip:
552
* @item: the canvas item containing the svp that needs updating.
553
* @p_svp: a pointer to the existing svp
554
* @new_svp: the new svp
555
* @clip_svp: a clip path, if non-null
557
* Sets the svp to the new value, clipping if necessary, and requesting repaint
558
* on what's changed. This function takes responsibility for freeing new_svp.
561
gnome_canvas_item_update_svp_clip (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp,
566
if (clip_svp != NULL) {
567
clipped_svp = art_svp_intersect (new_svp, clip_svp);
568
art_svp_free (new_svp);
570
clipped_svp = new_svp;
573
gnome_canvas_item_update_svp (item, p_svp, clipped_svp);
577
* gnome_canvas_item_request_redraw_svp
578
* @item: the item containing the svp
579
* @svp: the svp that needs to be redrawn
581
* Request redraw of the svp if in aa mode, or the entire item in in xlib mode.
584
gnome_canvas_item_request_redraw_svp (GnomeCanvasItem *item, const ArtSVP *svp)
589
canvas = item->canvas;
592
uta = art_uta_from_svp (svp);
593
gnome_canvas_request_redraw_uta (canvas, uta);
596
gnome_canvas_request_redraw (canvas, item->x1, item->y1, item->x2, item->y2);
601
* gnome_canvas_update_bbox:
602
* @item: the canvas item needing update
603
* @x1: Left coordinate of the new bounding box
604
* @y1: Top coordinate of the new bounding box
605
* @x2: Right coordinate of the new bounding box
606
* @y2: Bottom coordinate of the new bounding box
608
* Sets the bbox to the new value, requesting full repaint.
611
gnome_canvas_update_bbox (GnomeCanvasItem *item, int x1, int y1, int x2, int y2)
613
gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
618
gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
622
* gnome_canvas_buf_ensure_buf:
623
* @buf: the buf that needs to be represened in RGB format
625
* Ensure that the buffer is in RGB format, suitable for compositing.
628
gnome_canvas_buf_ensure_buf (GnomeCanvasBuf *buf)
635
for (y = buf->rect.y0; y < buf->rect.y1; y++) {
636
art_rgb_fill_run (bufptr,
638
(buf->bg_color >> 8) & 0xff,
639
buf->bg_color & 0xff,
640
buf->rect.x1 - buf->rect.x0);
641
bufptr += buf->buf_rowstride;
648
* gnome_canvas_join_gdk_to_art
649
* @gdk_join: a join type, represented in GDK format
651
* Convert from GDK line join specifier to libart.
653
* Return value: The line join specifier in libart format.
655
ArtPathStrokeJoinType
656
gnome_canvas_join_gdk_to_art (GdkJoinStyle gdk_join)
660
return ART_PATH_STROKE_JOIN_MITER;
663
return ART_PATH_STROKE_JOIN_ROUND;
666
return ART_PATH_STROKE_JOIN_BEVEL;
669
g_assert_not_reached ();
670
return ART_PATH_STROKE_JOIN_MITER; /* shut up the compiler */
675
* gnome_canvas_cap_gdk_to_art
676
* @gdk_cap: a cap type, represented in GDK format
678
* Convert from GDK line cap specifier to libart.
680
* Return value: The line cap specifier in libart format.
683
gnome_canvas_cap_gdk_to_art (GdkCapStyle gdk_cap)
687
case GDK_CAP_NOT_LAST:
688
return ART_PATH_STROKE_CAP_BUTT;
691
return ART_PATH_STROKE_CAP_ROUND;
693
case GDK_CAP_PROJECTING:
694
return ART_PATH_STROKE_CAP_SQUARE;
697
g_assert_not_reached ();
698
return ART_PATH_STROKE_CAP_BUTT; /* shut up the compiler */