1 /*
2 This file is part of darktable,
3 Copyright (C) 2011-2020 darktable developers.
4
5 darktable is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 darktable is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17
18 Part of this file is based on nikon_curve.c from UFraw
19 Copyright 2004-2008 by Shawn Freeman, Udi Fuchs
20 */
21
22 #include "curve_tools.h"
23 #include <float.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #define EPSILON 2 * FLT_MIN
29 #define MAX_ITER 10
30
31 static const int curvedata_anchors_max = 20;
32
33 // declare some functions and so I can use the function pointer
34 float spline_cubic_val(int n, float t[], float tval, float y[], float ypp[]);
35 float catmull_rom_val(int n, float x[], float xval, float y[], float tangents[]);
36
37 float *spline_cubic_set(int n, float t[], float y[]);
38 float *catmull_rom_set(int n, float x[], float y[]);
39 float *monotone_hermite_set(int n, float x[], float y[]);
40
41 float (*spline_val[])(int, float[], float, float[], float[])
42 = { spline_cubic_val, catmull_rom_val, catmull_rom_val };
43
44 float *(*spline_set[])(int, float[], float[]) = { spline_cubic_set, catmull_rom_set, monotone_hermite_set };
45
46 /**********************************************************************
47
48 Purpose:
49
50 D3_NP_FS factors and solves a D3 system.
51
52 Discussion:
53
54 The D3 storage format is used for a tridiagonal matrix.
55 The superdiagonal is stored in entries (1,2:N), the diagonal in
56 entries (2,1:N), and the subdiagonal in (3,1:N-1). Thus, the
57 original matrix is "collapsed" vertically into the array.
58
59 This algorithm requires that each diagonal entry be nonzero.
60 It does not use pivoting, and so can fail on systems that
61 are actually nonsingular.
62
63 Example:
64
65 Here is how a D3 matrix of order 5 would be stored:
66
67 * A12 A23 A34 A45
68 A11 A22 A33 A44 A55
69 A21 A32 A43 A54 *
70
71 Modified:
72
73 07 January 2005 Shawn Freeman (pure C modifications)
74 15 November 2003 John Burkardt
75
76 Author:
77
78 John Burkardt
79
80 Parameters:
81
82 Input, int N, the order of the linear system.
83
84 Input/output, float A[3*N].
85 On input, the nonzero diagonals of the linear system.
86 On output, the data in these vectors has been overwritten
87 by factorization information.
88
89 Input, float B[N], the right hand side.
90
91 Output, float D3_NP_FS[N], the solution of the linear system.
92 This is NULL if there was an error because one of the diagonal
93 entries was zero.
94 **********************************************************************/
d3_np_fs(int n,float a[],float b[])95 float *d3_np_fs(int n, float a[], float b[])
96
97 {
98 if(n <= 0 || n > curvedata_anchors_max) return NULL;
99
100 int i;
101 float *x;
102 float xmult;
103 //
104 // Check.
105 //
106 for(i = 0; i < n; i++)
107 {
108 if(a[1 + i * 3] == 0.0E+00)
109 {
110 return NULL;
111 }
112 }
113 x = (float *)calloc(n, sizeof(float));
114 // nc_merror(x, "d3_np_fs");
115
116 for(i = 0; i < n; i++)
117 {
118 x[i] = b[i];
119 }
120
121 for(i = 1; i < n; i++)
122 {
123 xmult = a[2 + (i - 1) * 3] / a[1 + (i - 1) * 3];
124 a[1 + i * 3] = a[1 + i * 3] - xmult * a[0 + i * 3];
125 x[i] = x[i] - xmult * x[i - 1];
126 }
127
128 x[n - 1] = x[n - 1] / a[1 + (n - 1) * 3];
129 for(i = n - 2; 0 <= i; i--)
130 {
131 x[i] = (x[i] - a[0 + (i + 1) * 3] * x[i + 1]) / a[1 + i * 3];
132 }
133
134 return x;
135 }
136
137 /**********************************************************************
138
139 Purpose:
140
141 SPLINE_CUBIC_SET computes the second derivatives of a piecewise cubic spline.
142
143 Discussion:
144
145 For data interpolation, the user must call SPLINE_SET to determine
146 the second derivative data, passing in the data to be interpolated,
147 and the desired boundary conditions.
148
149 The data to be interpolated, plus the SPLINE_SET output, defines
150 the spline. The user may then call SPLINE_VAL to evaluate the
151 spline at any point.
152
153 The cubic spline is a piecewise cubic polynomial. The intervals
154 are determined by the "knots" or abscissas of the data to be
155 interpolated. The cubic spline has continuous first and second
156 derivatives over the entire interval of interpolation.
157
158 For any point T in the interval T(IVAL), T(IVAL+1), the form of
159 the spline is
160
161 SPL(T) = A(IVAL)
162 + B(IVAL) * ( T - T(IVAL) )
163 + C(IVAL) * ( T - T(IVAL) )**2
164 + D(IVAL) * ( T - T(IVAL) )**3
165
166 If we assume that we know the values Y(*) and YPP(*), which represent
167 the values and second derivatives of the spline at each knot, then
168 the coefficients can be computed as:
169
170 A(IVAL) = Y(IVAL)
171 B(IVAL) = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) )
172 - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6
173 C(IVAL) = YPP(IVAL) / 2
174 D(IVAL) = ( YPP(IVAL+1) - YPP(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) )
175
176 Since the first derivative of the spline is
177
178 SPL'(T) = B(IVAL)
179 + 2 * C(IVAL) * ( T - T(IVAL) )
180 + 3 * D(IVAL) * ( T - T(IVAL) )**2,
181
182 the requirement that the first derivative be continuous at interior
183 knot I results in a total of N-2 equations, of the form:
184
185 B(IVAL-1) + 2 C(IVAL-1) * (T(IVAL)-T(IVAL-1))
186 + 3 * D(IVAL-1) * (T(IVAL) - T(IVAL-1))**2 = B(IVAL)
187
188 or, setting H(IVAL) = T(IVAL+1) - T(IVAL)
189
190 ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1)
191 - ( YPP(IVAL) + 2 * YPP(IVAL-1) ) * H(IVAL-1) / 6
192 + YPP(IVAL-1) * H(IVAL-1)
193 + ( YPP(IVAL) - YPP(IVAL-1) ) * H(IVAL-1) / 2
194 =
195 ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL)
196 - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * H(IVAL) / 6
197
198 or
199
200 YPP(IVAL-1) * H(IVAL-1) + 2 * YPP(IVAL) * ( H(IVAL-1) + H(IVAL) )
201 + YPP(IVAL) * H(IVAL)
202 =
203 6 * ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL)
204 - 6 * ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1)
205
206 Boundary conditions must be applied at the first and last knots.
207 The resulting tridiagonal system can be solved for the YPP values.
208
209 Modified:
210
211 07 January 2005 Shawn Freeman (pure C modifications)
212 06 February 2004 John Burkardt
213
214
215 Author:
216
217 John Burkardt
218
219 Parameters:
220
221 Input, int N, the number of data points. N must be at least 2.
222 In the special case where N = 2 and IBCBEG = IBCEND = 0, the
223 spline will actually be linear.
224
225 Input, float T[N], the knot values, that is, the points were data is
226 specified. The knot values should be distinct, and increasing.
227
228 Input, float Y[N], the data values to be interpolated.
229
230 Input, int IBCBEG, left boundary condition flag:
231 0: the cubic spline should be a quadratic over the first interval;
232 1: the first derivative at the left endpoint should be YBCBEG;
233 2: the second derivative at the left endpoint should be YBCBEG.
234
235 Input, float YBCBEG, the values to be used in the boundary
236 conditions if IBCBEG is equal to 1 or 2.
237
238 Input, int IBCEND, right boundary condition flag:
239 0: the cubic spline should be a quadratic over the last interval;
240 1: the first derivative at the right endpoint should be YBCEND;
241 2: the second derivative at the right endpoint should be YBCEND.
242
243 Input, float YBCEND, the values to be used in the boundary
244 conditions if IBCEND is equal to 1 or 2.
245
246 Output, float SPLINE_CUBIC_SET[N], the second derivatives of the cubic spline.
247 **********************************************************************/
spline_cubic_set_internal(int n,float t[],float y[],int ibcbeg,float ybcbeg,int ibcend,float ybcend)248 static float *spline_cubic_set_internal(int n, float t[], float y[], int ibcbeg, float ybcbeg, int ibcend,
249 float ybcend)
250 {
251 float *a;
252 float *b;
253 int i;
254 float *ypp;
255 //
256 // Check.
257 //
258 if(n <= 1)
259 {
260 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
261 // "The number of data points must be at least 2.\n");
262 return NULL;
263 }
264
265 for(i = 0; i < n - 1; i++)
266 {
267 if(t[i + 1] <= t[i])
268 {
269 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
270 // "The knots must be strictly increasing, but "
271 // "T(%u) = %e, T(%u) = %e\n",i,t[i],i+1,t[i+1]);
272 return NULL;
273 }
274 }
275 a = (float *)calloc(3 * n, sizeof(float));
276 // nc_merror(a, "spline_cubic_set");
277 b = (float *)calloc(n, sizeof(float));
278 // nc_merror(b, "spline_cubic_set");
279 //
280 // Set up the first equation.
281 //
282 if(ibcbeg == 0)
283 {
284 b[0] = 0.0E+00;
285 a[1 + 0 * 3] = 1.0E+00;
286 a[0 + 1 * 3] = -1.0E+00;
287 }
288 else if(ibcbeg == 1)
289 {
290 b[0] = (y[1] - y[0]) / (t[1] - t[0]) - ybcbeg;
291 a[1 + 0 * 3] = (t[1] - t[0]) / 3.0E+00;
292 a[0 + 1 * 3] = (t[1] - t[0]) / 6.0E+00;
293 }
294 else if(ibcbeg == 2)
295 {
296 b[0] = ybcbeg;
297 a[1 + 0 * 3] = 1.0E+00;
298 a[0 + 1 * 3] = 0.0E+00;
299 }
300 else
301 {
302 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
303 // "IBCBEG must be 0, 1 or 2. The input value is %u.\n", ibcbeg);
304 free(a);
305 free(b);
306 return NULL;
307 }
308 //
309 // Set up the intermediate equations.
310 //
311 for(i = 1; i < n - 1; i++)
312 {
313 b[i] = (y[i + 1] - y[i]) / (t[i + 1] - t[i]) - (y[i] - y[i - 1]) / (t[i] - t[i - 1]);
314 a[2 + (i - 1) * 3] = (t[i] - t[i - 1]) / 6.0E+00;
315 a[1 + i * 3] = (t[i + 1] - t[i - 1]) / 3.0E+00;
316 a[0 + (i + 1) * 3] = (t[i + 1] - t[i]) / 6.0E+00;
317 }
318 //
319 // Set up the last equation.
320 //
321 if(ibcend == 0)
322 {
323 b[n - 1] = 0.0E+00;
324 a[2 + (n - 2) * 3] = -1.0E+00;
325 a[1 + (n - 1) * 3] = 1.0E+00;
326 }
327 else if(ibcend == 1)
328 {
329 b[n - 1] = ybcend - (y[n - 1] - y[n - 2]) / (t[n - 1] - t[n - 2]);
330 a[2 + (n - 2) * 3] = (t[n - 1] - t[n - 2]) / 6.0E+00;
331 a[1 + (n - 1) * 3] = (t[n - 1] - t[n - 2]) / 3.0E+00;
332 }
333 else if(ibcend == 2)
334 {
335 b[n - 1] = ybcend;
336 a[2 + (n - 2) * 3] = 0.0E+00;
337 a[1 + (n - 1) * 3] = 1.0E+00;
338 }
339 else
340 {
341 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
342 // "IBCEND must be 0, 1 or 2. The input value is %u", ibcend);
343 free(a);
344 free(b);
345 return NULL;
346 }
347 //
348 // Solve the linear system.
349 //
350 if(n == 2 && ibcbeg == 0 && ibcend == 0)
351 {
352 ypp = (float *)calloc(2, sizeof(float));
353 // nc_merror(ypp, "spline_cubic_set");
354
355 ypp[0] = 0.0E+00;
356 ypp[1] = 0.0E+00;
357 }
358 else
359 {
360 ypp = d3_np_fs(n, a, b);
361
362 if(!ypp)
363 {
364 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
365 // "The linear system could not be solved.\n");
366 free(a);
367 free(b);
368 return NULL;
369 }
370 }
371
372 free(a);
373 free(b);
374 return ypp;
375 }
376 /************************************************************
377 *
378 * This is a convenience wrapper function around spline_cubic_set
379 *
380 ************************************************************/
spline_cubic_set(int n,float t[],float y[])381 float *spline_cubic_set(int n, float t[], float y[])
382 {
383 return spline_cubic_set_internal(n, t, y, 2, 0.0, 2, 0.0);
384 }
385
386 /*************************************************************
387 * monotone_hermite_set:
388 * calculates the tangents for a monotonic hermite spline curve.
389 * see http://en.wikipedia.org/wiki/Monotone_cubic_interpolation
390 *
391 * input:
392 * n = number of control points
393 * x = input x array
394 * y = input y array
395 * output:
396 * pointer to array containing the tangents
397 *************************************************************/
monotone_hermite_set(int n,float x[],float y[])398 float *monotone_hermite_set(int n, float x[], float y[])
399 {
400 float *delta;
401 float *m;
402 int i;
403 if(n <= 1)
404 {
405 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
406 // "The number of data points must be at least 2.\n");
407 return NULL;
408 }
409
410 for(i = 0; i < n - 1; i++)
411 {
412 if(x[i + 1] <= x[i])
413 {
414 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
415 // "The knots must be strictly increasing, but "
416 // "T(%u) = %e, T(%u) = %e\n",i,x[i],i+1,x[i+1]);
417 return NULL;
418 }
419 }
420
421 delta = (float *)calloc(n, sizeof(float));
422 // nc_merror(delta, "spline_cubic_set");
423 m = (float *)calloc(n + 1, sizeof(float));
424 // nc_merror(m, "spline_cubic_set");
425 // calculate the slopes
426 for(i = 0; i < n - 1; i++)
427 {
428 delta[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
429 }
430 delta[n - 1] = delta[n - 2];
431
432 m[0] = delta[0];
433 m[n - 1] = delta[n - 1];
434
435 for(i = 1; i < n - 1; i++)
436 {
437 m[i] = (delta[i - 1] + delta[i]) * .5f;
438 }
439 for(i = 0; i < n; i++)
440 {
441 if(fabsf(delta[i]) < EPSILON)
442 {
443 m[i] = 0.0f;
444 m[i + 1] = 0.0f;
445 }
446 else
447 {
448 const float alpha = m[i] / delta[i];
449 const float beta = m[i + 1] / delta[i];
450 const float tau = alpha * alpha + beta * beta;
451 if(tau > 9.0f)
452 {
453 m[i] = 3.0f * alpha * delta[i] / sqrtf(tau);
454 m[i + 1] = 3.0f * beta * delta[i] / sqrtf(tau);
455 }
456 }
457 }
458 free(delta);
459 return m;
460 }
461
462 /*************************************************************
463 * catmull_rom_set:
464 * calculates the tangents for a catmull_rom spline
465 * see http://en.wikipedia.org/wiki/Cubic_Hermite_spline
466 *
467 *
468 * input:
469 * n = number of control points
470 * x = input x array
471 * y = input y array
472 * output:
473 * pointer to array containing the tangents
474 *************************************************************/
catmull_rom_set(int n,float x[],float y[])475 float *catmull_rom_set(int n, float x[], float y[])
476 {
477 float *m;
478 int i;
479 if(n <= 1)
480 {
481 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
482 // "The number of data points must be at least 2.\n");
483 return NULL;
484 }
485
486 for(i = 0; i < n - 1; i++)
487 {
488 if(x[i + 1] <= x[i])
489 {
490 // nc_message(NC_SET_ERROR, "spline_cubic_set() error: "
491 // "The knots must be strictly increasing, but "
492 // "T(%u) = %e, T(%u) = %e\n",i,x[i],i+1,x[i+1]);
493 return NULL;
494 }
495 }
496 // nc_merror(delta, "spline_cubic_set");
497 m = (float *)calloc(n, sizeof(float));
498 // nc_merror(m, "spline_cubic_set");
499
500 // calculate the slopes
501 m[0] = (y[1] - y[0]) / (x[1] - x[0]);
502 for(i = 1; i < n - 1; i++)
503 {
504 m[i] = (y[i + 1] - y[i - 1]) / (x[i + 1] - x[i - 1]);
505 }
506 m[n - 1] = (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]);
507
508 return m;
509 }
510
interpolate_set(int n,float x[],float y[],unsigned int type)511 float *interpolate_set(int n, float x[], float y[], unsigned int type)
512 {
513 return (*spline_set[type])(n, x, y);
514 }
515
interpolate_val(int n,float x[],float xval,float y[],float tangents[],unsigned int type)516 float interpolate_val(int n, float x[], float xval, float y[], float tangents[], unsigned int type)
517 {
518 return (*spline_val[type])(n, x, xval, y, tangents);
519 }
520
521 /*************************************************************
522 * catmull_rom_val:
523 * piecewise catmull-rom interpolation
524 *
525 * n = number of control points
526 * x = input x array
527 * xval = input value where to interpolate the data
528 * y = input y array
529 * tangent = input array of tangents
530 * output:
531 * interpolated value at xval
532 *
533 *************************************************************/
catmull_rom_val(int n,float x[],float xval,float y[],float tangents[])534 float catmull_rom_val(int n, float x[], float xval, float y[], float tangents[])
535 {
536 //
537 // Determine the interval [ T(I), T(I+1) ] that contains TVAL.
538 // Values below T[0] or above T[N-1] use extrapolation.
539 //
540 int ival = n - 2;
541
542 for(int i = 0; i < n - 2; i++)
543 {
544 if(xval < x[i + 1])
545 {
546 ival = i;
547 break;
548 }
549 }
550
551 const float m0 = tangents[ival];
552 const float m1 = tangents[ival + 1];
553 //
554 // In the interval I, the polynomial is in terms of a normalized
555 // coordinate between 0 and 1.
556 //
557 const float h = x[ival + 1] - x[ival];
558 const float dx = (xval - x[ival]) / h;
559 const float dx2 = dx * dx;
560 const float dx3 = dx * dx2;
561
562 const float h00 = (2.0 * dx3) - (3.0 * dx2) + 1.0;
563 const float h10 = (1.0 * dx3) - (2.0 * dx2) + dx;
564 const float h01 = (-2.0 * dx3) + (3.0 * dx2);
565 const float h11 = (1.0 * dx3) - (1.0 * dx2);
566
567 return (h00 * y[ival]) + (h10 * h * m0) + (h01 * y[ival + 1]) + (h11 * h * m1);
568 }
569
570
571 /**********************************************************************
572
573 Purpose:
574
575 SPLINE_CUBIC_VAL evaluates a piecewise cubic spline at a point.
576
577 Discussion:
578
579 SPLINE_CUBIC_SET must have already been called to define the values of YPP.
580
581 For any point T in the interval T(IVAL), T(IVAL+1), the form of
582 the spline is
583
584 SPL(T) = A
585 + B * ( T - T(IVAL) )
586 + C * ( T - T(IVAL) )**2
587 + D * ( T - T(IVAL) )**3
588
589 Here:
590 A = Y(IVAL)
591 B = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) )
592 - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6
593 C = YPP(IVAL) / 2
594 D = ( YPP(IVAL+1) - YPP(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) )
595
596 Modified:
597
598 07 January 2005 Shawn Freeman (pure C modifications)
599 04 February 1999 John Burkardt
600
601 Author:
602
603 John Burkardt
604
605 Parameters:
606
607 Input, int n, the number of knots.
608
609 Input, float Y[N], the data values at the knots.
610
611 Input, float T[N], the knot values.
612
613 Input, float TVAL, a point, typically between T[0] and T[N-1], at
614 which the spline is to be evalulated. If TVAL lies outside
615 this range, extrapolation is used.
616
617 Input, float Y[N], the data values at the knots.
618
619 Input, float YPP[N], the second derivatives of the spline at
620 the knots.
621
622
623 Output, float SPLINE_VAL, the value of the spline at TVAL.
624
625 **********************************************************************/
spline_cubic_val(int n,float t[],float tval,float y[],float ypp[])626 float spline_cubic_val(int n, float t[], float tval, float y[], float ypp[])
627 {
628 float dt;
629 float h;
630 int i;
631 int ival;
632 float yval;
633 //
634 // Determine the interval [ T(I), T(I+1) ] that contains TVAL.
635 // Values below T[0] or above T[N-1] use extrapolation.
636 //
637 ival = n - 2;
638
639 for(i = 0; i < n - 1; i++)
640 {
641 if(tval < t[i + 1])
642 {
643 ival = i;
644 break;
645 }
646 }
647 //
648 // In the interval I, the polynomial is in terms of a normalized
649 // coordinate between 0 and 1.
650 //
651 dt = tval - t[ival];
652 h = t[ival + 1] - t[ival];
653
654 yval = y[ival]
655 + dt * ((y[ival + 1] - y[ival]) / h - (ypp[ival + 1] / 6.0E+00 + ypp[ival] / 3.0E+00) * h
656 + dt * (0.5E+00 * ypp[ival] + dt * ((ypp[ival + 1] - ypp[ival]) / (6.0E+00 * h))));
657
658 // we really never need the derivatives so commented this out
659 /**ypval = ( y[ival+1] - y[ival] ) / h
660 - ( ypp[ival+1] / 6.0E+00 + ypp[ival] / 3.0E+00 ) * h
661 + dt * ( ypp[ival]
662 + dt * ( 0.5E+00 * ( ypp[ival+1] - ypp[ival] ) / h ) );
663
664 *yppval = ypp[ival] + dt * ( ypp[ival+1] - ypp[ival] ) / h;*/
665
666 return yval;
667 }
668
669
670 /*********************************************
671 CurveDataSample:
672 Samples from a spline curve constructed from
673 the Nikon data.
674
675 curve - Pointer to curve struct to hold the data.
676 sample - Pointer to sample struct to hold the data.
677 **********************************************/
CurveDataSample(CurveData * curve,CurveSample * sample)678 int CurveDataSample(CurveData *curve, CurveSample *sample)
679 {
680 int i = 0, n;
681
682 float x[20] = { 0 };
683 float y[20] = { 0 };
684 float *ypp;
685
686 // The box points are what the anchor points are relative
687 // to so...
688
689 float box_width = curve->m_max_x - curve->m_min_x;
690 float box_height = curve->m_max_y - curve->m_min_y;
691
692 // build arrays for processing
693 if(curve->m_numAnchors == 0)
694 {
695 // just a straight line using box coordinates
696 x[0] = curve->m_min_x;
697 y[0] = curve->m_min_y;
698 x[1] = curve->m_max_x;
699 y[1] = curve->m_max_y;
700 n = 2;
701 }
702 else
703 {
704 for(i = 0; i < curve->m_numAnchors; i++)
705 {
706 x[i] = curve->m_anchors[i].x * box_width + curve->m_min_x;
707 y[i] = curve->m_anchors[i].y * box_height + curve->m_min_y;
708 }
709 n = curve->m_numAnchors;
710 }
711 int val;
712 float res = 1.0 / (float)(sample->m_samplingRes - 1);
713 int firstPointX = x[0] * (sample->m_samplingRes - 1);
714 int firstPointY = y[0] * (sample->m_outputRes - 1);
715 int lastPointX = x[n - 1] * (sample->m_samplingRes - 1);
716 int lastPointY = y[n - 1] * (sample->m_outputRes - 1);
717 int maxY = curve->m_max_y * (sample->m_outputRes - 1);
718 int minY = curve->m_min_y * (sample->m_outputRes - 1);
719 // returns an array of second derivatives used to calculate the spline curve.
720 // this is a malloc'd array that needs to be freed when done.
721 // The settings currently calculate the natural spline, which closely matches
722 // camera curve output in raw files.
723 ypp = interpolate_set(n, x, y, curve->m_spline_type);
724 if(ypp == NULL) return CT_ERROR;
725
726 for(i = 0; i < (int)sample->m_samplingRes; i++)
727 {
728 // get the value of the curve at a point
729 // take into account that curves may not necessarily begin at x = 0.0
730 // nor end at x = 1.0
731
732 // Before the first point and after the last point, take a strait line
733 if(i < firstPointX)
734 {
735 sample->m_Samples[i] = firstPointY;
736 }
737 else if(i > lastPointX)
738 {
739 sample->m_Samples[i] = lastPointY;
740 }
741 else
742 {
743 // within range, we can sample the curve
744 val = interpolate_val(n, x, i * res, y, ypp, curve->m_spline_type) * (sample->m_outputRes - 1) + 0.5;
745 if(val > maxY) val = maxY;
746 if(val < minY) val = minY;
747 sample->m_Samples[i] = val;
748 }
749 }
750
751 free(ypp);
752 return CT_SUCCESS;
753 }
754
755 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
756 // vim: shiftwidth=2 expandtab tabstop=2 cindent
757 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
758