From b9d2768e801e670ad2816b5d0fb9fe7393c49fcb Mon Sep 17 00:00:00 2001 From: lecoanet Date: Tue, 5 Nov 2002 10:04:55 +0000 Subject: * (Coords): Correction de warnings sans objet. Suppression de GPC et remplacement par le tesselateur GLU. Support des paths et de la nouvelle gestion des contours. --- generic/Curve.c | 1014 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 633 insertions(+), 381 deletions(-) (limited to 'generic') diff --git a/generic/Curve.c b/generic/Curve.c index a31210f..ee50dcd 100644 --- a/generic/Curve.c +++ b/generic/Curve.c @@ -34,9 +34,7 @@ #include "WidgetInfo.h" #include "Image.h" #include "Color.h" -#ifdef GPC -#include "gpc/gpc.h" -#endif +#include "tkZinc.h" #include #include @@ -53,8 +51,7 @@ static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " #define MARKED_BIT 1<<1 /* If the vertices are marked by a symbol */ #define CLOSED_BIT 1<<2 /* If the outline should be closed automatically */ #define SMOOTH_RELIEF_BIT 1<<3 /* If the relief should be continuous (arc) or discrete (angle) */ -#define REDUCED_BIT 1<<5 /* Tell if the contours are in the most reduced - * form. */ + #define FIRST_END_OK 1<<6 #define LAST_END_OK 1<<7 #define FILLED_OK 1<<8 @@ -91,7 +88,7 @@ typedef struct _CurveItemStruct { ZnImage tile; /* Private data */ - ZnPoly dev_shape; + ZnPoly outlines; ZnGradient *gradient; ZnTriStrip tristrip; ZnPoint *grad_geo; @@ -176,12 +173,11 @@ Init(Item item, { WidgetInfo *wi = item->wi; CurveItem cv = (CurveItem) item; - Tcl_Obj **elems; - int i, num_elems; + int i, num_points, count; ZnPoint *p, *points; - double dbl; + char *controls; - POLY_INIT(&cv->dev_shape); + cv->outlines.num_contours = 0; cv->tristrip.num_strips = 0; cv->gradient = NULL; cv->grad_geo = NULL; @@ -194,7 +190,6 @@ Init(Item item, SET(item->flags, COMPOSE_SCALE_BIT); CLEAR(cv->flags, CLOSED_BIT); CLEAR(cv->flags, SMOOTH_RELIEF_BIT); - SET(cv->flags, REDUCED_BIT); item->priority = DEFAULT_CURVE_PRIORITY; @@ -202,31 +197,46 @@ Init(Item item, Tcl_AppendResult(wi->interp, " curve coords expected", NULL); return ZN_ERROR; } - if ((Tcl_ListObjGetElements(wi->interp, (*args)[0], &num_elems, &elems) == ZN_ERROR) || - ((num_elems % 2) != 0)) { - cv_error: - Tcl_AppendResult(wi->interp, " malformed curve coords", NULL); + if (ZnParseCoordList(wi, (*args)[0], &points, &controls, &num_points) == ZN_ERROR) { return ZN_ERROR; } - if (num_elems == 0) { + if (num_points == 0) { POLY_INIT(&cv->shape); } else { - p = points = (ZnPoint *) ZnMalloc(num_elems/2 * sizeof(ZnPoint)); - POLY_CONTOUR1(&cv->shape, points, num_elems/2); - for (i = 0; i < num_elems; i += 2, p++) { - if (Tcl_GetDoubleFromObj(wi->interp, elems[i], &dbl) == ZN_ERROR) { - cv_error2: - POLY_FREE(&cv->shape); - goto cv_error; + /* + * Scan the control array (if any) to detect malformed + * curves (more than 2 consecutive control points). + */ + if (controls) { + count = 0; + if ((controls[0]) || (controls[num_points-1])) { + goto control_err; } - p->x = dbl; - if (Tcl_GetDoubleFromObj(wi->interp, elems[i+1], &dbl) == ZN_ERROR) { - goto cv_error2; + for (i = 1; i < num_points-1; i++) { + switch (controls[i]) { + case 'c': + count++; + if (count > 2) { + goto control_err; + } + break; + case 0: + count = 0; + break; + default: + control_err: + ZnFree(controls); + Tcl_AppendResult(wi->interp, " curve coords expected", NULL); + return ZN_ERROR; + } } - p->y = dbl; } + p = ZnMalloc(num_points * sizeof(ZnPoint)); + memcpy(p, points, num_points * sizeof(ZnPoint)); + POLY_CONTOUR1(&cv->shape, p, num_points); + cv->shape.contours[0].controls = controls; } (*args)++; (*argc)--; @@ -270,9 +280,6 @@ Clone(Item item) CurveItem cv = (CurveItem) item; int i; ZnContour *conts; - ZnBool *holes; - - POLY_INIT(&cv->dev_shape); if (cv->grad_geo) { ZnPoint *grad_geo = ZnMalloc(4*sizeof(ZnPoint)); @@ -282,21 +289,20 @@ Clone(Item item) if (cv->shape.num_contours) { conts = cv->shape.contours; - holes = cv->shape.holes; if (cv->shape.contours != &cv->shape.contour1) { cv->shape.contours = (ZnContour *) ZnMalloc(cv->shape.num_contours*sizeof(ZnContour)); - if (cv->shape.holes) { - cv->shape.holes = (ZnBool *) ZnMalloc(cv->shape.num_contours*sizeof(ZnBool)); - } } for (i = 0; i < cv->shape.num_contours; i++) { - if (cv->shape.holes) { - cv->shape.holes[i] = holes[i]; - } cv->shape.contours[i].num_points = conts[i].num_points; - cv->shape.contours[i].points = (ZnPoint *) ZnMalloc(conts[i].num_points*sizeof(ZnPoint)); + cv->shape.contours[i].points = ZnMalloc(conts[i].num_points*sizeof(ZnPoint)); memcpy(cv->shape.contours[i].points, conts[i].points, conts[i].num_points*sizeof(ZnPoint)); + cv->shape.contours[i].controls = NULL; + if (conts[i].controls) { + cv->shape.contours[i].controls = ZnMalloc(conts[i].num_points*sizeof(char)); + memcpy(cv->shape.contours[i].controls, conts[i].controls, + conts[i].num_points*sizeof(char)); + } } } @@ -325,6 +331,7 @@ Clone(Item item) cv->fill_color = ZnGetGradientByValue(cv->fill_color); cv->marker_color = ZnGetGradientByValue(cv->marker_color); cv->tristrip.num_strips = 0; + cv->outlines.num_contours = 0; } @@ -339,14 +346,22 @@ static void Destroy(Item item) { CurveItem cv = (CurveItem) item; + int i; + /* + * Need to free the control array here, it is only known + * by the Curve code. + */ + for (i = 0; i < cv->shape.num_contours; i++) { + if (cv->shape.contours[i].controls) { + ZnFree(cv->shape.contours[i].controls); + } + } POLY_FREE(&cv->shape); + if (cv->grad_geo) { ZnFree(cv->grad_geo); } - cv->dev_shape.holes = NULL; - POLY_FREE(&cv->dev_shape); - if (cv->first_end) { LineEndDelete(cv->first_end); } @@ -379,6 +394,9 @@ Destroy(Item item) if (cv->tristrip.num_strips) { TRI_FREE(&cv->tristrip); } + if (cv->outlines.num_contours) { + POLY_FREE(&cv->outlines); + } } @@ -479,72 +497,202 @@ Query(Item item, } -static ZnBool -TestCCW(ZnPoint *points, - int num_points) +static void +CurveTessBegin(GLenum type, + void *data) { - ZnPoint *p, *p_p, *p_n, min; - ZnReal xprod; - int i, min_index; - - if (num_points < 3) { - return True; + CurveItem cv = data; + WidgetInfo *wi = ((Item) data)->wi; + + ZnListEmpty(wi->work_pts); + wi->tess_type = type; + if (type == GL_LINE_LOOP) { + cv->outlines.num_contours++; + cv->outlines.contours = ZnRealloc(cv->outlines.contours, + cv->outlines.num_contours * sizeof(ZnContour)); } + else { + cv->tristrip.num_strips++; + cv->tristrip.strips = ZnRealloc(cv->tristrip.strips, + cv->tristrip.num_strips * sizeof(ZnStrip)); + cv->tristrip.strips[cv->tristrip.num_strips-1].fan = (type==GL_TRIANGLE_FAN); + } + /*printf("Début de fragment de type: %s\n", + (type == GL_TRIANGLE_FAN) ? "FAN" : + (type == GL_TRIANGLE_STRIP) ? "STRIP" : + (type == GL_TRIANGLES) ? "TRIANGLES" : + (type == GL_LINE_LOOP) ? "LINE LOOP" : "");*/ +} +static void +CurveTessVertex(void *vertex_data, + void *data) +{ + CurveItem cv = data; + WidgetInfo *wi = ((Item) data)->wi; + ZnPoint p; + int size; + + p.x = ((GLdouble *) vertex_data)[0]; + p.y = ((GLdouble *) vertex_data)[1]; + /*printf("Sommet en %g %g\n", p.x, p.y);*/ + size = ZnListSize(wi->work_pts); + if ((wi->tess_type == GL_TRIANGLES) && (size == 3)) { + cv->tristrip.strips[cv->tristrip.num_strips-1].num_points = size; + cv->tristrip.strips[cv->tristrip.num_strips-1].points = ZnMalloc(size * sizeof(ZnPoint)); + memcpy(cv->tristrip.strips[cv->tristrip.num_strips-1].points, + ZnListArray(wi->work_pts), size * sizeof(ZnPoint)); + + /* Allocate a new fragment */ + ZnListEmpty(wi->work_pts); + cv->tristrip.num_strips++; + cv->tristrip.strips = ZnRealloc(cv->tristrip.strips, + cv->tristrip.num_strips * sizeof(ZnStrip)); + cv->tristrip.strips[cv->tristrip.num_strips-1].fan = GL_TRIANGLES; + } + ZnListAdd(wi->work_pts, &p, ZnListTail); +} +static void +CurveTessEnd(void *data) +{ + CurveItem cv = data; + WidgetInfo *wi = ((Item) data)->wi; + int size = ZnListSize(wi->work_pts); + int num; + + if (wi->tess_type == GL_LINE_LOOP) { + /* Add the last point to close the outline */ + size++; + num = cv->outlines.num_contours; + cv->outlines.contours[num-1].num_points = size; + cv->outlines.contours[num-1].points = ZnMalloc(size * sizeof(ZnPoint)); + memcpy(cv->outlines.contours[num-1].points, + ZnListArray(wi->work_pts), size * sizeof(ZnPoint)); + cv->outlines.contours[num-1].points[size-1] = cv->outlines.contours[num-1].points[0]; + cv->outlines.contours[num-1].cw = !TestCCW(cv->outlines.contours[num-1].points, size); + } + else { + num = cv->tristrip.num_strips; + cv->tristrip.strips[num-1].num_points = size; + cv->tristrip.strips[num-1].points = ZnMalloc(size * sizeof(ZnPoint)); + memcpy(cv->tristrip.strips[num-1].points, + ZnListArray(wi->work_pts), size * sizeof(ZnPoint)); + } + /* printf("Fin de fragment %d\n", num);*/ +} +static void +CurveTessCombine(GLdouble coords[3], + void *vertex_data[4], + GLfloat weight[4], + void **out_data, + void *data) +{ + WidgetInfo *wi = ((Item) data)->wi; + ZnCombineData *cdata; + + cdata = ZnMalloc(sizeof(ZnCombineData)); + cdata->v[0] = coords[0]; + cdata->v[1] = coords[1]; + cdata->next = wi->tess_combine_list; + wi->tess_combine_list = cdata; + *out_data = &cdata->v; + /*printf("Création d'un nouveau sommet en %g %g\n", + cdata->v[0], cdata->v[1]);*/ +} +static void +CurveTessError(GLenum errno, + void *data) +{ + const GLubyte *msg; - /* - * 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; + msg = gluErrorString(errno); + fprintf(stderr, "Tesselation error in curve item: %s\n", msg); +} + +static void +UpdateTristrip(CurveItem cv, + ZnPoly *poly) +{ + WidgetInfo *wi = ((Item) cv)->wi; + ZnCombineData *cdata, *cnext; + GLdouble v[3]; + int i, j; + + gluTessCallback(wi->tess, GLU_TESS_BEGIN_DATA, (void (*)()) CurveTessBegin); + gluTessCallback(wi->tess, GLU_TESS_VERTEX_DATA, (void (*)()) CurveTessVertex); + gluTessCallback(wi->tess, GLU_TESS_END_DATA, (void (*)()) CurveTessEnd); + gluTessCallback(wi->tess, GLU_TESS_COMBINE_DATA, (void (*)()) CurveTessCombine); + gluTessCallback(wi->tess, GLU_TESS_ERROR_DATA, (void (*)()) CurveTessError); + gluTessProperty(wi->tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); + gluTessNormal(wi->tess, 0, 0, -1); + + if (cv->tristrip.num_strips == 0) { + gluTessProperty(wi->tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); + gluTessBeginPolygon(wi->tess, cv); + for (j = 0; j < poly->num_contours; j++){ + gluTessBeginContour(wi->tess); + /*printf("Début contour %d num_points %d %d\n", + j, poly->contours[j].num_points, poly->contours[j].cw);*/ + for (i = 0; i < poly->contours[j].num_points; i++) { + /*printf("%g@%g ", poly->contours[j].points[i].x, poly->contours[j].points[i].y);*/ + v[0] = poly->contours[j].points[i].x; + v[1] = poly->contours[j].points[i].y; + v[2] = 0; + gluTessVertex(wi->tess, v, &poly->contours[j].points[i]); + } + /*printf("\n");*/ + gluTessEndContour(wi->tess); + } + gluTessEndPolygon(wi->tess); + cdata = wi->tess_combine_list; + while (cdata) { + cnext = cdata->next; + ZnFree(cdata); + cdata = cnext; } + wi->tess_combine_list = NULL; } - /* - * Then find the indices of the previous and next - * vertices. - */ - p = &points[min_index]; - /*printf("min index %d, prev %d, next %d\n", min_index, - (min_index+(num_points-1))%num_points, (min_index+1)%num_points);*/ - 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. */ } - -/* - * Create a reduced polygon from an unknown one by - * adding/clipping all the shapes/holes in turn. - */ -#ifdef GPC static void -ReduceContours(ZnPoly *poly_in, - ZnPoly *poly_out) +UpdateOutlines(CurveItem cv, + ZnPoly *poly) { - int i; - ZnContour *c; - ZnBool *hole; - ZnPoly cpoly, rpoly; - - POLY_INIT(poly_out); - for (i = 0, hole = poly_in->holes, c = poly_in->contours; - i < poly_in->num_contours; i++, c++, hole++) { - POLY_CONTOUR1(&cpoly, c->points, c->num_points); - gpc_polygon_clip(*hole?GPC_DIFF:GPC_UNION, (gpc_polygon *) &poly_out, - (gpc_polygon *) &cpoly, (gpc_polygon *) &rpoly); - POLY_SET(poly_out, &rpoly); + WidgetInfo *wi = ((Item) cv)->wi; + ZnCombineData *cdata, *cnext; + GLdouble v[3]; + int i, j; + + gluTessCallback(wi->tess, GLU_TESS_BEGIN_DATA, (void (*)()) CurveTessBegin); + gluTessCallback(wi->tess, GLU_TESS_VERTEX_DATA, (void (*)()) CurveTessVertex); + gluTessCallback(wi->tess, GLU_TESS_END_DATA, (void (*)()) CurveTessEnd); + gluTessCallback(wi->tess, GLU_TESS_COMBINE_DATA, (void (*)()) CurveTessCombine); + gluTessCallback(wi->tess, GLU_TESS_ERROR_DATA, (void (*)()) CurveTessError); + gluTessProperty(wi->tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE); + gluTessNormal(wi->tess, 0, 0, -1); + + if (cv->outlines.num_contours == 0) { + gluTessProperty(wi->tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE); + gluTessBeginPolygon(wi->tess, cv); + for (j = 0; j < poly->num_contours; j++){ + gluTessBeginContour(wi->tess); + for (i = 0; i < poly->contours[j].num_points; i++) { + v[0] = poly->contours[j].points[i].x; + v[1] = poly->contours[j].points[i].y; + v[2] = 0; + gluTessVertex(wi->tess, v, &poly->contours[j].points[i]); + } + gluTessEndContour(wi->tess); + } + gluTessEndPolygon(wi->tess); + cdata = wi->tess_combine_list; + while (cdata) { + cnext = cdata->next; + ZnFree(cdata); + cdata = cnext; + } + wi->tess_combine_list = NULL; } } -#endif /* @@ -563,33 +711,18 @@ ComputeCoordinates(Item item, int i, j; ZnPoint end_points[LINE_END_POINTS]; ZnPoint *points; - int num_points, num_contours; + int num_points, num_contours, segment_start; ZnBBox bbox; int lw; ZnContour *c1, *c2; - ZnBool *holes, *cw; - + ZnPoly dev; + + ResetBBox(&item->item_bounding_box); - /*printf("flags %x\n", cv->flags);*/ + /* printf("Curve CC: flags %x\n", cv->flags);*/ SetRenderFlags(cv); - /* - * Try to reduce the contours if needed. This can be - * switched off and replaced by an explicit reduction. - */ - if (cv->shape.num_contours == 1) { - SET(cv->flags, REDUCED_BIT); - } - else if (ISCLEAR(cv->flags, REDUCED_BIT)) { -#ifdef GPC - ZnPoly poly; - ReduceContours(&cv->shape, &poly); - POLY_SET(&cv->shape, &poly); -#endif - SET(cv->flags, REDUCED_BIT); - } - num_contours = cv->shape.num_contours; if (num_contours == 0) { return; @@ -598,85 +731,115 @@ ComputeCoordinates(Item item, if (cv->tristrip.num_strips) { TRI_FREE(&cv->tristrip); } - - /* - * Allocate space for devices coordinates, the holes array is _NOT_ - * duplicated. - */ - cv->dev_shape.holes = NULL; - POLY_FREE(&cv->dev_shape); - if (cv->shape.contours != &cv->shape.contour1) { - cv->dev_shape.contours = (ZnContour *) ZnMalloc(num_contours*sizeof(ZnContour)); + if (cv->outlines.num_contours) { + POLY_FREE(&cv->outlines); + }; + + POLY_INIT(&dev); + if (num_contours != 1) { + dev.contours = ZnMalloc(num_contours * sizeof(ZnContour)); + dev.num_contours = num_contours; } else { - cv->dev_shape.contours = &cv->dev_shape.contour1; - cv->dev_shape.cw = &cv->dev_shape.cw1; - } - cv->dev_shape.holes = cv->shape.holes; - cv->dev_shape.num_contours = num_contours; - c1 = cv->shape.contours; - c2 = cv->dev_shape.contours; - for (i = 0; i < cv->shape.num_contours; i++, c1++, c2++) { + dev.contours = &dev.contour1; + dev.num_contours = 1; + } + + for (c1 = cv->shape.contours, c2 = dev.contours, i = 0; + i < cv->shape.num_contours; i++, c1++, c2++) { + c2->cw = c1->cw; c2->num_points = c1->num_points; /* * Add a point at the end of the contour to close it - * if needed. + * if needed. Works only if a single contour is given, in + * this case it can be used as a path. In the case of + * multiple contours, the outline is automatically + * closed by the tesselator. */ - if (ISSET(cv->flags, CLOSED_BIT) && + if ((num_contours == 1) && + (c1->num_points > 2) && + ISSET(cv->flags, CLOSED_BIT) && ((c1->points[0].x != c1->points[c2->num_points-1].x) || (c1->points[0].y != c1->points[c2->num_points-1].y)) && - (c1->num_points != 1)) { + (c1->num_points > 2)) { c2->num_points++; } - c2->points = (ZnPoint *) ZnMalloc((c2->num_points)*sizeof(ZnPoint)); + c2->points = ZnMalloc((c2->num_points)*sizeof(ZnPoint)); /*printf("CC: \"%d\" num_points %d\n", item->id, c1->num_points);*/ - } - - /* - * Process all points, transforming coordinates. - */ - c1 = cv->shape.contours; - c2 = cv->dev_shape.contours; - for (j = 0; j < num_contours; j++, c1++, c2++) { - ZnTransformPoints(wi->current_transfo, c1->points, c2->points, c1->num_points); - /* - * Close the curve if needed. - */ + ZnTransformPoints(wi->current_transfo, c1->points, c2->points, c1->num_points); if (c1->num_points != c2->num_points) { c2->points[c2->num_points-1] = c2->points[0]; } + /* + * Now expand the bezier segments into polylines. + */ + if (c1->controls) { + segment_start = 0; + ZnListEmpty(wi->work_pts); + ZnListAdd(wi->work_pts, &c2->points[0], ZnListTail); + /*printf("moveto %g@%g\n", c2->points[0].x, c2->points[0].y);*/ + for (j = 1; j < c1->num_points; j++) { + if (!c1->controls[j]) { + if (segment_start != j-1) { + /* traitement bezier */ + /* printf("arcto %g@%g %g@%g %g@%g\n", + c2->points[segment_start+1].x, c2->points[segment_start+1].y, + c2->points[j-1].x, c2->points[j-1].y, + c2->points[j].x, c2->points[j].y);*/ + GetBezierPoints(&c2->points[segment_start], + &c2->points[segment_start+1], &c2->points[j-1], + &c2->points[j], wi->work_pts, 2.0); + } + else { + /*printf("lineto %g@%g\n", c2->points[j].x, c2->points[j].y);*/ + ZnListAdd(wi->work_pts, &c2->points[j], ZnListTail); + } + segment_start = j; + } + } + /* + * Replce the original path by the expanded, closing it as + * needed (one open contour). + */ + num_points =ZnListSize(wi->work_pts); + if (c2->num_points != c1->num_points) { + num_points++; + } + c2->points = ZnRealloc(c2->points, num_points*sizeof(ZnPoint)); + memcpy(c2->points, ZnListArray(wi->work_pts), num_points*sizeof(ZnPoint)); + if (c2->num_points != c1->num_points) { + c2->points[num_points-1] = c2->points[0]; + } + c2->num_points = num_points; + } + } + + UpdateTristrip(cv, &dev); + if (num_contours == 1) { + POLY_CONTOUR1(&cv->outlines, dev.contours[0].points, dev.contours[0].num_points); + cv->outlines.contours[0].cw = dev.contours[0].cw; + } + else { + UpdateOutlines(cv, &dev); + POLY_FREE(&dev); } lw = cv->line_width; - + num_contours = cv->outlines.num_contours; if (ISSET(cv->flags, RELIEF_OK)) { - holes = cv->shape.holes; - c2 = cv->dev_shape.contours; - if (!cv->dev_shape.cw) { - cv->dev_shape.cw = (ZnBool *) ZnMalloc(num_contours*sizeof(ZnBool)); - } - cw = cv->dev_shape.cw; - for (j = 0; j < num_contours; j++, c2++, holes++, cw++) { - num_points = c2->num_points; - points = c2->points; - *cw = !TestCCW(points, num_points); - if (*holes) { - continue; - } + c2 = cv->outlines.contours; + for (i = 0; i < num_contours; i++, c2++) { /* * Add to bounding box. */ - ZnGetPolygonReliefBBox(points, num_points, (*cw ^ *holes)?-lw:lw, &bbox); + ZnGetPolygonReliefBBox(c2->points, c2->num_points, lw, &bbox); AddBBoxToBBox(&item->item_bounding_box, &bbox); } } else { - holes = cv->shape.holes; - c2 = cv->dev_shape.contours; - for (j = 0; j < num_contours; j++, c2++, holes++) { - if (!*holes) { - AddPointsToBBox(&item->item_bounding_box, c2->points, c2->num_points); - } + c2 = cv->outlines.contours; + for (i = 0; i < num_contours; i++, c2++) { + AddPointsToBBox(&item->item_bounding_box, c2->points, c2->num_points); } /* @@ -692,10 +855,9 @@ ComputeCoordinates(Item item, /* * Take care of miters, markers and arrows. */ - holes = cv->shape.holes; - c2 = cv->dev_shape.contours; - for (j = 0; j < num_contours; j++, c2++, holes++) { - if (*holes) { + c2 = cv->outlines.contours; + for (j = 0; j < num_contours; j++, c2++) { + if (c2->cw) { continue; } if (cv->join_style == JoinMiter) { @@ -760,7 +922,7 @@ ComputeCoordinates(Item item, ZnComputeAxialGradient(wi, &cv->shape, cv->fill_color->g.angle, cv->grad_geo); } else if (cv->fill_color->type == ZN_RADIAL_GRADIENT) { - ZnComputeRadialGradient(wi, &cv->dev_shape, &item->item_bounding_box, + ZnComputeRadialGradient(wi, &cv->outlines, &item->item_bounding_box, &cv->fill_color->g.p, cv->grad_geo); } else if (cv->fill_color->type == ZN_PATH_GRADIENT) { @@ -793,49 +955,56 @@ ToArea(Item item, CurveItem cv = (CurveItem) item; ZnBBox bbox, *area = ta->area; ZnPoint *points; + ZnPoint triangle[3]; ZnPoint end_points[LINE_END_POINTS]; - int i, num_points, result=-1, result2; + int i, j, num_points, result=-1, result2; int width, height; ZnBool first_done = False; - if (cv->dev_shape.num_contours == 0) { + if (cv->outlines.num_contours == 0) { return -1; } /*printf("============== poly %d ==============\n", item->id);*/ if (ISSET(cv->flags, FILLED_OK)) { - for (i = 0; i < cv->dev_shape.num_contours; i++) { - ZnBool area_enclosed; - - num_points = cv->dev_shape.contours[i].num_points; - points = cv->dev_shape.contours[i].points; - if (!first_done) { - first_done = True; - result = PolygonInBBox(points, num_points, area, &area_enclosed); - /*printf("contour %d, result %d, area_enclosed %d\n", - i, result, area_enclosed);*/ - if (cv->shape.holes[i] && area_enclosed) { - return -1; - } + /*printf("testing surfaces\n");*/ + for (i = 0; i < cv->tristrip.num_strips; i++) { + num_points = cv->tristrip.strips[i].num_points; + points = cv->tristrip.strips[i].points; + j = 0; + if (cv->tristrip.strips[i].fan) { + triangle[0] = points[0]; + j++; } - else { - result2 = PolygonInBBox(points, num_points, area, &area_enclosed); - /*printf("contour %d, result %d, area_enclosed %d\n", - i, result2, area_enclosed);*/ - if (cv->shape.holes[i] && area_enclosed) { - return -1; + for (; j < num_points-2; j++, points++) { + if (cv->tristrip.strips[i].fan) { + triangle[1] = points[0]; + triangle[2] = points[1]; } - if (result2 != result) { - return 0; + else { + triangle[0] = points[0]; + triangle[1] = points[1]; + triangle[2] = points[2]; + } + if (!first_done) { + first_done = True; + result = PolygonInBBox(triangle, 3, area, NULL); + } + else { + result2 = PolygonInBBox(triangle, 3, area, NULL); + if (result2 != result) { + return 0; + } } } } } if (cv->line_width > 0) { - for (i = 0; i < cv->dev_shape.num_contours; i++) { - num_points = cv->dev_shape.contours[i].num_points; - points = cv->dev_shape.contours[i].points; + /*printf("testing lines\n");*/ + for (i = 0; i < cv->outlines.num_contours; i++) { + num_points = cv->outlines.contours[i].num_points; + points = cv->outlines.contours[i].points; if (!first_done) { first_done = True; if (ISCLEAR(cv->flags, RELIEF_OK)) { @@ -843,9 +1012,7 @@ ToArea(Item item, cv->line_width, cv->cap_style, cv->join_style, area); } else { - result = ZnPolygonReliefInBBox(points, num_points, - (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, - area); + result = ZnPolygonReliefInBBox(points, num_points, cv->line_width, area); } if (result == 0) { return 0; @@ -857,9 +1024,7 @@ ToArea(Item item, cv->line_width, cv->cap_style, cv->join_style, area); } else { - result2 = ZnPolygonReliefInBBox(points, num_points, - (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, - area); + result2 = ZnPolygonReliefInBBox(points, num_points, cv->line_width, area); } if (result2 != result) { return 0; @@ -870,8 +1035,8 @@ ToArea(Item item, /* * Check line ends (only on first contour). */ - points = cv->dev_shape.contours[0].points; - num_points = cv->dev_shape.contours[0].num_points; + points = cv->outlines.contours[0].points; + num_points = cv->outlines.contours[0].num_points; if (ISSET(cv->flags, FIRST_END_OK)) { GetLineEnd(&points[0], &points[1], cv->line_width, cv->cap_style, cv->first_end, end_points); @@ -892,9 +1057,9 @@ ToArea(Item item, * Last, check markers */ if (ISSET(cv->flags, MARKER_OK)) { - for (i = 0; i < cv->dev_shape.num_contours; i++) { - points = cv->dev_shape.contours[i].points; - num_points = cv->dev_shape.contours[i].num_points; + for (i = 0; i < cv->outlines.num_contours; i++) { + points = cv->outlines.contours[i].points; + num_points = cv->outlines.contours[i].num_points; if (ISSET(cv->flags, FIRST_END_OK)) { num_points--; @@ -939,7 +1104,7 @@ Draw(Item item) ZnPoint *points=NULL; XPoint *xpoints=NULL; - if ((cv->dev_shape.num_contours == 0) || + if ((cv->outlines.num_contours == 0) || (ISCLEAR(cv->flags, FILLED_OK) && !cv->line_width && ISCLEAR(cv->flags, MARKER_OK))) { @@ -972,11 +1137,7 @@ Draw(Item item) } XChangeGC(wi->dpy, wi->gc, gc_mask, &values); -#ifdef GPC - if (cv->tristrip.num_strips == 0) { - gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, - (gpc_tristrip *) &cv->tristrip); - } + for (i = 0; i < cv->tristrip.num_strips; i++) { num_points = cv->tristrip.strips[i].num_points; points = cv->tristrip.strips[i].points; @@ -991,18 +1152,6 @@ Draw(Item item) &xpoints[j], 3, Convex, CoordModeOrigin); } } -#else - num_points = cv->dev_shape.contours[0].num_points; - points = cv->dev_shape.contours[0].points; - 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); -#endif } /* @@ -1011,35 +1160,20 @@ Draw(Item item) if (cv->line_width) { ZnPoint end_points[LINE_END_POINTS]; XPoint xp[LINE_END_POINTS]; - ReliefStyle relief; - int lw, relief_dir; /* * Drawing with relief disables: ends, line style and line pattern. */ if (ISSET(cv->flags, RELIEF_OK)) { - for (j = 0; j < cv->dev_shape.num_contours; j++) { - num_points = cv->dev_shape.contours[j].num_points; - points = cv->dev_shape.contours[j].points; - /*printf("Draw: item %d, num_points %d %g@%g %g@%g, holes %d cw %d i/o %d\n", + for (j = 0; j < cv->outlines.num_contours; j++) { + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; + /*printf("Draw: item %d, num_points %d %g@%g %g@%g, cw %d i/o %d\n", item->id, num_points, points[0].x, points[0].y, - points[num_points-1].x, points[num_points-1].y,cv->shape.holes[j], - cv->dev_shape.cw[j], cv->dev_shape.cw[j]^cv->shape.holes[j]);*/ - lw = cv->line_width; - relief = cv->relief; - relief_dir = relief & RELIEF_MASK; - if (cv->dev_shape.cw[j]^cv->shape.holes[j]) { - 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, cv->gradient, points, num_points, lw); + points[num_points-1].x, points[num_points-1].y, + cv->outlines.contours[j].cw);*/ + ZnDrawPolygonRelief(wi, cv->relief, cv->gradient, points, num_points, cv->line_width); } } else { @@ -1060,9 +1194,9 @@ Draw(Item item) GCFillStyle|GCStipple|GCLineWidth|GCJoinStyle|GCCapStyle|GCForeground, &values); } - for (j = 0; j < cv->dev_shape.num_contours; j++) { - num2 = num_points = cv->dev_shape.contours[j].num_points; - points = cv->dev_shape.contours[j].points; + for (j = 0; j < cv->outlines.num_contours; j++) { + num2 = num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; ZnListAssertSize(wi->work_xpts, num_points); xpoints = (XPoint *) ZnListArray(wi->work_xpts); for (i = 0; i < num2; i++) { @@ -1113,9 +1247,9 @@ Draw(Item item) values.stipple = ZnImagePixmap(cv->marker, NULL); values.foreground = ZnPixel(ZnGetGradientColor(cv->marker_color, 0, NULL)); XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCStipple|GCForeground, &values); - for (j = 0; j < cv->dev_shape.num_contours; j++) { - num_points = cv->dev_shape.contours[j].num_points; - points = cv->dev_shape.contours[j].points; + for (j = 0; j < cv->outlines.num_contours; j++) { + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; ZnListAssertSize(wi->work_xpts, num_points); xpoints = (XPoint *) ZnListArray(wi->work_xpts); for (i = 0; i < num_points; i++) { @@ -1152,25 +1286,22 @@ Draw(Item item) ********************************************************************************** */ #ifdef GLX -void +static void CurveRenderCB(void *closure) { CurveItem cv = (CurveItem) closure; int i, j, num_points; ZnPoint *points; - -#ifdef GPC - if (cv->tristrip.num_strips == 0) { - gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, - (gpc_tristrip *) &cv->tristrip); - } -#else -#error "GPC needed to render filled curves with GLX" -#endif + for (i = 0; i < cv->tristrip.num_strips; i++) { num_points = cv->tristrip.strips[i].num_points; points = cv->tristrip.strips[i].points; - glBegin(GL_TRIANGLE_STRIP); + if (cv->tristrip.strips[i].fan) { + glBegin(GL_TRIANGLE_FAN); + } + else { + glBegin(GL_TRIANGLE_STRIP); + } for (j = 0; j < num_points; j++, points++) { glVertex2f(points->x, points->y); } @@ -1189,7 +1320,7 @@ Render(Item item) XColor *color; int alpha; - if ((cv->dev_shape.num_contours == 0) || + if ((cv->outlines.num_contours == 0) || (ISCLEAR(cv->flags, FILLED_OK) && !cv->line_width && ISCLEAR(cv->flags, MARKER_OK))) { @@ -1203,7 +1334,7 @@ Render(Item item) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (!ZnGradientFlat(cv->fill_color)) { ZnRenderGradient(wi, cv->fill_color, CurveRenderCB, cv, cv->grad_geo, - &cv->dev_shape); + &cv->outlines); } else if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ ZnRenderTile(wi, cv->tile, cv->fill_color, CurveRenderCB, cv, @@ -1235,43 +1366,26 @@ Render(Item item) ZnGetGradientColor(cv->line_color, 0, &alpha); alpha = ZnComposeAlpha(alpha, wi->alpha); if (ISSET(cv->flags, RELIEF_OK)) { - ReliefStyle relief; - ZnDim line_width; - int relief_dir; - - for (j = 0; j < cv->dev_shape.num_contours; j++) { - num_points = cv->dev_shape.contours[j].num_points; - points = cv->dev_shape.contours[j].points; - /*printf("Render: item %d, num_points %d %g@%g %g@%g, holes %d cw %d i/o %d\n", + for (j = 0; j < cv->outlines.num_contours; j++) { + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; + /*printf("Render: item %d, num_points %d %g@%g %g@%g, cw %d i/o %d\n", item->id, num_points, points[0].x, points[0].y, - points[num_points-1].x, points[num_points-1].y,cv->shape.holes[j], - cv->dev_shape.cw[j], cv->dev_shape.cw[j]^cv->shape.holes[j]);*/ - relief = cv->relief; - line_width = cv->line_width; - relief_dir = relief & RELIEF_MASK; - if (cv->dev_shape.cw[j]^cv->shape.holes[j]) { - line_width = -line_width; - if (relief_dir == RELIEF_SUNKEN) { - relief_dir = RELIEF_RAISED; - } - else { - relief_dir = RELIEF_SUNKEN; - } - relief = (relief & ~RELIEF_MASK) | relief_dir; - } - ZnRenderPolygonRelief(wi, relief, cv->gradient, ISSET(cv->flags, SMOOTH_RELIEF_BIT), - points, num_points, line_width); + points[num_points-1].x, points[num_points-1].y, + cv->outlines.contours[j].cw);*/ + ZnRenderPolygonRelief(wi, cv->relief, cv->gradient, ISSET(cv->flags, SMOOTH_RELIEF_BIT), + points, num_points, cv->line_width); } } else { ZnLineEnd first = ISSET(cv->flags, FIRST_END_OK) ? cv->first_end : NULL; ZnLineEnd last = ISSET(cv->flags, LAST_END_OK) ? cv->last_end : NULL; - for (j = 0; j < cv->dev_shape.num_contours; j++) { + for (j = 0; j < cv->outlines.num_contours; j++) { ZnRenderPolyline(wi, - cv->dev_shape.contours[j].points, - cv->dev_shape.contours[j].num_points, + cv->outlines.contours[j].points, + cv->outlines.contours[j].num_points, cv->line_width, cv->line_style, cv->cap_style, cv->join_style, first, last, cv->line_color); } @@ -1289,9 +1403,9 @@ Render(Item item) ZnSizeOfImage(cv->marker, &h_width, & h_height); h_width = (h_width+1.0)/2.0; h_height = (h_height+1.0)/2.0; - for (j = 0; j < cv->dev_shape.num_contours; j++) { - num_points = cv->dev_shape.contours[j].num_points; - points = cv->dev_shape.contours[j].points; + for (j = 0; j < cv->outlines.num_contours; j++) { + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; if (ISSET(cv->flags, FIRST_END_OK)) { num_points--; points++; @@ -1346,7 +1460,7 @@ Pick(Item item, int width, height; int i; - if (cv->dev_shape.num_contours == 0) { + if (cv->outlines.num_contours == 0) { return dist; } @@ -1357,23 +1471,24 @@ Pick(Item item, * Check all contours. Compute distance to holes * in the same pass. */ - for (i = 0; i < cv->dev_shape.num_contours; i++) { - if (cv->shape.holes[i]) { - new_hole_dist = PolygonToPointDist(cv->dev_shape.contours[i].points, - cv->dev_shape.contours[i].num_points, p); + for (i = 0; i < cv->outlines.num_contours; i++) { + if (cv->outlines.contours[i].cw) { + new_hole_dist = PolygonToPointDist(cv->outlines.contours[i].points, + cv->outlines.contours[i].num_points, p); if (new_hole_dist < hole_dist) { hole_dist = new_hole_dist; } } else { - new_dist = PolygonToPointDist(cv->dev_shape.contours[i].points, - cv->dev_shape.contours[i].num_points, p); + new_dist = PolygonToPointDist(cv->outlines.contours[i].points, + cv->outlines.contours[i].num_points, p); if (new_dist < dist) { dist = new_dist; } } } if ((dist <= 0.0) && (hole_dist >= 0.0)) { + /*printf("dist %g hole dist: %g\n", dist, hole_dist);*/ return 0.0; } if (hole_dist < 0.0) { @@ -1391,9 +1506,9 @@ Pick(Item item, /* * Check all contours. */ - for (i = 0; i < cv->dev_shape.num_contours; i++) { - points = cv->dev_shape.contours[i].points; - num_points = cv->dev_shape.contours[i].num_points; + for (i = 0; i < cv->outlines.num_contours; i++) { + points = cv->outlines.contours[i].points; + num_points = cv->outlines.contours[i].num_points; if (ISCLEAR(cv->flags, RELIEF_OK)) { new_dist = PolylineToPointDist(points, num_points, cv->line_width, cv->cap_style, cv->join_style, p); @@ -1401,17 +1516,17 @@ Pick(Item item, dist = new_dist; } if (dist <= 0.0) { + /*printf("dist %g\n", dist);*/ return 0.0; } } else { - new_dist = ZnPolygonReliefToPointDist(points, num_points, - (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, - p); + new_dist = ZnPolygonReliefToPointDist(points, num_points, cv->line_width, p); if (new_dist < dist) { dist = new_dist; } if (dist <= 0.0) { + /*printf("dist %g\n", dist);*/ return 0.0; } } @@ -1421,8 +1536,8 @@ Pick(Item item, /* * Line ends are checked only on the first contour. */ - points = cv->dev_shape.contours[0].points; - num_points = cv->dev_shape.contours[0].num_points; + points = cv->outlines.contours[0].points; + num_points = cv->outlines.contours[0].num_points; /* * Check line ends. */ @@ -1434,6 +1549,7 @@ Pick(Item item, dist = new_dist; } if (dist <= 0.0) { + /*printf("dist %g\n", dist);*/ return 0.0; } } @@ -1445,6 +1561,7 @@ Pick(Item item, dist = new_dist; } if (dist <= 0.0) { + /*printf("dist %g\n", dist);*/ return 0.0; } } @@ -1453,9 +1570,9 @@ Pick(Item item, * Last, check markers on all contours. */ if (ISSET(cv->flags, MARKER_OK)) { - for (i = 0; i < cv->dev_shape.num_contours; i++) { - points = cv->dev_shape.contours[i].points; - num_points = cv->dev_shape.contours[i].num_points; + for (i = 0; i < cv->outlines.num_contours; i++) { + points = cv->outlines.contours[i].points; + num_points = cv->outlines.contours[i].num_points; if (ISSET(cv->flags, FIRST_END_OK)) { num_points--; @@ -1476,12 +1593,14 @@ Pick(Item item, dist = new_dist; } if (dist <= 0.0) { + /*printf("dist %g\n", dist);*/ return 0.0; } } } } + /*printf("dist %g\n", dist);*/ return dist; } @@ -1514,40 +1633,21 @@ GetClipVertices(Item item, ZnTriStrip *tristrip) { CurveItem cv = (CurveItem) item; -#ifndef GPC - ZnPoint *points; -#endif -#ifdef GPC tristrip->num_strips = 0; - if (cv->tristrip.num_strips == 0) { - gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, - (gpc_tristrip *) &cv->tristrip); - } - if (cv->tristrip.num_strips == 1) { TRI_STRIP1(tristrip, cv->tristrip.strips[0].points, - cv->tristrip.strips[0].num_points); + cv->tristrip.strips[0].num_points, + cv->tristrip.strips[0].fan); } else if (cv->tristrip.num_strips > 1) { tristrip->num_strips = cv->tristrip.num_strips; tristrip->strips = cv->tristrip.strips; } - tristrip->fan = False; - 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 } @@ -1566,13 +1666,13 @@ GetContours(Item item, { CurveItem cv = (CurveItem) item; - if (cv->dev_shape.num_contours == 1) { - POLY_CONTOUR1(poly, cv->dev_shape.contours[0].points, - cv->dev_shape.contours[0].num_points); + if (cv->outlines.num_contours == 1) { + POLY_CONTOUR1(poly, cv->outlines.contours[0].points, + cv->outlines.contours[0].num_points); } - else if (cv->dev_shape.num_contours > 1) { - poly->num_contours = cv->dev_shape.num_contours; - poly->contours = cv->dev_shape.contours; + else if (cv->outlines.num_contours > 1) { + poly->num_contours = cv->outlines.num_contours; + poly->contours = cv->outlines.contours; } return False; @@ -1593,11 +1693,12 @@ Coords(Item item, int index, int cmd, ZnPoint **pts, + char **controls, int *num_pts) { CurveItem cv = (CurveItem) item; - int i; - ZnContour *c; + int i, num_controls; + ZnContour *c=NULL; /*printf("contour %d, num_pts %d, index %d, cmd %d\n", contour, *num_pts, index, cmd);*/ @@ -1632,11 +1733,15 @@ Coords(Item item, } if (*num_pts) { if (c->points) { - ZnFree(c->points); + ZnFree(c->points); } c->points = (ZnPoint *) ZnMalloc(*num_pts*sizeof(ZnPoint)); c->num_points = *num_pts; memcpy(c->points, *pts, *num_pts*sizeof(ZnPoint)); + if (*controls) { + c->controls = ZnRealloc(c->controls, *num_pts*sizeof(char)); + memcpy(c->controls, *controls, *num_pts*sizeof(char)); + } } else { goto cont_remove; @@ -1663,8 +1768,31 @@ Coords(Item item, return ZN_ERROR; } c->points[index] = (*pts)[0]; + if (!c->controls && *controls && (*controls)[0]) { + c->controls = ZnMalloc(c->num_points*sizeof(char)); + memset(c->controls, 0, c->num_points*sizeof(char)); + } + if (c->controls) { + if (!*controls) { + c->controls[index] = 0; + } + else { + if ((*controls)[0]) { + /* Check if the edit is allowable, there should be + * no more than 2 consecutive control points . + */ + for (num_controls = 0, i = index-1; !c->controls[i]; i--, num_controls++); + for (i = index+1; !c->controls[i]; i++, num_controls++); + if (num_controls > 1) { + control_err: + Tcl_AppendResult(item->wi->interp, " too many consecutive control points in a curve", NULL); + return ZN_ERROR; + } + } + c->controls[index] = (*controls)[0]; + } + } } - CLEAR(cv->flags, REDUCED_BIT); ITEM.Invalidate(item, ZN_COORDS_FLAG); } @@ -1680,6 +1808,9 @@ Coords(Item item, if (cmd == COORDS_READ_ALL) { *num_pts = c->num_points; *pts = c->points; + if (c->controls) { + *controls = c->controls; + } } else { if (index < 0) { @@ -1690,6 +1821,9 @@ Coords(Item item, } *num_pts = 1; *pts = &c->points[index]; + if (c->controls) { + *controls = &c->controls[index]; + } } } @@ -1716,19 +1850,51 @@ Coords(Item item, if ((index < 0) || (index > c->num_points)) { goto range_err; } - c->points = (ZnPoint *) ZnRealloc(c->points, - (c->num_points+*num_pts)*sizeof(ZnPoint)); + if (*controls) { + /* Check if the edit is allowable, there should be + * no more than 2 consecutive control points . + */ + if (c->controls) { + for (num_controls = 0, i = index-1; !c->controls[i]; i--, num_controls++); + } + for (i = 0; i < *num_pts; i++) { + if (!(*controls)[i]) { + num_controls = 0; + } + else { + num_controls++; + if (num_controls > 2) { + goto control_err; + } + } + } + if (c->controls) { + for (i = index+1; !c->controls[i]; i++, num_controls++); + } + if (num_controls > 2) { + goto control_err; + } + } + c->points = ZnRealloc(c->points, (c->num_points+*num_pts)*sizeof(ZnPoint)); + if (*controls || c->controls) { + c->controls = ZnRealloc(c->controls, (c->num_points+*num_pts)*sizeof(char)); + } /* * Make a hole if needed. */ for (i = c->num_points-1; i >= index; i--) { c->points[i+*num_pts] = c->points[i]; + if (c->controls) { + c->controls[i+*num_pts] = c->controls[i]; + } } for (i = 0; i < *num_pts; i++, index++) { c->points[index] = (*pts)[i]; + if (c->controls) { + c->controls[index] = (*controls)?(*controls)[i]:0; + } } c->num_points += *num_pts; - CLEAR(cv->flags, REDUCED_BIT); ITEM.Invalidate(item, ZN_COORDS_FLAG); } @@ -1747,17 +1913,32 @@ Coords(Item item, if ((index < 0) || (index >= c->num_points)) { goto range_err; } + + if (c->controls) { + /* Check if the edit is allowable, there should be + * no more than 2 consecutive control points . + */ + for (num_controls = 0, i = index-1; !c->controls[i]; i--, num_controls++); + for (i = index+1; !c->controls[i]; i++, num_controls++); + if (num_controls > 2) { + goto control_err; + } + } + c->num_points--; if (c->num_points == 0) { /* * Contour is removed. */ cont_remove: + if (c->controls) { + ZnFree(c->controls); + } + ZnFree(c->points); if (cv->shape.num_contours == 1) { POLY_FREE(&cv->shape); } else { - ZnFree(c->points); for (i = contour; i < cv->shape.num_contours; i++) { cv->shape.contours[i] = cv->shape.contours[i+1]; } @@ -1766,9 +1947,11 @@ Coords(Item item, else if (index != c->num_points) { for (i = index; i < c->num_points; i++) { c->points[i] = c->points[i+1]; + if (c->controls) { + c->controls[i] = c->controls[i+1]; + } } } - CLEAR(cv->flags, REDUCED_BIT); ITEM.Invalidate(item, ZN_COORDS_FLAG); } @@ -1784,32 +1967,96 @@ Coords(Item item, * ********************************************************************************** */ -#ifdef GPC static int Contour(Item item, int cmd, + int index, ZnPoly *poly) { CurveItem cv = (CurveItem) item; - ZnPoly rpoly; + int i, num_contours; switch (cmd) { - case GPC_DIFF: - case GPC_INT: - case GPC_UNION: - case GPC_XOR: - POLY_INIT(&rpoly); - gpc_polygon_clip(cmd, (gpc_polygon *) &cv->shape, (gpc_polygon *) poly, - (gpc_polygon *) &rpoly); - - POLY_SET(&cv->shape, &rpoly); - + case ZN_CONTOUR_ADD: + if (index < 0) { + index += cv->shape.num_contours; + } + if (index > cv->shape.num_contours) { + index = cv->shape.num_contours; + } + if (index < 0) { + contour_err: + Tcl_AppendResult(item->wi->interp, " contour index out of range", NULL); + return ZN_ERROR; + } + num_contours = cv->shape.num_contours + poly->num_contours; + if (cv->shape.contours == &cv->shape.contour1) { + cv->shape.contours = ZnMalloc(num_contours*sizeof(ZnContour)); + cv->shape.contours[0].num_points = cv->shape.contour1.num_points; + cv->shape.contours[0].cw = cv->shape.contour1.cw; + cv->shape.contours[0].points = cv->shape.contour1.points; + cv->shape.contours[0].controls = cv->shape.contour1.controls; + } + else { + cv->shape.contours = ZnRealloc(cv->shape.contours, num_contours*sizeof(ZnContour)); + /*printf("Reallocating shape contours (%d) 0x%X\n", num_contours, cv->shape.contours);*/ + } + /* + * Make a hole if needed. + */ + /*printf("index : %d, i : %d\n", index, cv->shape.num_contours-1);*/ + for (i = cv->shape.num_contours-1; i >= index; i--) { + cv->shape.contours[i+poly->num_contours] = cv->shape.contours[i]; + } + for (i = 0; i < poly->num_contours; i++, index++) { + cv->shape.contours[index].num_points = poly->contours[i].num_points; + cv->shape.contours[index].cw = poly->contours[i].cw; + cv->shape.contours[index].points = ZnMalloc(poly->contours[i].num_points * sizeof(ZnPoint)); + memcpy(cv->shape.contours[index].points, poly->contours[i].points, + poly->contours[i].num_points * sizeof(ZnPoint)); + cv->shape.contours[index].controls = NULL; + if (poly->contours[i].controls) { + /* + * The controls array in poly is shared, duplicate it + * to keep a locally owned copy. + */ + cv->shape.contours[index].controls = ZnMalloc(poly->contours[i].num_points * sizeof(char)); + memcpy(cv->shape.contours[index].controls, poly->contours[i].controls, + poly->contours[i].num_points * sizeof(char)); + } + } + cv->shape.num_contours = num_contours; ITEM.Invalidate(item, ZN_COORDS_FLAG); + break; + case ZN_CONTOUR_REMOVE: + if (index < 0) { + index += cv->shape.num_contours; + } + if (index >= cv->shape.num_contours) { + index = cv->shape.num_contours - 1; + } + if (index < 0) { + goto contour_err; + } + cv->shape.num_contours--; + if (cv->shape.num_contours == 0) { + POLY_FREE(&cv->shape); + } + else { + ZnFree(cv->shape.contours[index].points); + if (cv->shape.contours[index].controls) { + ZnFree(cv->shape.contours[index].controls); + } + for (i = index; i < cv->shape.num_contours; i++) { + cv->shape.contours[i] = cv->shape.contours[i+1]; + } + } + ITEM.Invalidate(item, ZN_COORDS_FLAG); + break; } return cv->shape.num_contours; } -#endif /* @@ -1831,22 +2078,31 @@ PickVertex(Item item, { CurveItem cv = (CurveItem) item; int i, j, k, num_points; - ZnPoint *points; + ZnPoint *points, po; ZnReal dist=1.0e40, new_dist, dist2; - + ZnTransfo t, inv; + *contour = *vertex = *o_vertex = -1; if ((cv->line_width > 0) || ISSET(cv->flags, FILLED_OK) || ISSET(cv->flags, MARKER_OK)) { + + /* + * Get the point in the item coordinate space. + */ + ITEM.GetItemTransform(item, &t); + ZnTransfoInvert(&t, &inv); + ZnTransformPoint(&inv, p, &po); + /* * Check all contours. */ - for (i = 0; i < cv->dev_shape.num_contours; i++) { - points = cv->dev_shape.contours[i].points; - num_points = cv->dev_shape.contours[i].num_points; + for (i = 0; i < cv->shape.num_contours; i++) { + points = cv->shape.contours[i].points; + num_points = cv->shape.contours[i].num_points; for (j = 0; j < num_points; j++) { - new_dist = hypot(points[j].x - p->x, points[j].y - p->y); + new_dist = hypot(points[j].x - po.x, points[j].y - po.y); if (new_dist < dist) { dist = new_dist; *contour = i; @@ -1859,9 +2115,9 @@ PickVertex(Item item, */ if (i == *contour) { j = (*vertex+1) % num_points; - new_dist = LineToPointDist(&points[*vertex], &points[j], p); + new_dist = LineToPointDist(&points[*vertex], &points[j], &po); k = ((unsigned)(*vertex-1)) % num_points; - dist2 = LineToPointDist(&points[*vertex], &points[k], p); + dist2 = LineToPointDist(&points[*vertex], &points[k], &po); if (dist2 < new_dist) { *o_vertex = k; } @@ -1903,11 +2159,7 @@ static ItemClassStruct CURVE_ITEM_CLASS = { NULL, /* Index */ NULL, /* Part */ NULL, /* Selection */ -#ifdef GPC Contour, -#else - NULL, -#endif ComputeCoordinates, ToArea, Draw, -- cgit v1.1