int TkMakeBezierCurve( 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 spline * segments (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 closed, outputPoints, i; int numCoords = numPoints*2; double control[8]; /* * If the curve is a closed one then generate a special spline that spans * the last points and the first ones. Otherwise just put the first point * into the output. */ if (!pointPtr) { /* * Of 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 + numPoints * numSteps; } outputPoints = 0; if ((pointPtr[0] == pointPtr[numCoords-2]) && (pointPtr[1] == pointPtr[numCoords-1])) { closed = 1; control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; if (xPoints != NULL) { Tk_CanvasDrawableCoords(canvas, control[0], control[1], &xPoints->x, &xPoints->y); TkBezierScreenPoints(canvas, control, numSteps, xPoints+1); xPoints += numSteps+1; } if (dblPoints != NULL) { dblPoints[0] = control[0]; dblPoints[1] = control[1]; TkBezierPoints(control, numSteps, dblPoints+2); dblPoints += 2*(numSteps+1); } outputPoints += numSteps+1; } else { closed = 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; } for (i = 2; i < numPoints; i++, pointPtr += 2) { /* * Set up the first two control points. This is done differently for * the first spline of an open curve than for other cases. */ if ((i == 2) && !closed) { control[0] = pointPtr[0]; control[1] = pointPtr[1]; control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2]; control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3]; } else { control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2]; control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3]; } /* * Set up the last two control points. This is done differently for * the last spline of an open curve than for other cases. */ if ((i == (numPoints-1)) && !closed) { control[4] = .667*pointPtr[2] + .333*pointPtr[4]; control[5] = .667*pointPtr[3] + .333*pointPtr[5]; control[6] = pointPtr[4]; control[7] = pointPtr[5]; } else { control[4] = .833*pointPtr[2] + .167*pointPtr[4]; control[5] = .833*pointPtr[3] + .167*pointPtr[5]; control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4]; control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5]; } /* * If the first two points coincide, or if the last two points * coincide, then generate a single straight-line segment by * outputting the last control point. */ if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3])) || ((pointPtr[2] == pointPtr[4]) && (pointPtr[3] == pointPtr[5]))) { if (xPoints != NULL) { Tk_CanvasDrawableCoords(canvas, control[6], control[7], &xPoints[0].x, &xPoints[0].y); xPoints++; } if (dblPoints != NULL) { dblPoints[0] = control[6]; dblPoints[1] = control[7]; dblPoints += 2; } outputPoints += 1; continue; } /* * Generate a Bezier spline using the control points. */ if (xPoints != NULL) { TkBezierScreenPoints(canvas, control, numSteps, xPoints); xPoints += numSteps; } if (dblPoints != NULL) { TkBezierPoints(control, numSteps, dblPoints); dblPoints += 2*numSteps; } outputPoints += numSteps; } return outputPoints; }
int TkMakeRawCurve( 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; }
static int TkMakeBezierCurve( int *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 * spline segments (determines * smoothness of curve). */ Point xPoints[]) /* Array of Points to fill in (e.g. * for display. NULL means don't * fill in any Points. */ { int closed, outputPoints, i; int numCoords = numPoints*2; double control[8]; /* * If the curve is a closed one then generate a special spline * that spans the last points and the first ones. Otherwise * just put the first point into the output. */ if (!pointPtr) { /* Of 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 + numPoints * numSteps; } outputPoints = 0; if ((pointPtr[0] == pointPtr[numCoords-2]) && (pointPtr[1] == pointPtr[numCoords-1])) { closed = 1; control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; if (xPoints != NULL) { xPoints-> x = control[0]; xPoints-> y = control[1]; TkBezierScreenPoints( control, numSteps, xPoints+1); xPoints += numSteps+1; } outputPoints += numSteps+1; } else { closed = 0; if (xPoints != NULL) { xPoints->x = pointPtr[0]; xPoints->y = pointPtr[1]; xPoints += 1; } outputPoints += 1; } for (i = 2; i < numPoints; i++, pointPtr += 2) { /* * Set up the first two control points. This is done * differently for the first spline of an open curve * than for other cases. */ if ((i == 2) && !closed) { control[0] = pointPtr[0]; control[1] = pointPtr[1]; control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2]; control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3]; } else { control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2]; control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3]; } /* * Set up the last two control points. This is done * differently for the last spline of an open curve * than for other cases. */ if ((i == (numPoints-1)) && !closed) { control[4] = .667*pointPtr[2] + .333*pointPtr[4]; control[5] = .667*pointPtr[3] + .333*pointPtr[5]; control[6] = pointPtr[4]; control[7] = pointPtr[5]; } else { control[4] = .833*pointPtr[2] + .167*pointPtr[4]; control[5] = .833*pointPtr[3] + .167*pointPtr[5]; control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4]; control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5]; } /* * If the first two points coincide, or if the last * two points coincide, then generate a single * straight-line segment by outputting the last control * point. */ if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3])) || ((pointPtr[2] == pointPtr[4]) && (pointPtr[3] == pointPtr[5]))) { if (xPoints != NULL) { xPoints[0].x = control[6]; xPoints[0].y = control[7]; xPoints++; } outputPoints += 1; continue; } /* * Generate a Bezier spline using the control points. */ if (xPoints != NULL) { TkBezierScreenPoints(control, numSteps, xPoints); xPoints += numSteps; } outputPoints += numSteps; } return outputPoints; }