diff options
-rw-r--r-- | generic/Arc.c | 1100 |
1 files changed, 1100 insertions, 0 deletions
diff --git a/generic/Arc.c b/generic/Arc.c new file mode 100644 index 0000000..77e655c --- /dev/null +++ b/generic/Arc.c @@ -0,0 +1,1100 @@ +/* + * Arc.c -- Implementation of Arc item. + * + * Authors : Patrick Lecoanet. + * Creation date : Wed Mar 30 16:24:09 1994 + * + * $Id$ + */ + +/* + * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet -- + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this code; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <malloc.h> + +#include "Item.h" +#include "Geo.h" +#include "Draw.h" +#include "Types.h" +#include "WidgetInfo.h" +#include "Image.h" + + +static const char rcsid[] = "$Id$"; +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} +}; + + +/* + ********************************************************************************** + * + * Specific Arc item record. + * + ********************************************************************************** + */ +typedef struct _ArcItemStruct { + ItemStruct header; + + /* Public data */ + RadarPoint coords[2]; + int start_angle; + int angle_extent; + Pixmap line_pattern; + Pixmap fill_pattern; + RadarColor fill_color; + RadarColor line_color; + int line_width; + LineStyle line_style; + char *tile_name; + unsigned char flags; + + /* Private data */ + RadarPoint orig; + RadarPoint corner; + RadarPoint center1; + RadarPoint center2; + RadarImage tile; + RadarList render_shape; +} ArcItemStruct, *ArcItem; + + +static RadarAttrConfig arc_attrs[] = { + { RADAR_CONFIG_BOOL, "-closed", NULL, + Tk_Offset(ArcItemStruct, flags), CLOSED_BIT, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-composerotation", NULL, + Tk_Offset(ArcItemStruct, header.flags), COMPOSE_ROTATION_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-composescale", NULL, + Tk_Offset(ArcItemStruct, header.flags), COMPOSE_SCALE_BIT, + RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_ANGLE, "-extent", NULL, + Tk_Offset(ArcItemStruct, angle_extent), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_COLOR, "-fillcolor", NULL, + Tk_Offset(ArcItemStruct, fill_color), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_BOOL, "-filled", NULL, + 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_COLOR, "-linecolor", NULL, + Tk_Offset(ArcItemStruct, line_color), 0, + RADAR_DRAW_FLAG|RADAR_BORDER_FLAG, False }, + { RADAR_CONFIG_PATTERN, "-linepattern", NULL, + Tk_Offset(ArcItemStruct, line_pattern), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_LINE_STYLE, "-linestyle", NULL, + Tk_Offset(ArcItemStruct, line_style), 0, RADAR_DRAW_FLAG, False }, + { RADAR_CONFIG_DIM, "-linewidth", NULL, + Tk_Offset(ArcItemStruct, line_width), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_BOOL, "-pieslice", NULL, + Tk_Offset(ArcItemStruct, flags), PIE_SLICE_BIT, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_PRI, "-priority", NULL, + Tk_Offset(ArcItemStruct, header.priority), 0, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_BOOL, "-sensitive", NULL, + Tk_Offset(ArcItemStruct, header.flags), SENSITIVE_BIT, + RADAR_REPICK_FLAG, False }, + { RADAR_CONFIG_ANGLE, "-startangle", NULL, + Tk_Offset(ArcItemStruct, start_angle), 0, RADAR_COORDS_FLAG, False }, + { RADAR_CONFIG_TAGS, "-tags", NULL, + Tk_Offset(ArcItemStruct, header.tags), 0, 0, False }, + { RADAR_CONFIG_IMAGE, "-tile", NULL, + Tk_Offset(ArcItemStruct, tile_name), 0, + RADAR_DRAW_FLAG|RADAR_TILE_FLAG, False }, + { RADAR_CONFIG_BOOL, "-visible", NULL, + Tk_Offset(ArcItemStruct, header.flags), VISIBLE_BIT, + RADAR_DRAW_FLAG|RADAR_REPICK_FLAG|RADAR_VIS_FLAG, False }, + + { RADAR_CONFIG_END, NULL, NULL, 0, 0, 0 } +}; + + +/* + ********************************************************************************** + * + * ArcTileChange -- + * + ********************************************************************************** + */ +static void +ArcTileChange(ClientData client_data, + int x, + int y, + int width, + int height, + int image_width, + int image_height) +{ + ArcItem arc = (ArcItem) client_data; + + InvalidateImage(arc->tile); + ITEM.Invalidate((Item) arc, RADAR_COORDS_FLAG); +} + + +/* + ********************************************************************************** + * + * Init -- + * + ********************************************************************************** + */ +static int +Init(Item item, + int *argc, + Arg **args) +{ + WidgetInfo *wi = item->wi; + ArcItem arc = (ArcItem) item; + Arg *elems; + int result, num_elems; +#ifdef PTK + LangFreeProc *freeProc = NULL; +#endif + + /* Init attributes */ + SET(item->flags, VISIBLE_BIT); + SET(item->flags, SENSITIVE_BIT); + SET(item->flags, COMPOSE_ROTATION_BIT); + SET(item->flags, COMPOSE_SCALE_BIT); + item->priority = DEFAULT_ARC_PRIORITY; + + arc->start_angle = 0; + arc->angle_extent = 360; + CLEAR(arc->flags, FILLED_BIT); + CLEAR(arc->flags, CLOSED_BIT); + CLEAR(arc->flags, PIE_SLICE_BIT); + arc->line_pattern = RadarUnspecifiedPattern; + arc->fill_pattern = RadarUnspecifiedPattern; + arc->line_style = LINE_SIMPLE; + arc->line_width = 1; + arc->tile_name = ""; + arc->tile = RadarUnspecifiedImage; + arc->render_shape = NULL; + + if (*argc < 1) { + Tcl_AppendResult(wi->interp, " arc coords expected", NULL); + return RADAR_ERROR; + } + result = Lang_SplitList(wi->interp, (*args)[0], &num_elems, &elems, &freeProc); + if ((result == RADAR_ERROR) || (num_elems != 4)) { + arc_error: +#ifdef PTK + if (elems != NULL && freeProc) { + (*freeProc)(num_elems, elems); + } +#endif + Tcl_AppendResult(wi->interp, " malformed arc coords", NULL); + return RADAR_ERROR; + } + if (Tcl_GetDouble(wi->interp, elems[0], &arc->coords[0].x) == RADAR_ERROR) { + arc_error2: +#ifndef PTK + Tcl_Free((char *) elems); +#endif + goto arc_error; + }; + if (Tcl_GetDouble(wi->interp, elems[1], &arc->coords[0].y) == RADAR_ERROR) { + goto arc_error2; + }; + if (Tcl_GetDouble(wi->interp, elems[2], &arc->coords[1].x) == RADAR_ERROR) { + goto arc_error2; + }; + if (Tcl_GetDouble(wi->interp, elems[3], &arc->coords[1].y) == RADAR_ERROR) { + goto arc_error2; + }; + (*args)++; + (*argc)--; +#ifndef PTK + Tcl_Free((char *) elems); +#else + if (freeProc) { + (*freeProc)(num_elems, elems); + } +#endif + + arc->fill_color = RadarGetColorByValue(wi->win, wi->fore_color); + arc->line_color = RadarGetColorByValue(wi->win, wi->fore_color); + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * Clone -- + * + ********************************************************************************** + */ +static void +Clone(Item item) +{ + ArcItem arc = (ArcItem) item; + WidgetInfo *wi = item->wi; + char *text; + + if (strlen(arc->tile_name) != 0) { + text = RadarMalloc((strlen(arc->tile_name) + 1) * sizeof(char)); + strcpy(text, arc->tile_name); + arc->tile_name = text; + arc->tile = Tk_GetImage(wi->interp, wi->win, arc->tile_name, + ArcTileChange, (ClientData) arc); + } + if (arc->line_pattern != RadarUnspecifiedPattern) { + arc->line_pattern = Tk_GetBitmap(wi->interp, wi->win, + Tk_NameOfBitmap(wi->dpy, arc->line_pattern)); + } + if (arc->fill_pattern != RadarUnspecifiedPattern) { + arc->fill_pattern = Tk_GetBitmap(wi->interp, wi->win, + Tk_NameOfBitmap(wi->dpy, arc->fill_pattern)); + } + arc->line_color = RadarGetColorByValue(wi->win, arc->line_color); + arc->fill_color = RadarGetColorByValue(wi->win, arc->fill_color); + arc->render_shape = NULL; +} + + +/* + ********************************************************************************** + * + * Destroy -- + * + ********************************************************************************** + */ +static void +Destroy(Item item) +{ + WidgetInfo *wi = item->wi; + ArcItem arc = (ArcItem) item; + + if (arc->render_shape) { + RadarListFree(arc->render_shape); + } + if (strlen(arc->tile_name) != 0) { + RadarFree(arc->tile_name); + } + if (arc->tile != RadarUnspecifiedImage) { + Tk_FreeImage(arc->tile); + arc->tile = RadarUnspecifiedImage; + } + if (arc->line_pattern != RadarUnspecifiedPattern) { + Tk_FreeBitmap(wi->dpy, arc->line_pattern); + } + if (arc->fill_pattern != RadarUnspecifiedPattern) { + Tk_FreeBitmap(wi->dpy, arc->fill_pattern); + } + RadarFreeColor(arc->fill_color); + RadarFreeColor(arc->line_color); +} + + +/* + ********************************************************************************** + * + * Configure -- + * + ********************************************************************************** + */ +static int +Configure(Item item, + int argc, + RadarAttrList argv, + int *flags) +{ + WidgetInfo *wi = item->wi; + ArcItem arc = (ArcItem) item; + + if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == RADAR_ERROR) { + return RADAR_ERROR; + } + + if (ISSET(*flags, RADAR_TILE_FLAG)) { + Tk_Image tile; + + if (strcmp(arc->tile_name, "") != 0) { + tile = Tk_GetImage(wi->interp, wi->win, arc->tile_name, + ArcTileChange, (ClientData) arc); + if (tile == NULL) { + /* + * The name will not be in sync with the image in + * this case. + */ + return RADAR_ERROR; + } + } + else { + tile = RadarUnspecifiedImage; + } + if (arc->tile != RadarUnspecifiedImage) { + Tk_FreeImage(arc->tile); + } + arc->tile = tile; + } + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * Query -- + * + ********************************************************************************** + */ +static int +Query(Item item, + int argc, + RadarAttrList argv) +{ + if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == RADAR_ERROR) { + return RADAR_ERROR; + } + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * ComputeCoordinates -- + * + ********************************************************************************** + */ +static void +ComputeCoordinates(Item item, + RadarBool force) +{ + 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; + RadarPoint *p_list, p; + RadarReal width_2, height_2, ox, oy; + + ResetBBox(&item->item_bounding_box); + /* + * If it is neither filled nor outlined, then nothing to show. + */ + if (!arc->line_width && ISCLEAR(arc->flags, FILLED_BIT)) { + return; + } + + /* + * Special casing for rotation. This should eventually be the + * only code but it lacks the arc capability. + */ + 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); + } + p_list = (RadarPoint *) RadarListArray(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; + 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; + 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; + return; + } + + RadarTransformPoint(wi->current_transfo, &arc->coords[0], &arc->orig); + RadarTransformPoint(wi->current_transfo, &arc->coords[1], &arc->corner); + + if (arc->orig.x > arc->corner.x) { + tmp = arc->orig.x; + arc->orig.x = arc->corner.x; + arc->corner.x = tmp; + } + if (arc->orig.y > arc->corner.y) { + tmp = arc->orig.y; + arc->orig.y = arc->corner.y; + arc->corner.y = tmp; + } + + /* + * 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. + */ + angle = -(arc->start_angle * M_PI / 180.0); + sin1 = sin(angle); + cos1 = cos(angle); + angle -= (arc->angle_extent * M_PI / 180.0); + sin2 = sin(angle); + cos2 = cos(angle); + + w_2 = (arc->corner.x - arc->orig.x) / 2; + h_2 = (arc->corner.y - arc->orig.y) / 2; + center_x = (arc->corner.x + arc->orig.x) / 2; + center_y = (arc->corner.y + arc->orig.y) / 2; + + arc->center1.x = center_x + REAL_TO_INT(cos1*w_2); + arc->center1.y = center_y + REAL_TO_INT(sin1*h_2); + arc->center2.x = center_x + REAL_TO_INT(cos2*w_2); + arc->center2.y = center_y + REAL_TO_INT(sin2*h_2); + + /* + * Add the ends centers to the bbox. + */ + AddPointToBBox(&item->item_bounding_box, arc->center1.x, arc->center1.y); + AddPointToBBox(&item->item_bounding_box, arc->center2.x, arc->center2.y); + + /* + * If the arc is filled or if the outline is closed in pie slice, + * add the center of the arc. + */ + if ((ISSET(arc->flags, FILLED_BIT) || ISSET(arc->flags, CLOSED_BIT)) && + ISSET(arc->flags, PIE_SLICE_BIT)) { + AddPointToBBox(&item->item_bounding_box, center_x, center_y); + } + + /* + * Then add the 3-o'clock, 6-o'clock, 9-o'clock, 12-o'clock position + * as required. + */ + tmp = -arc->start_angle; + if (tmp < 0) { + tmp += 360; + } + if ((tmp < arc->angle_extent) || ((tmp - 360) > arc->angle_extent)) { + AddPointToBBox(&item->item_bounding_box, arc->corner.x, center_y); + } + + 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, center_x, arc->orig.y); + } + + 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, arc->orig.x, center_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); + } + + /* + * Now take care of the arc outline width plus one pixel of margin. + */ + tmp = (arc->line_width + 1) / 2 + 1; + 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; +} + + +/* + ********************************************************************************** + * + * ToArea -- + * Tell if the object is entirely outside (-1), + * entirely inside (1) or in between (0). + * + ********************************************************************************** + */ +static int +ToArea(Item item, + RadarBBox *area, + Tk_Uid tag_uid, + int enclosed, + RadarBool report) +{ + ArcItem arc = (ArcItem) item; + RadarPoint center; + RadarBBox tran_rect; + int rx, ry; + int lw = arc->line_width; + + /* + * Translate both the arc and the area so that they are + * centered on the origin. rx,ry are the radiuses in x and y. + */ + 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; + + return -1; +} + + +/* + ********************************************************************************** + * + * Draw -- + * + ********************************************************************************** + */ +static void +Draw(Item item) +{ + WidgetInfo *wi = item->wi; + ArcItem arc = (ArcItem) item; + XGCValues values; + int width, height; + RadarPoint *p; + XPoint xp[PTS_IN_SHAPE+1]; + 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); + 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++; + } + + /* Fill if requested */ + if (ISSET(arc->flags, FILLED_BIT)) { + values.foreground = RadarPixel(arc->fill_color); + values.arc_mode = ISSET(arc->flags, PIE_SLICE_BIT) ? ArcPieSlice : ArcChord; + if (arc->tile != RadarUnspecifiedImage) { /* Fill Tiled */ + Pixmap pmap = GetImagePixmap(wi->win, arc->tile); + values.fill_style = FillTiled; + values.tile = pmap; + values.ts_x_origin = (int) item->item_bounding_box.orig.x; + values.ts_y_origin = (int) item->item_bounding_box.orig.y; + XChangeGC(wi->dpy, wi->gc, + GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCTile|GCArcMode, + &values); + } + else if (arc->fill_pattern != RadarUnspecifiedPattern) { /* Fill stippled */ + values.fill_style = FillStippled; + values.stipple = arc->fill_pattern; + values.ts_x_origin = (int) item->item_bounding_box.orig.x; + values.ts_y_origin = (int) item->item_bounding_box.orig.y; + XChangeGC(wi->dpy, wi->gc, + GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle|GCStipple|GCForeground|GCArcMode, + &values); + } + else { /* Fill solid */ + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, GCForeground|GCFillStyle|GCArcMode, &values); + } + if (arc->render_shape) { + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, + xp, num_points, Convex, CoordModeOrigin); + } + 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); + } + } + + /* + * Draw the arc. + */ + if (arc->line_width) { + 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; + values.cap_style = CapRound; + values.join_style = JoinRound; + if (arc->line_pattern == RadarUnspecifiedPattern) { + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, + GCFillStyle|GCLineWidth|GCCapStyle|GCJoinStyle|GCForeground, &values); + } + else { + values.fill_style = FillStippled; + values.stipple = arc->line_pattern; + XChangeGC(wi->dpy, wi->gc, + GCFillStyle|GCStipple|GCLineWidth|GCCapStyle|GCJoinStyle|GCForeground, + &values); + } + if (arc->render_shape) { + XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, + xp, num_points, 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); + } + else { + XDrawLine(wi->dpy, wi->draw_buffer, wi->gc, + arc->center1.x, arc->center1.y, arc->center2.x, arc->center2.y); + } + } + } +} + + +/* + ********************************************************************************** + * + * IsSensitive -- + * + ********************************************************************************** + */ +static RadarBool +IsSensitive(Item item, + int item_part) +{ + return (ISSET(item->flags, SENSITIVE_BIT) && + item->parent->class->IsSensitive(item->parent, RADAR_NO_PART)); +} + + +/* + ********************************************************************************** + * + * Pick -- + * + ********************************************************************************** + */ +static double +Pick(Item item, + RadarPoint *p, + Item start_item, + int aperture, + Item *a_item, + int *a_part) +{ + ArcItem arc = (ArcItem) item; + double dist, new_dist; + RadarBool point_in_angle, filled, closed; + RadarBool in_triangle, acute_angle; + RadarPoint p1, center; + int width, height; + RadarDim lw = arc->line_width; + + 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; + height = arc->corner.y - arc->orig.y; + + /* + * 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; + point_in_angle = PointInAngle(arc->start_angle, arc->angle_extent, &p1); + + /* + * Now try to compute the distance dealing with the + * many possible configurations. + */ + filled = !ISCLEAR(arc->flags, FILLED_BIT); + closed = !ISCLEAR(arc->flags, CLOSED_BIT); + + /* + * First the case of an arc not filled, not closed. We suppose + * here that the outline is drawn since we cannot get here without + * filling or outlining. + */ + if (!filled && !closed) { + if (point_in_angle) { + dist = OvalToPointDist(¢er, width, height, lw, p); + if (dist < 0.0) { + dist = -dist; + } + return dist; + } + 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; + } + /* Take into account CapRounded path. */ + if (lw > 1) { + dist -= lw/2; + if (dist < 0.0) { + dist = 0.0; + } + } + return dist; + } + + /* + * Try to deal with filled and/or outline-closed arcs (not having full + * angular extent). + */ + if (ISSET(arc->flags, PIE_SLICE_BIT)) { + dist = LineToPointDist(¢er, &arc->center1, p); + new_dist = LineToPointDist(¢er, &arc->center2, p); + if (new_dist < dist) { + dist = new_dist; + } + if (arc->line_width > 1) { + if (closed) { + dist -= arc->line_width/2; + } + /* + * The arc outline is CapRounded so if it is not + * full extent, includes the caps. + */ + else { + new_dist = hypot(p->x - arc->center1.x, p->y - arc->center1.y) - lw/2; + if (new_dist < dist) { + dist = new_dist; + } + new_dist = hypot(p->x - arc->center2.x, p->y - arc->center2.y) - lw/2; + if (new_dist < dist) { + dist = new_dist; + } + } + } + if (dist <= 0.0) { + return 0.0; + } + if (point_in_angle) { + new_dist = OvalToPointDist(¢er, width, height, lw, p); + if (new_dist < dist) { + dist = new_dist; + } + if (dist < 0.0) { + dist = filled ? 0.0 : -dist; + } + } + return dist; + } + + /* + * This is a chord closed oval. + */ + dist = LineToPointDist(&arc->center1, &arc->center2, p); + if (arc->line_width > 1) { + if (closed) { + dist -= arc->line_width/2; + } + /* + * The arc outline is CapRounded so if it is not + * full extent, includes the caps. + */ + else { + new_dist = hypot(p->x - arc->center1.x, p->y - arc->center1.y) - lw/2; + if (new_dist < dist) { + dist = new_dist; + } + new_dist = hypot(p->x - arc->center2.x, p->y - arc->center2.y) - lw/2; + if (new_dist < dist) { + dist = new_dist; + } + } + } + if (dist <= 0.0) { + return 0.0; + } + + /* + * Need to check the point against the triangle formed + * by the difference between Chord mode and PieSlice mode. + * This triangle needs to be included if extend is more than + * 180 degrees and excluded otherwise. We try to see if + * the center of the arc and the point are both on the same + * side of the chord. If they are, the point is in the triangle + */ + if (arc->center1.x == arc->center2.x) { + in_triangle = ((center.x <= arc->center1.x) && (p->x <= arc->center1.x)) || + ((center.x > arc->center1.x) && (p->x > arc->center1.x)); + } + else { + double a, b; + + a = ((double) (arc->center2.y - arc->center1.y)) / + ((double) (arc->center2.x - arc->center1.x)); + b = arc->center1.y - a*arc->center1.x; + in_triangle = (((a*center.x + b - center.y) >= 0.0) == + ((a*p->x + b - p->y) >= 0.0)); + } + + acute_angle = ((arc->angle_extent > -180) && (arc->angle_extent < 180)); + if (!point_in_angle && !acute_angle && filled && in_triangle) { + return 0.0; + } + + if (point_in_angle && (!acute_angle || !in_triangle)) { + new_dist = OvalToPointDist(¢er, width, height, lw, p); + if (new_dist < dist) { + dist = new_dist; + } + if (dist < 0.0) { + dist = filled ? 0.0 : -dist; + } + } + + return dist; +} + + +/* + ********************************************************************************** + * + * GetClipVertices -- + * Get the clipping shape. + * + ********************************************************************************** + */ +static RadarBool +GetClipVertices(Item item, + RadarPoint **points, + int *num_points) +{ + return False; +} + + +/* + ********************************************************************************** + * + * Coords -- + * Return or edit the item vertices. + * + ********************************************************************************** + */ +static int +Coords(Item item, + int index, + int cmd, + RadarPoint **pts, + int *num_pts) +{ + ArcItem arc = (ArcItem) item; + + if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST) || (cmd == COORDS_REMOVE)) { + Tcl_AppendResult(item->wi->interp, + " arcs can't add or remove vertices", NULL); + return RADAR_ERROR; + } + else if (cmd == COORDS_REPLACE_ALL) { + if (*num_pts != 2) { + Tcl_AppendResult(item->wi->interp, + " coords command need 2 points on arcs", NULL); + return RADAR_ERROR; + } + arc->coords[0] = (*pts)[0]; + arc->coords[1] = (*pts)[1]; + ITEM.Invalidate(item, RADAR_COORDS_FLAG); + } + else if (cmd == COORDS_REPLACE) { + if (*num_pts < 1) { + Tcl_AppendResult(item->wi->interp, + " coords command need at least 1 point", NULL); + return RADAR_ERROR; + } + if (index < 0) { + index += 2; + } + if ((index < 0) || (index > 1)) { + range_err: + Tcl_AppendResult(item->wi->interp, + " incorrect coord index, should be between -2 and 1", NULL); + return RADAR_ERROR; + } + arc->coords[index] = (*pts)[0]; + ITEM.Invalidate(item, RADAR_COORDS_FLAG); + } + else if (cmd == COORDS_READ_ALL) { + *num_pts = 2; + *pts = arc->coords; + } + else if (cmd == COORDS_READ) { + if (index < 0) { + index += 2; + } + if ((index < 0) || (index > 1)) { + goto range_err; + } + *num_pts = 1; + *pts = &arc->coords[index]; + } + + return RADAR_OK; +} + + +/* + ********************************************************************************** + * + * PostScript -- + * + ********************************************************************************** + */ +static void +PostScript(Item item, + PostScriptInfo ps_info) +{ +} + + +/* + ********************************************************************************** + * + * Exported functions struct -- + * + ********************************************************************************** + */ +static ItemClassStruct ARC_ITEM_CLASS = { + sizeof(ArcItemStruct), + False, + False, + False, + "arc", + arc_attrs, + Init, + Clone, + Destroy, + Configure, + Query, + NULL, + NULL, + GetClipVertices, + Coords, + ComputeCoordinates, + ToArea, + Draw, + IsSensitive, + Pick, + PostScript +}; + +RadarItemClassId RadarArc = (RadarItemClassId) &ARC_ITEM_CLASS; |