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