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