aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generic/Arc.c1100
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(&center, 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(&center, &arc->center1, p);
+ new_dist = LineToPointDist(&center, &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(&center, 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(&center, 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;