aboutsummaryrefslogtreecommitdiff
path: root/generic/Arc.c
diff options
context:
space:
mode:
authorlecoanet2000-01-26 13:36:57 +0000
committerlecoanet2000-01-26 13:36:57 +0000
commit65c1342e3831bd04543e64c226ac6372bbaef905 (patch)
tree71faae3436900c3288da74f6b4ef37ee505362ea /generic/Arc.c
parent8e39d5bd6f4e40a4425ad4d984714dcd5215070a (diff)
downloadtkzinc-65c1342e3831bd04543e64c226ac6372bbaef905.zip
tkzinc-65c1342e3831bd04543e64c226ac6372bbaef905.tar.gz
tkzinc-65c1342e3831bd04543e64c226ac6372bbaef905.tar.bz2
tkzinc-65c1342e3831bd04543e64c226ac6372bbaef905.tar.xz
Fin de la r�alisation de l'item. Ajout des fleches, prise
en compte de la rotation, r�alisation de Pick et ToArea.
Diffstat (limited to 'generic/Arc.c')
-rw-r--r--generic/Arc.c778
1 files changed, 636 insertions, 142 deletions
diff --git a/generic/Arc.c b/generic/Arc.c
index 77e655c..a5203b5 100644
--- a/generic/Arc.c
+++ b/generic/Arc.c
@@ -27,6 +27,7 @@
*/
+#include <alloca.h>
#include <malloc.h>
#include "Item.h"
@@ -44,78 +45,16 @@ static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ "
/*
* Bit offset of flags.
*/
-#define FILLED_BIT 1 /* If the arc is filled with color/pattern */
-#define CLOSED_BIT 2 /* If the arc outline is closed */
-#define PIE_SLICE_BIT 4 /* If the arc is closed as a pie slice or a chord */
-
-
-#define PTS_IN_SHAPE 64
-static RadarPoint oval_shape[PTS_IN_SHAPE] = {
- {1.0, 0.0}, /* 0 */
- {0.99518472653, 0.0980171417729},
- {0.980785279837, 0.195090324861},
- {0.956940334469, 0.290284681418},
- {0.923879530291, 0.382683437725},
- {0.88192126093, 0.471396743221},
- {0.831469607468, 0.555570240255},
- {0.773010446922, 0.634393292011},
- {0.707106772982, 0.707106789391},
- {0.634393274074, 0.773010461643},
- {0.555570220961, 0.83146962036},
- {0.471396722756, 0.881921271869},
- {0.382683416286, 0.923879539171},
- {0.290284659212, 0.956940341205},
- {0.195090302102, 0.980785284364},
- {0.0980171186795, 0.995184728805},
- {0.0, 1.0}, /* PI/2 */
- {-0.0980171648663, 0.995184724256},
- {-0.19509034762, 0.98078527531},
- {-0.290284703624, 0.956940327733},
- {-0.382683459163, 0.923879521411},
- {-0.471396763686, 0.881921249991},
- {-0.555570259549, 0.831469594576},
- {-0.634393309949, 0.773010432201},
- {-0.707106805799, 0.707106756574},
- {-0.773010476365, 0.634393256136},
- {-0.831469633252, 0.555570201666},
- {-0.881921282808, 0.471396702291},
- {-0.923879548052, 0.382683394847},
- {-0.956940347941, 0.290284637006},
- {-0.980785288892, 0.195090279343},
- {-0.995184731079, 0.0980170955862},
- {-1.0, 0.0}, /* PI */
- {-0.995184721981, -0.0980171879596},
- {-0.980785270783, -0.195090370379},
- {-0.956940320997, -0.29028472583},
- {-0.923879512531, -0.382683480602},
- {-0.881921239052, -0.471396784151},
- {-0.831469581684, -0.555570278844},
- {-0.77301041748, -0.634393327887},
- {-0.707106740165, -0.707106822208},
- {-0.634393238198, -0.773010491086},
- {-0.555570182372, -0.831469646144},
- {-0.471396681826, -0.881921293746},
- {-0.382683373409, -0.923879556932},
- {-0.2902846148, -0.956940354677},
- {-0.195090256583, -0.980785293419},
- {-0.0980170724928, -0.995184733354},
- {0.0, -1.0}, /* 3*PI/2 */
- {0.098017211053, -0.995184719707},
- {0.195090393139, -0.980785266256},
- {0.290284748036, -0.956940314261},
- {0.382683502041, -0.923879503651},
- {0.471396804617, -0.881921228114},
- {0.555570298138, -0.831469568792},
- {0.634393345825, -0.773010402759},
- {0.707106838616, -0.707106723757},
- {0.773010505807, -0.63439322026},
- {0.831469659036, -0.555570163078},
- {0.881921304685, -0.471396661361},
- {0.923879565812, -0.38268335197},
- {0.956940361414, -0.290284592594},
- {0.980785297946, -0.195090233824},
- {0.995184735628, -0.0980170493994}
-};
+#define FILLED_BIT 1<<0 /* If the arc is filled with color/pattern */
+#define CLOSED_BIT 1<<1 /* If the arc outline is closed */
+#define PIE_SLICE_BIT 1<<2 /* If the arc is closed as a pie slice or a chord */
+
+#define FIRST_END_OK 1<<3
+#define LAST_END_OK 1<<4
+
+
+static double Pick(Item item, RadarPoint *p, Item start_item, int aperture,
+ Item *a_item, int *a_part);
/*
@@ -138,6 +77,8 @@ typedef struct _ArcItemStruct {
RadarColor line_color;
int line_width;
LineStyle line_style;
+ LineEnd first_end;
+ LineEnd last_end;
char *tile_name;
unsigned char flags;
@@ -168,6 +109,10 @@ static RadarAttrConfig arc_attrs[] = {
Tk_Offset(ArcItemStruct, flags), FILLED_BIT, RADAR_COORDS_FLAG, False },
{ RADAR_CONFIG_PATTERN, "-fillpattern", NULL,
Tk_Offset(ArcItemStruct, fill_pattern), 0, RADAR_DRAW_FLAG, False },
+ { RADAR_CONFIG_LINE_END, "-firstend", NULL,
+ Tk_Offset(ArcItemStruct, first_end), 0, RADAR_COORDS_FLAG, False },
+ { RADAR_CONFIG_LINE_END, "-lastend", NULL,
+ Tk_Offset(ArcItemStruct, last_end), 0, RADAR_COORDS_FLAG, False },
{ RADAR_CONFIG_COLOR, "-linecolor", NULL,
Tk_Offset(ArcItemStruct, line_color), 0,
RADAR_DRAW_FLAG|RADAR_BORDER_FLAG, False },
@@ -259,6 +204,7 @@ Init(Item item,
arc->fill_pattern = RadarUnspecifiedPattern;
arc->line_style = LINE_SIMPLE;
arc->line_width = 1;
+ arc->first_end = arc->last_end = NULL;
arc->tile_name = "";
arc->tile = RadarUnspecifiedImage;
arc->render_shape = NULL;
@@ -332,6 +278,12 @@ Clone(Item item)
arc->tile = Tk_GetImage(wi->interp, wi->win, arc->tile_name,
ArcTileChange, (ClientData) arc);
}
+ if (arc->first_end) {
+ LineEndDuplicate(arc->first_end);
+ }
+ if (arc->last_end) {
+ LineEndDuplicate(arc->last_end);
+ }
if (arc->line_pattern != RadarUnspecifiedPattern) {
arc->line_pattern = Tk_GetBitmap(wi->interp, wi->win,
Tk_NameOfBitmap(wi->dpy, arc->line_pattern));
@@ -342,7 +294,9 @@ Clone(Item item)
}
arc->line_color = RadarGetColorByValue(wi->win, arc->line_color);
arc->fill_color = RadarGetColorByValue(wi->win, arc->fill_color);
- arc->render_shape = NULL;
+ if (arc->render_shape) {
+ arc->render_shape = RadarListDuplicate(arc->render_shape);
+ }
}
@@ -365,6 +319,12 @@ Destroy(Item item)
if (strlen(arc->tile_name) != 0) {
RadarFree(arc->tile_name);
}
+ if (arc->first_end) {
+ LineEndDelete(arc->first_end);
+ }
+ if (arc->last_end) {
+ LineEndDelete(arc->last_end);
+ }
if (arc->tile != RadarUnspecifiedImage) {
Tk_FreeImage(arc->tile);
arc->tile = RadarUnspecifiedImage;
@@ -383,6 +343,29 @@ Destroy(Item item)
/*
**********************************************************************************
*
+ * Setup flags to control the precedence between the
+ * graphical attributes.
+ *
+ **********************************************************************************
+ */
+static void
+SetRenderFlags(ArcItem arc)
+{
+ ASSIGN(arc->flags, FIRST_END_OK,
+ (arc->first_end != NULL) && ISCLEAR(arc->flags, CLOSED_BIT) &&
+ ISCLEAR(arc->flags, FILLED_BIT) && arc->line_width
+ /*&& ISCLEAR(arc->flags, RELIEF_OK)*/);
+
+ ASSIGN(arc->flags, LAST_END_OK,
+ (arc->last_end != NULL) && ISCLEAR(arc->flags, CLOSED_BIT) &&
+ ISCLEAR(arc->flags, FILLED_BIT) && arc->line_width
+ /*&& ISCLEAR(arc->flags, RELIEF_OK)*/);
+}
+
+
+/*
+ **********************************************************************************
+ *
* Configure --
*
**********************************************************************************
@@ -423,6 +406,8 @@ Configure(Item item,
arc->tile = tile;
}
+ SetRenderFlags(arc);
+
return RADAR_OK;
}
@@ -448,6 +433,66 @@ Query(Item item,
/*
+ * Tangent --
+ * Compute a point describing the arc tangent at the first/last
+ * end of the arc. The point is on the tangent segment next to
+ * the arc (ie: it is suitable for drawing arrows).
+ */
+void
+Tangent(ArcItem arc,
+ RadarBool first,
+ RadarPoint *p)
+{
+ double a2, b2, w_2, h_2;
+ double angle;
+ RadarPoint p1, center;
+
+ if (first) {
+ angle = DegreesToRadian(arc->start_angle);
+ }
+ else {
+ angle = DegreesToRadian(arc->start_angle + arc->angle_extent);
+ }
+ p1.x = cos(angle);
+ p1.y = sin(angle);
+ w_2 = (arc->corner.x - arc->orig.x) / 2.0;
+ h_2 = (arc->corner.y - arc->orig.y) / 2.0;
+ center.x = (arc->orig.x + arc->corner.x) / 2.0;
+ center.y = (arc->orig.y + arc->corner.y) / 2.0;
+
+ /*
+ * Slope of the initial segment.
+ *
+ * a1 = (center->y - p1.y) / (center->x - p1.x);
+ * a2 = -1/a1;
+ */
+ a2 = - p1.x / p1.y;
+ b2 = p1.y - a2*p1.x;
+
+ if (p1.y == 0.0) {
+ p->x = p1.x;
+ if (!first) {
+ p->y = p1.y - 10.0;
+ }
+ else {
+ p->y = p1.y + 10.0;
+ }
+ }
+ else {
+ if ((!first && (p1.y < 0.0)) || (first && (p1.y > 0.0))) {
+ p->x = p1.x - 10.0;
+ }
+ else {
+ p->x = p1.x + 10.0;
+ }
+ p->y = a2*p->x + b2;
+ }
+ p->x = center.x + REAL_TO_INT(p->x*w_2);
+ p->y = center.y + REAL_TO_INT(p->y*h_2);
+}
+
+
+/*
**********************************************************************************
*
* ComputeCoordinates --
@@ -461,8 +506,10 @@ ComputeCoordinates(Item item,
WidgetInfo *wi = item->wi;
ArcItem arc = (ArcItem) item;
RadarReal angle, sin1, cos1, sin2, cos2;
- int tmp, w_2, h_2, center_x, center_y,i;
+ RadarReal tmp, w_2, h_2, center_x, center_y;
+ int num_p, i;
RadarPoint *p_list, p;
+ RadarPoint end_points[LINE_END_POINTS];
RadarReal width_2, height_2, ox, oy;
ResetBBox(&item->item_bounding_box);
@@ -474,35 +521,64 @@ ComputeCoordinates(Item item,
}
/*
- * Special casing for rotation. This should eventually be the
- * only code but it lacks the arc capability.
+ * Special casing for rotation and/or relief.
+ * This could eventually be the only code but it has to
+ * good results and be fast enough.
*/
RadarTransfoDecompose(wi->current_transfo, NULL, NULL, &angle, NULL);
if (angle >= PRECISION_LIMIT) {
if (!arc->render_shape) {
- arc->render_shape = RadarListNew(PTS_IN_SHAPE, sizeof(RadarPoint));
- RadarListAssertSize(arc->render_shape, PTS_IN_SHAPE);
+ arc->render_shape = RadarListNew(4, sizeof(RadarPoint));
}
+ GetArcPath(DegreesToRadian(arc->start_angle),
+ DegreesToRadian(arc->start_angle+arc->angle_extent),
+ (ISCLEAR(arc->flags, CLOSED_BIT) ? 0 :
+ ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2), arc->render_shape);
p_list = (RadarPoint *) RadarListArray(arc->render_shape);
+ num_p = RadarListSize(arc->render_shape);
width_2 = (arc->coords[1].x - arc->coords[0].x)/2.0;
height_2 = (arc->coords[1].y - arc->coords[0].y)/2.0;
ox = (arc->coords[1].x + arc->coords[0].x)/2.0;
oy = (arc->coords[1].y + arc->coords[0].y)/2.0;
- for (i = 0; i < PTS_IN_SHAPE; i++, p_list++) {
- p.x = ox + oval_shape[i].x*width_2;
- p.y = oy + oval_shape[i].y*height_2;
+ for (i = 0; i < num_p; i++, p_list++) {
+ p.x = ox + p_list->x*width_2;
+ p.y = oy + p_list->y*height_2;
RadarTransformPoint(wi->current_transfo, &p, p_list);
AddPointToBBox(&item->item_bounding_box, p_list->x, p_list->y);
}
- tmp = (arc->line_width + 1) / 2 + 1;
+ tmp = (arc->line_width + 1.0) / 2.0 + 1.0;
item->item_bounding_box.orig.x -= tmp;
item->item_bounding_box.orig.y -= tmp;
item->item_bounding_box.corner.x += tmp;
item->item_bounding_box.corner.y += tmp;
+
+ /*
+ * Add the arrows if any.
+ */
+ p_list = (RadarPoint *) RadarListArray(arc->render_shape);
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ GetLineEnd(p_list, p_list+1, arc->line_width, CapRound,
+ arc->first_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ GetLineEnd(&p_list[num_p-1], &p_list[num_p-2], arc->line_width, CapRound,
+ arc->last_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
+ }
return;
}
+ /*
+ ******* ******** **********
+ * This part is for X drawn arcs: not rotated, without relief.
+ ******* ******** **********
+ */
+ if (arc->render_shape) {
+ RadarListFree(arc->render_shape);
+ arc->render_shape = NULL;
+ }
RadarTransformPoint(wi->current_transfo, &arc->coords[0], &arc->orig);
RadarTransformPoint(wi->current_transfo, &arc->coords[1], &arc->corner);
@@ -521,13 +597,12 @@ ComputeCoordinates(Item item,
* now compute the two points at the centers of the ends of the arc.
* We first compute the position for a unit circle and then scale
* to fit the shape.
- * Angles are running counter clockwise and y coordinates are inverted.
- * To handle these, the angles are negated.
+ * Angles are running clockwise and y coordinates are inverted.
*/
- angle = -(arc->start_angle * M_PI / 180.0);
+ angle = DegreesToRadian(arc->start_angle);
sin1 = sin(angle);
cos1 = cos(angle);
- angle -= (arc->angle_extent * M_PI / 180.0);
+ angle += DegreesToRadian(arc->angle_extent);
sin2 = sin(angle);
cos2 = cos(angle);
@@ -568,38 +643,54 @@ ComputeCoordinates(Item item,
AddPointToBBox(&item->item_bounding_box, arc->corner.x, center_y);
}
- tmp = 90 - arc->start_angle;
+ tmp = 180 - arc->start_angle;
if (tmp < 0) {
tmp += 360;
}
if ((tmp < arc->angle_extent) || ((tmp - 360) > arc->angle_extent)) {
- AddPointToBBox(&item->item_bounding_box, center_x, arc->orig.y);
+ AddPointToBBox(&item->item_bounding_box, arc->orig.x, center_y);
}
- tmp = 180 - arc->start_angle;
+ tmp = 90 - arc->start_angle;
if (tmp < 0) {
tmp += 360;
}
if ((tmp < arc->angle_extent) || ((tmp - 360) > arc->angle_extent)) {
- AddPointToBBox(&item->item_bounding_box, arc->orig.x, center_y);
+ AddPointToBBox(&item->item_bounding_box, center_x, arc->corner.y);
}
-
+
tmp = 270 - arc->start_angle;
if (tmp < 0) {
tmp += 360;
}
if ((tmp < arc->angle_extent) || ((tmp - 360) > arc->angle_extent)) {
- AddPointToBBox(&item->item_bounding_box, center_x, arc->corner.y);
+ AddPointToBBox(&item->item_bounding_box, center_x, arc->orig.y);
}
-
+
/*
* Now take care of the arc outline width plus one pixel of margin.
*/
- tmp = (arc->line_width + 1) / 2 + 1;
+ tmp = (arc->line_width + 1.0) / 2.0 + 1.0;
item->item_bounding_box.orig.x -= tmp;
item->item_bounding_box.orig.y -= tmp;
item->item_bounding_box.corner.x += tmp;
item->item_bounding_box.corner.y += tmp;
+
+ /*
+ * Then add the arrows if any.
+ */
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ Tangent(arc, True, &p);
+ GetLineEnd(&arc->center1, &p, arc->line_width, CapRound,
+ arc->first_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ Tangent(arc, False, &p);
+ GetLineEnd(&arc->center2, &p, arc->line_width, CapRound,
+ arc->last_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
+ }
}
@@ -620,22 +711,272 @@ ToArea(Item item,
RadarBool report)
{
ArcItem arc = (ArcItem) item;
- RadarPoint center;
- RadarBBox tran_rect;
- int rx, ry;
- int lw = arc->line_width;
+ WidgetInfo *wi = item->wi;
+ RadarPoint *points;
+ RadarPoint pts[20]; /* Should be at least LINE_END_POINTS large */
+ RadarPoint center, tang;
+ RadarBBox t_area;
+ int num_points, result, result2;
+ RadarReal lw = arc->line_width;
+ RadarReal rx, ry, angle, tmp;
+ RadarBool inside, new_inside;
+
+ if (arc->render_shape &&
+ (ISSET(arc->flags, FILLED_BIT) || (arc->line_width))) {
+ GetBezierPath(arc->render_shape, wi->work_pts);
+ points = (RadarPoint *) RadarListArray(wi->work_pts);
+ num_points = RadarListSize(wi->work_pts);
+
+ if (ISSET(arc->flags, FILLED_BIT)) {
+ result = PolygonInBBox(points, num_points, area);
+ if (result == 0) {
+ return 0;
+ }
+ }
+ if (arc->line_width > 0) {
+ result2 = PolylineInBBox(points, num_points, arc->line_width,
+ CapRound, JoinRound, area);
+ if (ISCLEAR(arc->flags, FILLED_BIT)) {
+ if (result2 == 0) {
+ return 0;
+ }
+ result = result2;
+ }
+ else if (result2 != result) {
+ return 0;
+ }
+ if (ISSET(arc->flags, CLOSED_BIT) && ISSET(arc->flags, PIE_SLICE_BIT)) {
+ pts[0] = points[num_points-1];
+ pts[1] = points[0];
+ if (PolylineInBBox(pts, 2, arc->line_width,
+ CapRound, JoinRound, area) != result) {
+ return 0;
+ }
+ }
+ /*
+ * Check line ends.
+ */
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ GetLineEnd(&points[0], &points[1], arc->line_width, CapRound,
+ arc->first_end, pts);
+ if (PolygonInBBox(pts, LINE_END_POINTS, area) != result) {
+ return 0;
+ }
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ GetLineEnd(&points[num_points-1], &points[num_points-2], arc->line_width,
+ CapRound, arc->last_end, pts);
+ if (PolygonInBBox(pts, LINE_END_POINTS, area) != result) {
+ return 0;
+ }
+ }
+ }
+ return result;
+ }
/*
- * Translate both the arc and the area so that they are
- * centered on the origin. rx,ry are the radiuses in x and y.
+ ******* ******** **********
+ * The rest of this code deal with non rotated or relief arcs. *
+ * It has been stolen from tkCanvArc.c *
+ ******* ******** **********
*/
- center.x = (arc->corner.x + arc->orig.x) / 2;
- center.y = (arc->corner.y + arc->orig.y) / 2;
- tran_rect.orig.x = area->orig.x - center.x;
- tran_rect.orig.y = area->orig.y - center.y;
- rx = arc->corner.x - center.x + lw/2;
- ry = arc->corner.y - center.y + lw/2;
+ /*
+ * Transform both the arc and the rectangle so that the arc's oval
+ * is centered on the origin.
+ */
+ center.x = (arc->orig.x + arc->corner.x)/2.0;
+ center.y = (arc->orig.y + arc->corner.y)/2.0;
+ t_area.orig.x = area->orig.x - center.x;
+ t_area.orig.y = area->orig.y - center.y;
+ t_area.corner.x = area->corner.x - center.x;
+ t_area.corner.y = area->corner.y - center.y;
+ rx = arc->corner.x - center.x + lw/2.0;
+ ry = arc->corner.y - center.y + lw/2.0;
+
+ /*
+ * Find the extreme points of the arc and see whether these are all
+ * inside the rectangle (in which case we're done), partly in and
+ * partly out (in which case we're done), or all outside (in which
+ * case we have more work to do). The extreme points include the
+ * following, which are checked in order:
+ *
+ * 1. The outside points of the arc, corresponding to start and
+ * extent.
+ * 2. The center of the arc (but only in pie-slice mode).
+ * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
+ * includes those angles).
+ */
+ points = pts;
+ angle = DegreesToRadian(arc->start_angle);
+ points->x = rx*cos(angle);
+ points->y = ry*sin(angle);
+ angle += DegreesToRadian(arc->angle_extent);
+ points[1].x = rx*cos(angle);
+ points[1].y = ry*sin(angle);
+ num_points = 2;
+ points += 2;
+
+ if (ISSET(arc->flags, PIE_SLICE_BIT) && (arc->angle_extent < 180.0)) {
+ points->x = 0.0;
+ points->y = 0.0;
+ num_points++;
+ points++;
+ }
+
+ tmp = -arc->start_angle;
+ if (tmp < 0) {
+ tmp += 360.0;
+ }
+ if ((tmp < arc->angle_extent) || ((tmp-360) > arc->angle_extent)) {
+ points->x = rx;
+ points->y = 0.0;
+ num_points++;
+ points++;
+ }
+ tmp = 180.0 - arc->start_angle;
+ if (tmp < 0) {
+ tmp += 360.0;
+ }
+ if ((tmp < arc->angle_extent) || ((tmp-360) > arc->angle_extent)) {
+ points->x = 0.0;
+ points->y = ry;
+ num_points++;
+ points++;
+ }
+ tmp = 90.0 - arc->start_angle;
+ if (tmp < 0) {
+ tmp += 360.0;
+ }
+ if ((tmp < arc->angle_extent) || ((tmp-360) > arc->angle_extent)) {
+ points->x = -rx;
+ points->y = 0.0;
+ num_points++;
+ points++;
+ }
+ tmp = 270.0 - arc->start_angle;
+ if (tmp < 0) {
+ tmp += 360.0;
+ }
+ if ((tmp < arc->angle_extent) || ((tmp-360) > arc->angle_extent)) {
+ points->x = 0.0;
+ points->y = -ry;
+ num_points++;
+ }
+
+ /*
+ * Now that we've located the extreme points, loop through them all
+ * to see which are inside the rectangle.
+ */
+ inside = PointInBBox(&t_area, pts->x, pts->y);
+ for (points = pts+1; num_points > 1; points++, num_points--) {
+ new_inside = PointInBBox(&t_area, points->x, points->y);
+ if (new_inside != inside) {
+ return 0;
+ }
+ }
+ result = inside ? 1 : -1;
+ /*
+ * So far, oval appears to be outside rectangle, but can't yet tell
+ * for sure. Next, test each of the four sides of the rectangle
+ * against the bounding region for the arc. If any intersections
+ * are found, then return "overlapping". First, test against the
+ * polygon(s) forming the sides of a chord or pie-slice.
+ */
+ if ((lw >= 1.0) && (ISSET(arc->flags, CLOSED_BIT))) {
+ if (ISSET(arc->flags, PIE_SLICE_BIT)) {
+ pts[0] = arc->center1;
+ pts[1] = center;
+ pts[2] = arc->center2;
+ num_points = 3;
+ }
+ else {
+ pts[0] = arc->center1;
+ pts[1] = arc->center2;
+ num_points = 2;
+ }
+ if (PolylineInBBox(pts, num_points, lw, CapRound, JoinRound, area) != result) {
+ return 0;
+ }
+ }
+ else if (ISSET(arc->flags, FILLED_BIT)) {
+ if (ISSET(arc->flags, PIE_SLICE_BIT)) {
+ if ((LineInBBox(&center, &arc->center1, area) != result) ||
+ (LineInBBox(&center, &arc->center2, area) != result)) {
+ return 0;
+ }
+ }
+ else {
+ if (LineInBBox(&arc->center1, &arc->center2, area) != result) {
+ return 0;
+ }
+ }
+ }
+
+ /*
+ * Check line ends.
+ */
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ Tangent(arc, True, &tang);
+ GetLineEnd(&arc->center1, &tang, arc->line_width, CapRound,
+ arc->first_end, pts);
+ if (PolygonInBBox(pts, LINE_END_POINTS, area) != result) {
+ return 0;
+ }
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ Tangent(arc, False, &tang);
+ GetLineEnd(&arc->center2, &tang, arc->line_width, CapRound,
+ arc->last_end, pts);
+ if (PolygonInBBox(pts, LINE_END_POINTS, area) != result) {
+ return 0;
+ }
+ }
+ if (result == 1) {
+ return result;
+ }
+
+ /*
+ * Next check for overlap between each of the four sides and the
+ * outer perimiter of the arc. If the arc isn't filled, then also
+ * check the inner perimeter of the arc.
+ */
+ if (HorizLineToArc(t_area.orig.x, t_area.corner.x, t_area.orig.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ HorizLineToArc(t_area.orig.x, t_area.corner.x, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ VertLineToArc(t_area.orig.x, t_area.orig.y, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ VertLineToArc(t_area.corner.x, t_area.orig.y, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent)) {
+ return 0;
+ }
+ if ((lw > 1.0) && ISCLEAR(arc->flags, FILLED_BIT)) {
+ rx -= lw;
+ ry -= lw;
+ if (HorizLineToArc(t_area.orig.x, t_area.corner.x, t_area.orig.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ HorizLineToArc(t_area.orig.x, t_area.corner.x, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ VertLineToArc(t_area.orig.x, t_area.orig.y, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent) ||
+ VertLineToArc(t_area.corner.x, t_area.orig.y, t_area.corner.y,
+ rx, ry, arc->start_angle, arc->angle_extent)) {
+ return 0;
+ }
+ }
+
+ /*
+ * The arc still appears to be totally disjoint from the rectangle,
+ * but it's also possible that the rectangle is totally inside the arc.
+ * Do one last check, which is to check one point of the rectangle
+ * to see if it's inside the arc. If it is, we've got overlap. If
+ * it isn't, the arc's really outside the rectangle.
+ */
+ if (Pick(item, &area->orig, RADAR_NO_ITEM, 0, NULL, NULL) == 0.0) {
+ return 0;
+ }
+
return -1;
}
@@ -655,22 +996,23 @@ Draw(Item item)
XGCValues values;
int width, height;
RadarPoint *p;
- XPoint xp[PTS_IN_SHAPE+1];
+ XPoint *xp;
int num_points, i;
- width = arc->corner.x - arc->orig.x;
- height = arc->corner.y - arc->orig.y;
-
if (arc->render_shape &&
(ISSET(arc->flags, FILLED_BIT) || (arc->line_width))) {
- p = (RadarPoint *) RadarListArray(arc->render_shape);
- num_points = RadarListSize(arc->render_shape);
+ GetBezierPath(arc->render_shape, wi->work_pts);
+ p = (RadarPoint *) RadarListArray(wi->work_pts);
+ num_points = RadarListSize(wi->work_pts);
+ xp = (XPoint *) alloca(num_points*sizeof(XPoint));
for (i = 0; i < num_points; i++, p++) {
xp[i].x = (short) p->x;
xp[i].y = (short) p->y;
}
- xp[i] = xp[0];
- num_points++;
+ }
+ else {
+ width = arc->corner.x - arc->orig.x;
+ height = arc->corner.y - arc->orig.y;
}
/* Fill if requested */
@@ -707,7 +1049,7 @@ Draw(Item item)
else {
XFillArc(wi->dpy, wi->draw_buffer, wi->gc,
arc->orig.x, arc->orig.y, width, height,
- arc->start_angle*64, arc->angle_extent*64);
+ -arc->start_angle*64, -arc->angle_extent*64);
}
}
@@ -715,6 +1057,10 @@ Draw(Item item)
* Draw the arc.
*/
if (arc->line_width) {
+ RadarPoint end_points[LINE_END_POINTS];
+ XPoint xap[LINE_END_POINTS];
+ RadarPoint tang;
+
SetLineStyle(wi->dpy, wi->gc, arc->line_style);
values.foreground = RadarPixel(arc->line_color);
values.line_width = (arc->line_width == 1) ? 0 : arc->line_width;
@@ -735,31 +1081,80 @@ Draw(Item item)
if (arc->render_shape) {
XDrawLines(wi->dpy, wi->draw_buffer, wi->gc,
xp, num_points, CoordModeOrigin);
+ if (ISSET(arc->flags, CLOSED_BIT) && ISSET(arc->flags, PIE_SLICE_BIT)) {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ xp[num_points-1].x, xp[num_points-1].y,
+ xp[0].x, xp[0].y);
+ }
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ p = (RadarPoint *) RadarListArray(arc->render_shape);
+ GetLineEnd(p, p+1, arc->line_width, CapRound,
+ arc->first_end, end_points);
+ for (i = 0; i < LINE_END_POINTS; i++) {
+ xap[i].x = end_points[i].x;
+ xap[i].y = end_points[i].y;
+ }
+ XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xap, LINE_END_POINTS,
+ Nonconvex, CoordModeOrigin);
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ p = (RadarPoint *) RadarListArray(arc->render_shape);
+ num_points = RadarListSize(arc->render_shape);
+ GetLineEnd(&p[num_points-1], &p[num_points-2], arc->line_width,
+ CapRound, arc->last_end, end_points);
+ for (i = 0; i < LINE_END_POINTS; i++) {
+ xap[i].x = end_points[i].x;
+ xap[i].y = end_points[i].y;
+ }
+ XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xap, LINE_END_POINTS,
+ Nonconvex, CoordModeOrigin);
+ }
}
else {
XDrawArc(wi->dpy, wi->draw_buffer, wi->gc,
arc->orig.x, arc->orig.y, width, height,
- arc->start_angle*64, arc->angle_extent*64);
- }
-
- /*
- * If the outline is closed, draw the closure.
- */
- if (ISSET(arc->flags, CLOSED_BIT)) {
- if (ISSET(arc->flags, PIE_SLICE_BIT)) {
- XPoint points[3];
-
- points[0].x = arc->center1.x;
- points[0].y = arc->center1.y;
- points[1].x = (arc->corner.x + arc->orig.x) / 2;
- points[1].y = (arc->corner.y + arc->orig.y) / 2;
- points[2].x = arc->center2.x;
- points[2].y = arc->center2.y;
- XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, points, 3, CoordModeOrigin);
+ -arc->start_angle*64, -arc->angle_extent*64);
+ /*
+ * If the outline is closed, draw the closure.
+ */
+ if (ISSET(arc->flags, CLOSED_BIT)) {
+ if (ISSET(arc->flags, PIE_SLICE_BIT)) {
+ XPoint points[3];
+
+ points[0].x = arc->center1.x;
+ points[0].y = arc->center1.y;
+ points[1].x = (arc->corner.x + arc->orig.x) / 2;
+ points[1].y = (arc->corner.y + arc->orig.y) / 2;
+ points[2].x = arc->center2.x;
+ points[2].y = arc->center2.y;
+ XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, points, 3, CoordModeOrigin);
+ }
+ else {
+ XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
+ arc->center1.x, arc->center1.y, arc->center2.x, arc->center2.y);
+ }
}
- else {
- XDrawLine(wi->dpy, wi->draw_buffer, wi->gc,
- arc->center1.x, arc->center1.y, arc->center2.x, arc->center2.y);
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ Tangent(arc, True, &tang);
+ GetLineEnd(&arc->center1, &tang, arc->line_width, CapRound,
+ arc->first_end, end_points);
+ for (i = 0; i < LINE_END_POINTS; i++) {
+ xap[i].x = end_points[i].x;
+ xap[i].y = end_points[i].y;
+ }
+ XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xap, LINE_END_POINTS,
+ Nonconvex, CoordModeOrigin);
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ Tangent(arc, False, &tang);
+ GetLineEnd(&arc->center2, &tang, arc->line_width, CapRound,
+ arc->last_end, end_points);
+ for (i = 0; i < LINE_END_POINTS; i++) {
+ xap[i].x = end_points[i].x;
+ xap[i].y = end_points[i].y;
+ }
+ XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xap, LINE_END_POINTS,
+ Nonconvex, CoordModeOrigin);
}
}
}
@@ -797,14 +1192,79 @@ Pick(Item item,
Item *a_item,
int *a_part)
{
+ WidgetInfo *wi = item->wi;
ArcItem arc = (ArcItem) item;
- double dist, new_dist;
+ double dist = 1e40, new_dist;
RadarBool point_in_angle, filled, closed;
RadarBool in_triangle, acute_angle;
- RadarPoint p1, center;
+ RadarPoint p1, center, tang;
+ RadarPoint *points;
+ RadarPoint end_points[LINE_END_POINTS];
+ int num_points;
int width, height;
RadarDim lw = arc->line_width;
+
+ if (arc->render_shape &&
+ (ISSET(arc->flags, FILLED_BIT) || (arc->line_width))) {
+ GetBezierPath(arc->render_shape, wi->work_pts);
+ points = (RadarPoint *) RadarListArray(wi->work_pts);
+ num_points = RadarListSize(wi->work_pts);
+
+ if (ISSET(arc->flags, FILLED_BIT)) {
+ dist = PolygonToPointDist(points, num_points, p);
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
+ if (arc->line_width > 0) {
+ new_dist = PolylineToPointDist(points, num_points, arc->line_width,
+ CapRound, JoinRound, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (ISSET(arc->flags, CLOSED_BIT) && ISSET(arc->flags, PIE_SLICE_BIT)) {
+ new_dist = LineToPointDist(&points[num_points-1], &points[0], p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
+ /*
+ * Check line ends.
+ */
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ GetLineEnd(&points[0], &points[1], arc->line_width, CapRound,
+ arc->first_end, end_points);
+ new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ GetLineEnd(&points[num_points-1], &points[num_points-2], arc->line_width,
+ CapRound, arc->last_end, end_points);
+ new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
+ return dist;
+ }
+ /*
+ ******* ******** **********
+ * The rest of this code deal with non rotated or relief arcs. *
+ ******* ******** **********
+ */
center.x = (arc->corner.x + arc->orig.x) / 2;
center.y = (arc->corner.y + arc->orig.y) / 2;
width = arc->corner.x - arc->orig.x;
@@ -813,10 +1273,9 @@ Pick(Item item,
/*
* Let see if the point is in the angular range. First
* transform the coordinates so that the oval is circular.
- * The 8192 factor avoids rounding errors.
*/
- p1.y = ((int)(p->y - center.y)*8192) / height;
- p1.x = ((int)(p->x - center.x)*8192) / width;
+ p1.y = (p->y - center.y) / height;
+ p1.x = (p->x - center.x) / width;
point_in_angle = PointInAngle(arc->start_angle, arc->angle_extent, &p1);
/*
@@ -837,9 +1296,10 @@ Pick(Item item,
if (dist < 0.0) {
dist = -dist;
}
- return dist;
}
- dist = hypot((p->x - arc->center1.x), (p->y - arc->center1.y));
+ else {
+ dist = hypot((p->x - arc->center1.x), (p->y - arc->center1.y));
+ }
new_dist = hypot((p->x - arc->center2.x), (p->y - arc->center2.y));
if (new_dist < dist) {
dist = new_dist;
@@ -851,6 +1311,37 @@ Pick(Item item,
dist = 0.0;
}
}
+ if (dist == 0.0) {
+ return 0.0;
+ }
+
+ /*
+ * Check line ends.
+ */
+ if (ISSET(arc->flags, FIRST_END_OK)) {
+ Tangent(arc, True, &tang);
+ GetLineEnd(&arc->center1, &tang, arc->line_width, CapRound,
+ arc->first_end, end_points);
+ new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
+ if (ISSET(arc->flags, LAST_END_OK)) {
+ Tangent(arc, False, &tang);
+ GetLineEnd(&arc->center2, &tang, arc->line_width,
+ CapRound, arc->last_end, end_points);
+ new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
+ }
return dist;
}
@@ -960,6 +1451,9 @@ Pick(Item item,
if (dist < 0.0) {
dist = filled ? 0.0 : -dist;
}
+ if (dist == 0.0) {
+ return 0.0;
+ }
}
return dist;