summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--doc/canvas.n50
-rw-r--r--generic/tkCanvUtil.c137
-rw-r--r--generic/tkInt.decls15
-rw-r--r--generic/tkTrig.c297
-rw-r--r--tests/canvas.test12
6 files changed, 470 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index 949ccfd..0a1180e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2004-08-19 Donal K. Fellows <donal.k.fellows@man.ac.uk>
+
+ TIP#168 IMPLEMENTATION
+
+ * generic/tkTrig.c (TkMakeRawCurve, TkMakeRawCurvePostscript):
+ * generic/tkInt.decls: New functions to handle the geometry for
+ "raw" bezier curves.
+ * generic/tkCanvUtil.c (tkRawSmoothMethod, InitSmoothMethods)
+ (TkSmoothParseProc): Add new type of smoothing method, simplify
+ the method initialization, and change the old smoothing method to
+ be called "true" and just keep "bezier" as an alias.
+ * tests/canvas.test (canvas-17.1): Basic test of built-in
+ smoothing method support.
+ * doc/canvas.n: Documentation updates.
+
2004-08-18 Donal K. Fellows <donal.k.fellows@man.ac.uk>
* generic/tkPanedWindow.c (optionSpecs): Add missing GEOMETRY flag
diff --git a/doc/canvas.n b/doc/canvas.n
index a9bee5f..7403907 100644
--- a/doc/canvas.n
+++ b/doc/canvas.n
@@ -6,7 +6,7 @@
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
-'\" RCS: @(#) $Id: canvas.n,v 1.15 2004/08/16 08:24:45 dkf Exp $
+'\" RCS: @(#) $Id: canvas.n,v 1.16 2004/08/19 14:41:52 dkf Exp $
'\"
.so man.macros
.TH canvas n 8.3 Tk "Tk Built-In Commands"
@@ -1396,20 +1396,29 @@ irrelevant.
.TP
\fB\-smooth \fIsmoothMethod\fR
\fIsmoothMethod\fR must have one of the forms accepted by
-\fBTk_GetBoolean\fR or a line smoothing method. Only \fBbezier\fR is
-supported in the core, but more can be added at runtime. If a boolean
+\fBTk_GetBoolean\fR or a line smoothing method. Only \fBtrue\fR and \fBraw\fR are
+supported in the core (with \fBbezier\fR being an alias for \fBtrue\fR), but more can be added at runtime. If a boolean
false value or empty string is given, no smoothing is applied. A boolean
-truth value assumes \fBbezier\fR smoothing.
-It indicates whether or not the line should be drawn as a curve.
-If so, the line is rendered as a set of parabolic splines: one spline
+truth value assumes \fBtrue\fR smoothing.
+If the smoothing method is \fBtrue\fR, this indicates that the line
+should be drawn as a curve, rendered as a set of quadratic splines: one spline
is drawn for the first and second line segments, one for the second
and third, and so on. Straight-line segments can be generated within
a curve by duplicating the end-points of the desired line segment.
+If the smoothing method is \fBraw\fR, this indicates that the line
+should also be drawn as a curve but where the list of coordinates is
+such that the first coordinate pair (and every third coordinate pair
+thereafter) is a knot point on a cubic Bezier curve, and the other
+coordinates are control points on the cubic Bezier curve. Straight
+line segments can be venerated within a curve by making control points
+equal to their neighbouring knot points. If the last point is a
+control point and not a knot point, the point is repeated (one or two
+times) so that it also becomes a knot point.
.TP
\fB\-splinesteps \fInumber\fR
Specifies the degree of smoothness desired for curves: each spline
will be approximated with \fInumber\fR line segments. This
-option is ignored unless the \fB\-smooth\fR option is true.
+option is ignored unless the \fB\-smooth\fR option is true or \fBraw\fR.
.SH "OVAL ITEMS"
.PP
Items of type \fBoval\fR appear as circular or oval regions on
@@ -1516,17 +1525,30 @@ If this option isn't specified then it defaults to \fBmiter\fR.
.TP
\fB\-smooth \fIboolean\fR
\fIBoolean\fR must have one of the forms accepted by \fBTk_GetBoolean\fR
-It indicates whether or not the polygon should be drawn with a
-curved perimeter.
-If so, the outline of the polygon becomes a set of parabolic splines,
-one spline for the first and second line segments, one for the second
-and third, and so on. Straight-line segments can be generated in a
-smoothed polygon by duplicating the end-points of the desired line segment.
+or a line smoothing method. Only \fBtrue\fR and \fBraw\fR are
+supported in the core (with \fBbezier\fR being an alias for \fBtrue\fR), but more can be added at runtime. If a boolean
+false value or empty string is given, no smoothing is applied. A boolean
+truth value assumes \fBtrue\fR smoothing.
+If the smoothing method is \fBtrue\fR, this indicates that the polygon
+should be drawn as a curve, rendered as a set of quadratic splines: one spline
+is drawn for the first and second line segments, one for the second
+and third, and so on. Straight-line segments can be generated within
+a curve by duplicating the end-points of the desired line segment.
+If the smoothing method is \fBraw\fR, this indicates that the polygon
+should also be drawn as a curve but where the list of coordinates is
+such that the first coordinate pair (and every third coordinate pair
+thereafter) is a knot point on a cubic Bezier curve, and the other
+coordinates are control points on the cubic Bezier curve. Straight
+line segments can be venerated within a curve by making control points
+equal to their neighbouring knot points. If the last point is not the
+second point of a pair of control points, the point is repeated (one or two
+times) so that it also becomes the second point of a pair of control
+points (the associated knot point will be the first control point).
.TP
\fB\-splinesteps \fInumber\fR
Specifies the degree of smoothness desired for curves: each spline
will be approximated with \fInumber\fR line segments. This
-option is ignored unless the \fB\-smooth\fR option is true.
+option is ignored unless the \fB\-smooth\fR option is true or \fBraw\fR.
.PP
Polygon items are different from other items such as rectangles, ovals
and arcs in that interior points are considered to be ``inside'' a
diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c
index ceabca4..ff0d720 100644
--- a/generic/tkCanvUtil.c
+++ b/generic/tkCanvUtil.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkCanvUtil.c,v 1.11 2004/03/16 19:53:18 hobbs Exp $
+ * RCS: @(#) $Id: tkCanvUtil.c,v 1.12 2004/08/19 14:41:52 dkf Exp $
*/
#include "tkInt.h"
@@ -18,6 +18,45 @@
#include "tkPort.h"
#include <assert.h>
+/*
+ * Structures defined only in this file.
+ */
+
+typedef struct SmoothAssocData {
+ struct SmoothAssocData *nextPtr; /* pointer to next SmoothAssocData */
+ Tk_SmoothMethod smooth; /* name and functions associated with
+ * this option */
+} SmoothAssocData;
+
+Tk_SmoothMethod tkBezierSmoothMethod = {
+ "true",
+ TkMakeBezierCurve,
+ (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ double *coordPtr, int numPoints, int numSteps)))
+ TkMakeBezierPostscript,
+};
+static Tk_SmoothMethod tkRawSmoothMethod = {
+ "raw",
+ TkMakeRawCurve,
+ (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
+ double *coordPtr, int numPoints, int numSteps)))
+ TkMakeRawCurvePostscript,
+};
+
+/*
+ * Function forward-declarations.
+ */
+
+static void SmoothMethodCleanupProc _ANSI_ARGS_((
+ ClientData clientData, Tcl_Interp *interp));
+static SmoothAssocData *InitSmoothMethods _ANSI_ARGS_((Tcl_Interp *interp));
+static int DashConvert _ANSI_ARGS_((char *l, CONST char *p,
+ int n, double width));
+static void translateAndAppendCoords _ANSI_ARGS_((
+ TkCanvas *canvPtr, double x, double y,
+ XPoint *outArr, int numOut));
+
+#define ABS(a) ((a>=0)?(a):(-(a)))
/*
*----------------------------------------------------------------------
@@ -458,11 +497,6 @@ Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
return Tcl_Merge(itemPtr->numTags, (CONST char **) itemPtr->tagPtr);
}
-
-static int DashConvert _ANSI_ARGS_((char *l, CONST char *p,
- int n, double width));
-#define ABS(a) ((a>=0)?(a):(-(a)))
-
/*
*--------------------------------------------------------------
*
@@ -557,6 +591,49 @@ TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
/*
*--------------------------------------------------------------
*
+ * InitSmoothMethods --
+ *
+ * This procedure is invoked to set up the initial state of the
+ * list of "-smooth" methods. It should only be called when the
+ * list installed in the interpreter is NULL.
+ *
+ * Results:
+ * Pointer to the start of the list of default smooth methods.
+ *
+ * Side effects:
+ * A linked list of smooth methods is created and attached to the
+ * interpreter's association key "smoothMethod"
+ *
+ *--------------------------------------------------------------
+ */
+
+static SmoothAssocData *
+InitSmoothMethods(interp)
+ Tcl_Interp *interp;
+{
+ SmoothAssocData *methods, *ptr;
+
+ methods = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData));
+ methods->smooth.name = tkRawSmoothMethod.name;
+ methods->smooth.coordProc = tkRawSmoothMethod.coordProc;
+ methods->smooth.postscriptProc = tkRawSmoothMethod.postscriptProc;
+
+ methods->nextPtr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData));
+
+ ptr = methods->nextPtr;
+ ptr->smooth.name = tkBezierSmoothMethod.name;
+ ptr->smooth.coordProc = tkBezierSmoothMethod.coordProc;
+ ptr->smooth.postscriptProc = tkBezierSmoothMethod.postscriptProc;
+ ptr->nextPtr = NULL;
+
+ Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,
+ (ClientData) methods);
+ return methods;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
* Tk_CreateSmoothMethod --
*
* This procedure is invoked to add additional values
@@ -572,23 +649,6 @@ TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
*--------------------------------------------------------------
*/
-Tk_SmoothMethod tkBezierSmoothMethod = {
- "bezier",
- TkMakeBezierCurve,
- (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
- double *coordPtr, int numPoints, int numSteps)))
- TkMakeBezierPostscript,
-};
-
-static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp));
-
-typedef struct SmoothAssocData {
- struct SmoothAssocData *nextPtr; /* pointer to next SmoothAssocData */
- Tk_SmoothMethod smooth; /* name and functions associated with this
- * option */
-} SmoothAssocData;
-
void
Tk_CreateSmoothMethod(interp, smooth)
Tcl_Interp *interp;
@@ -599,6 +659,14 @@ Tk_CreateSmoothMethod(interp, smooth)
(Tcl_InterpDeleteProc **) NULL);
/*
+ * Initialize if we were not previously initialized.
+ */
+
+ if (methods == NULL) {
+ methods = InitSmoothMethods(interp);
+ }
+
+ /*
* If there's already a smooth method with the given name, remove it.
*/
@@ -680,7 +748,7 @@ TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)
int offset; /* Offset into item. */
{
register Tk_SmoothMethod **smoothPtr =
- (Tk_SmoothMethod **) (widgRec + offset);
+ (Tk_SmoothMethod **) (widgRec + offset);
Tk_SmoothMethod *smooth = NULL;
int b;
size_t length;
@@ -693,10 +761,22 @@ TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)
length = strlen(value);
methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",
(Tcl_InterpDeleteProc **) NULL);
+ /*
+ * Not initialized yet; fix that now.
+ */
+ if (methods == NULL) {
+ methods = InitSmoothMethods(interp);
+ }
+ /*
+ * Backward compatability hack
+ */
+ if (strncmp(value, "bezier", length) == 0) {
+ smooth = &tkBezierSmoothMethod;
+ }
while (methods != (SmoothAssocData *) NULL) {
if (strncmp(value, methods->smooth.name, length) == 0) {
if (smooth != (Tk_SmoothMethod *) NULL) {
- Tcl_AppendResult(interp, "ambigeous smooth method \"", value,
+ Tcl_AppendResult(interp, "ambiguous smooth method \"", value,
"\"", (char *) NULL);
return TCL_ERROR;
}
@@ -707,15 +787,8 @@ TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)
if (smooth) {
*smoothPtr = smooth;
return TCL_OK;
- } else if (strncmp(value, tkBezierSmoothMethod.name, length) == 0) {
- /*
- * We need to do handle the built-in bezier method.
- */
- *smoothPtr = &tkBezierSmoothMethod;
- return TCL_OK;
}
-
if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) {
return TCL_ERROR;
}
diff --git a/generic/tkInt.decls b/generic/tkInt.decls
index ebfae12..12a560d 100644
--- a/generic/tkInt.decls
+++ b/generic/tkInt.decls
@@ -9,7 +9,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: tkInt.decls,v 1.35 2004/03/17 18:15:43 das Exp $
+# RCS: @(#) $Id: tkInt.decls,v 1.36 2004/08/19 14:41:52 dkf Exp $
library tk
@@ -630,7 +630,18 @@ declare 148 generic {
declare 149 generic {
CONST Tk_OptionSpec * TkGetOptionSpec (CONST char *name,
- Tk_OptionTable optionTable)
+ Tk_OptionTable optionTable)
+}
+
+# TIP#168
+declare 150 generic {
+ int TkMakeRawCurve (Tk_Canvas canvas,
+ double *pointPtr, int numPoints, int numSteps,
+ XPoint xPoints[], double dblPoints[])
+}
+declare 151 generic {
+ void TkMakeRawCurvePostscript (Tcl_Interp *interp,
+ Tk_Canvas canvas, double *pointPtr, int numPoints)
}
##############################################################################
diff --git a/generic/tkTrig.c b/generic/tkTrig.c
index b8a88e7..f3561b1 100644
--- a/generic/tkTrig.c
+++ b/generic/tkTrig.c
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkTrig.c,v 1.4 1999/12/14 06:52:33 hobbs Exp $
+ * RCS: @(#) $Id: tkTrig.c,v 1.5 2004/08/19 14:41:52 dkf Exp $
*/
#include <stdio.h>
@@ -918,7 +918,7 @@ TkIncludePoint(itemPtr, pointPtr)
* TkBezierScreenPoints --
*
* Given four control points, create a larger set of XPoints
- * for a Bezier spline based on the points.
+ * for a Bezier curve based on the points.
*
* Results:
* The array at *xPointPtr gets filled in with numSteps XPoints
@@ -969,7 +969,7 @@ TkBezierScreenPoints(canvas, control, numSteps, xPointPtr)
* TkBezierPoints --
*
* Given four control points, create a larger set of points
- * for a Bezier spline based on the points.
+ * for a Bezier curve based on the points.
*
* Results:
* The array at *coordPtr gets filled in with 2*numSteps
@@ -1019,10 +1019,12 @@ TkBezierPoints(control, numSteps, coordPtr)
* parabolic splines to the line segments connecting the original
* points. Produces output points in either of two forms.
*
- * Note: in spite of this procedure's name, it does *not* generate
- * Bezier curves. Since only three control points are used for
- * each curve segment, not four, the curves are actually just
- * parabolic.
+ * Note: the name of this procedure should *not* be taken to
+ * mean that it interprets the input points as directly defining
+ * Bezier curves. Rather, it internally computes a Bezier curve
+ * representation of each parabolic spline segment. (These
+ * Bezier curves are then flattened to produce the points
+ * filled into the output arrays.)
*
* Results:
* Either or both of the xPoints or dblPoints arrays are filled
@@ -1196,6 +1198,185 @@ TkMakeBezierCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints)
/*
*--------------------------------------------------------------
*
+ * TkMakeRawCurve --
+ *
+ * Interpret the given set of points as the raw knots and
+ * control points defining a sequence of cubic Bezier curves.
+ * Create a new set of points that fit these Bezier curves.
+ * Output points are produced in either of two forms.
+ *
+ * Results:
+ * Either or both of the xPoints or dblPoints arrays are filled
+ * in. The return value is the number of points placed in the
+ * arrays.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TkMakeRawCurve(canvas, pointPtr, numPoints, numSteps, xPoints, dblPoints)
+ Tk_Canvas canvas; /* Canvas in which curve is to be
+ * drawn. */
+ double *pointPtr; /* Array of input coordinates: x0,
+ * y0, x1, y1, etc.. */
+ int numPoints; /* Number of points at pointPtr. */
+ int numSteps; /* Number of steps to use for each
+ * curve segment (determines
+ * smoothness of curve). */
+ XPoint xPoints[]; /* Array of XPoints to fill in (e.g.
+ * for display. NULL means don't
+ * fill in any XPoints. */
+ double dblPoints[]; /* Array of points to fill in as
+ * doubles, in the form x0, y0,
+ * x1, y1, .... NULL means don't
+ * fill in anything in this form.
+ * Caller must make sure that this
+ * array has enough space. */
+{
+ int outputPoints, i;
+ int numSegments = (numPoints+1)/3;
+ double *segPtr;
+
+ /*
+ * The input describes a curve with s Bezier curve segments if
+ * there are 3s+1, 3s, or 3s-1 input points. In the last two
+ * cases, 1 or 2 initial points from the first curve segment
+ * are reused as defining points also for the last curve segment.
+ * In the case of 3s input points, this will automatically close
+ * the curve.
+ */
+
+ if (!pointPtr) {
+ /*
+ * If pointPtr == NULL, this function returns an upper limit.
+ * of the array size to store the coordinates. This can be
+ * used to allocate storage, before the actual coordinates
+ * are calculated.
+ */
+ return 1 + numSegments * numSteps;
+ }
+
+ outputPoints = 0;
+ if (xPoints != NULL) {
+ Tk_CanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1],
+ &xPoints->x, &xPoints->y);
+ xPoints += 1;
+ }
+ if (dblPoints != NULL) {
+ dblPoints[0] = pointPtr[0];
+ dblPoints[1] = pointPtr[1];
+ dblPoints += 2;
+ }
+ outputPoints += 1;
+
+ /*
+ * The next loop handles all curve segments except one that
+ * overlaps the end of the list of coordinates.
+ */
+
+ for (i=numPoints,segPtr=pointPtr ; i>=4 ; i-=3,segPtr+=6) {
+ if (segPtr[0]==segPtr[2] && segPtr[1]==segPtr[3] &&
+ segPtr[4]==segPtr[6] && segPtr[5]==segPtr[7]) {
+ /*
+ * The control points on this segment are equal to
+ * their neighbouring knots, so this segment is just
+ * a straight line. A single point is sufficient.
+ */
+ if (xPoints != NULL) {
+ Tk_CanvasDrawableCoords(canvas, segPtr[6], segPtr[7],
+ &xPoints->x, &xPoints->y);
+ xPoints += 1;
+ }
+ if (dblPoints != NULL) {
+ dblPoints[0] = segPtr[6];
+ dblPoints[1] = segPtr[7];
+ dblPoints += 2;
+ }
+ outputPoints += 1;
+ } else {
+ /*
+ * This is a generic Bezier curve segment.
+ */
+ if (xPoints != NULL) {
+ TkBezierScreenPoints(canvas, segPtr, numSteps, xPoints);
+ xPoints += numSteps;
+ }
+ if (dblPoints != NULL) {
+ TkBezierPoints(segPtr, numSteps, dblPoints);
+ dblPoints += 2*numSteps;
+ }
+ outputPoints += numSteps;
+ }
+ }
+
+ /*
+ * If at this point i>1, then there is some point which has not
+ * yet been used. Make another curve segment.
+ */
+
+ if (i>1) {
+ int j;
+ double control[8];
+
+ /*
+ * Copy the relevant coordinates to control[], so that
+ * it can be passed as a unit to e.g. TkBezierPoints.
+ */
+
+ for (j=0; j<2*i; j++) {
+ control[j] = segPtr[j];
+ }
+ for (; j<8; j++) {
+ control[j] = pointPtr[j-2*i];
+ }
+
+ /*
+ * Then we just do the same things as above.
+ */
+
+ if (control[0]==control[2] && control[1]==control[3] &&
+ control[4]==control[6] && control[5]==control[7]) {
+ /*
+ * The control points on this segment are equal to
+ * their neighbouring knots, so this segment is just
+ * a straight line. A single point is sufficient.
+ */
+ if (xPoints != NULL) {
+ Tk_CanvasDrawableCoords(canvas, control[6], control[7],
+ &xPoints->x, &xPoints->y);
+ xPoints += 1;
+ }
+ if (dblPoints != NULL) {
+ dblPoints[0] = control[6];
+ dblPoints[1] = control[7];
+ dblPoints += 2;
+ }
+ outputPoints += 1;
+ } else {
+ /*
+ * This is a generic Bezier curve segment.
+ */
+ if (xPoints != NULL) {
+ TkBezierScreenPoints(canvas, control, numSteps, xPoints);
+ xPoints += numSteps;
+ }
+ if (dblPoints != NULL) {
+ TkBezierPoints(control, numSteps, dblPoints);
+ dblPoints += 2*numSteps;
+ }
+ outputPoints += numSteps;
+ }
+ }
+
+ return outputPoints;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
* TkMakeBezierPostscript --
*
* This procedure generates Postscript commands that create
@@ -1293,6 +1474,108 @@ TkMakeBezierPostscript(interp, canvas, pointPtr, numPoints)
/*
*--------------------------------------------------------------
*
+ * TkMakeRawCurvePostscript --
+ *
+ * This procedure interprets the input points as the raw knot
+ * and control points for a curve composed of Bezier curve
+ * segments, just like TkMakeRawCurve. It generates Postscript
+ * commands that create a path corresponding to this given curve.
+ *
+ * Results:
+ * None. Postscript commands to generate the path are appended
+ * to the interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkMakeRawCurvePostscript(interp, canvas, pointPtr, numPoints)
+ Tcl_Interp *interp; /* Interpreter in whose result the
+ * Postscript is to be stored. */
+ Tk_Canvas canvas; /* Canvas widget for which the
+ * Postscript is being generated. */
+ double *pointPtr; /* Array of input coordinates: x0,
+ * y0, x1, y1, etc.. */
+ int numPoints; /* Number of points at pointPtr. */
+{
+ int i;
+ double *segPtr;
+ char buffer[200];
+
+ /*
+ * Put the first point into the path.
+ */
+
+ sprintf(buffer, "%.15g %.15g moveto\n",
+ pointPtr[0], Tk_CanvasPsY(canvas, pointPtr[1]));
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+
+ /*
+ * Loop through all the remaining points in the curve, generating
+ * a straight line or curve section for every three of them.
+ */
+
+ for (i=numPoints-1,segPtr=pointPtr ; i>=3 ; i-=3,segPtr+=6) {
+ if (segPtr[0]==segPtr[2] && segPtr[1]==segPtr[3] &&
+ segPtr[4]==segPtr[6] && segPtr[5]==segPtr[7]) {
+ /*
+ * The control points on this segment are equal to
+ * their neighbouring knots, so this segment is just
+ * a straight line.
+ */
+ sprintf(buffer, "%.15g %.15g lineto\n",
+ segPtr[6], Tk_CanvasPsY(canvas, segPtr[7]));
+ } else {
+ /*
+ * This is a generic Bezier curve segment.
+ */
+ sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",
+ segPtr[2], Tk_CanvasPsY(canvas, segPtr[3]),
+ segPtr[4], Tk_CanvasPsY(canvas, segPtr[5]),
+ segPtr[6], Tk_CanvasPsY(canvas, segPtr[7]));
+ }
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ }
+
+ /*
+ * If there are any points left that haven't been used,
+ * then build the last segment and generate Postscript in
+ * the same way for that.
+ */
+
+ if (i>0) {
+ int j;
+ double control[8];
+
+ for (j=0; j<2*i+2; j++) {
+ control[j] = segPtr[j];
+ }
+ for (; j<8; j++) {
+ control[j] = pointPtr[j-2*i-2];
+ }
+
+ if (control[0]==control[2] && control[1]==control[3] &&
+ control[4]==control[6] && control[5]==control[7]) {
+ /* Straight line */
+ sprintf(buffer, "%.15g %.15g lineto\n",
+ control[6], Tk_CanvasPsY(canvas, control[7]));
+ } else {
+ /* Bezier curve segment */
+ sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n",
+ control[2], Tk_CanvasPsY(canvas, control[3]),
+ control[4], Tk_CanvasPsY(canvas, control[5]),
+ control[6], Tk_CanvasPsY(canvas, control[7]));
+ }
+ Tcl_AppendResult(interp, buffer, (char *) NULL);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
* TkGetMiterPoints --
*
* Given three points forming an angle, compute the
diff --git a/tests/canvas.test b/tests/canvas.test
index efa6b16..84f18b3 100644
--- a/tests/canvas.test
+++ b/tests/canvas.test
@@ -6,7 +6,7 @@
# Copyright (c) 1998-2000 Ajuba Solutions.
# All rights reserved.
#
-# RCS: @(#) $Id: canvas.test,v 1.19 2004/06/15 21:06:40 dkf Exp $
+# RCS: @(#) $Id: canvas.test,v 1.20 2004/08/19 14:41:52 dkf Exp $
package require tcltest 2.1
eval tcltest::configure $argv
@@ -476,6 +476,16 @@ test canvas-16.1 {arc coords check} {
.c itemcget $id -start
} {33.0}
+test canvas-17.1 {default smooth method handling} {
+ destroy .c; canvas .c
+ set id [.c create line {0 0 1 1 2 2 3 3 4 4 5 5 6 6}]
+ set result [.c itemcget $id -smooth]
+ foreach smoother {yes 1 bezier raw r b} {
+ .c itemconfigure $id -smooth $smoother
+ lappend result [.c itemcget $id -smooth]
+ }
+} {0 true true true raw raw true}
+
destroy .c
# cleanup