118
102
/* cycle through the curves */
120
104
for (i = 0; i < CURVES_NUM_POINTS; i++)
121
if (curves->points[channel][i][0] != -1)
122
points[num_pts++] = i;
105
if (curves->points[channel][i][0] != -1)
106
points[num_pts++] = i;
124
108
/* Initialize boundary curve points */
125
109
if (num_pts != 0)
127
for (i = 0; i < curves->points[channel][points[0]][0]; i++)
128
curves->curve[channel][i] = curves->points[channel][points[0]][1];
129
for (i = curves->points[channel][points[num_pts - 1]][0]; i < 256; i++)
130
curves->curve[channel][i] = curves->points[channel][points[num_pts - 1]][1];
111
for (i = 0; i < curves->points[channel][points[0]][0]; i++)
112
curves->curve[channel][i] = curves->points[channel][points[0]][1];
114
for (i = curves->points[channel][points[num_pts - 1]][0];
117
curves->curve[channel][i] =
118
curves->points[channel][points[num_pts - 1]][1];
133
121
for (i = 0; i < num_pts - 1; i++)
135
p1 = (i == 0) ? points[i] : points[(i - 1)];
137
p3 = points[(i + 1)];
138
p4 = (i == (num_pts - 2)) ? points[(num_pts - 1)] : points[(i + 2)];
123
p1 = points[MAX (i - 1, 0)];
126
p4 = points[MIN (i + 2, num_pts - 1)];
140
curves_plot_curve (curves, channel, p1, p2, p3, p4);
128
curves_plot_curve (curves, channel, p1, p2, p3, p4);
143
131
/* ensure that the control points are used exactly */
144
132
for (i = 0; i < num_pts; i++)
134
gint x = curves->points[channel][points[i]][0];
135
gint y = curves->points[channel][points[i]][1];
148
x = curves->points[channel][points[i]][0];
149
y = curves->points[channel][points[i]][1];
150
137
curves->curve[channel][x] = y;
209
196
/* private functions */
199
* This function calculates the curve values between the control points
200
* p2 and p3, taking the potentially existing neighbors p1 and p4 into
203
* This function uses a cubic bezier curve for the individual segments and
204
* calculates the necessary intermediate control points depending on the
205
* neighbor curve control points.
212
209
curves_plot_curve (Curves *curves,
222
gdouble x, dx, dx2, dx3;
223
gdouble y, dy, dy2, dy3;
229
/* construct the geometry matrix from the segment */
230
for (i = 0; i < 4; i++)
236
for (i = 0; i < 2; i++)
238
geometry[0][i] = curves->points[channel][p1][i];
239
geometry[1][i] = curves->points[channel][p2][i];
240
geometry[2][i] = curves->points[channel][p3][i];
241
geometry[3][i] = curves->points[channel][p4][i];
244
/* subdivide the curve 1000 times */
245
/* n can be adjusted to give a finer or coarser curve */
250
/* construct a temporary matrix for determining the forward differencing deltas */
251
tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
252
tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
253
tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
254
tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
256
/* compose the basis and geometry matrices */
257
curves_CR_compose (CR_basis, geometry, tmp1);
259
/* compose the above results to get the deltas matrix */
260
curves_CR_compose (tmp2, tmp1, deltas);
262
/* extract the x deltas */
268
/* extract the y deltas */
274
lastx = CLAMP (x, 0, 255);
275
lasty = CLAMP (y, 0, 255);
277
curves->curve[channel][lastx] = lasty;
279
/* loop over the curve */
280
for (i = 0; i < 1000; i++)
282
/* increment the x values */
287
/* increment the y values */
292
newx = CLAMP0255 (ROUND (x));
293
newy = CLAMP0255 (ROUND (y));
295
/* if this point is different than the last one...then draw it */
296
if ((lastx != newx) || (lasty != newy))
297
curves->curve[channel][newx] = newy;
305
curves_CR_compose (CRMatrix a,
311
for (i = 0; i < 4; i++)
313
for (j = 0; j < 4; j++)
315
ab[i][j] = (a[i][0] * b[0][j] +
218
gdouble y0, y1, y2, y3;
223
/* the outer control points for the bezier curve. */
224
x0 = curves->points[channel][p2][0];
225
y0 = curves->points[channel][p2][1];
226
x3 = curves->points[channel][p3][0];
227
y3 = curves->points[channel][p3][1];
230
* the x values of the inner control points are fixed at
231
* x1 = 1/3*x0 + 2/3*x3 and x2 = 2/3*x0 + 1/3*x3
232
* this ensures that the x values increase linearily with the
233
* parameter t and enables us to skip the calculation of the x
234
* values altogehter - just calculate y(t) evenly spaced.
240
g_return_if_fail (dx > 0);
242
if (p1 == p2 && p3 == p4)
244
/* No information about the neighbors,
245
* calculate y1 and y2 to get a straight line
248
y2 = y0 + dy * 2.0 / 3.0;
250
else if (p1 == p2 && p3 != p4)
252
/* only the right neighbor is available. Make the tangent at the
253
* right endpoint parallel to the line between the left endpoint
254
* and the right neighbor. Then point the tangent at the left towards
255
* the control handle of the right tangent, to ensure that the curve
256
* does not have an inflection point.
258
slope = (curves->points[channel][p4][1] - y0) /
259
(curves->points[channel][p4][0] - x0);
261
y2 = y3 - slope * dx / 3.0;
262
y1 = y0 + (y2 - y0) / 2.0;
264
else if (p1 != p2 && p3 == p4)
266
/* see previous case */
267
slope = (y3 - curves->points[channel][p1][1]) /
268
(x3 - curves->points[channel][p1][0]);
270
y1 = y0 + slope * dx / 3.0;
271
y2 = y3 + (y1 - y3) / 2.0;
273
else /* (p1 != p2 && p3 != p4) */
275
/* Both neighbors are available. Make the tangents at the endpoints
276
* parallel to the line between the opposite endpoint and the adjacent
279
slope = (y3 - curves->points[channel][p1][1]) /
280
(x3 - curves->points[channel][p1][0]);
282
y1 = y0 + slope * dx / 3.0;
284
slope = (curves->points[channel][p4][1] - y0) /
285
(curves->points[channel][p4][0] - x0);
287
y2 = y3 - slope * dx / 3.0;
291
* finally calculate the y(t) values for the given bezier values. We can
292
* use homogenously distributed values for t, since x(t) increases linearily.
294
for (i = 0; i <= dx; i++)
297
y = y0 * (1-t) * (1-t) * (1-t) +
298
3 * y1 * (1-t) * (1-t) * t +
299
3 * y2 * (1-t) * t * t +
302
curves->curve[channel][ROUND(x0) + i] = CLAMP0255 (ROUND (y));