aboutsummaryrefslogtreecommitdiff
path: root/generic/Curve.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/Curve.c')
-rw-r--r--generic/Curve.c997
1 files changed, 581 insertions, 416 deletions
diff --git a/generic/Curve.c b/generic/Curve.c
index 0c6704d..38faabb 100644
--- a/generic/Curve.c
+++ b/generic/Curve.c
@@ -34,6 +34,7 @@
#include "WidgetInfo.h"
#include "Image.h"
#include "Color.h"
+#include "gpc/gpc.h"
#include <ctype.h>
#include <malloc.h>
@@ -48,17 +49,13 @@ static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ "
*/
#define FILLED_BIT 1<<0 /* If the item is filled with color/pattern */
#define MARKED_BIT 1<<1 /* If the vertices are marked by a symbol */
-#define SMOOTHED_BIT 1<<2 /* If we `smooth' the path with Bezier curves */
-#define BEZIER_BIT 1<<3 /* If we interpret the vertices as Bezier controls. */
-
-#define CCW 1<<5 /* Tell if the vertices are described in
- * clockwise or ccw order. */
+#define CLOSED_BIT 1<<2 /* If the outline should be closed automatically */
+#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
-#define SMOOTHED_OK 1<<9
#define RELIEF_OK 1<<10
-#define BEZIER_OK 1<<11
#define MARKER_OK 1<<12
@@ -73,7 +70,7 @@ typedef struct _CurveItemStruct {
ItemStruct header;
/* Public data */
- ZnList points;
+ ZnPoly shape;
unsigned int flags;
Pixmap marker;
ZnLineEnd first_end; /* These two are considered only if relief is flat */
@@ -93,22 +90,17 @@ typedef struct _CurveItemStruct {
/* Private data */
ZnImage tile;
- ZnList dev_points;
+ ZnPoly dev_shape;
ZnColorGradient gradient;
+ gpc_tristrip tristrip;
} CurveItemStruct, *CurveItem;
-/*
- * Need ZN_COORDS_FLAG in -smoothed and -bezier because
- * -relief may need a reversing of vertices and this is done
- * lazily.
- */
static ZnAttrConfig cv_attrs[] = {
- { ZN_CONFIG_BOOL, "-bezier", NULL,
- Tk_Offset(CurveItemStruct, flags), BEZIER_BIT,
- ZN_COORDS_FLAG, False },
{ ZN_CONFIG_CAP_STYLE, "-capstyle", NULL,
Tk_Offset(CurveItemStruct, cap_style), 0,
ZN_COORDS_FLAG, False },
+ { ZN_CONFIG_BOOL, "-closed", NULL,
+ Tk_Offset(CurveItemStruct, flags), CLOSED_BIT, ZN_COORDS_FLAG, False },
{ ZN_CONFIG_BOOL, "-composerotation", NULL,
Tk_Offset(CurveItemStruct, header.flags), COMPOSE_ROTATION_BIT,
ZN_COORDS_FLAG, False },
@@ -152,9 +144,6 @@ static ZnAttrConfig cv_attrs[] = {
{ ZN_CONFIG_BOOL, "-sensitive", NULL,
Tk_Offset(CurveItemStruct, header.flags), SENSITIVE_BIT,
ZN_REPICK_FLAG, False },
- { ZN_CONFIG_BOOL, "-smoothed", NULL,
- Tk_Offset(CurveItemStruct, flags), SMOOTHED_BIT,
- ZN_COORDS_FLAG, False },
{ ZN_CONFIG_TAGS, "-tags", NULL,
Tk_Offset(CurveItemStruct, header.tags), 0, 0, False },
{ ZN_CONFIG_IMAGE, "-tile", NULL,
@@ -207,12 +196,14 @@ Init(Item item,
CurveItem cv = (CurveItem) item;
Arg *elems;
int i, result, num_elems;
- ZnPoint p;
+ ZnPoint *p, *points;
+ double dbl;
#ifdef PTK
LangFreeProc *freeProc = NULL;
#endif
- cv->dev_points = NULL;
+ POLY_INIT(&cv->dev_shape);
+ cv->tristrip.num_strips = 0;
cv->gradient = NULL;
/* Init attributes */
@@ -220,7 +211,10 @@ Init(Item item,
SET(item->flags, SENSITIVE_BIT);
SET(item->flags, COMPOSE_ROTATION_BIT);
SET(item->flags, COMPOSE_SCALE_BIT);
- item->priority = DEFAULT_MULTI_POINT_PRIORITY;
+ SET(item->flags, CLOSED_BIT);
+ SET(item->flags, REDUCED_BIT);
+
+ item->priority = DEFAULT_CURVE_PRIORITY;
if (*argc < 1) {
Tcl_AppendResult(wi->interp, " curve coords expected", NULL);
@@ -238,21 +232,27 @@ Init(Item item,
return ZN_ERROR;
}
- cv->points = ZnListNew(num_elems/2, sizeof(ZnPoint));
- for (i = 0; i < num_elems; i += 2) {
- if (Tcl_GetDouble(wi->interp, elems[i], &p.x) == ZN_ERROR) {
- cv_error2:
+ if (num_elems == 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_GetDouble(wi->interp, elems[i], &dbl) == ZN_ERROR) {
+ cv_error2:
#ifndef PTK
- Tcl_Free((char *) elems);
+ Tcl_Free((char *) elems);
#endif
- ZnListFree(cv->points);
- cv->points = NULL;
- goto cv_error;
- }
- if (Tcl_GetDouble(wi->interp, elems[i+1], &p.y) == ZN_ERROR) {
- goto cv_error2;
+ POLY_FREE(&cv->shape);
+ goto cv_error;
+ }
+ p->x = dbl;
+ if (Tcl_GetDouble(wi->interp, elems[i+1], &dbl) == ZN_ERROR) {
+ goto cv_error2;
+ }
+ p->y = dbl;
}
- ZnListAdd(cv->points, &p, ZnListTail);
}
(*args)++;
(*argc)--;
@@ -265,8 +265,6 @@ Init(Item item,
#endif
CLEAR(cv->flags, FILLED_BIT);
- CLEAR(cv->flags, SMOOTHED_BIT);
- CLEAR(cv->flags, BEZIER_BIT);
cv->first_end = NULL;
cv->last_end = NULL;
cv->line_style = LINE_SIMPLE;
@@ -308,15 +306,35 @@ Clone(Item item)
CurveItem cv = (CurveItem) item;
WidgetInfo *wi = item->wi;
char *text;
+ int i;
+ ZnContour *conts;
+ ZnBool *holes;
+
+ POLY_INIT(&cv->dev_shape);
+
+ 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));
+ memcpy(cv->shape.contours[i].points, conts[i].points,
+ conts[i].num_points*sizeof(ZnPoint));
+ }
+ }
- cv->dev_points = NULL;
-
if (cv->gradient) {
cv->gradient = ZnGetColorGradientByValue(cv->gradient);
}
- if (cv->points) {
- cv->points = ZnListDuplicate(cv->points);
- }
if (cv->line_pattern != ZnUnspecifiedPattern) {
cv->line_pattern = Tk_GetBitmap(wi->interp, wi->win,
Tk_NameOfBitmap(wi->dpy, cv->line_pattern));
@@ -363,13 +381,10 @@ Destroy(Item item)
{
WidgetInfo *wi = item->wi;
CurveItem cv = (CurveItem) item;
+
+ POLY_FREE(&cv->shape);
+ POLY_FREE(&cv->dev_shape);
- if (cv->points) {
- ZnListFree(cv->points);
- }
- if (cv->dev_points) {
- ZnListFree(cv->dev_points);
- }
if (cv->first_end) {
LineEndDelete(cv->first_end);
}
@@ -416,35 +431,30 @@ static void
SetRenderFlags(CurveItem cv)
{
ASSIGN(cv->flags, FILLED_OK,
- ISSET(cv->flags, FILLED_BIT) && (ZnListSize(cv->points) > 2));
-
- ASSIGN(cv->flags, BEZIER_OK,
- ISSET(cv->flags, BEZIER_BIT) && (ZnListSize(cv->points) > 2) &&
- (ISSET(cv->flags, FILLED_BIT) || cv->line_width));
-
- ASSIGN(cv->flags, SMOOTHED_OK,
- ISSET(cv->flags, SMOOTHED_BIT) && (ZnListSize(cv->points) > 2) &&
- ISCLEAR(cv->flags, BEZIER_OK) &&
- (ISSET(cv->flags, FILLED_BIT) || cv->line_width));
+ ISSET(cv->flags, FILLED_BIT) && (cv->shape.num_contours >= 1));
ASSIGN(cv->flags, RELIEF_OK,
- (cv->relief != RELIEF_FLAT) && (ZnListSize(cv->points) > 1) &&
- (cv->line_width > 1)/* && ISCLEAR(cv->flags, SMOOTHED_OK) &&
- ISCLEAR(cv->flags, BEZIER_OK)*/);
+ (cv->relief != RELIEF_FLAT) &&
+ (cv->shape.num_contours >= 1) &&
+ (cv->line_width > 1));
ASSIGN(cv->flags, MARKER_OK,
- (cv->marker != ZnUnspecifiedPattern) && ISCLEAR(cv->flags, BEZIER_OK) &&
- ISCLEAR(cv->flags, SMOOTHED_OK) && ISCLEAR(cv->flags, RELIEF_OK));
+ (cv->marker != ZnUnspecifiedPattern) &&
+ ISCLEAR(cv->flags, RELIEF_OK));
ASSIGN(cv->flags, FIRST_END_OK,
- (cv->first_end != NULL) && (ZnListSize(cv->points) > 1) &&
+ (cv->first_end != NULL) &&
+ (cv->shape.num_contours == 1) && (cv->shape.contours[0].num_points > 1) &&
ISCLEAR(cv->flags, FILLED_BIT) && cv->line_width &&
- ISCLEAR(cv->flags, RELIEF_OK));
+ ISCLEAR(cv->flags, RELIEF_OK) &&
+ ISCLEAR(cv->flags, CLOSED_BIT));
ASSIGN(cv->flags, LAST_END_OK,
- (cv->last_end != NULL) && (ZnListSize(cv->points) > 1) &&
+ (cv->last_end != NULL) &&
+ (cv->shape.num_contours == 1) && (cv->shape.contours[0].num_points > 1) &&
ISCLEAR(cv->flags, FILLED_BIT) && cv->line_width &&
- ISCLEAR(cv->flags, RELIEF_OK));
+ ISCLEAR(cv->flags, RELIEF_OK) &&
+ ISCLEAR(cv->flags, CLOSED_BIT));
}
@@ -499,8 +509,6 @@ Configure(Item item,
cv->tile = tile;
}
- SetRenderFlags(cv);
-
return status;
}
@@ -556,6 +564,8 @@ TestCCW(ZnPoint *points,
* 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) +
@@ -566,6 +576,30 @@ TestCCW(ZnPoint *points,
/*
+ * Create a reduced polygon from an unknown one by
+ * adding/clipping all the shapes/holes in turn.
+ */
+static void
+ReduceContours(ZnPoly *poly_in,
+ ZnPoly *poly_out)
+{
+ 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);
+ }
+}
+
+
+/*
**********************************************************************************
*
* ComputeCoordinates --
@@ -579,90 +613,124 @@ ComputeCoordinates(Item item,
WidgetInfo *wi = item->wi;
CurveItem cv = (CurveItem) item;
int i, j;
- ZnPoint *points;
ZnPoint end_points[LINE_END_POINTS];
- ZnPoint *dev_points, *p;
- int num_points;
+ ZnPoint *points;
+ int num_points, num_contours;
ZnBBox bbox;
int lw;
+ ZnContour *c1, *c2;
+ ZnBool *holes, *cw;
ResetBBox(&item->item_bounding_box);
- if (cv->points == NULL) {
- return;
- }
- points = (ZnPoint *) ZnListArray(cv->points);
- num_points = ZnListSize(cv->points);
+ SetRenderFlags(cv);
/*
- * Allocate space for devices coordinates
+ * Try to reduce the contours if needed. This can be
+ * switched off and replaced by an explicit reduction.
*/
- if (cv->dev_points == NULL) {
- cv->dev_points = ZnListNew(num_points, sizeof(ZnPoint));
+ if (cv->shape.num_contours == 1) {
+ SET(cv->flags, REDUCED_BIT);
+ }
+ else if (ISCLEAR(cv->flags, REDUCED_BIT)) {
+ ZnPoly poly;
+ printf("Contour reduction\n");
+ ReduceContours(&cv->shape, &poly);
+ POLY_SET(&cv->shape, &poly);
+ SET(cv->flags, REDUCED_BIT);
+ }
+
+ num_contours = cv->shape.num_contours;
+ if (num_contours == 0) {
+ return;
}
- ZnListAssertSize(cv->dev_points, num_points);
- dev_points = (ZnPoint *) ZnListArray(cv->dev_points);
+ if (cv->tristrip.num_strips) {
+ gpc_free_tristrip(&cv->tristrip);
+ }
+
/*
- * Process all points, skipping adjacent points that transform
- * to the same device location.
+ * Allocate space for devices coordinates, the holes array is _NOT_
+ * duplicated.
*/
- for (i = 0, j = 0; i < num_points; i++, j++) {
- /* Compute device coordinates.
- * Identical vertices are no longer skipped to allow a better control
- * on Bezier curves and smoothing.
- */
- ZnTransformPoint(wi->current_transfo, &points[i], &dev_points[j]);
+ POLY_FREE(&cv->dev_shape);
+ if (cv->shape.contours != &cv->shape.contour1) {
+ cv->dev_shape.contours = (ZnContour *) ZnMalloc(num_contours*sizeof(ZnContour));
+ }
+ else {
+ cv->dev_shape.contours = &cv->dev_shape.contour1;
+ cv->dev_shape.cw = &cv->dev_shape.cw1;
+ }
+ 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++) {
/*
- if ((j == 0) || (dev_points[j].x != dev_points[j-1].x) ||
- (dev_points[j].y != dev_points[j-1].y)) {
- j++;
+ * Drop the last point of a contour if it is the same as
+ * the first.
+ */
+ if ((c1->points[0].x == c1->points[c1->num_points-1].x) &&
+ (c1->points[0].y == c1->points[c1->num_points-1].y)) {
+ c1->num_points--;
}
- */
+ c2->num_points = c1->num_points;
+ /*
+ * The device array is always one point larger to accomodate
+ * the outline end point when CLOSED is specified.
+ */
+ c2->points = (ZnPoint *) ZnMalloc((c1->num_points+1)*sizeof(ZnPoint));
+ /*printf("CC: \"%d\" num_points %d\n", item->id, c1->num_points);*/
}
/*
- * Adjust the device coords list to the actual size.
+ * Process all points, transforming coordinates.
*/
- ZnListTruncate(cv->dev_points, j);
- /*printf("==========num_points %d=============\n", ZnListSize(cv->dev_points));*/
+ 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);
+ if (ISSET(cv->flags, CLOSED_BIT)) {
+ c2->points[c2->num_points] = c2->points[0];
+ }
+ }
lw = cv->line_width;
- ASSIGN(cv->flags, CCW, TestCCW(dev_points, num_points));
- if (ISCLEAR(cv->flags, CCW)) {
- if (ISSET(cv->flags, RELIEF_OK)) {
- ZnPoint tmp;
- int mid = num_points/2;
+ 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;
+ }
/*
- * Revert the points to draw the relief inside.
+ * Add to bounding box.
*/
- for (i = 0; i < mid; i++) {
- tmp = dev_points[i];
- dev_points[i] = dev_points[num_points-i-1];
- dev_points[num_points-i-1] = tmp;
- }
+ GetPolygonReliefBBox(points, num_points, (*cw ^ *holes)?-lw:lw, &bbox);
+ AddBBoxToBBox(&item->item_bounding_box, &bbox);
}
- }
-
- /*
- * Add to bounding box.
- */
- if (ISSET(cv->flags, RELIEF_OK)) {
- GetPolygonReliefBBox(cv->dev_points, lw, &bbox);
- AddBBoxToBBox(&item->item_bounding_box, &bbox);
return;
}
- for (i = 0; i < j; i++) {
- AddPointToBBox(&item->item_bounding_box, dev_points[i].x, dev_points[i].y);
+ 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);
+ }
}
/*
* 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.
+ * but is simple.
*/
item->item_bounding_box.orig.x -= lw;
item->item_bounding_box.orig.y -= lw;
@@ -670,48 +738,55 @@ ComputeCoordinates(Item item,
item->item_bounding_box.corner.y += lw;
/*
- * Take care of miters.
+ * Take care of miters, markers and arrows.
*/
- if (cv->join_style == JoinMiter) {
- ZnPoint miter_i, miter_o;
- for (i = j, p = dev_points; i >= 3; i--, p++) {
- GetMiterPoints(p, p+1, p+2, lw, &miter_i, &miter_o);
- AddPointToBBox(&item->item_bounding_box, miter_i.x, miter_i.y);
- AddPointToBBox(&item->item_bounding_box, miter_o.x, miter_o.y);
+ holes = cv->shape.holes;
+ c2 = cv->dev_shape.contours;
+ for (j = 0; j < num_contours; j++, c2++, holes++) {
+ if (*holes) {
+ continue;
}
- }
-
- /*
- * Add the markers.
- */
- if (ISSET(cv->flags, MARKER_OK)) {
- int w, h;
- ZnBBox bbox;
-
- Tk_SizeOfBitmap(wi->dpy, cv->marker, &w, &h);
- w = w/2 + 2;
- h = w/2 + 2;
- for (i = 0; i < j; i++) {
- bbox.orig.x = dev_points[i].x - w;
- bbox.orig.y = dev_points[i].y - h;
- bbox.corner.x = dev_points[i].x + w;
- bbox.corner.y = dev_points[i].y + h;
- AddBBoxToBBox(&item->item_bounding_box, &bbox);
+ if (cv->join_style == JoinMiter) {
+ ZnPoint miter_i, miter_o;
+ for (i = c2->num_points-1, points = c2->points; i >= 3; i--, points++) {
+ GetMiterPoints(points, points+1, points+2, lw, &miter_i, &miter_o);
+ AddPointToBBox(&item->item_bounding_box, miter_i.x, miter_i.y);
+ AddPointToBBox(&item->item_bounding_box, miter_o.x, miter_o.y);
+ }
+ }
+ /*
+ * Add the markers.
+ */
+ if (ISSET(cv->flags, MARKER_OK)) {
+ int w, h;
+ ZnBBox bbox;
+ Tk_SizeOfBitmap(wi->dpy, cv->marker, &w, &h);
+ w = w/2 + 2;
+ h = w/2 + 2;
+ num_points = c2->num_points;
+ for (i = 0, points = c2->points; i < num_points; i++, points++) {
+ bbox.orig.x = points->x - w;
+ bbox.orig.y = points->y - h;
+ bbox.corner.x = points->x + w;
+ bbox.corner.y = points->y + h;
+ AddBBoxToBBox(&item->item_bounding_box, &bbox);
+ }
+ }
+ /*
+ * Process arrows.
+ */
+ num_points = c2->num_points;
+ points = c2->points;
+ if (ISSET(cv->flags, FIRST_END_OK)) {
+ GetLineEnd(&points[0], &points[1], lw, cv->cap_style,
+ cv->first_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
+ }
+ if (ISSET(cv->flags, LAST_END_OK)) {
+ GetLineEnd(&points[num_points-1], &points[num_points-2],
+ lw, cv->cap_style, cv->last_end, end_points);
+ AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
}
- }
-
- /*
- * Process arrows.
- */
- if (ISSET(cv->flags, FIRST_END_OK)) {
- GetLineEnd(&dev_points[0], &dev_points[1], lw, cv->cap_style,
- cv->first_end, end_points);
- AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
- }
- if (ISSET(cv->flags, LAST_END_OK)) {
- GetLineEnd(&dev_points[j-1], &dev_points[j-2], lw, cv->cap_style,
- cv->last_end, end_points);
- AddPointsToBBox(&item->item_bounding_box, end_points, LINE_END_POINTS);
}
/*
@@ -747,88 +822,115 @@ ToArea(Item item,
ZnBBox bbox;
ZnPoint *points;
ZnPoint end_points[LINE_END_POINTS];
- int num_points, result, result2;
- ZnList actual_points;
+ int i, num_points, result, result2;
+ int width, height;
+ ZnBool first_done = False;
- if (cv->dev_points == NULL) {
+ if (cv->dev_shape.num_contours == 0) {
return -1;
}
/*printf("============== poly %d ==============\n", item->id);*/
- if (ISSET(cv->flags, SMOOTHED_OK)) {
- SmoothPathWithBezier(cv->dev_points, wi->work_pts);
- actual_points = wi->work_pts;
- }
- else if (ISSET(cv->flags, BEZIER_OK)) {
- GetBezierPath(cv->dev_points, wi->work_pts);
- actual_points = wi->work_pts;
- }
- else {
- actual_points = cv->dev_points;
- }
-
- points = (ZnPoint *) ZnListArray(actual_points);
- num_points = ZnListSize(actual_points);
if (ISSET(cv->flags, FILLED_OK)) {
- result = PolygonInBBox(points, num_points, area);
- if (result == 0) {
- return 0;
+ 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;
+ }
+ }
+ 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;
+ }
+ if (result2 != result) {
+ return 0;
+ }
+ }
}
}
if (cv->line_width > 0) {
- if (ISCLEAR(cv->flags, RELIEF_OK)) {
- result2 = PolylineInBBox(points, num_points, cv->line_width,
- cv->cap_style, cv->join_style, area);
- }
- else {
- result2 = PolygonReliefInBBox(actual_points, cv->line_width, area);
- }
- if (ISCLEAR(cv->flags, FILLED_OK)) {
- if (result2 == 0) {
- return 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;
+ if (!first_done) {
+ first_done = True;
+ if (ISCLEAR(cv->flags, RELIEF_OK)) {
+ result = PolylineInBBox(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ cv->line_width, cv->cap_style, cv->join_style, area);
+ }
+ else {
+ result = PolygonReliefInBBox(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, area);
+ }
+ if (result == 0) {
+ return 0;
+ }
+ }
+ else {
+ if (ISCLEAR(cv->flags, RELIEF_OK)) {
+ result2 = PolylineInBBox(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ cv->line_width, cv->cap_style, cv->join_style, area);
+ }
+ else {
+ result2 = PolygonReliefInBBox(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, area);
+ }
+ if (result2 != result) {
+ return 0;
+ }
}
- result = result2;
- }
- else if (result2 != result) {
- return 0;
}
-
+
/*
- * Check line ends.
+ * Check line ends (only on first contour).
*/
+ points = cv->dev_shape.contours[0].points;
+ num_points = cv->dev_shape.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);
- if (PolygonInBBox(end_points, LINE_END_POINTS, area) != result) {
+ if (PolygonInBBox(end_points, LINE_END_POINTS, area, NULL) != result) {
return 0;
}
}
if (ISSET(cv->flags, LAST_END_OK)) {
GetLineEnd(&points[num_points-1], &points[num_points-2], cv->line_width,
cv->cap_style, cv->last_end, end_points);
- if (PolygonInBBox(end_points, LINE_END_POINTS, area) != result) {
+ if (PolygonInBBox(end_points, LINE_END_POINTS, area, NULL) != result) {
return 0;
}
- }
-
- /*
- * Last, check markers
- */
- if (ISSET(cv->flags, MARKER_OK)) {
- int num_points, width, height;
- ZnPoint *points;
-
- points = (ZnPoint *) ZnListArray(actual_points);
- num_points = ZnListSize(actual_points);
+ }
+ }
+
+ /*
+ * 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;
if (ISSET(cv->flags, FIRST_END_OK)) {
num_points--;
points++;
}
- if (ISSET(cv->flags, LAST_END_OK) ||
- ((points[0].x == points[num_points-1].x) &&
- (points[0].y == points[num_points-1].y))) {
+ if (ISSET(cv->flags, LAST_END_OK)) {
num_points--;
}
@@ -862,36 +964,24 @@ Draw(Item item)
WidgetInfo *wi = item->wi;
CurveItem cv = (CurveItem) item;
XGCValues values;
- int i, num_points;
+ int i, j, num_points, num2;
unsigned int gc_mask;
ZnPoint *points;
XPoint *xpoints = NULL;
- if (cv->dev_points == NULL) {
+ if ((cv->dev_shape.num_contours == 0) ||
+ (ISCLEAR(cv->flags, FILLED_OK) &&
+ !cv->line_width &&
+ ISCLEAR(cv->flags, MARKER_OK))) {
return;
}
- if (ISSET(cv->flags, SMOOTHED_OK)) {
- SmoothPathWithBezier(cv->dev_points, wi->work_pts);
- points = (ZnPoint *) ZnListArray(wi->work_pts);
- num_points = ZnListSize(wi->work_pts);
- }
- else if (ISSET(cv->flags, BEZIER_OK)) {
- GetBezierPath(cv->dev_points, wi->work_pts);
- points = (ZnPoint *) ZnListArray(wi->work_pts);
- num_points = ZnListSize(wi->work_pts);
- }
- else {
- points = (ZnPoint *) ZnListArray(cv->dev_points);
- num_points = ZnListSize(cv->dev_points);
- }
-
/*
* Fill if requested.
*/
if (ISSET(cv->flags, FILLED_OK)) {
if (cv->grad_geom) {
- DrawPolygonGradient(wi, cv->grad_geom, cv->fill_color, points, num_points,
+ DrawPolygonGradient(wi, cv->grad_geom, cv->fill_color, &cv->dev_shape,
&item->item_bounding_box);
}
else {
@@ -918,16 +1008,23 @@ Draw(Item item)
}
XChangeGC(wi->dpy, wi->gc, gc_mask, &values);
- if (!xpoints) {
+ if (cv->tristrip.num_strips == 0) {
+ gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, &cv->tristrip);
+ }
+ for (i = 0; i < cv->tristrip.num_strips; i++) {
+ num_points = cv->tristrip.strip[i].num_vertices;
+ points = (ZnPoint *) cv->tristrip.strip[i].vertex;
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);
+ for (j = 0; j < num_points; j++) {
+ xpoints[j].x = REAL_TO_INT(points[j].x);
+ xpoints[j].y = REAL_TO_INT(points[j].y);
+ }
+ for (j = 0; j < num_points-2; j++) {
+ XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc,
+ &xpoints[j], 3, Convex, CoordModeOrigin);
}
}
- XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc,
- xpoints, num_points, Complex, CoordModeOrigin);
}
}
@@ -935,15 +1032,26 @@ Draw(Item item)
* Draw the lines between points
*/
if (cv->line_width) {
- ZnPoint end_points[LINE_END_POINTS];
- XPoint xp[LINE_END_POINTS];
+ ZnPoint end_points[LINE_END_POINTS];
+ XPoint xp[LINE_END_POINTS];
/*
* Drawing with relief disables: ends, line style and line pattern.
*/
if (ISSET(cv->flags, RELIEF_OK)) {
- DrawPolygonRelief(wi, cv->relief, cv->gradient,
- points, num_points, cv->line_width);
+ 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;
+ if (ISSET(cv->flags, CLOSED_BIT)) {
+ num_points++;
+ }
+ /*printf("Draw: num_points %d %g@%g %g@%g, cw %d\n",
+ num_points, points[0].x, points[0].y,
+ points[num_points-1].x, points[num_points-1].y,
+ cv->dev_shape.cw[j]);*/
+ DrawPolygonRelief(wi, cv->relief, cv->gradient, points, num_points,
+ (cv->dev_shape.cw[j]^cv->shape.holes[j])?-cv->line_width:cv->line_width);
+ }
}
else {
SetLineStyle(wi->dpy, wi->gc, cv->line_style);
@@ -963,17 +1071,24 @@ Draw(Item item)
GCFillStyle|GCStipple|GCLineWidth|GCJoinStyle|GCCapStyle|GCForeground,
&values);
}
- if (!xpoints) {
+ 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;
+ if (ISSET(cv->flags, CLOSED_BIT)) {
+ num_points++;
+ }
ZnListAssertSize(wi->work_xpts, num_points);
xpoints = (XPoint *) ZnListArray(wi->work_xpts);
- for (i = 0; i < num_points; i++) {
+ for (i = 0; i < num2; i++) {
xpoints[i].x = REAL_TO_INT(points[i].x);
xpoints[i].y = REAL_TO_INT(points[i].y);
}
+ if (ISSET(cv->flags, CLOSED_BIT)) {
+ xpoints[num2] = xpoints[0];
+ }
+ XDrawLines(wi->dpy, wi->draw_buffer, wi->gc,
+ xpoints, num_points, CoordModeOrigin);
}
- XDrawLines(wi->dpy, wi->draw_buffer, wi->gc,
- xpoints, num_points, CoordModeOrigin);
-
if (ISSET(cv->flags, FIRST_END_OK)) {
GetLineEnd(&points[0], &points[1], cv->line_width, cv->cap_style,
cv->first_end, end_points);
@@ -998,66 +1113,47 @@ Draw(Item item)
}
/*
- * Draw the marks at each point. Smoothed line or relief disable this.
- * If ends are specified or if last point join first point suppress
- * markers as needed.
+ * Draw the marks at each point. If arrows are specified or
+ * if last point join first point suppress markers at end points.
*/
if (ISSET(cv->flags, MARKER_OK)) {
- int width, h_width, height, h_height;
- ZnPoint ptmp, *p;
- int i;
-
- i = num_points;
- p = points;
- if (ISSET(cv->flags, FIRST_END_OK)) {
- i--;
- p++;
- }
- if (ISSET(cv->flags, LAST_END_OK) ||
- ((p[0].x == p[num_points-1].x) &&
- (p[0].y == p[num_points-1].y))) {
- i--;
- }
-
- values.foreground = ZnPixel(cv->marker_color);
+ int width, h_width, height, h_height;
+ ZnPoint ptmp;
+
Tk_SizeOfBitmap(wi->dpy, cv->marker, &width, &height);
h_width = (width+1)/2;
h_height = (height+1)/2;
values.fill_style = FillStippled;
values.stipple = cv->marker;
- for (; i > 0; i--, p++) {
- ptmp.x = p->x - h_width;
- ptmp.y = p->y - h_height;
- values.ts_x_origin = ptmp.x;
- values.ts_y_origin = ptmp.y;
- XChangeGC(wi->dpy, wi->gc,
- GCFillStyle|GCStipple|GCTileStipXOrigin|GCTileStipYOrigin|GCForeground,
- &values);
- XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, ptmp.x, ptmp.y,
- width, height);
- }
- }
-
- /*
- * If nothing useful is requested then why have you
- * created this item ? Try to do something useful, we
- * guess that drawing points is useful.
- */
- if (ISCLEAR(cv->flags, FILLED_OK) && !cv->line_width &&
- (cv->marker == ZnUnspecifiedPattern)) {
values.foreground = ZnPixel(cv->marker_color);
- values.fill_style = FillSolid;
- XChangeGC(wi->dpy, wi->gc, GCForeground | GCFillStyle, &values);
-
- if (!xpoints) {
+ 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;
ZnListAssertSize(wi->work_xpts, num_points);
xpoints = (XPoint *) ZnListArray(wi->work_xpts);
for (i = 0; i < num_points; i++) {
- xpoints[i].x = points[i].x;
- xpoints[i].y = points[i].y;
+ xpoints[i].x = REAL_TO_INT(points[i].x);
+ xpoints[i].y = REAL_TO_INT(points[i].y);
+ }
+ if (ISSET(cv->flags, FIRST_END_OK)) {
+ num_points--;
+ points++;
+ }
+ if (ISSET(cv->flags, LAST_END_OK)) {
+ num_points--;
+ }
+ for (; num_points > 0; num_points--, points++) {
+ ptmp.x = points->x - h_width;
+ ptmp.y = points->y - h_height;
+ values.ts_x_origin = ptmp.x;
+ values.ts_y_origin = ptmp.y;
+ XChangeGC(wi->dpy, wi->gc,
+ GCTileStipXOrigin|GCTileStipYOrigin|GCForeground, &values);
+ XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, ptmp.x, ptmp.y,
+ width, height);
}
}
- XDrawPoints(wi->dpy, wi->draw_buffer, wi->gc, xpoints, num_points, CoordModeOrigin);
}
}
@@ -1100,58 +1196,88 @@ Pick(Item item,
ZnPoint *points;
ZnPoint end_points[LINE_END_POINTS];
int num_points;
- ZnList actual_points;
-
- if (cv->dev_points == NULL) {
+ int width, height;
+ int i;
+
+ if (cv->dev_shape.num_contours == 0) {
return dist;
}
/*printf("Pick in curve\n");*/
- if (ISSET(cv->flags, SMOOTHED_OK)) {
- SmoothPathWithBezier(cv->dev_points, wi->work_pts);
- actual_points = wi->work_pts;
- }
- else if (ISSET(cv->flags, BEZIER_OK)) {
- GetBezierPath(cv->dev_points, wi->work_pts);
- actual_points = wi->work_pts;
- }
- else {
- actual_points = cv->dev_points;
- }
-
- points = (ZnPoint *) ZnListArray(actual_points);
- num_points = ZnListSize(actual_points);
-
if (ISSET(cv->flags, FILLED_OK)) {
- dist = PolygonToPointDist(points, num_points, p);
- if (dist <= 0.0) {
+ double hole_dist=1.0e40, new_hole_dist;
+ /*
+ * 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);
+ 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);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ }
+ }
+ if ((dist <= 0.0) && (hole_dist >= 0.0)) {
return 0.0;
}
+ if (hole_dist < 0.0) {
+ hole_dist = -hole_dist;
+ }
+ if (dist <= 0.0) {
+ dist = hole_dist;
+ }
+ else if (hole_dist < dist) {
+ dist = hole_dist;
+ }
}
if (cv->line_width > 0) {
- if (ISCLEAR(cv->flags, RELIEF_OK)) {
- new_dist = PolylineToPointDist(points, num_points, cv->line_width,
- cv->cap_style, cv->join_style, p);
- if (new_dist < dist) {
- dist = new_dist;
- }
- if (dist <= 0.0) {
- return 0.0;
- }
- }
- else {
- new_dist = PolygonReliefToPointDist(actual_points, cv->line_width, p);
- if (new_dist < dist) {
- dist = new_dist;
+ /*
+ * 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;
+ if (ISCLEAR(cv->flags, RELIEF_OK)) {
+ new_dist = PolylineToPointDist(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ cv->line_width, cv->cap_style, cv->join_style, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
}
- if (dist <= 0.0) {
- return 0.0;
+ else {
+ new_dist = PolygonReliefToPointDist(points,
+ ISSET(cv->flags, CLOSED_BIT)?num_points+1:num_points,
+ (cv->dev_shape.cw[0]^cv->shape.holes[0])?-cv->line_width:cv->line_width, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
}
}
}
/*
+ * 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;
+ /*
* Check line ends.
*/
if (ISSET(cv->flags, FIRST_END_OK)) {
@@ -1178,37 +1304,34 @@ Pick(Item item,
}
/*
- * Last, check markers
+ * Last, check markers on all contours.
*/
if (ISSET(cv->flags, MARKER_OK)) {
- int num_points, width, height;
- ZnPoint *points;
-
- points = (ZnPoint *) ZnListArray(actual_points);
- num_points = ZnListSize(actual_points);
-
- if (ISSET(cv->flags, FIRST_END_OK)) {
- num_points--;
- points++;
- }
- if (ISSET(cv->flags, LAST_END_OK) ||
- ((points[0].x == points[num_points-1].x) &&
- (points[0].y == points[num_points-1].y))) {
- num_points--;
- }
-
- Tk_SizeOfBitmap(wi->dpy, cv->marker, &width, &height);
- for (; num_points > 0; num_points--, points++) {
- bbox.orig.x = points->x - (width+1)/2;
- bbox.orig.y = points->y - (height+1)/2;
- bbox.corner.x = bbox.orig.x + width;
- bbox.corner.y = bbox.orig.y + height;
- new_dist = RectangleToPointDist(&bbox, p);
- if (new_dist < dist) {
- dist = new_dist;
+ 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;
+
+ if (ISSET(cv->flags, FIRST_END_OK)) {
+ num_points--;
+ points++;
}
- if (dist <= 0.0) {
- return 0.0;
+ if (ISSET(cv->flags, LAST_END_OK)) {
+ num_points--;
+ }
+
+ Tk_SizeOfBitmap(wi->dpy, cv->marker, &width, &height);
+ for (; num_points > 0; num_points--, points++) {
+ bbox.orig.x = points->x - (width+1)/2;
+ bbox.orig.y = points->y - (height+1)/2;
+ bbox.corner.x = bbox.orig.x + width;
+ bbox.corner.y = bbox.orig.y + height;
+ new_dist = RectangleToPointDist(&bbox, p);
+ if (new_dist < dist) {
+ dist = new_dist;
+ }
+ if (dist <= 0.0) {
+ return 0.0;
+ }
}
}
}
@@ -1241,17 +1364,19 @@ PostScript(Item item,
*/
static ZnBool
GetClipVertices(Item item,
- ZnPoint **points,
- int *num_points)
+ ZnPoly *poly)
{
CurveItem cv = (CurveItem) item;
- *points = NULL;
- *num_points = 0;
+ POLY_INIT(poly);
- if (cv->dev_points) {
- *points = (ZnPoint *) ZnListArray(cv->dev_points);
- *num_points = ZnListSize(cv->dev_points);
+ if (cv->dev_shape.num_contours == 1) {
+ POLY_CONTOUR1(poly, cv->dev_shape.contours[0].points,
+ cv->dev_shape.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;
}
return False;
@@ -1268,15 +1393,26 @@ GetClipVertices(Item item,
*/
static int
Coords(Item item,
+ int contour,
int index,
int cmd,
ZnPoint **pts,
int *num_pts)
{
CurveItem cv = (CurveItem) item;
- int num_points, i;
- ZnPoint *points;
+ int i;
+ ZnContour *c;
+ if (contour < 0) {
+ contour += cv->shape.num_contours;
+ }
+ if ((contour < 0) || (contour >= cv->shape.num_contours)) {
+ Tcl_AppendResult(item->wi->interp,
+ " curve contour index out of range", NULL);
+ return ZN_ERROR;
+ }
+ c = &cv->shape.contours[contour];
+
if ((cmd == COORDS_REPLACE) || (cmd == COORDS_REPLACE_ALL)) {
if (*num_pts == 0) {
Tcl_AppendResult(item->wi->interp,
@@ -1284,99 +1420,98 @@ Coords(Item item,
return ZN_ERROR;
}
if (cmd == COORDS_REPLACE_ALL) {
- ZnList tmp;
replace_all:
- tmp = ZnListFromArray(*pts, *num_pts, sizeof(ZnPoint));
- if (!cv->points) {
- ZnListEmpty(cv->points);
+ if (c->points) {
+ ZnFree(c->points);
}
- else {
- cv->points = ZnListNew(*num_pts, sizeof(ZnPoint));
- }
- ZnListAppend(cv->points, tmp);
- ZnListFree(tmp);
+ c->points = (ZnPoint *) ZnMalloc(*num_pts*sizeof(ZnPoint));
+ memcpy(c->points, *pts, *num_pts*sizeof(ZnPoint));
}
else {
- if (!cv->points) {
+ if (c->num_points == 0) {
edit_err:
Tcl_AppendResult(item->wi->interp,
- " coords command cannot edit empty curves", NULL);
+ " coords command cannot edit empty curve contour", NULL);
return ZN_ERROR;
}
- points = ZnListArray(cv->points);
- num_points = ZnListSize(cv->points);
if (index < 0) {
- index += num_points;
+ index += c->num_points;
}
- if ((index < 0) || (index >= num_points)) {
+ if ((index < 0) || (index >= c->num_points)) {
range_err:
Tcl_AppendResult(item->wi->interp, " coord index out of range", NULL);
return ZN_ERROR;
}
- points[index] = (*pts)[0];
+ c->points[index] = (*pts)[0];
}
+ CLEAR(cv->flags, REDUCED_BIT);
ITEM.Invalidate(item, ZN_COORDS_FLAG);
}
else if ((cmd == COORDS_READ) || (cmd == COORDS_READ_ALL)) {
- if (!cv->points) {
+ if (c->num_points == 0) {
*num_pts = 0;
*pts = NULL;
return ZN_OK;
}
- points = ZnListArray(cv->points);
- num_points = ZnListSize(cv->points);
if (cmd == COORDS_READ_ALL) {
- *num_pts = num_points;
- *pts = points;
+ *num_pts = c->num_points;
+ *pts = c->points;
}
else {
if (index < 0) {
- index += num_points;
+ index += c->num_points;
}
- if ((index < 0) || (index >= num_points)) {
+ if ((index < 0) || (index >= c->num_points)) {
goto range_err;
}
*num_pts = 1;
- *pts = &points[index];
+ *pts = &c->points[index];
}
}
else if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST)) {
- if (!cv->points) {
+ if (c->num_points == 0) {
goto replace_all;
}
- else if (cmd == COORDS_ADD) {
- num_points = ZnListSize(cv->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(cv->points, &(*pts)[i], index);
- }
+ if (cmd == COORDS_ADD_LAST) {
+ index = c->num_points;
}
- else {
- ZnList tmp;
- tmp = ZnListFromArray(*pts, *num_pts, sizeof(ZnPoint));
- ZnListAppend(cv->points, tmp);
- ZnListFree(tmp);
+ if (index < 0) {
+ index += c->num_points;
+ }
+ if ((index < 0) || (index > c->num_points)) {
+ goto range_err;
+ }
+ c->points = (ZnPoint *) ZnRealloc(c->points,
+ (c->num_points+*num_pts)*sizeof(ZnPoint));
+ /*
+ * Make a hole if needed.
+ */
+ for (i = c->num_points-1; i >= index; i--) {
+ c->points[i+*num_pts] = c->points[i];
+ }
+ for (i = 0; i < *num_pts; i++, index++) {
+ c->points[index] = (*pts)[i];
}
+ CLEAR(cv->flags, REDUCED_BIT);
ITEM.Invalidate(item, ZN_COORDS_FLAG);
}
else if (cmd == COORDS_REMOVE) {
- if (!cv->points) {
+ if (c->num_points == 0) {
goto edit_err;
}
- points = ZnListArray(cv->points);
- num_points = ZnListSize(cv->points);
if (index < 0) {
- index += num_points;
+ index += c->num_points;
}
- if ((index < 0) || (index >= num_points)) {
+ if ((index < 0) || (index >= c->num_points)) {
goto range_err;
}
- ZnListDelete(cv->points, index);
+ c->num_points--;
+ if (index != c->num_points) {
+ for (i = index; i < c->num_points; i++) {
+ c->points[i] = c->points[i+1];
+ }
+ }
+ CLEAR(cv->flags, REDUCED_BIT);
ITEM.Invalidate(item, ZN_COORDS_FLAG);
}
@@ -1387,15 +1522,43 @@ Coords(Item item,
/*
**********************************************************************************
*
+ * Contour --
+ * Perform geometric operations on curve contours.
+ *
+ **********************************************************************************
+ */
+static void
+Contour(Item item,
+ int cmd,
+ ZnPoly *poly)
+{
+ CurveItem cv = (CurveItem) item;
+ ZnPoly rpoly;
+
+ POLY_INIT(&rpoly);
+ gpc_polygon_clip(cmd, (gpc_polygon *) &cv->shape, (gpc_polygon *) poly,
+ (gpc_polygon *) &rpoly);
+ POLY_SET(&cv->shape, &rpoly);
+ /*printf("cmd %d, num contours %d, num vertices %d\n",
+ cmd,
+ cv->shape.num_contours,
+ cv->shape.contours[0].num_points);*/
+ ITEM.Invalidate(item, ZN_COORDS_FLAG);
+}
+
+
+/*
+ **********************************************************************************
+ *
* Exported functions struct --
*
**********************************************************************************
*/
static ItemClassStruct CURVE_ITEM_CLASS = {
sizeof(CurveItemStruct),
- False,
- False,
- False,
+ False, /* has_fields */
+ False, /* has_parts */
+ False, /* has_anchors */
"curve",
cv_attrs,
Init,
@@ -1403,15 +1566,17 @@ static ItemClassStruct CURVE_ITEM_CLASS = {
Destroy,
Configure,
Query,
- NULL,
- NULL,
+ NULL, /* GetFieldSet */
+ NULL, /* GetAnchor */
GetClipVertices,
Coords,
+ Contour,
ComputeCoordinates,
ToArea,
Draw,
IsSensitive,
Pick,
+ NULL, /* PickVertex */
PostScript
};