00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 #include <gimp-print/gimp-print.h>
00028 #include "gimp-print-internal.h"
00029 #include <gimp-print/gimp-print-intl-internal.h>
00030 #include <math.h>
00031 #ifdef sun
00032 #include <ieeefp.h>
00033 #endif
00034 #include <string.h>
00035 #include <stdlib.h>
00036 #include <limits.h>
00037 #include <unistd.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040
00041 #ifdef __GNUC__
00042 #define inline __inline__
00043 #endif
00044
00045 #undef inline
00046 #define inline
00047
00048 static const int curve_point_limit = 1048576;
00049
00050 struct stp_curve
00051 {
00052 stp_curve_type_t curve_type;
00053 stp_curve_wrap_mode_t wrap_mode;
00054 int piecewise;
00055 int recompute_interval;
00056 double gamma;
00057 stp_sequence_t *seq;
00058 double *interval;
00059
00060
00061 };
00062
00063 static const char *const stpi_curve_type_names[] =
00064 {
00065 "linear",
00066 "spline",
00067 };
00068
00069 static const int stpi_curve_type_count =
00070 (sizeof(stpi_curve_type_names) / sizeof(const char *));
00071
00072 static const char *const stpi_wrap_mode_names[] =
00073 {
00074 "nowrap",
00075 "wrap"
00076 };
00077
00078 static const int stpi_wrap_mode_count =
00079 (sizeof(stpi_wrap_mode_names) / sizeof(const char *));
00080
00081
00082
00083
00084 static void
00085 check_curve(const stp_curve_t *curve)
00086 {
00087 if (curve == NULL)
00088 {
00089 stp_erprintf("Null curve! Please report this bug.\n");
00090 stp_abort();
00091 }
00092 if (curve->seq == NULL)
00093 {
00094 stp_erprintf("Bad curve (seq == NULL)! Please report this bug.\n");
00095 stp_abort();
00096 }
00097 }
00098
00099
00100
00101
00102 static size_t
00103 get_real_point_count(const stp_curve_t *curve)
00104 {
00105 if (curve->piecewise)
00106 return stp_sequence_get_size(curve->seq) / 2;
00107 else
00108 return stp_sequence_get_size(curve->seq);
00109 }
00110
00111
00112
00113
00114
00115
00116 static size_t
00117 get_point_count(const stp_curve_t *curve)
00118 {
00119 size_t count = get_real_point_count(curve);
00120 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00121 count -= 1;
00122
00123 return count;
00124 }
00125
00126 static void
00127 invalidate_auxiliary_data(stp_curve_t *curve)
00128 {
00129 STP_SAFE_FREE(curve->interval);
00130 }
00131
00132 static void
00133 clear_curve_data(stp_curve_t *curve)
00134 {
00135 if (curve->seq)
00136 stp_sequence_set_size(curve->seq, 0);
00137 curve->recompute_interval = 0;
00138 invalidate_auxiliary_data(curve);
00139 }
00140
00141 static void
00142 compute_linear_deltas(stp_curve_t *curve)
00143 {
00144 int i;
00145 size_t delta_count;
00146 size_t seq_point_count;
00147 const double *data;
00148
00149 stp_sequence_get_data(curve->seq, &seq_point_count, &data);
00150 if (data == NULL)
00151 return;
00152
00153 delta_count = get_real_point_count(curve);
00154
00155 if (delta_count <= 1)
00156 return;
00157 delta_count--;
00158
00159
00160 curve->interval = stp_malloc(sizeof(double) * delta_count);
00161 for (i = 0; i < delta_count; i++)
00162 {
00163 if (curve->piecewise)
00164 curve->interval[i] = data[(2 * (i + 1)) + 1] - data[(2 * i) + 1];
00165 else
00166 curve->interval[i] = data[i + 1] - data[i];
00167 }
00168 }
00169
00170 static void
00171 compute_spline_deltas_piecewise(stp_curve_t *curve)
00172 {
00173 int i;
00174 int k;
00175 double *u;
00176 double *y2;
00177 const double *data = NULL;
00178 const stp_curve_point_t *dp;
00179 size_t point_count;
00180 size_t real_point_count;
00181 double sig;
00182 double p;
00183
00184 point_count = get_point_count(curve);
00185
00186 stp_sequence_get_data(curve->seq, &real_point_count, &data);
00187 dp = (const stp_curve_point_t *)data;
00188 real_point_count = real_point_count / 2;
00189
00190 u = stp_malloc(sizeof(double) * real_point_count);
00191 y2 = stp_malloc(sizeof(double) * real_point_count);
00192
00193 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00194 {
00195 int reps = 3;
00196 int count = reps * real_point_count;
00197 double *y2a = stp_malloc(sizeof(double) * count);
00198 double *ua = stp_malloc(sizeof(double) * count);
00199 y2a[0] = 0.0;
00200 ua[0] = 0.0;
00201 for (i = 1; i < count - 1; i++)
00202 {
00203 int im1 = (i - 1) % point_count;
00204 int ia = i % point_count;
00205 int ip1 = (i + 1) % point_count;
00206
00207 sig = (dp[ia].x - dp[im1].x) / (dp[ip1].x - dp[im1].x);
00208 p = sig * y2a[im1] + 2.0;
00209 y2a[i] = (sig - 1.0) / p;
00210
00211 ua[i] = ((dp[ip1].y - dp[ia].y) / (dp[ip1].x - dp[ia].x)) -
00212 ((dp[ia].y - dp[im1].y) / (dp[ia].x - dp[im1].x));
00213 ua[i] =
00214 (((6.0 * ua[ia]) / (dp[ip1].x - dp[im1].x)) - (sig * ua[im1])) / p;
00215 }
00216 y2a[count - 1] = 0.0;
00217 for (k = count - 2 ; k >= 0; k--)
00218 y2a[k] = y2a[k] * y2a[k + 1] + ua[k];
00219 memcpy(u, ua + ((reps / 2) * point_count),
00220 sizeof(double) * real_point_count);
00221 memcpy(y2, y2a + ((reps / 2) * point_count),
00222 sizeof(double) * real_point_count);
00223 stp_free(y2a);
00224 stp_free(ua);
00225 }
00226 else
00227 {
00228 int count = real_point_count - 1;
00229
00230 y2[0] = 0;
00231 u[0] = 2 * (dp[1].y - dp[0].y);
00232 for (i = 1; i < count; i++)
00233 {
00234 int im1 = (i - 1);
00235 int ip1 = (i + 1);
00236
00237 sig = (dp[i].x - dp[im1].x) / (dp[ip1].x - dp[im1].x);
00238 p = sig * y2[im1] + 2.0;
00239 y2[i] = (sig - 1.0) / p;
00240
00241 u[i] = ((dp[ip1].y - dp[i].y) / (dp[ip1].x - dp[i].x)) -
00242 ((dp[i].y - dp[im1].y) / (dp[i].x - dp[im1].x));
00243 u[i] =
00244 (((6.0 * u[i]) / (dp[ip1].x - dp[im1].x)) - (sig * u[im1])) / p;
00245 stp_deprintf(STP_DBG_CURVE,
00246 "%d sig %f p %f y2 %f u %f x %f %f %f y %f %f %f\n",
00247 i, sig, p, y2[i], u[i],
00248 dp[im1].x, dp[i].x, dp[ip1].x,
00249 dp[im1].y, dp[i].y, dp[ip1].y);
00250 }
00251 y2[count] = 0.0;
00252 u[count] = 0.0;
00253 for (k = real_point_count - 2; k >= 0; k--)
00254 y2[k] = y2[k] * y2[k + 1] + u[k];
00255 }
00256
00257 curve->interval = y2;
00258 stp_free(u);
00259 }
00260
00261 static void
00262 compute_spline_deltas_dense(stp_curve_t *curve)
00263 {
00264 int i;
00265 int k;
00266 double *u;
00267 double *y2;
00268 const double *y;
00269 size_t point_count;
00270 size_t real_point_count;
00271 double sig;
00272 double p;
00273
00274 point_count = get_point_count(curve);
00275
00276 stp_sequence_get_data(curve->seq, &real_point_count, &y);
00277 u = stp_malloc(sizeof(double) * real_point_count);
00278 y2 = stp_malloc(sizeof(double) * real_point_count);
00279
00280 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00281 {
00282 int reps = 3;
00283 int count = reps * real_point_count;
00284 double *y2a = stp_malloc(sizeof(double) * count);
00285 double *ua = stp_malloc(sizeof(double) * count);
00286 y2a[0] = 0.0;
00287 ua[0] = 0.0;
00288 for (i = 1; i < count - 1; i++)
00289 {
00290 int im1 = (i - 1);
00291 int ip1 = (i + 1);
00292 int im1a = im1 % point_count;
00293 int ia = i % point_count;
00294 int ip1a = ip1 % point_count;
00295
00296 sig = (i - im1) / (ip1 - im1);
00297 p = sig * y2a[im1] + 2.0;
00298 y2a[i] = (sig - 1.0) / p;
00299
00300 ua[i] = y[ip1a] - 2 * y[ia] + y[im1a];
00301 ua[i] = 3.0 * ua[i] - sig * ua[im1] / p;
00302 }
00303 y2a[count - 1] = 0.0;
00304 for (k = count - 2 ; k >= 0; k--)
00305 y2a[k] = y2a[k] * y2a[k + 1] + ua[k];
00306 memcpy(u, ua + ((reps / 2) * point_count),
00307 sizeof(double) * real_point_count);
00308 memcpy(y2, y2a + ((reps / 2) * point_count),
00309 sizeof(double) * real_point_count);
00310 stp_free(y2a);
00311 stp_free(ua);
00312 }
00313 else
00314 {
00315 int count = real_point_count - 1;
00316
00317 y2[0] = 0;
00318 u[0] = 2 * (y[1] - y[0]);
00319 for (i = 1; i < count; i++)
00320 {
00321 int im1 = (i - 1);
00322 int ip1 = (i + 1);
00323
00324 sig = (i - im1) / (ip1 - im1);
00325 p = sig * y2[im1] + 2.0;
00326 y2[i] = (sig - 1.0) / p;
00327
00328 u[i] = y[ip1] - 2 * y[i] + y[im1];
00329 u[i] = 3.0 * u[i] - sig * u[im1] / p;
00330 }
00331
00332 u[count] = 2 * (y[count] - y[count - 1]);
00333 y2[count] = 0.0;
00334
00335 u[count] = 0.0;
00336 for (k = real_point_count - 2; k >= 0; k--)
00337 y2[k] = y2[k] * y2[k + 1] + u[k];
00338 }
00339
00340 curve->interval = y2;
00341 stp_free(u);
00342 }
00343
00344 static void
00345 compute_spline_deltas(stp_curve_t *curve)
00346 {
00347 if (curve->piecewise)
00348 compute_spline_deltas_piecewise(curve);
00349 else
00350 compute_spline_deltas_dense(curve);
00351 }
00352
00353
00354
00355
00356
00357
00358 static void
00359 compute_intervals(stp_curve_t *curve)
00360 {
00361 if (curve->interval)
00362 {
00363 stp_free(curve->interval);
00364 curve->interval = NULL;
00365 }
00366 if (stp_sequence_get_size(curve->seq) > 0)
00367 {
00368 switch (curve->curve_type)
00369 {
00370 case STP_CURVE_TYPE_SPLINE:
00371 compute_spline_deltas(curve);
00372 break;
00373 case STP_CURVE_TYPE_LINEAR:
00374 compute_linear_deltas(curve);
00375 break;
00376 }
00377 }
00378 curve->recompute_interval = 0;
00379 }
00380
00381 static int
00382 stpi_curve_set_points(stp_curve_t *curve, size_t points)
00383 {
00384 if (points < 2)
00385 return 0;
00386 if (points > curve_point_limit ||
00387 (curve->wrap_mode == STP_CURVE_WRAP_AROUND &&
00388 points > curve_point_limit - 1))
00389 return 0;
00390 clear_curve_data(curve);
00391 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00392 points++;
00393 if (curve->piecewise)
00394 points *= 2;
00395 if ((stp_sequence_set_size(curve->seq, points)) == 0)
00396 return 0;
00397 return 1;
00398 }
00399
00400
00401
00402
00403 static void
00404 stpi_curve_ctor(stp_curve_t *curve, stp_curve_wrap_mode_t wrap_mode)
00405 {
00406 curve->seq = stp_sequence_create();
00407 stp_sequence_set_bounds(curve->seq, 0.0, 1.0);
00408 curve->curve_type = STP_CURVE_TYPE_LINEAR;
00409 curve->wrap_mode = wrap_mode;
00410 curve->piecewise = 0;
00411 stpi_curve_set_points(curve, 2);
00412 curve->recompute_interval = 1;
00413 if (wrap_mode == STP_CURVE_WRAP_NONE)
00414 curve->gamma = 1.0;
00415 stp_sequence_set_point(curve->seq, 0, 0);
00416 stp_sequence_set_point(curve->seq, 1, 1);
00417 }
00418
00419 stp_curve_t *
00420 stp_curve_create(stp_curve_wrap_mode_t wrap_mode)
00421 {
00422 stp_curve_t *ret;
00423 if (wrap_mode != STP_CURVE_WRAP_NONE && wrap_mode != STP_CURVE_WRAP_AROUND)
00424 return NULL;
00425 ret = stp_zalloc(sizeof(stp_curve_t));
00426 stpi_curve_ctor(ret, wrap_mode);
00427 return ret;
00428 }
00429
00430 static void
00431 curve_dtor(stp_curve_t *curve)
00432 {
00433 check_curve(curve);
00434 clear_curve_data(curve);
00435 if (curve->seq)
00436 stp_sequence_destroy(curve->seq);
00437 memset(curve, 0, sizeof(stp_curve_t));
00438 curve->curve_type = -1;
00439 }
00440
00441 void
00442 stp_curve_destroy(stp_curve_t *curve)
00443 {
00444 curve_dtor(curve);
00445 stp_free(curve);
00446 }
00447
00448 void
00449 stp_curve_copy(stp_curve_t *dest, const stp_curve_t *source)
00450 {
00451 check_curve(dest);
00452 check_curve(source);
00453 curve_dtor(dest);
00454 dest->curve_type = source->curve_type;
00455 dest->wrap_mode = source->wrap_mode;
00456 dest->gamma = source->gamma;
00457 dest->seq = stp_sequence_create_copy(source->seq);
00458 dest->piecewise = source->piecewise;
00459 dest->recompute_interval = 1;
00460 }
00461
00462 stp_curve_t *
00463 stp_curve_create_copy(const stp_curve_t *curve)
00464 {
00465 stp_curve_t *ret;
00466 check_curve(curve);
00467 ret = stp_curve_create(curve->wrap_mode);
00468 stp_curve_copy(ret, curve);
00469 return ret;
00470 }
00471
00472 int
00473 stp_curve_set_bounds(stp_curve_t *curve, double low, double high)
00474 {
00475 check_curve(curve);
00476 return stp_sequence_set_bounds(curve->seq, low, high);
00477 }
00478
00479 void
00480 stp_curve_get_bounds(const stp_curve_t *curve, double *low, double *high)
00481 {
00482 check_curve(curve);
00483 stp_sequence_get_bounds(curve->seq, low, high);
00484 }
00485
00486
00487
00488
00489
00490
00491
00492 void
00493 stp_curve_get_range(const stp_curve_t *curve, double *low, double *high)
00494 {
00495 check_curve(curve);
00496 stp_sequence_get_range(curve->seq, low, high);
00497 }
00498
00499 size_t
00500 stp_curve_count_points(const stp_curve_t *curve)
00501 {
00502 check_curve(curve);
00503 return get_point_count(curve);
00504 }
00505
00506 stp_curve_wrap_mode_t
00507 stp_curve_get_wrap(const stp_curve_t *curve)
00508 {
00509 check_curve(curve);
00510 return curve->wrap_mode;
00511 }
00512
00513 int
00514 stp_curve_is_piecewise(const stp_curve_t *curve)
00515 {
00516 check_curve(curve);
00517 return curve->piecewise;
00518 }
00519
00520 int
00521 stp_curve_set_interpolation_type(stp_curve_t *curve, stp_curve_type_t itype)
00522 {
00523 check_curve(curve);
00524 if (itype < 0 || itype >= stpi_curve_type_count)
00525 return 0;
00526 curve->curve_type = itype;
00527 return 1;
00528 }
00529
00530 stp_curve_type_t
00531 stp_curve_get_interpolation_type(const stp_curve_t *curve)
00532 {
00533 check_curve(curve);
00534 return curve->curve_type;
00535 }
00536
00537 int
00538 stp_curve_set_gamma(stp_curve_t *curve, double fgamma)
00539 {
00540 check_curve(curve);
00541 if (curve->wrap_mode || ! finite(fgamma) || fgamma == 0.0)
00542 return 0;
00543 clear_curve_data(curve);
00544 curve->gamma = fgamma;
00545 stp_curve_resample(curve, 2);
00546 return 1;
00547 }
00548
00549 double
00550 stp_curve_get_gamma(const stp_curve_t *curve)
00551 {
00552 check_curve(curve);
00553 return curve->gamma;
00554 }
00555
00556 int
00557 stp_curve_set_data(stp_curve_t *curve, size_t count, const double *data)
00558 {
00559 size_t i;
00560 size_t real_count = count;
00561 double low, high;
00562 check_curve(curve);
00563 if (count < 2)
00564 return 0;
00565 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00566 real_count++;
00567 if (real_count > curve_point_limit)
00568 return 0;
00569
00570
00571 stp_sequence_get_bounds(curve->seq, &low, &high);
00572 for (i = 0; i < count; i++)
00573 if (! finite(data[i]) || data[i] < low || data[i] > high)
00574 {
00575 stp_deprintf(STP_DBG_CURVE_ERRORS,
00576 "stp_curve_set_data: datum out of bounds: "
00577 "%g (require %g <= x <= %g), n = %d\n",
00578 data[i], low, high, i);
00579 return 0;
00580 }
00581
00582 stpi_curve_set_points(curve, count);
00583 curve->gamma = 0.0;
00584 stp_sequence_set_subrange(curve->seq, 0, count, data);
00585
00586 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00587 stp_sequence_set_point(curve->seq, count, data[0]);
00588 curve->recompute_interval = 1;
00589 curve->piecewise = 0;
00590
00591 return 1;
00592 }
00593
00594 int
00595 stp_curve_set_data_points(stp_curve_t *curve, size_t count,
00596 const stp_curve_point_t *data)
00597 {
00598 size_t i;
00599 size_t real_count = count;
00600 double low, high;
00601 double last_x = -1;
00602 check_curve(curve);
00603 if (count < 2)
00604 {
00605 stp_deprintf(STP_DBG_CURVE_ERRORS,
00606 "stp_curve_set_data_points: too few points %d\n", count);
00607 return 0;
00608 }
00609 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00610 real_count++;
00611 if (real_count > curve_point_limit)
00612 {
00613 stp_deprintf(STP_DBG_CURVE_ERRORS,
00614 "stp_curve_set_data_points: too many points %d\n",
00615 real_count);
00616 return 0;
00617 }
00618
00619
00620 stp_sequence_get_bounds(curve->seq, &low, &high);
00621 for (i = 0; i < count; i++)
00622 {
00623 if (! finite(data[i].y) || data[i].y < low || data[i].y > high)
00624 {
00625 stp_deprintf(STP_DBG_CURVE_ERRORS,
00626 "stp_curve_set_data_points: datum out of bounds: "
00627 "%g (require %g <= x <= %g), n = %d\n",
00628 data[i].y, low, high, i);
00629 return 0;
00630 }
00631 if (i == 0 && data[i].x != 0.0)
00632 {
00633 stp_deprintf(STP_DBG_CURVE_ERRORS,
00634 "stp_curve_set_data_points: first point must have x=0\n");
00635 return 0;
00636 }
00637 if (curve->wrap_mode == STP_CURVE_WRAP_NONE && i == count - 1 &&
00638 data[i].x != 1.0)
00639 {
00640 stp_deprintf(STP_DBG_CURVE_ERRORS,
00641 "stp_curve_set_data_points: last point must have x=1\n");
00642 return 0;
00643 }
00644 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND &&
00645 data[i].x >= 1.0 - .000001)
00646 {
00647 stp_deprintf(STP_DBG_CURVE_ERRORS,
00648 "stp_curve_set_data_points: horizontal value must "
00649 "not exceed .99999\n");
00650 return 0;
00651 }
00652 if (data[i].x < 0 || data[i].x > 1)
00653 {
00654 stp_deprintf(STP_DBG_CURVE_ERRORS,
00655 "stp_curve_set_data_points: horizontal position out of bounds: "
00656 "%g, n = %d\n",
00657 data[i].x, i);
00658 return 0;
00659 }
00660 if (data[i].x - .000001 < last_x)
00661 {
00662 stp_deprintf(STP_DBG_CURVE_ERRORS,
00663 "stp_curve_set_data_points: horizontal position must "
00664 "exceed previous position by .000001: %g, %g, n = %d\n",
00665 data[i].x, last_x, i);
00666 return 0;
00667 }
00668 last_x = data[i].x;
00669 }
00670
00671 curve->piecewise = 1;
00672 stpi_curve_set_points(curve, count);
00673 curve->gamma = 0.0;
00674 stp_sequence_set_subrange(curve->seq, 0, count * 2, (const double *) data);
00675
00676 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00677 {
00678 stp_sequence_set_point(curve->seq, count * 2, data[0].x);
00679 stp_sequence_set_point(curve->seq, count * 2 + 1, data[0].y);
00680 }
00681 curve->recompute_interval = 1;
00682
00683 return 1;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692 const double *
00693 stp_curve_get_data(const stp_curve_t *curve, size_t *count)
00694 {
00695 const double *ret;
00696 check_curve(curve);
00697 if (curve->piecewise)
00698 return NULL;
00699 stp_sequence_get_data(curve->seq, count, &ret);
00700 *count = get_point_count(curve);
00701 return ret;
00702 }
00703
00704 const stp_curve_point_t *
00705 stp_curve_get_data_points(const stp_curve_t *curve, size_t *count)
00706 {
00707 const stp_curve_point_t *ret;
00708 check_curve(curve);
00709 if (!curve->piecewise)
00710 return NULL;
00711 stp_sequence_get_data(curve->seq, count, (const double **) &ret);
00712 *count = get_point_count(curve);
00713 return ret;
00714 }
00715
00716 static const double *
00717 stpi_curve_get_data_internal(const stp_curve_t *curve, size_t *count)
00718 {
00719 const double *ret;
00720 check_curve(curve);
00721 stp_sequence_get_data(curve->seq, count, &ret);
00722 *count = get_point_count(curve);
00723 if (curve->piecewise)
00724 *count *= 2;
00725 return ret;
00726 }
00727
00728
00729
00730
00731 #define DEFINE_DATA_SETTER(t, name) \
00732 int \
00733 stp_curve_set_##name##_data(stp_curve_t *curve, size_t count, const t *data) \
00734 { \
00735 double *tmp_data; \
00736 size_t i; \
00737 int status; \
00738 size_t real_count = count; \
00739 \
00740 check_curve(curve); \
00741 if (count < 2) \
00742 return 0; \
00743 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND) \
00744 real_count++; \
00745 if (real_count > curve_point_limit) \
00746 return 0; \
00747 tmp_data = stp_malloc(count * sizeof(double)); \
00748 for (i = 0; i < count; i++) \
00749 tmp_data[i] = (double) data[i]; \
00750 status = stp_curve_set_data(curve, count, tmp_data); \
00751 stp_free(tmp_data); \
00752 return status; \
00753 }
00754
00755 DEFINE_DATA_SETTER(float, float)
00756 DEFINE_DATA_SETTER(long, long)
00757 DEFINE_DATA_SETTER(unsigned long, ulong)
00758 DEFINE_DATA_SETTER(int, int)
00759 DEFINE_DATA_SETTER(unsigned int, uint)
00760 DEFINE_DATA_SETTER(short, short)
00761 DEFINE_DATA_SETTER(unsigned short, ushort)
00762
00763
00764 #define DEFINE_DATA_ACCESSOR(t, name) \
00765 const t * \
00766 stp_curve_get_##name##_data(const stp_curve_t *curve, size_t *count) \
00767 { \
00768 if (curve->piecewise) \
00769 return 0; \
00770 return stp_sequence_get_##name##_data(curve->seq, count); \
00771 }
00772
00773 DEFINE_DATA_ACCESSOR(float, float)
00774 DEFINE_DATA_ACCESSOR(long, long)
00775 DEFINE_DATA_ACCESSOR(unsigned long, ulong)
00776 DEFINE_DATA_ACCESSOR(int, int)
00777 DEFINE_DATA_ACCESSOR(unsigned int, uint)
00778 DEFINE_DATA_ACCESSOR(short, short)
00779 DEFINE_DATA_ACCESSOR(unsigned short, ushort)
00780
00781
00782 stp_curve_t *
00783 stp_curve_get_subrange(const stp_curve_t *curve, size_t start, size_t count)
00784 {
00785 stp_curve_t *retval;
00786 size_t ncount;
00787 double blo, bhi;
00788 const double *data;
00789 if (start + count > stp_curve_count_points(curve) || count < 2)
00790 return NULL;
00791 if (curve->piecewise)
00792 return NULL;
00793 retval = stp_curve_create(STP_CURVE_WRAP_NONE);
00794 stp_curve_get_bounds(curve, &blo, &bhi);
00795 stp_curve_set_bounds(retval, blo, bhi);
00796 data = stp_curve_get_data(curve, &ncount);
00797 if (! stp_curve_set_data(retval, count, data + start))
00798 {
00799 stp_curve_destroy(retval);
00800 return NULL;
00801 }
00802 return retval;
00803 }
00804
00805 int
00806 stp_curve_set_subrange(stp_curve_t *curve, const stp_curve_t *range,
00807 size_t start)
00808 {
00809 double blo, bhi;
00810 double rlo, rhi;
00811 const double *data;
00812 size_t count;
00813 check_curve(curve);
00814 if (start + stp_curve_count_points(range) > stp_curve_count_points(curve))
00815 return 0;
00816 if (curve->piecewise)
00817 return 0;
00818 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00819 stp_sequence_get_range(curve->seq, &rlo, &rhi);
00820 if (rlo < blo || rhi > bhi)
00821 return 0;
00822 stp_sequence_get_data(range->seq, &count, &data);
00823 curve->recompute_interval = 1;
00824 curve->gamma = 0.0;
00825 invalidate_auxiliary_data(curve);
00826 stp_sequence_set_subrange(curve->seq, start, stp_curve_count_points(range),
00827 data);
00828 return 1;
00829 }
00830
00831
00832 int
00833 stp_curve_set_point(stp_curve_t *curve, size_t where, double data)
00834 {
00835 check_curve(curve);
00836 if (where >= get_point_count(curve))
00837 return 0;
00838 curve->gamma = 0.0;
00839
00840 if (curve->piecewise)
00841 return 0;
00842 if ((stp_sequence_set_point(curve->seq, where, data)) == 0)
00843 return 0;
00844 if (where == 0 && curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00845 if ((stp_sequence_set_point(curve->seq,
00846 get_point_count(curve), data)) == 0)
00847 return 0;
00848 invalidate_auxiliary_data(curve);
00849 return 1;
00850 }
00851
00852 int
00853 stp_curve_get_point(const stp_curve_t *curve, size_t where, double *data)
00854 {
00855 check_curve(curve);
00856 if (where >= get_point_count(curve))
00857 return 0;
00858 if (curve->piecewise)
00859 return 0;
00860 return stp_sequence_get_point(curve->seq, where, data);
00861 }
00862
00863 const stp_sequence_t *
00864 stp_curve_get_sequence(const stp_curve_t *curve)
00865 {
00866 check_curve(curve);
00867 if (curve->piecewise)
00868 return NULL;
00869 return curve->seq;
00870 }
00871
00872 int
00873 stp_curve_rescale(stp_curve_t *curve, double scale,
00874 stp_curve_compose_t mode, stp_curve_bounds_t bounds_mode)
00875 {
00876 size_t real_point_count;
00877 int i;
00878 double nblo;
00879 double nbhi;
00880 size_t count;
00881
00882 check_curve(curve);
00883
00884 real_point_count = get_real_point_count(curve);
00885
00886 stp_sequence_get_bounds(curve->seq, &nblo, &nbhi);
00887 if (bounds_mode == STP_CURVE_BOUNDS_RESCALE)
00888 {
00889 switch (mode)
00890 {
00891 case STP_CURVE_COMPOSE_ADD:
00892 nblo += scale;
00893 nbhi += scale;
00894 break;
00895 case STP_CURVE_COMPOSE_MULTIPLY:
00896 if (scale < 0)
00897 {
00898 double tmp = nblo * scale;
00899 nblo = nbhi * scale;
00900 nbhi = tmp;
00901 }
00902 else
00903 {
00904 nblo *= scale;
00905 nbhi *= scale;
00906 }
00907 break;
00908 case STP_CURVE_COMPOSE_EXPONENTIATE:
00909 if (scale == 0.0)
00910 return 0;
00911 if (nblo < 0)
00912 return 0;
00913 nblo = pow(nblo, scale);
00914 nbhi = pow(nbhi, scale);
00915 break;
00916 default:
00917 return 0;
00918 }
00919 }
00920
00921 if (! finite(nbhi) || ! finite(nblo))
00922 return 0;
00923
00924 count = get_point_count(curve);
00925 if (count)
00926 {
00927 double *tmp;
00928 size_t scount;
00929 int stride = 1;
00930 int offset = 0;
00931 const double *data;
00932 if (curve->piecewise)
00933 {
00934 stride = 2;
00935 offset = 1;
00936 }
00937 stp_sequence_get_data(curve->seq, &scount, &data);
00938 tmp = stp_malloc(sizeof(double) * scount);
00939 memcpy(tmp, data, scount * sizeof(double));
00940 for (i = offset; i < scount; i += stride)
00941 {
00942 switch (mode)
00943 {
00944 case STP_CURVE_COMPOSE_ADD:
00945 tmp[i] = tmp[i] + scale;
00946 break;
00947 case STP_CURVE_COMPOSE_MULTIPLY:
00948 tmp[i] = tmp[i] * scale;
00949 break;
00950 case STP_CURVE_COMPOSE_EXPONENTIATE:
00951 tmp[i] = pow(tmp[i], scale);
00952 break;
00953 }
00954 if (tmp[i] > nbhi || tmp[i] < nblo)
00955 {
00956 if (bounds_mode == STP_CURVE_BOUNDS_ERROR)
00957 {
00958 stp_free(tmp);
00959 return(0);
00960 }
00961 else if (tmp[i] > nbhi)
00962 tmp[i] = nbhi;
00963 else
00964 tmp[i] = nblo;
00965 }
00966 }
00967 stp_sequence_set_bounds(curve->seq, nblo, nbhi);
00968 curve->gamma = 0.0;
00969 stpi_curve_set_points(curve, count);
00970 stp_sequence_set_subrange(curve->seq, 0, scount, tmp);
00971 stp_free(tmp);
00972 curve->recompute_interval = 1;
00973 invalidate_auxiliary_data(curve);
00974 }
00975 return 1;
00976 }
00977
00978 static int
00979 stpi_curve_check_parameters(stp_curve_t *curve, size_t points)
00980 {
00981 double blo, bhi;
00982 if (curve->gamma && curve->wrap_mode)
00983 {
00984 stp_deprintf(STP_DBG_CURVE_ERRORS,
00985 "curve sets both gamma and wrap_mode\n");
00986 return 0;
00987 }
00988 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00989 if (blo > bhi)
00990 {
00991 stp_deprintf(STP_DBG_CURVE_ERRORS,
00992 "curve low bound is greater than high bound\n");
00993 return 0;
00994 }
00995 return 1;
00996 }
00997
00998 static inline double
00999 interpolate_gamma_internal(const stp_curve_t *curve, double where)
01000 {
01001 double fgamma = curve->gamma;
01002 double blo, bhi;
01003 size_t real_point_count;
01004
01005 real_point_count = get_real_point_count(curve);;
01006
01007 if (real_point_count)
01008 where /= (real_point_count - 1);
01009 if (fgamma < 0)
01010 {
01011 where = 1.0 - where;
01012 fgamma = -fgamma;
01013 }
01014 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
01015 stp_deprintf(STP_DBG_CURVE,
01016 "interpolate_gamma %f %f %f %f %f\n", where, fgamma,
01017 blo, bhi, pow(where, fgamma));
01018 return blo + (bhi - blo) * pow(where, fgamma);
01019 }
01020
01021 static inline double
01022 do_interpolate_spline(double low, double high, double frac,
01023 double interval_low, double interval_high,
01024 double x_interval)
01025 {
01026 double a = 1.0 - frac;
01027 double b = frac;
01028 double retval =
01029 ((a * a * a - a) * interval_low) + ((b * b * b - b) * interval_high);
01030 retval = retval * x_interval * x_interval / 6;
01031 retval += (a * low) + (b * high);
01032 return retval;
01033 }
01034
01035 static inline double
01036 interpolate_point_internal(stp_curve_t *curve, double where)
01037 {
01038 int integer = where;
01039 double frac = where - (double) integer;
01040 double bhi, blo;
01041
01042 if (frac == 0.0)
01043 {
01044 double val;
01045 if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
01046 return HUGE_VAL;
01047 return val;
01048 }
01049 if (curve->recompute_interval)
01050 compute_intervals(curve);
01051 if (curve->curve_type == STP_CURVE_TYPE_LINEAR)
01052 {
01053 double val;
01054 if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
01055 return HUGE_VAL;
01056 return val + frac * curve->interval[integer];
01057 }
01058 else
01059 {
01060 size_t point_count;
01061 double ival, ip1val;
01062 double retval;
01063 int i = integer;
01064 int ip1 = integer + 1;
01065
01066 point_count = get_point_count(curve);
01067
01068 if (ip1 >= point_count)
01069 ip1 -= point_count;
01070
01071 if ((stp_sequence_get_point(curve->seq, i, &ival)) == 0 ||
01072 (stp_sequence_get_point(curve->seq, ip1, &ip1val)) == 0)
01073 return HUGE_VAL;
01074
01075 retval = do_interpolate_spline(ival, ip1val, frac, curve->interval[i],
01076 curve->interval[ip1], 1.0);
01077
01078 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
01079 if (retval > bhi)
01080 retval = bhi;
01081 if (retval < blo)
01082 retval = blo;
01083 return retval;
01084 }
01085 }
01086
01087 int
01088 stp_curve_interpolate_value(const stp_curve_t *curve, double where,
01089 double *result)
01090 {
01091 size_t limit;
01092
01093 check_curve(curve);
01094 if (curve->piecewise)
01095 return 0;
01096
01097 limit = get_real_point_count(curve);
01098
01099 if (where < 0 || where > limit)
01100 return 0;
01101 if (curve->gamma)
01102 *result = interpolate_gamma_internal(curve, where);
01103 else
01104 *result = interpolate_point_internal((stp_curve_t *) curve, where);
01105 return 1;
01106 }
01107
01108 int
01109 stp_curve_resample(stp_curve_t *curve, size_t points)
01110 {
01111 size_t limit = points;
01112 size_t old;
01113 size_t i;
01114 double *new_vec;
01115
01116 check_curve(curve);
01117
01118 if (points == get_point_count(curve) && curve->seq && !(curve->piecewise))
01119 return 1;
01120
01121 if (points < 2)
01122 return 1;
01123
01124 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
01125 limit++;
01126 if (limit > curve_point_limit)
01127 return 0;
01128 old = get_real_point_count(curve);
01129 if (old)
01130 old--;
01131 if (!old)
01132 old = 1;
01133
01134 new_vec = stp_malloc(sizeof(double) * limit);
01135
01136
01137
01138
01139
01140
01141 if (curve->piecewise)
01142 {
01143 double blo, bhi;
01144 int curpos = 0;
01145 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
01146 if (curve->recompute_interval)
01147 compute_intervals(curve);
01148 for (i = 0; i < old; i++)
01149 {
01150 double low;
01151 double high;
01152 double low_y;
01153 double high_y;
01154 double x_delta;
01155 if (!stp_sequence_get_point(curve->seq, i * 2, &low))
01156 {
01157 stp_free(new_vec);
01158 return 0;
01159 }
01160 if (i == old - 1)
01161 high = 1.0;
01162 else if (!stp_sequence_get_point(curve->seq, ((i + 1) * 2), &high))
01163 {
01164 stp_free(new_vec);
01165 return 0;
01166 }
01167 if (!stp_sequence_get_point(curve->seq, (i * 2) + 1, &low_y))
01168 {
01169 stp_free(new_vec);
01170 return 0;
01171 }
01172 if (!stp_sequence_get_point(curve->seq, ((i + 1) * 2) + 1, &high_y))
01173 {
01174 stp_free(new_vec);
01175 return 0;
01176 }
01177 stp_deprintf(STP_DBG_CURVE,
01178 "Filling slots at %d %d: %f %f %f %f %d\n",
01179 i,curpos, high, low, high_y, low_y, limit);
01180 x_delta = high - low;
01181 high *= (limit - 1);
01182 low *= (limit - 1);
01183 while (curpos <= high)
01184 {
01185 double frac = (curpos - low) / (high - low);
01186 if (curve->curve_type == STP_CURVE_TYPE_LINEAR)
01187 new_vec[curpos] = low_y + frac * (high_y - low_y);
01188 else
01189 new_vec[curpos] =
01190 do_interpolate_spline(low_y, high_y, frac,
01191 curve->interval[i],
01192 curve->interval[i + 1],
01193 x_delta);
01194 if (new_vec[curpos] < blo)
01195 new_vec[curpos] = blo;
01196 if (new_vec[curpos] > bhi)
01197 new_vec[curpos] = bhi;
01198 stp_deprintf(STP_DBG_CURVE,
01199 " Filling slot %d %f %f\n",
01200 curpos, frac, new_vec[curpos]);
01201 curpos++;
01202 }
01203 }
01204 curve->piecewise = 0;
01205 }
01206 else
01207 {
01208 for (i = 0; i < limit; i++)
01209 if (curve->gamma)
01210 new_vec[i] =
01211 interpolate_gamma_internal(curve, ((double) i * (double) old /
01212 (double) (limit - 1)));
01213 else
01214 new_vec[i] =
01215 interpolate_point_internal(curve, ((double) i * (double) old /
01216 (double) (limit - 1)));
01217 }
01218 stpi_curve_set_points(curve, points);
01219 stp_sequence_set_subrange(curve->seq, 0, limit, new_vec);
01220 curve->recompute_interval = 1;
01221 stp_free(new_vec);
01222 return 1;
01223 }
01224
01225 static unsigned
01226 gcd(unsigned a, unsigned b)
01227 {
01228 unsigned tmp;
01229 if (b > a)
01230 {
01231 tmp = a;
01232 a = b;
01233 b = tmp;
01234 }
01235 while (1)
01236 {
01237 tmp = a % b;
01238 if (tmp == 0)
01239 return b;
01240 a = b;
01241 b = tmp;
01242 }
01243 }
01244
01245 static unsigned
01246 lcm(unsigned a, unsigned b)
01247 {
01248 if (a == b)
01249 return a;
01250 else if (a * b == 0)
01251 return a > b ? a : b;
01252 else
01253 {
01254 double rval = (double) a / gcd(a, b) * b;
01255 if (rval > curve_point_limit)
01256 return curve_point_limit;
01257 else
01258 return rval;
01259 }
01260 }
01261
01262 static int
01263 create_gamma_curve(stp_curve_t **retval, double lo, double hi, double fgamma,
01264 int points)
01265 {
01266 *retval = stp_curve_create(STP_CURVE_WRAP_NONE);
01267 if (stp_curve_set_bounds(*retval, lo, hi) &&
01268 stp_curve_set_gamma(*retval, fgamma) &&
01269 stp_curve_resample(*retval, points))
01270 return 1;
01271 stp_curve_destroy(*retval);
01272 *retval = 0;
01273 return 0;
01274 }
01275
01276 static int
01277 interpolate_points(stp_curve_t *a, stp_curve_t *b,
01278 stp_curve_compose_t mode,
01279 int points, double *tmp_data)
01280 {
01281 double pa, pb;
01282 int i;
01283 size_t points_a = stp_curve_count_points(a);
01284 size_t points_b = stp_curve_count_points(b);
01285 for (i = 0; i < points; i++)
01286 {
01287 if (!stp_curve_interpolate_value
01288 (a, (double) i * (points_a - 1) / (points - 1), &pa))
01289 {
01290 stp_deprintf(STP_DBG_CURVE_ERRORS,
01291 "interpolate_points: interpolate curve a value failed\n");
01292 return 0;
01293 }
01294 if (!stp_curve_interpolate_value
01295 (b, (double) i * (points_b - 1) / (points - 1), &pb))
01296 {
01297 stp_deprintf(STP_DBG_CURVE_ERRORS,
01298 "interpolate_points: interpolate curve b value failed\n");
01299 return 0;
01300 }
01301 if (mode == STP_CURVE_COMPOSE_ADD)
01302 pa += pb;
01303 else
01304 pa *= pb;
01305 if (! finite(pa))
01306 {
01307 stp_deprintf(STP_DBG_CURVE_ERRORS,
01308 "interpolate_points: interpolated point %lu is invalid\n",
01309 (unsigned long) i);
01310 return 0;
01311 }
01312 tmp_data[i] = pa;
01313 }
01314 return 1;
01315 }
01316
01317 int
01318 stp_curve_compose(stp_curve_t **retval,
01319 stp_curve_t *a, stp_curve_t *b,
01320 stp_curve_compose_t mode, int points)
01321 {
01322 stp_curve_t *ret;
01323 double *tmp_data;
01324 double gamma_a = stp_curve_get_gamma(a);
01325 double gamma_b = stp_curve_get_gamma(b);
01326 unsigned points_a = stp_curve_count_points(a);
01327 unsigned points_b = stp_curve_count_points(b);
01328 double alo, ahi, blo, bhi;
01329
01330 if (a->piecewise && b->piecewise)
01331 return 0;
01332 if (a->piecewise)
01333 {
01334 stp_curve_t *a_save = a;
01335 a = stp_curve_create_copy(a_save);
01336 stp_curve_resample(a, stp_curve_count_points(b));
01337 }
01338 if (b->piecewise)
01339 {
01340 stp_curve_t *b_save = b;
01341 b = stp_curve_create_copy(b_save);
01342 stp_curve_resample(b, stp_curve_count_points(a));
01343 }
01344
01345 if (mode != STP_CURVE_COMPOSE_ADD && mode != STP_CURVE_COMPOSE_MULTIPLY)
01346 return 0;
01347 if (stp_curve_get_wrap(a) != stp_curve_get_wrap(b))
01348 return 0;
01349 stp_curve_get_bounds(a, &alo, &ahi);
01350 stp_curve_get_bounds(b, &blo, &bhi);
01351 if (mode == STP_CURVE_COMPOSE_MULTIPLY && (alo < 0 || blo < 0))
01352 return 0;
01353
01354 if (stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND)
01355 {
01356 points_a++;
01357 points_b++;
01358 }
01359 if (points == -1)
01360 {
01361 points = lcm(points_a, points_b);
01362 if (stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND)
01363 points--;
01364 }
01365 if (points < 2 || points > curve_point_limit ||
01366 ((stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND) &&
01367 points > curve_point_limit - 1))
01368 return 0;
01369
01370 if (gamma_a && gamma_b && gamma_a * gamma_b > 0 &&
01371 mode == STP_CURVE_COMPOSE_MULTIPLY)
01372 return create_gamma_curve(retval, alo * blo, ahi * bhi, gamma_a + gamma_b,
01373 points);
01374 tmp_data = stp_malloc(sizeof(double) * points);
01375 if (!interpolate_points(a, b, mode, points, tmp_data))
01376 {
01377 stp_free(tmp_data);
01378 return 0;
01379 }
01380 ret = stp_curve_create(stp_curve_get_wrap(a));
01381 if (mode == STP_CURVE_COMPOSE_ADD)
01382 {
01383 stp_curve_rescale(ret, (ahi - alo) + (bhi - blo),
01384 STP_CURVE_COMPOSE_MULTIPLY, STP_CURVE_BOUNDS_RESCALE);
01385 stp_curve_rescale(ret, alo + blo,
01386 STP_CURVE_COMPOSE_ADD, STP_CURVE_BOUNDS_RESCALE);
01387 }
01388 else
01389 {
01390 stp_curve_rescale(ret, (ahi - alo) * (bhi - blo),
01391 STP_CURVE_COMPOSE_MULTIPLY, STP_CURVE_BOUNDS_RESCALE);
01392 stp_curve_rescale(ret, alo * blo,
01393 STP_CURVE_COMPOSE_ADD, STP_CURVE_BOUNDS_RESCALE);
01394 }
01395 if (! stp_curve_set_data(ret, points, tmp_data))
01396 goto bad1;
01397 *retval = ret;
01398 stp_free(tmp_data);
01399 return 1;
01400 bad1:
01401 stp_curve_destroy(ret);
01402 stp_free(tmp_data);
01403 return 0;
01404 }
01405
01406
01407 stp_curve_t *
01408 stp_curve_create_from_xmltree(stp_mxml_node_t *curve)
01409 {
01410 const char *stmp;
01411 stp_mxml_node_t *child;
01412 stp_curve_t *ret = NULL;
01413 stp_curve_type_t curve_type;
01414 stp_curve_wrap_mode_t wrap_mode;
01415 double fgamma;
01416 stp_sequence_t *seq = NULL;
01417 double low, high;
01418 int piecewise = 0;
01419
01420 stp_xml_init();
01421
01422 stmp = stp_mxmlElementGetAttr(curve, "type");
01423 if (stmp)
01424 {
01425 if (!strcmp(stmp, "linear"))
01426 curve_type = STP_CURVE_TYPE_LINEAR;
01427 else if (!strcmp(stmp, "spline"))
01428 curve_type = STP_CURVE_TYPE_SPLINE;
01429 else
01430 {
01431 stp_deprintf(STP_DBG_CURVE_ERRORS,
01432 "stp_curve_create_from_xmltree: %s: \"type\" invalid\n", stmp);
01433 goto error;
01434 }
01435 }
01436 else
01437 {
01438 stp_deprintf(STP_DBG_CURVE_ERRORS,
01439 "stp_curve_create_from_xmltree: \"type\" missing\n");
01440 goto error;
01441 }
01442
01443 stmp = stp_mxmlElementGetAttr(curve, "wrap");
01444 if (stmp)
01445 {
01446 if (!strcmp(stmp, "nowrap"))
01447 wrap_mode = STP_CURVE_WRAP_NONE;
01448 else if (!strcmp(stmp, "wrap"))
01449 {
01450 wrap_mode = STP_CURVE_WRAP_AROUND;
01451 }
01452 else
01453 {
01454 stp_deprintf(STP_DBG_CURVE_ERRORS,
01455 "stp_curve_create_from_xmltree: %s: \"wrap\" invalid\n", stmp);
01456 goto error;
01457 }
01458 }
01459 else
01460 {
01461 stp_deprintf(STP_DBG_CURVE_ERRORS,
01462 "stp_curve_create_from_xmltree: \"wrap\" missing\n");
01463 goto error;
01464 }
01465
01466 stmp = stp_mxmlElementGetAttr(curve, "gamma");
01467 if (stmp)
01468 {
01469 fgamma = stp_xmlstrtod(stmp);
01470 }
01471 else
01472 {
01473 stp_deprintf(STP_DBG_CURVE_ERRORS,
01474 "stp_curve_create_from_xmltree: \"gamma\" missing\n");
01475 goto error;
01476 }
01477
01478 if (fgamma && wrap_mode != STP_CURVE_WRAP_NONE)
01479 {
01480 stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: "
01481 "gamma set and \"wrap\" is not STP_CURVE_WRAP_NONE\n");
01482 goto error;
01483 }
01484 stmp = stp_mxmlElementGetAttr(curve, "piecewise");
01485 if (stmp && strcmp(stmp, "true") == 0)
01486 piecewise = 1;
01487
01488
01489 ret = stp_curve_create(wrap_mode);
01490 stp_curve_set_interpolation_type(ret, curve_type);
01491
01492 child = stp_mxmlFindElement(curve, curve, "sequence", NULL, NULL, STP_MXML_DESCEND);
01493 if (child)
01494 seq = stp_sequence_create_from_xmltree(child);
01495
01496 if (seq == NULL)
01497 {
01498 stp_deprintf(STP_DBG_CURVE_ERRORS,
01499 "stp_curve_create_from_xmltree: sequence read failed\n");
01500 goto error;
01501 }
01502
01503
01504 stp_sequence_get_bounds(seq, &low, &high);
01505 stp_curve_set_bounds(ret, low, high);
01506
01507 if (fgamma)
01508 stp_curve_set_gamma(ret, fgamma);
01509 else
01510 {
01511 size_t seq_count;
01512 const double* data;
01513
01514 stp_sequence_get_data(seq, &seq_count, &data);
01515 if (piecewise)
01516 {
01517 if ((seq_count % 2) != 0)
01518 {
01519 stp_deprintf(STP_DBG_CURVE_ERRORS,
01520 "stp_curve_create_from_xmltree: invalid data count %d\n",
01521 seq_count);
01522 goto error;
01523 }
01524 if (stp_curve_set_data_points(ret, seq_count / 2,
01525 (const stp_curve_point_t *) data) == 0)
01526 {
01527 stp_deprintf(STP_DBG_CURVE_ERRORS,
01528 "stp_curve_create_from_xmltree: failed to set curve data points\n");
01529 goto error;
01530 }
01531 }
01532 else
01533 {
01534 if (stp_curve_set_data(ret, seq_count, data) == 0)
01535 {
01536 stp_deprintf(STP_DBG_CURVE_ERRORS,
01537 "stp_curve_create_from_xmltree: failed to set curve data\n");
01538 goto error;
01539 }
01540 }
01541 }
01542
01543 if (seq)
01544 {
01545 stp_sequence_destroy(seq);
01546 seq = NULL;
01547 }
01548
01549
01550 if (stpi_curve_check_parameters(ret, stp_curve_count_points(ret)) == 0)
01551 {
01552 stp_deprintf(STP_DBG_CURVE_ERRORS,
01553 "stp_curve_create_from_xmltree: parameter check failed\n");
01554 goto error;
01555 }
01556
01557 stp_xml_exit();
01558
01559 return ret;
01560
01561 error:
01562 stp_deprintf(STP_DBG_CURVE_ERRORS,
01563 "stp_curve_create_from_xmltree: error during curve read\n");
01564 if (ret)
01565 stp_curve_destroy(ret);
01566 stp_xml_exit();
01567 return NULL;
01568 }
01569
01570
01571 stp_mxml_node_t *
01572 stp_xmltree_create_from_curve(const stp_curve_t *curve)
01573 {
01574 stp_curve_wrap_mode_t wrapmode;
01575 stp_curve_type_t interptype;
01576 double gammaval, low, high;
01577 stp_sequence_t *seq;
01578
01579 char *cgamma;
01580
01581 stp_mxml_node_t *curvenode = NULL;
01582 stp_mxml_node_t *child = NULL;
01583
01584 stp_xml_init();
01585
01586
01587 wrapmode = stp_curve_get_wrap(curve);
01588 interptype = stp_curve_get_interpolation_type(curve);
01589 gammaval = stp_curve_get_gamma(curve);
01590
01591 if (gammaval && wrapmode != STP_CURVE_WRAP_NONE)
01592 {
01593 stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_xmltree_create_from_curve: "
01594 "curve sets gamma and wrap_mode is not STP_CURVE_WRAP_NONE\n");
01595 goto error;
01596 }
01597
01598
01599 stp_asprintf(&cgamma, "%g", gammaval);
01600
01601 curvenode = stp_mxmlNewElement(NULL, "curve");
01602 stp_mxmlElementSetAttr(curvenode, "wrap", stpi_wrap_mode_names[wrapmode]);
01603 stp_mxmlElementSetAttr(curvenode, "type", stpi_curve_type_names[interptype]);
01604 stp_mxmlElementSetAttr(curvenode, "gamma", cgamma);
01605 if (curve->piecewise)
01606 stp_mxmlElementSetAttr(curvenode, "piecewise", "true");
01607 else
01608 stp_mxmlElementSetAttr(curvenode, "piecewise", "false");
01609
01610 stp_free(cgamma);
01611
01612 seq = stp_sequence_create();
01613 stp_curve_get_bounds(curve, &low, &high);
01614 stp_sequence_set_bounds(seq, low, high);
01615 if (gammaval != 0)
01616 {
01617 stp_sequence_set_size(seq, 0);
01618 }
01619 else
01620 {
01621 const double *data;
01622 size_t count;
01623 data = stpi_curve_get_data_internal(curve, &count);
01624 stp_sequence_set_data(seq, count, data);
01625 }
01626
01627 child = stp_xmltree_create_from_sequence(seq);
01628
01629 if (seq)
01630 {
01631 stp_sequence_destroy(seq);
01632 seq = NULL;
01633 }
01634
01635 if (child == NULL)
01636 {
01637 stp_deprintf(STP_DBG_CURVE_ERRORS,
01638 "stp_xmltree_create_from_curve: sequence node is NULL\n");
01639 goto error;
01640 }
01641 stp_mxmlAdd(curvenode, STP_MXML_ADD_AFTER, NULL, child);
01642
01643 stp_xml_exit();
01644
01645 return curvenode;
01646
01647 error:
01648 stp_deprintf(STP_DBG_CURVE_ERRORS,
01649 "stp_xmltree_create_from_curve: error during xmltree creation\n");
01650 if (curvenode)
01651 stp_mxmlDelete(curvenode);
01652 if (child)
01653 stp_mxmlDelete(child);
01654 stp_xml_exit();
01655
01656 return NULL;
01657 }
01658
01659 static stp_mxml_node_t *
01660 xmldoc_create_from_curve(const stp_curve_t *curve)
01661 {
01662 stp_mxml_node_t *xmldoc;
01663 stp_mxml_node_t *rootnode;
01664 stp_mxml_node_t *curvenode;
01665
01666
01667 curvenode = stp_xmltree_create_from_curve(curve);
01668 if (curvenode == NULL)
01669 {
01670 stp_deprintf(STP_DBG_CURVE_ERRORS,
01671 "xmldoc_create_from_curve: error creating curve node\n");
01672 return NULL;
01673 }
01674
01675 xmldoc = stp_xmldoc_create_generic();
01676 if (xmldoc == NULL)
01677 {
01678 stp_deprintf(STP_DBG_CURVE_ERRORS,
01679 "xmldoc_create_from_curve: error creating XML document\n");
01680 return NULL;
01681 }
01682 rootnode = xmldoc->child;
01683 if (rootnode == NULL)
01684 {
01685 stp_mxmlDelete(xmldoc);
01686 stp_deprintf(STP_DBG_CURVE_ERRORS,
01687 "xmldoc_create_from_curve: error getting XML document root node\n");
01688 return NULL;
01689 }
01690
01691 stp_mxmlAdd(rootnode, STP_MXML_ADD_AFTER, NULL, curvenode);
01692
01693 return xmldoc;
01694 }
01695
01696 static int
01697 curve_whitespace_callback(stp_mxml_node_t *node, int where)
01698 {
01699 if (node->type != STP_MXML_ELEMENT)
01700 return 0;
01701 if (strcasecmp(node->value.element.name, "gimp-print") == 0)
01702 {
01703 switch (where)
01704 {
01705 case STP_MXML_WS_AFTER_OPEN:
01706 case STP_MXML_WS_BEFORE_CLOSE:
01707 case STP_MXML_WS_AFTER_CLOSE:
01708 return '\n';
01709 case STP_MXML_WS_BEFORE_OPEN:
01710 default:
01711 return 0;
01712 }
01713 }
01714 else if (strcasecmp(node->value.element.name, "curve") == 0)
01715 {
01716 switch (where)
01717 {
01718 case STP_MXML_WS_AFTER_OPEN:
01719 return '\n';
01720 case STP_MXML_WS_BEFORE_CLOSE:
01721 case STP_MXML_WS_AFTER_CLOSE:
01722 case STP_MXML_WS_BEFORE_OPEN:
01723 default:
01724 return 0;
01725 }
01726 }
01727 else if (strcasecmp(node->value.element.name, "sequence") == 0)
01728 {
01729 const char *count;
01730 switch (where)
01731 {
01732 case STP_MXML_WS_BEFORE_CLOSE:
01733 count = stp_mxmlElementGetAttr(node, "count");
01734 if (strcmp(count, "0") == 0)
01735 return 0;
01736 else
01737 return '\n';
01738 case STP_MXML_WS_AFTER_OPEN:
01739 case STP_MXML_WS_AFTER_CLOSE:
01740 return '\n';
01741 case STP_MXML_WS_BEFORE_OPEN:
01742 default:
01743 return 0;
01744 }
01745 }
01746 else
01747 return 0;
01748 }
01749
01750
01751 int
01752 stp_curve_write(FILE *file, const stp_curve_t *curve)
01753 {
01754 stp_mxml_node_t *xmldoc = NULL;
01755
01756 stp_xml_init();
01757
01758 xmldoc = xmldoc_create_from_curve(curve);
01759 if (xmldoc == NULL)
01760 {
01761 stp_xml_exit();
01762 return 1;
01763 }
01764
01765 stp_mxmlSaveFile(xmldoc, file, curve_whitespace_callback);
01766
01767 if (xmldoc)
01768 stp_mxmlDelete(xmldoc);
01769
01770 stp_xml_exit();
01771
01772 return 0;
01773 }
01774
01775 char *
01776 stp_curve_write_string(const stp_curve_t *curve)
01777 {
01778 stp_mxml_node_t *xmldoc = NULL;
01779 char *retval;
01780
01781 stp_xml_init();
01782
01783 xmldoc = xmldoc_create_from_curve(curve);
01784 if (xmldoc == NULL)
01785 {
01786 stp_xml_exit();
01787 return NULL;
01788 }
01789
01790 retval = stp_mxmlSaveAllocString(xmldoc, curve_whitespace_callback);
01791
01792 if (xmldoc)
01793 stp_mxmlDelete(xmldoc);
01794
01795 stp_xml_exit();
01796
01797 return retval;
01798 }
01799
01800 static stp_curve_t *
01801 xml_doc_get_curve(stp_mxml_node_t *doc)
01802 {
01803 stp_mxml_node_t *cur;
01804 stp_mxml_node_t *xmlcurve;
01805 stp_curve_t *curve = NULL;
01806
01807 if (doc == NULL )
01808 {
01809 stp_deprintf(STP_DBG_CURVE_ERRORS,
01810 "xml_doc_get_curve: XML file not parsed successfully.\n");
01811 return NULL;
01812 }
01813
01814 cur = doc->child;
01815
01816 if (cur == NULL)
01817 {
01818 stp_deprintf(STP_DBG_CURVE_ERRORS,
01819 "xml_doc_get_curve: empty document\n");
01820 return NULL;
01821 }
01822
01823 xmlcurve = stp_xml_get_node(cur, "gimp-print", "curve", NULL);
01824
01825 if (xmlcurve)
01826 curve = stp_curve_create_from_xmltree(xmlcurve);
01827
01828 return curve;
01829 }
01830
01831 stp_curve_t *
01832 stp_curve_create_from_file(const char* file)
01833 {
01834 stp_curve_t *curve = NULL;
01835 stp_mxml_node_t *doc;
01836 FILE *fp = fopen(file, "r");
01837 if (!fp)
01838 {
01839 stp_deprintf(STP_DBG_CURVE_ERRORS,
01840 "stp_curve_create_from_file: unable to open %s: %s\n",
01841 file, strerror(errno));
01842 return NULL;
01843 }
01844 stp_deprintf(STP_DBG_XML, "stp_curve_create_from_file: reading `%s'...\n",
01845 file);
01846
01847 stp_xml_init();
01848
01849 doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
01850
01851 curve = xml_doc_get_curve(doc);
01852
01853 if (doc)
01854 stp_mxmlDelete(doc);
01855
01856 stp_xml_exit();
01857 (void) fclose(fp);
01858 return curve;
01859
01860 }
01861
01862 stp_curve_t *
01863 stp_curve_create_from_stream(FILE* fp)
01864 {
01865 stp_curve_t *curve = NULL;
01866 stp_mxml_node_t *doc;
01867 stp_deprintf(STP_DBG_XML, "stp_curve_create_from_fp: reading...\n");
01868
01869 stp_xml_init();
01870
01871 doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
01872
01873 curve = xml_doc_get_curve(doc);
01874
01875 if (doc)
01876 stp_mxmlDelete(doc);
01877
01878 stp_xml_exit();
01879 return curve;
01880
01881 }
01882
01883 stp_curve_t *
01884 stp_curve_create_from_string(const char* string)
01885 {
01886 stp_curve_t *curve = NULL;
01887 stp_mxml_node_t *doc;
01888 stp_deprintf(STP_DBG_XML,
01889 "stp_curve_create_from_string: reading '%s'...\n", string);
01890 stp_xml_init();
01891
01892 doc = stp_mxmlLoadString(NULL, string, STP_MXML_NO_CALLBACK);
01893
01894 curve = xml_doc_get_curve(doc);
01895
01896 if (doc)
01897 stp_mxmlDelete(doc);
01898
01899 stp_xml_exit();
01900 return curve;
01901 }