diff options
-rw-r--r-- | Bezier.c | 1359 |
1 files changed, 0 insertions, 1359 deletions
diff --git a/Bezier.c b/Bezier.c deleted file mode 100644 index a61ff5f..0000000 --- a/Bezier.c +++ /dev/null @@ -1,1359 +0,0 @@ -/* - * Bezier.c -- Implementation of bezier item. - * - * Authors : Patrick Lecoanet. - * Creation date : Fri May 5 12:33:32 2000 - * - * $Id$ - */ - -/* - * Copyright (c) 1993 - 2000 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 "Draw.h" -#include "Item.h" -#include "Geo.h" -#include "Types.h" -#include "WidgetInfo.h" -#include "Image.h" -#include "Color.h" -#ifdef GPC -#include "gpc/gpc.h" -#endif - -#include <ctype.h> -#include <malloc.h> - - -static const char rcsid[] = "$Id$"; -static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; - - -/* - * Bit offset of flags. - */ -#define FILLED_BIT 1<<0 /* If the item is filled with color/pattern */ -#define CCW 1<<2 /* Tell if the controls are described in - * clockwise or ccw order. */ -#define FIRST_END_OK 1<<3 -#define LAST_END_OK 1<<4 -#define FILLED_OK 1<<5 -#define RELIEF_OK 1<<6 - - -/* - ********************************************************************************** - * - * Specific Bezier item record - * - ********************************************************************************** - */ -typedef struct _BezierItemStruct { - ItemStruct header; - - /* Public data */ - ZnList points; - unsigned short flags; - ZnLineEnd first_end; /* These two are considered only if relief is flat */ - ZnLineEnd last_end; - LineStyle line_style; /* This is considered only if relief is flat */ - int cap_style; - ReliefStyle relief; - ZnDim line_width; /* If 0 the path is not drawn, if <2 relief is flat */ - ZnImage fill_pattern; - ZnGradient *fill_color; - ZnImage line_pattern; - ZnGradient *line_color; - ZnImage tile; - - /* Private data */ - ZnList dev_points; - ZnGradient *gradient; - ZnTriStrip tristrip; - ZnPoint *grad_geo; -} BezierItemStruct, *BezierItem; - - -static ZnAttrConfig bz_attrs[] = { - { ZN_CONFIG_CAP_STYLE, "-capstyle", NULL, - Tk_Offset(BezierItemStruct, cap_style), 0, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_BOOL, "-composealpha", NULL, - Tk_Offset(BezierItemStruct, header.flags), COMPOSE_ALPHA_BIT, - ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-composerotation", NULL, - Tk_Offset(BezierItemStruct, header.flags), COMPOSE_ROTATION_BIT, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_BOOL, "-composescale", NULL, - Tk_Offset(BezierItemStruct, header.flags), COMPOSE_SCALE_BIT, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-fillcolor", NULL, - Tk_Offset(BezierItemStruct, fill_color), 0, - ZN_COORDS_FLAG|ZN_BORDER_FLAG, False }, - { ZN_CONFIG_BITMAP, "-fillpattern", NULL, - Tk_Offset(BezierItemStruct, fill_pattern), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-filled", NULL, - Tk_Offset(BezierItemStruct, flags), FILLED_BIT, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_LINE_END, "-firstend", NULL, - Tk_Offset(BezierItemStruct, first_end), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_LINE_END, "-lastend", NULL, - Tk_Offset(BezierItemStruct, last_end), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_GRADIENT, "-linecolor", NULL, - Tk_Offset(BezierItemStruct, line_color), 0, - ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BITMAP, "-linepattern", NULL, - Tk_Offset(BezierItemStruct, line_pattern), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_LINE_STYLE, "-linestyle", NULL, - Tk_Offset(BezierItemStruct, line_style), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_DIM, "-linewidth", NULL, - Tk_Offset(BezierItemStruct, line_width), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_PRI, "-priority", NULL, - Tk_Offset(BezierItemStruct, header.priority), 0, - ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, - { ZN_CONFIG_RELIEF, "-relief", NULL, Tk_Offset(BezierItemStruct, relief), 0, - ZN_COORDS_FLAG, False }, - { ZN_CONFIG_BOOL, "-sensitive", NULL, - Tk_Offset(BezierItemStruct, header.flags), SENSITIVE_BIT, - ZN_REPICK_FLAG, False }, - { ZN_CONFIG_TAG_LIST, "-tags", NULL, - Tk_Offset(BezierItemStruct, header.tags), 0, 0, False }, - { ZN_CONFIG_IMAGE, "-tile", NULL, - Tk_Offset(BezierItemStruct, tile), 0, ZN_DRAW_FLAG, False }, - { ZN_CONFIG_BOOL, "-visible", NULL, - Tk_Offset(BezierItemStruct, header.flags), VISIBLE_BIT, - ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, - - { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 } -}; - - - -/* - ********************************************************************************** - * - * Init -- - * - ********************************************************************************** - */ -static int -Init(Item item, - int *argc, - Tcl_Obj *CONST *args[]) -{ - WidgetInfo *wi = item->wi; - BezierItem bz = (BezierItem) item; - Tcl_Obj **elems; - int i, num_elems; - ZnPoint p; - - bz->dev_points = NULL; - bz->tristrip.num_strips = 0; - bz->gradient = NULL; - bz->grad_geo = NULL; - - /* Init attributes */ - SET(item->flags, VISIBLE_BIT); - SET(item->flags, SENSITIVE_BIT); - SET(item->flags, COMPOSE_ALPHA_BIT); - SET(item->flags, COMPOSE_ROTATION_BIT); - SET(item->flags, COMPOSE_SCALE_BIT); - item->priority = DEFAULT_BEZIER_PRIORITY; - - if (*argc < 1) { - Tcl_AppendResult(wi->interp, " bezier coords expected", NULL); - return ZN_ERROR; - } - if ((Tcl_ListObjGetElements(wi->interp, (*args)[0], &num_elems, &elems) == ZN_ERROR) || - ((num_elems % 2) != 0)) { - bz_error: - Tcl_AppendResult(wi->interp, " malformed bezier coords", NULL); - return ZN_ERROR; - } - - bz->points = ZnListNew(num_elems/2, sizeof(ZnPoint)); - for (i = 0; i < num_elems; i += 2) { - if (Tcl_GetDoubleFromObj(wi->interp, elems[i], &p.x) == ZN_ERROR) { - bz_error2: - ZnListFree(bz->points); - bz->points = NULL; - goto bz_error; - } - if (Tcl_GetDoubleFromObj(wi->interp, elems[i+1], &p.y) == ZN_ERROR) { - goto bz_error2; - } - ZnListAdd(bz->points, &p, ZnListTail); - } - (*args)++; - (*argc)--; - - CLEAR(bz->flags, FILLED_BIT); - bz->first_end = NULL; - bz->last_end = NULL; - bz->line_style = LINE_SIMPLE; - bz->relief = RELIEF_FLAT; - bz->line_width = 1; - bz->tile = ZnUnspecifiedImage; - bz->fill_pattern = ZnUnspecifiedImage; - bz->line_pattern = ZnUnspecifiedImage; - bz->cap_style = CapRound; - - bz->fill_color = ZnGetGradientByValue(wi->fore_color); - bz->line_color = ZnGetGradientByValue(wi->fore_color); - - return ZN_OK; -} - - -/* - ********************************************************************************** - * - * Clone -- - * - ********************************************************************************** - */ -static void -Clone(Item item) -{ - BezierItem bz = (BezierItem) item; - - bz->dev_points = NULL; - bz->tristrip.num_strips = 0; - - if (bz->grad_geo) { - ZnPoint *grad_geo = ZnMalloc(4*sizeof(ZnPoint)); - memcpy(grad_geo, bz->grad_geo, 4*sizeof(ZnPoint)); - bz->grad_geo = grad_geo; - } - if (bz->gradient) { - bz->gradient = ZnGetGradientByValue(bz->gradient); - } - if (bz->points) { - bz->points = ZnListDuplicate(bz->points); - } - if (bz->first_end) { - LineEndDuplicate(bz->first_end); - } - if (bz->last_end) { - LineEndDuplicate(bz->last_end); - } - if (bz->tile != ZnUnspecifiedImage) { - bz->tile = ZnGetImageByValue(bz->tile); - } - if (bz->line_pattern != ZnUnspecifiedImage) { - bz->line_pattern = ZnGetImageByValue(bz->line_pattern); - } - if (bz->fill_pattern != ZnUnspecifiedImage) { - bz->fill_pattern = ZnGetImageByValue(bz->fill_pattern); - } - bz->line_color = ZnGetGradientByValue(bz->line_color); - bz->fill_color = ZnGetGradientByValue(bz->fill_color); -} - - -/* - ********************************************************************************** - * - * Destroy -- - * - ********************************************************************************** - */ -static void -Destroy(Item item) -{ - BezierItem bz = (BezierItem) item; - - if (bz->points) { - ZnListFree(bz->points); - } - if (bz->dev_points) { - ZnListFree(bz->dev_points); - } - if (bz->grad_geo) { - ZnFree(bz->grad_geo); - } - if (bz->tristrip.num_strips) { - TRI_FREE(&bz->tristrip); - } - if (bz->first_end) { - LineEndDelete(bz->first_end); - } - if (bz->last_end) { - LineEndDelete(bz->last_end); - } - if (bz->gradient) { - ZnFreeGradient(bz->gradient); - } - if (bz->tile != ZnUnspecifiedImage) { - ZnFreeImage(bz->tile); - bz->tile = ZnUnspecifiedImage; - } - if (bz->line_pattern != ZnUnspecifiedImage) { - ZnFreeImage(bz->line_pattern); - bz->line_pattern = ZnUnspecifiedImage; - } - if (bz->fill_pattern != ZnUnspecifiedImage) { - ZnFreeImage(bz->fill_pattern); - bz->fill_pattern = ZnUnspecifiedImage; - } - ZnFreeGradient(bz->fill_color); - ZnFreeGradient(bz->line_color); -} - - -/* - ********************************************************************************** - * - * Setup flags to control the precedence between the - * graphical attributes. - * - ********************************************************************************** - */ -static void -SetRenderFlags(BezierItem bz) -{ - ASSIGN(bz->flags, FILLED_OK, - ISSET(bz->flags, FILLED_BIT) && (ZnListSize(bz->points) > 2)); - - ASSIGN(bz->flags, RELIEF_OK, - (bz->relief != RELIEF_FLAT) && (ZnListSize(bz->points) > 1) && - (bz->line_width > 1)); - - ASSIGN(bz->flags, FIRST_END_OK, - (bz->first_end != NULL) && (ZnListSize(bz->points) > 1) && - ISCLEAR(bz->flags, FILLED_BIT) && bz->line_width && - ISCLEAR(bz->flags, RELIEF_OK)); - - ASSIGN(bz->flags, LAST_END_OK, - (bz->last_end != NULL) && (ZnListSize(bz->points) > 1) && - ISCLEAR(bz->flags, FILLED_BIT) && bz->line_width && - ISCLEAR(bz->flags, RELIEF_OK)); -} - - -/* - ********************************************************************************** - * - * Configure -- - * - ********************************************************************************** - */ -static int -Configure(Item item, - int argc, - Tcl_Obj *CONST argv[], - int *flags) -{ - WidgetInfo *wi = item->wi; - BezierItem bz = (BezierItem) item; - int status = ZN_OK; - XColor *color; - int alpha; - - status = ZnConfigureAttributes(wi, item, bz_attrs, argc, argv, flags); - - if (bz->gradient && - (ISSET(*flags, ZN_BORDER_FLAG) || (bz->relief == RELIEF_FLAT))) { - ZnFreeGradient(bz->gradient); - bz->gradient = NULL; - } - if ((bz->relief != RELIEF_FLAT) && !bz->gradient) { - color = ZnGetGradientColor(bz->line_color, 51.0, &alpha); - bz->gradient = ZnGetReliefGradient(wi->interp, wi->win, - ZnNameOfColor(color), alpha); - if (bz->gradient == NULL) { - status = ZN_ERROR; - } - } - - return status; -} - - -/* - ********************************************************************************** - * - * Query -- - * - ********************************************************************************** - */ -static int -Query(Item item, - int argc, - Tcl_Obj *CONST argv[]) -{ - if (ZnQueryAttribute(item->wi, item, bz_attrs, argv[0]) == ZN_ERROR) { - return ZN_ERROR; - } - - return ZN_OK; -} - - -static ZnBool -TestCCW(ZnPoint *points, - int num_points) -{ - ZnPoint *p, *p_p, *p_n, min; - ZnReal xprod; - int i, min_index; - - if (num_points < 3) { - return True; - } - - /* - * First find the lowest rightmost vertex. In X11 this is the - * topmost one. - */ - p = points; - min = *p; - min_index = 0; - for (i = 1, p++; i < num_points; i++, p++) { - if ((p->y < min.y) || - ((p->y == min.y) && (p->x > min.x))) { - min_index = i; - min = *p; - } - } - /* - * Then find the indices of the previous and next - * vertices. - */ - p = &points[min_index]; - p_p = &points[(min_index+(num_points-1))%num_points]; /* min_index-1 */ - p_n = &points[(min_index+1)%num_points]; - xprod = ((p_p->x*p->y - p_p->y*p->x) + - (p_p->y*p_n->x - p_p->x*p_n->y) + - (p->x*p_n->y - p->y*p_n->x)); - return (xprod <= 0.0); /* Should be >= 0 but X11 has Y axis reverted. */ -} - - -/* - ********************************************************************************** - * - * ComputeCoordinates -- - * - ********************************************************************************** - */ -static void -ComputeCoordinates(Item item, - ZnBool force) -{ - WidgetInfo *wi = item->wi; - BezierItem bz = (BezierItem) item; - ZnPoint *points; - ZnPoint end_points[LINE_END_POINTS]; - ZnPoint *dev_points; - int num_points; - ZnBBox bbox; - int lw; - - ResetBBox(&item->item_bounding_box); - if (bz->points == NULL) { - return; - } - - SetRenderFlags(bz); - - if (bz->tristrip.num_strips) { - TRI_FREE(&bz->tristrip); - } - - points = (ZnPoint *) ZnListArray(bz->points); - num_points = ZnListSize(bz->points); - - /* - * Allocate space for devices coordinates - */ - if (bz->dev_points == NULL) { - bz->dev_points = ZnListNew(num_points, sizeof(ZnPoint)); - } - ZnListAssertSize(bz->dev_points, num_points); - dev_points = (ZnPoint *) ZnListArray(bz->dev_points); - - /* - * Compute device coordinates. - */ - ZnTransformPoints(wi->current_transfo, points, dev_points, num_points); - - lw = bz->line_width; - - if (ISSET(bz->flags, RELIEF_OK)) { - ASSIGN(bz->flags, CCW, TestCCW(dev_points, num_points)); - - /* - * Compute the bounding box. - */ - ZnGetPolygonReliefBBox(dev_points, num_points, - ISCLEAR(bz->flags, CCW)?-lw:lw, &bbox); - AddBBoxToBBox(&item->item_bounding_box, &bbox); - return; - } - - /* - * Compute the bounding box. - */ - AddPointsToBBox(&item->item_bounding_box, dev_points, num_points); - - /* - * Add the line width in all directions. - * This overestimates the space needed to draw the polyline - * but is simple. This is even more true for smoothed polygons but is - * even faster. - */ - item->item_bounding_box.orig.x -= lw; - item->item_bounding_box.orig.y -= lw; - item->item_bounding_box.corner.x += lw; - item->item_bounding_box.corner.y += lw; - - /* - * Process arrows. - */ - if (ISSET(bz->flags, FIRST_END_OK)) { - GetLineEnd(&dev_points[0], &dev_points[1], lw, bz->cap_style, - bz->first_end, end_points); - AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS); - } - if (ISSET(bz->flags, LAST_END_OK)) { - GetLineEnd(&dev_points[num_points-1], &dev_points[num_points-2], - lw, bz->cap_style, bz->last_end, end_points); - AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS); - } - - /* - * Expand again the bounding box by one pixel in all - * directions to take care of rounding errors. - */ - item->item_bounding_box.orig.x -= 1; - item->item_bounding_box.orig.y -= 1; - item->item_bounding_box.corner.x += 1; - item->item_bounding_box.corner.y += 1; - - if (!ZnGradientFlat(bz->fill_color)) { - ZnPoly poly; - - if (!bz->grad_geo) { - bz->grad_geo = ZnMalloc(4*sizeof(ZnPoint)); - } - if (bz->fill_color->type == ZN_AXIAL_GRADIENT) { - POLY_CONTOUR1(&poly, points, num_points); - ZnComputeAxialGradient(wi, &poly, bz->fill_color->g.angle, - bz->grad_geo); - } - else if (bz->fill_color->type == ZN_RADIAL_GRADIENT) { - POLY_CONTOUR1(&poly, dev_points, num_points); - ZnComputeRadialGradient(wi, &poly, &item->item_bounding_box, - &bz->fill_color->g.p, bz->grad_geo); - } - else if (bz->fill_color->type == ZN_PATH_GRADIENT) { - ZnTransformPoint(wi->current_transfo, &bz->fill_color->g.p, - &bz->grad_geo[0]); - } - } - else { - if (bz->grad_geo) { - ZnFree(bz->grad_geo); - bz->grad_geo = NULL; - } - } -} - - - -/* - ********************************************************************************** - * - * ToArea -- - * Tell if the object is entirely outside (-1), - * entirely inside (1) or in between (0). - * - ********************************************************************************** - */ -static int -ToArea(Item item, - ZnToArea ta) -{ - BezierItem bz = (BezierItem) item; - WidgetInfo *wi = item->wi; - ZnPoint *points; - ZnPoint end_points[LINE_END_POINTS]; - int num_points, result=-1, result2; - int lw = bz->line_width; - ZnBBox *area = ta->area; - - if (bz->dev_points == NULL) { - return -1; - } - - /*printf("============== bezier %d ==============\n", item->id);*/ - GetBezierPath(bz->dev_points, wi->work_pts); - points = (ZnPoint *) ZnListArray(wi->work_pts); - num_points = ZnListSize(wi->work_pts); - - if (ISSET(bz->flags, FILLED_OK)) { - result = PolygonInBBox(points, num_points, area, NULL); - if (result == 0) { - return 0; - } - } - - if (lw > 0) { - if (ISCLEAR(bz->flags, RELIEF_OK)) { - result2 = PolylineInBBox(points, num_points, lw, - bz->cap_style, JoinRound, area); - } - else { - result2 = ZnPolygonReliefInBBox(points, num_points, - ISCLEAR(bz->flags, CCW)?-lw:lw, area); - } - if (ISCLEAR(bz->flags, FILLED_OK)) { - if (result2 == 0) { - return 0; - } - result = result2; - } - else if (result2 != result) { - return 0; - } - - /* - * Check line ends. - */ - if (ISSET(bz->flags, FIRST_END_OK)) { - GetLineEnd(&points[0], &points[1], lw, bz->cap_style, - bz->first_end, end_points); - if (PolygonInBBox(end_points, LINE_END_POINTS, area, NULL) != result) { - return 0; - } - } - if (ISSET(bz->flags, LAST_END_OK)) { - GetLineEnd(&points[num_points-1], &points[num_points-2], lw, - bz->cap_style, bz->last_end, end_points); - if (PolygonInBBox(end_points, LINE_END_POINTS, area, NULL) != result) { - return 0; - } - } - } - - return result; -} - - -/* - ********************************************************************************** - * - * Draw -- - * - ********************************************************************************** - */ -static void -Draw(Item item) -{ - WidgetInfo *wi = item->wi; - BezierItem bz = (BezierItem) item; - XGCValues values; - int i, num_points; - unsigned int gc_mask; - ZnPoint *points; - XPoint *xpoints = NULL; - int lw = bz->line_width; - - if (bz->dev_points == NULL) { - return; - } - - GetBezierPath(bz->dev_points, wi->work_pts); - points = ZnListArray(wi->work_pts); - num_points = ZnListSize(wi->work_pts); - - /* - * Fill if requested. - */ - if (ISSET(bz->flags, FILLED_OK)) { - values.foreground = ZnPixel(ZnGetGradientColor(bz->fill_color, 0.0, NULL)); - gc_mask = GCFillStyle; - if (bz->tile != ZnUnspecifiedImage) { /* Fill tiled */ - values.fill_style = FillTiled; - values.tile = ZnImagePixmap(bz->tile, NULL); - values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); - values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); - gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCTile; - } - else if (bz->fill_pattern != ZnUnspecifiedImage) { /* Fill stippled */ - values.fill_style = FillStippled; - values.stipple = ZnImagePixmap(bz->fill_pattern, NULL); - values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); - values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); - gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCStipple|GCForeground; - } - else { /* Fill solid */ - values.fill_style = FillSolid; - gc_mask |= GCForeground; - } - XChangeGC(wi->dpy, wi->gc, gc_mask, &values); - - if (!xpoints) { - ZnListAssertSize(wi->work_xpts, num_points); - xpoints = (XPoint *) ZnListArray(wi->work_xpts); - for (i = 0; i < num_points; i++) { - xpoints[i].x = REAL_TO_INT(points[i].x); - xpoints[i].y = REAL_TO_INT(points[i].y); - } - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, - xpoints, num_points, Complex, CoordModeOrigin); - } - - /* - * Draw the lines between points - */ - if (lw) { - ZnPoint end_points[LINE_END_POINTS]; - XPoint xp[LINE_END_POINTS]; - - /* - * Drawing with relief disables: ends, line style and line pattern. - */ - if (ISSET(bz->flags, RELIEF_OK)) { - ReliefStyle relief; - int relief_dir; - - relief = bz->relief; - relief_dir = relief & RELIEF_MASK; - if (ISCLEAR(bz->flags, CCW)) { - lw = -lw; - if (relief_dir == RELIEF_SUNKEN) { - relief_dir = RELIEF_RAISED; - } - else { - relief_dir = RELIEF_SUNKEN; - } - relief = (relief & ~RELIEF_MASK) | relief_dir; - } - ZnDrawPolygonRelief(wi, relief, bz->gradient, points, num_points, lw); - } - else { - ZnSetLineStyle(wi, bz->line_style); - values.foreground = ZnPixel(ZnGetGradientColor(bz->line_color, 0, NULL)); - values.line_width = (lw == 1) ? 0 : lw; - values.join_style = JoinRound; - values.cap_style = bz->cap_style; - if (bz->line_pattern == ZnUnspecifiedImage) { - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, - GCFillStyle|GCLineWidth|GCJoinStyle|GCCapStyle|GCForeground, &values); - } - else { - values.fill_style = FillStippled; - values.stipple = ZnImagePixmap(bz->line_pattern, NULL); - XChangeGC(wi->dpy, wi->gc, - GCFillStyle|GCStipple|GCLineWidth|GCJoinStyle|GCCapStyle|GCForeground, - &values); - } - if (!xpoints) { - ZnListAssertSize(wi->work_xpts, num_points); - xpoints = (XPoint *) ZnListArray(wi->work_xpts); - for (i = 0; i < num_points; i++) { - xpoints[i].x = REAL_TO_INT(points[i].x); - xpoints[i].y = REAL_TO_INT(points[i].y); - } - } - XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, - xpoints, num_points, CoordModeOrigin); - - if (ISSET(bz->flags, FIRST_END_OK)) { - GetLineEnd(&points[0], &points[1], lw, bz->cap_style, - bz->first_end, end_points); - for (i = 0; i < LINE_END_POINTS; i++) { - xp[i].x = end_points[i].x; - xp[i].y = end_points[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, LINE_END_POINTS, - Nonconvex, CoordModeOrigin); - } - if (ISSET(bz->flags, LAST_END_OK)) { - GetLineEnd(&points[num_points-1], &points[num_points-2], lw, - bz->cap_style, bz->last_end, end_points); - for (i = 0; i < LINE_END_POINTS; i++) { - xp[i].x = end_points[i].x; - xp[i].y = end_points[i].y; - } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, xp, LINE_END_POINTS, - Nonconvex, CoordModeOrigin); - } - } - } -} - - -/* - ********************************************************************************** - * - * Render -- - * - ********************************************************************************** - */ -#ifdef GLX -void -BezierRenderCB(void *closure) -{ -#ifdef GPC - BezierItem bz = (BezierItem) closure; - WidgetInfo *wi = ((Item) closure)->wi; - int i, j, num_points; - ZnPoint *points; - - if (bz->tristrip.num_strips == 0) { - ZnPoly poly; - POLY_CONTOUR1(&poly, (ZnPoint *) ZnListArray(wi->work_pts), - ZnListSize(wi->work_pts)); - gpc_polygon_to_tristrip((gpc_polygon *) &poly, - (gpc_tristrip *) &bz->tristrip); - } - - for (i = 0; i < bz->tristrip.num_strips; i++) { - num_points = bz->tristrip.strips[i].num_points; - points = bz->tristrip.strips[i].points; - glBegin(GL_TRIANGLE_STRIP); - for (j = 0; j < num_points; j++, points++) { - glVertex2f(points->x, points->y); - } - glEnd(); - } -#endif -} -#endif -static void -Render(Item item) -{ -#ifdef GLX - WidgetInfo *wi = item->wi; - BezierItem bz = (BezierItem) item; - ZnPoint *points; - int num_points; - XColor *color; - int alpha; - - if (bz->dev_points == NULL) { - return; - } - - GetBezierPath(bz->dev_points, wi->work_pts); - points = ZnListArray(wi->work_pts); - num_points = ZnListSize(wi->work_pts); - - /* - * Fill if requested. - */ - if (ISSET(bz->flags, FILLED_OK)) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - if (!ZnGradientFlat(bz->fill_color)) { - ZnPoly poly; - - POLY_CONTOUR1(&poly, points, num_points); - ZnRenderGradient(wi, bz->fill_color, BezierRenderCB, bz, - bz->grad_geo, &poly); - } - else if (bz->tile != ZnUnspecifiedImage) { /* Fill tiled */ - ZnRenderTile(wi, bz->tile, bz->fill_color, BezierRenderCB, bz, - (ZnPoint *) &item->item_bounding_box); - } - else { - if (bz->fill_pattern != ZnUnspecifiedImage) { /* Fill stippled */ - /* - * Setup polygon stippling. - */ - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(ZnImagePattern(bz->fill_pattern, NULL)); - } - color = ZnGetGradientColor(bz->fill_color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - BezierRenderCB(bz); - glDisable(GL_POLYGON_STIPPLE); - } - } - - /* - * Draw the lines between points - */ - if (bz->line_width) { - /* - * Drawing with relief disables: ends, line style and line pattern. - */ - if (ISSET(bz->flags, RELIEF_OK)) { - ReliefStyle relief; - ZnDim line_width; - int relief_dir; - - relief = bz->relief; - line_width = bz->line_width; - if (ISCLEAR(bz->flags, CCW)) { - line_width = -line_width; - relief_dir = relief & RELIEF_MASK; - if (relief_dir == RELIEF_SUNKEN) { - relief_dir = RELIEF_RAISED; - } - else { - relief_dir = RELIEF_SUNKEN; - } - relief = (relief & ~RELIEF_MASK) | relief_dir; - } - ZnRenderPolygonRelief(wi, relief, bz->gradient, True, - points, num_points, line_width); - } - else { - ZnLineEnd first = ISSET(bz->flags, FIRST_END_OK) ? bz->first_end : NULL; - ZnLineEnd last = ISSET(bz->flags, LAST_END_OK) ? bz->last_end : NULL; - - ZnRenderPolyline(wi, points, num_points, - bz->line_width, bz->line_style, bz->cap_style, - JoinRound, first, last, bz->line_color); - } - } -#endif -} - - -/* - ********************************************************************************** - * - * IsSensitive -- - * - ********************************************************************************** - */ -static ZnBool -IsSensitive(Item item, - int item_part) -{ - return (ISSET(item->flags, SENSITIVE_BIT) && - item->parent->class->IsSensitive(item->parent, ZN_NO_PART)); -} - - -/* - ********************************************************************************** - * - * Pick -- - * - ********************************************************************************** - */ -static double -Pick(Item item, - ZnPick ps) -{ - BezierItem bz = (BezierItem) item; - WidgetInfo *wi = item->wi; - double dist=1.0e40, new_dist; - ZnPoint *points, *p = ps->point; - ZnPoint end_points[LINE_END_POINTS]; - int num_points; - int lw = bz->line_width; - - if (bz->dev_points == NULL) { - return dist; - } - -/*printf("Pick in curve\n");*/ - GetBezierPath(bz->dev_points, wi->work_pts); - points = (ZnPoint *) ZnListArray(wi->work_pts); - num_points = ZnListSize(wi->work_pts); - - if (ISSET(bz->flags, FILLED_OK)) { - dist = PolygonToPointDist(points, num_points, p); - if (dist <= 0.0) { - return 0.0; - } - } - - if (lw > 0) { - if (ISCLEAR(bz->flags, RELIEF_OK)) { - new_dist = PolylineToPointDist(points, num_points, lw, - bz->cap_style, JoinRound, p); - if (new_dist < dist) { - dist = new_dist; - } - if (dist <= 0.0) { - return 0.0; - } - } - else { - new_dist = ZnPolygonReliefToPointDist(points, num_points, - ISCLEAR(bz->flags, CCW)?-lw:lw, p); - if (new_dist < dist) { - dist = new_dist; - } - if (dist <= 0.0) { - return 0.0; - } - } - } - - /* - * Check line ends. - */ - if (ISSET(bz->flags, FIRST_END_OK)) { - GetLineEnd(&points[0], &points[1], lw, bz->cap_style, - bz->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(bz->flags, LAST_END_OK)) { - GetLineEnd(&points[num_points-1], &points[num_points-2], lw, - bz->cap_style, bz->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; -} - - -/* - ********************************************************************************** - * - * PostScript -- - * - ********************************************************************************** - */ -static void -PostScript(Item item, - PostScriptInfo ps_info) -{ -} - - -/* - ********************************************************************************** - * - * GetClipVertices -- - * Get the clipping shape. - * Never ever call TRI_FREE on the tristrip returned by GetClipVertices. - * - ********************************************************************************** - */ -static ZnBool -GetClipVertices(Item item, - ZnTriStrip *tristrip) -{ -#ifdef GPC - BezierItem bz = (BezierItem) item; - WidgetInfo *wi = item->wi; -#else - ZnPoint *points; -#endif - -#ifdef GPC - tristrip->fan = False; - tristrip->num_strips = 0; - - if (bz->dev_points) { - if (bz->tristrip.num_strips == 0) { - ZnPoly poly; - - GetBezierPath(bz->dev_points, wi->work_pts); - POLY_CONTOUR1(&poly, (ZnPoint *) ZnListArray(wi->work_pts), - ZnListSize(wi->work_pts)); - gpc_polygon_to_tristrip((gpc_polygon *) &poly, - (gpc_tristrip *) &bz->tristrip); - } - - if (bz->tristrip.num_strips == 1) { - TRI_STRIP1(tristrip, - bz->tristrip.strips[0].points, - bz->tristrip.strips[0].num_points); - } - else if (bz->tristrip.num_strips > 1) { - tristrip->num_strips = bz->tristrip.num_strips; - tristrip->strips = bz->tristrip.strips; - } - } - - return False; -#else - ZnListAssertSize(item->wi->work_pts, 2); - points = (ZnPoint *) ZnListArray(item->wi->work_pts); - TRI_STRIP1(tristrip, points, 2); - points[0] = item->item_bounding_box.orig; - points[1] = item->item_bounding_box.corner; - - return True; -#endif -} - - -/* - ********************************************************************************** - * - * GetContours -- - * Get the external contour(s). - * Never ever call POLY_FREE on the poly returned by GetContours. - * - ********************************************************************************** - */ -static ZnBool -GetContours(Item item, - ZnPoly *poly) -{ - BezierItem bz = (BezierItem) item; - WidgetInfo *wi = item->wi; - - if (bz->dev_points) { - GetBezierPath(bz->dev_points, wi->work_pts); - - POLY_CONTOUR1(poly, (ZnPoint *) ZnListArray(wi->work_pts), - ZnListSize(wi->work_pts)); - } - - return False; -} - - -/* - ********************************************************************************** - * - * Coords -- - * Return or edit the item vertices. - * - ********************************************************************************** - */ -static int -Coords(Item item, - int contour, - int index, - int cmd, - ZnPoint **pts, - int *num_pts) -{ - BezierItem bz = (BezierItem) item; - int num_points, i; - ZnPoint *points; - - if ((cmd == COORDS_REPLACE) || (cmd == COORDS_REPLACE_ALL)) { - if (*num_pts == 0) { - Tcl_AppendResult(item->wi->interp, - " coords command need at least 1 point on beziers", NULL); - return ZN_ERROR; - } - if (cmd == COORDS_REPLACE_ALL) { - ZnList tmp; - replace_all: - tmp = ZnListFromArray(*pts, *num_pts, sizeof(ZnPoint)); - if (!bz->points) { - ZnListEmpty(bz->points); - } - else { - bz->points = ZnListNew(*num_pts, sizeof(ZnPoint)); - } - ZnListAppend(bz->points, tmp); - ZnListFree(tmp); - } - else { - if (!bz->points) { - edit_err: - Tcl_AppendResult(item->wi->interp, - " coords command cannot edit empty beziers", NULL); - return ZN_ERROR; - } - points = ZnListArray(bz->points); - num_points = ZnListSize(bz->points); - if (index < 0) { - index += num_points; - } - if ((index < 0) || (index >= num_points)) { - range_err: - Tcl_AppendResult(item->wi->interp, " coord index out of range", NULL); - return ZN_ERROR; - } - points[index] = (*pts)[0]; - } - ITEM.Invalidate(item, ZN_COORDS_FLAG); - } - else if ((cmd == COORDS_READ) || (cmd == COORDS_READ_ALL)) { - if (!bz->points) { - *num_pts = 0; - *pts = NULL; - return ZN_OK; - } - points = ZnListArray(bz->points); - num_points = ZnListSize(bz->points); - if (cmd == COORDS_READ_ALL) { - *num_pts = num_points; - *pts = points; - } - else { - if (index < 0) { - index += num_points; - } - if ((index < 0) || (index >= num_points)) { - goto range_err; - } - *num_pts = 1; - *pts = &points[index]; - } - } - else if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST)) { - if (!bz->points) { - goto replace_all; - } - else if (cmd == COORDS_ADD) { - num_points = ZnListSize(bz->points); - if (index < 0) { - index += num_points; - } - if ((index < 0) || (index >= num_points)) { - goto range_err; - } - for (i = 0; i < *num_pts; i++, index++) { - ZnListAdd(bz->points, &(*pts)[i], index); - } - } - else { - ZnList tmp; - tmp = ZnListFromArray(*pts, *num_pts, sizeof(ZnPoint)); - ZnListAppend(bz->points, tmp); - ZnListFree(tmp); - } - ITEM.Invalidate(item, ZN_COORDS_FLAG); - } - else if (cmd == COORDS_REMOVE) { - if (!bz->points) { - goto edit_err; - } - points = ZnListArray(bz->points); - num_points = ZnListSize(bz->points); - if (index < 0) { - index += num_points; - } - if ((index < 0) || (index >= num_points)) { - goto range_err; - } - ZnListDelete(bz->points, index); - ITEM.Invalidate(item, ZN_COORDS_FLAG); - } - - return ZN_OK; -} - - -/* - ********************************************************************************** - * - * PickVertex -- - * Return in 'vertex' the vertex closest to p and in 'o_vertex' the - * opposite vertex on the closest edge, if such an edge exists or -1 - * in the other case. - * - ********************************************************************************** - */ -static void -PickVertex(Item item, - ZnPoint *p, - int *contour, - int *vertex, - int *o_vertex) -{ - BezierItem bz = (BezierItem) item; - int i, k, num_points; - ZnPoint *points; - ZnReal dist=1.0e40, new_dist, dist2; - - *contour = *vertex = *o_vertex = -1; - - if ((bz->line_width > 0) || ISSET(bz->flags, FILLED_OK)) { - points = (ZnPoint *) ZnListArray(bz->dev_points); - num_points = ZnListSize(bz->dev_points); - for (i = 0; i < num_points; i++) { - new_dist = hypot(points[i].x - p->x, points[i].y - p->y); - if (new_dist < dist) { - dist = new_dist; - *contour = 0; - *vertex = i; - } - } - /* - * Update the opposite vertex. - */ - i = (*vertex+1) % num_points; - new_dist = LineToPointDist(&points[*vertex], &points[i], p); - k = ((unsigned)(*vertex-1)) % num_points; - dist2 = LineToPointDist(&points[*vertex], &points[k], p); - if (dist2 < new_dist) { - *o_vertex = k; - } - else { - *o_vertex = i; - } - } -} - - -/* - ********************************************************************************** - * - * Exported functions struct -- - * - ********************************************************************************** - */ -static ItemClassStruct BEZIER_ITEM_CLASS = { - sizeof(BezierItemStruct), - 0, /* num_parts */ - False, /* has_anchors */ - "bezier", - bz_attrs, - Init, - Clone, - Destroy, - Configure, - Query, - NULL, - NULL, - GetClipVertices, - GetContours, - Coords, - NULL, /* InsertChars */ - NULL, /* DeleteChars */ - NULL, /* Cursor */ - NULL, /* Index */ - NULL, /* Part */ - NULL, /* Selection */ - NULL, /* Contour */ - ComputeCoordinates, - ToArea, - Draw, - Render, - IsSensitive, - Pick, - PickVertex, /* PickVertex */ - PostScript -}; - -ZnItemClassId ZnBezier = (ZnItemClassId) &BEZIER_ITEM_CLASS; |