diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/Arc.c | 778 |
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(¢er, &arc->center1, area) != result) || + (LineInBBox(¢er, &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; |