Annotation of OpenXM_contrib/gnuplot/interpol.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: interpol.c,v 1.29 1998/04/14 00:15:45 drd Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - interpol.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
! 9: *
! 10: * Permission to use, copy, and distribute this software and its
! 11: * documentation for any purpose with or without fee is hereby granted,
! 12: * provided that the above copyright notice appear in all copies and
! 13: * that both that copyright notice and this permission notice appear
! 14: * in supporting documentation.
! 15: *
! 16: * Permission to modify the software is granted, but not the right to
! 17: * distribute the complete modified source code. Modifications are to
! 18: * be distributed as patches to the released version. Permission to
! 19: * distribute binaries produced by compiling modified sources is granted,
! 20: * provided you
! 21: * 1. distribute the corresponding source modifications from the
! 22: * released version in the form of a patch file along with the binaries,
! 23: * 2. add special version identification to distinguish your version
! 24: * in addition to the base release version number,
! 25: * 3. provide your name and address as the primary contact for the
! 26: * support of your modified version, and
! 27: * 4. retain our contact information in regard to use of the base
! 28: * software.
! 29: * Permission to distribute the released version of the source code along
! 30: * with corresponding source modifications in the form of a patch file is
! 31: * granted with same provisions 2 through 4 for binary distributions.
! 32: *
! 33: * This software is provided "as is" without express or implied warranty
! 34: * to the extent permitted by applicable law.
! 35: ]*/
! 36:
! 37:
! 38: /*
! 39: * C-Source file identification Header
! 40: *
! 41: * This file belongs to a project which is:
! 42: *
! 43: * done 1993 by MGR-Software, Asgard (Lars Hanke)
! 44: * written by Lars Hanke
! 45: *
! 46: * Contact me via:
! 47: *
! 48: * InterNet: mgr@asgard.bo.open.de
! 49: * FIDO: Lars Hanke @ 2:243/4802.22 (as long as they keep addresses)
! 50: *
! 51: **************************************************************************
! 52: *
! 53: * Project: gnuplot
! 54: * Module:
! 55: * File: interpol.c
! 56: *
! 57: * Revisor: Lars Hanke
! 58: * Revised: 26/09/93
! 59: * Revision: 1.0
! 60: *
! 61: **************************************************************************
! 62: *
! 63: * LEGAL
! 64: * This module is part of gnuplot and distributed under whatever terms
! 65: * gnuplot is or will be published, unless exclusive rights are claimed.
! 66: *
! 67: * DESCRIPTION
! 68: * Supplies 2-D data interpolation and approximation routines
! 69: *
! 70: * IMPORTS
! 71: * plot.h
! 72: * - cp_extend()
! 73: * - structs: curve_points, coordval, coordinate
! 74: *
! 75: * setshow.h
! 76: * - samples, is_log_x, base_log_x, xmin, xmax, autoscale_lx
! 77: * - plottypes
! 78: *
! 79: * proto.h
! 80: * - solve_tri_diag()
! 81: * - typedef tri_diag
! 82: *
! 83: * EXPORTS
! 84: * gen_interp()
! 85: * sort_points()
! 86: * cp_implode()
! 87: *
! 88: * BUGS and TODO
! 89: * I would really have liked to use Gershon Elbers contouring code for
! 90: * all the stuff done here, but I failed. So I used my own code.
! 91: * If somebody is able to consolidate Gershon's code for this purpose
! 92: * a lot of gnuplot users would be very happy - due to memory problems.
! 93: *
! 94: **************************************************************************
! 95: *
! 96: * HISTORY
! 97: * Changes:
! 98: * Nov 24, 1995 Markus Schuh (M.Schuh@meteo.uni-koeln.de):
! 99: * changed the algorithm for csplines
! 100: * added algorithm for approximation csplines
! 101: * copied point storage and range fix from plot2d.c
! 102: *
! 103: * Dec 12, 1995 David Denholm
! 104: * oops - at the time this is called, stored co-ords are
! 105: * internal (ie maybe log of data) but min/max are in
! 106: * user co-ordinates.
! 107: * Work with min and max of internal co-ords, and
! 108: * check at the end whether external min and max need to
! 109: * be increased. (since samples is typically 100 ; we
! 110: * dont want to take more logs than necessary)
! 111: * Also, need to take into account which axes are active
! 112: *
! 113: * Jun 30, 1996 Jens Emmerich
! 114: * implemented handling of UNDEFINED points
! 115: */
! 116:
! 117: #include "plot.h"
! 118: #include "setshow.h"
! 119:
! 120:
! 121: /* in order to support multiple axes, and to simplify ranging in
! 122: * parametric plots, we use arrays to store some things. For 2d plots,
! 123: * elements are z=0,y1=1,x1=2,z2=4,y2=5,x2=6 these are given symbolic
! 124: * names in plot.h
! 125: */
! 126:
! 127: extern double min_array[AXIS_ARRAY_SIZE];
! 128: extern double max_array[AXIS_ARRAY_SIZE];
! 129: extern int auto_array[AXIS_ARRAY_SIZE];
! 130: extern TBOOLEAN log_array[AXIS_ARRAY_SIZE];
! 131: extern double base_array[AXIS_ARRAY_SIZE];
! 132: extern double log_base_array[AXIS_ARRAY_SIZE];
! 133:
! 134:
! 135: #define Inc_c_token if (++c_token >= num_tokens) \
! 136: int_error ("Syntax error", c_token);
! 137:
! 138:
! 139: /*
! 140: * IMHO, code is getting too cluttered with repeated chunks of
! 141: * code. Some macros to simplify, I hope.
! 142: *
! 143: * do { } while(0) is comp.lang.c recommendation for complex macros
! 144: * also means that break can be specified as an action, and it will
! 145: *
! 146: */
! 147:
! 148:
! 149: /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
! 150: * Do OUT_ACTION or UNDEF_ACTION as appropriate
! 151: * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
! 152: * VALUE must not be same as STORE
! 153: */
! 154:
! 155: #define STORE_AND_FIXUP_RANGE(STORE, VALUE, TYPE, MIN, MAX, AUTO, OUT_ACTION, UNDEF_ACTION)\
! 156: do { STORE=VALUE; \
! 157: if (TYPE != INRANGE) break; /* dont set y range if x is outrange, for example */ \
! 158: if ( VALUE<MIN ) { \
! 159: if (AUTO & 1) MIN=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; break; } \
! 160: } \
! 161: if ( VALUE>MAX ) {\
! 162: if (AUTO & 2) MAX=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; } \
! 163: } \
! 164: } while(0)
! 165:
! 166: #define UPDATE_RANGE(TEST,OLD,NEW,AXIS) \
! 167: do { if (TEST) { \
! 168: if (log_array[AXIS]) OLD = pow(base_array[AXIS], NEW); else OLD = NEW; \
! 169: } \
! 170: } while(0)
! 171:
! 172: /* use this instead empty macro arguments to work around NeXT cpp bug */
! 173: /* if this fails on any system, we might use ((void)0) */
! 174:
! 175: #define NOOP /* */
! 176:
! 177: #define spline_coeff_size 4
! 178: typedef double spline_coeff[spline_coeff_size];
! 179: typedef double five_diag[5];
! 180:
! 181: static int next_curve __PROTO((struct curve_points * plot, int *curve_start));
! 182: static int num_curves __PROTO((struct curve_points * plot));
! 183: static double *cp_binomial __PROTO((int points));
! 184: GP_INLINE static double s_pow __PROTO((double base, unsigned int exponent));
! 185: static void eval_bezier __PROTO((struct curve_points * cp, int first_point, int num_points, double sr, coordval * px, coordval * py, double *c));
! 186: static void do_bezier __PROTO((struct curve_points * cp, double *bc, int first_point, int num_points, struct coordinate * dest));
! 187: static int solve_five_diag __PROTO((five_diag m[], double r[], double x[], int n));
! 188: static spline_coeff *cp_approx_spline __PROTO((struct curve_points * plot, int first_point, int num_points));
! 189: static spline_coeff *cp_tridiag __PROTO((struct curve_points * plot, int first_point, int num_points));
! 190: static void do_cubic __PROTO((struct curve_points * plot, spline_coeff * sc, int first_point, int num_points, struct coordinate * dest));
! 191: static int compare_points __PROTO((struct coordinate * p1, struct coordinate * p2));
! 192:
! 193:
! 194: /*
! 195: * position curve_start to index the next non-UNDEFINDED point,
! 196: * start search at initial curve_start,
! 197: * return number of non-UNDEFINDED points from there on,
! 198: * if no more valid points are found, curve_start is set
! 199: * to plot->p_count and 0 is returned
! 200: */
! 201:
! 202: static int next_curve(plot, curve_start)
! 203: struct curve_points *plot;
! 204: int *curve_start;
! 205: {
! 206: int curve_length;
! 207:
! 208: /* Skip undefined points */
! 209: while (*curve_start < plot->p_count
! 210: && plot->points[*curve_start].type == UNDEFINED) {
! 211: (*curve_start)++;
! 212: };
! 213: curve_length = 0;
! 214: /* curve_length is first used as an offset, then the correkt # points */
! 215: while ((*curve_start) + curve_length < plot->p_count
! 216: && plot->points[(*curve_start) + curve_length].type != UNDEFINED) {
! 217: curve_length++;
! 218: };
! 219: return (curve_length);
! 220: }
! 221:
! 222:
! 223: /*
! 224: * determine the number of curves in plot->points, separated by
! 225: * UNDEFINED points
! 226: */
! 227:
! 228: static int num_curves(plot)
! 229: struct curve_points *plot;
! 230: {
! 231: int curves;
! 232: int first_point;
! 233: int num_points;
! 234:
! 235: first_point = 0;
! 236: curves = 0;
! 237: while ((num_points = next_curve(plot, &first_point)) > 0) {
! 238: curves++;
! 239: first_point += num_points;
! 240: }
! 241: return (curves);
! 242: }
! 243:
! 244:
! 245:
! 246: /*
! 247: * build up a cntr_struct list from curve_points
! 248: * this funtion is only used for the alternate entry point to
! 249: * Gershon's code and thus commented out
! 250: ***deleted***
! 251: */
! 252:
! 253:
! 254: /*
! 255: * cp_binomial() computes the binomial coefficients needed for BEZIER stuff
! 256: * and stores them into an array which is hooked to sdat.
! 257: * (MGR 1992)
! 258: */
! 259: static double *cp_binomial(points)
! 260: int points;
! 261: {
! 262: register double *coeff;
! 263: register int n, k;
! 264: int e;
! 265:
! 266: e = points; /* well we're going from k=0 to k=p_count-1 */
! 267: coeff = (double *) gp_alloc(e * sizeof(double), "bezier coefficients");
! 268:
! 269: n = points - 1;
! 270: e = n / 2;
! 271: coeff[0] = 1.0;
! 272:
! 273: for (k = 0; k < e; k++) {
! 274: coeff[k + 1] = coeff[k] * ((double) (n - k)) / ((double) (k + 1));
! 275: }
! 276:
! 277: for (k = n; k >= e; k--)
! 278: coeff[k] = coeff[n - k];
! 279:
! 280: return (coeff);
! 281: }
! 282:
! 283:
! 284: /* This is a subfunction of do_bezier() for BEZIER style computations.
! 285: * It is passed the stepration (STEP/MAXSTEPS) and the addresses of
! 286: * the double values holding the next x and y coordinates.
! 287: * (MGR 1992)
! 288: */
! 289:
! 290: /*
! 291: * well, this routine runs faster with the 68040 striptease FPU
! 292: * and it handles zeroes correctly - there had been some trouble with TC
! 293: */
! 294:
! 295: GP_INLINE static double s_pow(base, exponent)
! 296: double base;
! 297: unsigned int exponent;
! 298: {
! 299: double y;
! 300:
! 301: if (exponent == 0)
! 302: return (1.0);
! 303: if (base == 0.0)
! 304: return (0.0);
! 305:
! 306: /* consider i in binary = abcd
! 307: * x^i = x^(8a+4b+2c+d) = x^8a * x^4b * x^2b * x^d
! 308: * = a?x^2^2^2:1 * b?x^2^2:1 + ...
! 309: * so for each bit in exponent, square x, multiplying it into accumulator
! 310: *
! 311: */
! 312:
! 313: y = 1;
! 314: while (exponent) {
! 315: if (exponent & 1)
! 316: y *= base;
! 317: base *= base;
! 318: /* if exponent was signed, this could be trouble ! */
! 319: exponent >>= 1;
! 320: }
! 321:
! 322: return (y);
! 323: }
! 324:
! 325: static void eval_bezier(cp, first_point, num_points, sr, px, py, c)
! 326: struct curve_points *cp;
! 327: int first_point; /* where to start in plot->points (to find x-range) */
! 328: int num_points; /* to determine end in plot->points */
! 329: double sr;
! 330: coordval *px;
! 331: coordval *py;
! 332: double *c;
! 333: {
! 334: unsigned int n = num_points - 1;
! 335: /* HBB 980308: added 'GPHUGE' tag for DOS */
! 336: struct coordinate GPHUGE *this_points;
! 337:
! 338: this_points = (cp->points) + first_point;
! 339:
! 340: if (sr == 0.0) {
! 341: *px = this_points[0].x;
! 342: *py = this_points[0].y;
! 343: } else if (sr == 1.0) {
! 344: *px = this_points[n].x;
! 345: *py = this_points[n].y;
! 346: } else {
! 347: unsigned int i;
! 348: double lx = 0.0, ly = 0.0;
! 349: double sr_to_the_i = 1.0;
! 350: double dsr_to_the_di = s_pow(1 - sr, n);
! 351: double reciprocal_dsr = 1.0 / (1 - sr);
! 352:
! 353: for (i = 0; i <= n; i++) {
! 354: double u = c[i] * sr_to_the_i * s_pow(1 - sr, n - i);
! 355: lx += this_points[i].x * u;
! 356: ly += this_points[i].y * u;
! 357: sr_to_the_i *= sr;
! 358: dsr_to_the_di *= reciprocal_dsr;
! 359: }
! 360:
! 361: *px = lx;
! 362: *py = ly;
! 363: }
! 364: }
! 365:
! 366: /*
! 367: * generate a new set of coordinates representing the bezier curve and
! 368: * set it to the plot
! 369: */
! 370:
! 371: static void do_bezier(cp, bc, first_point, num_points, dest)
! 372: struct curve_points *cp;
! 373: double *bc;
! 374: int first_point; /* where to start in plot->points */
! 375: int num_points; /* to determine end in plot->points */
! 376: struct coordinate *dest; /* where to put the interpolated data */
! 377: {
! 378: int i;
! 379: coordval x, y;
! 380: int xaxis = cp->x_axis;
! 381: int yaxis = cp->y_axis;
! 382:
! 383: /* min and max in internal (eg logged) co-ordinates. We update
! 384: * these, then update the external extrema in user co-ordinates
! 385: * at the end.
! 386: */
! 387:
! 388: double ixmin, ixmax, iymin, iymax;
! 389: double sxmin, sxmax, symin, symax; /* starting values of above */
! 390:
! 391: if (log_array[xaxis]) {
! 392: ixmin = sxmin = log(min_array[xaxis]) / log_base_array[xaxis];
! 393: ixmax = sxmax = log(max_array[xaxis]) / log_base_array[xaxis];
! 394: } else {
! 395: ixmin = sxmin = min_array[xaxis];
! 396: ixmax = sxmax = max_array[xaxis];
! 397: }
! 398:
! 399: if (log_array[yaxis]) {
! 400: iymin = symin = log(min_array[yaxis]) / log_base_array[yaxis];
! 401: iymax = symax = log(max_array[yaxis]) / log_base_array[yaxis];
! 402: } else {
! 403: iymin = symin = min_array[yaxis];
! 404: iymax = symax = max_array[yaxis];
! 405: }
! 406:
! 407: for (i = 0; i < samples; i++) {
! 408: eval_bezier(cp, first_point, num_points, (double) i / (double) (samples - 1), &x, &y, bc);
! 409:
! 410: /* now we have to store the points and adjust the ranges */
! 411:
! 412: dest[i].type = INRANGE;
! 413: STORE_AND_FIXUP_RANGE(dest[i].x, x, dest[i].type, ixmin, ixmax, auto_array[xaxis], NOOP, continue);
! 414: STORE_AND_FIXUP_RANGE(dest[i].y, y, dest[i].type, iymin, iymax, auto_array[yaxis], NOOP, NOOP);
! 415:
! 416: dest[i].xlow = dest[i].xhigh = dest[i].x;
! 417: dest[i].ylow = dest[i].yhigh = dest[i].y;
! 418:
! 419: dest[i].z = -1;
! 420: }
! 421:
! 422: UPDATE_RANGE(ixmax > sxmax, max_array[xaxis], ixmax, xaxis);
! 423: UPDATE_RANGE(ixmin < sxmin, min_array[xaxis], ixmin, xaxis);
! 424: UPDATE_RANGE(iymax > symax, max_array[yaxis], iymax, yaxis);
! 425: UPDATE_RANGE(iymin < symin, min_array[yaxis], iymin, yaxis);
! 426: }
! 427:
! 428: /*
! 429: * call contouring routines -- main entry
! 430: */
! 431:
! 432: /*
! 433: * it should be like this, but it doesn't run. If you find out why,
! 434: * contact me: mgr@asgard.bo.open.de or Lars Hanke 2:243/4802.22@fidonet
! 435: *
! 436: * Well, all this had originally been inside contour.c, so maybe links
! 437: * to functions and of contour.c are broken.
! 438: * ***deleted***
! 439: * end of unused entry point to Gershon's code
! 440: *
! 441: */
! 442:
! 443: /*
! 444: * Solve five diagonal linear system equation. The five diagonal matrix is
! 445: * defined via matrix M, right side is r, and solution X i.e. M * X = R.
! 446: * Size of system given in n. Return TRUE if solution exist.
! 447: * G. Engeln-Muellges/ F.Reutter:
! 448: * "Formelsammlung zur Numerischen Mathematik mit Standard-FORTRAN-Programmen"
! 449: * ISBN 3-411-01677-9
! 450: *
! 451: * / m02 m03 m04 0 0 0 0 . . . \ / x0 \ / r0 \
! 452: * I m11 m12 m13 m14 0 0 0 . . . I I x1 I I r1 I
! 453: * I m20 m21 m22 m23 m24 0 0 . . . I * I x2 I = I r2 I
! 454: * I 0 m30 m31 m32 m33 m34 0 . . . I I x3 I I r3 I
! 455: * . . . . . . . . . . . .
! 456: * \ m(n-3)0 m(n-2)1 m(n-1)2 / \x(n-1)/ \r(n-1)/
! 457: *
! 458: */
! 459: static int solve_five_diag(m, r, x, n)
! 460: five_diag m[];
! 461: double r[], x[];
! 462: int n;
! 463: {
! 464: int i;
! 465: five_diag *hv;
! 466:
! 467: hv = (five_diag *) gp_alloc((n + 1) * sizeof(five_diag), "five_diag help vars");
! 468:
! 469: hv[0][0] = m[0][2];
! 470: if (hv[0][0] == 0) {
! 471: free(hv);
! 472: return FALSE;
! 473: }
! 474: hv[0][1] = m[0][3] / hv[0][0];
! 475: hv[0][2] = m[0][4] / hv[0][0];
! 476:
! 477: hv[1][3] = m[1][1];
! 478: hv[1][0] = m[1][2] - hv[1][3] * hv[0][1];
! 479: if (hv[1][0] == 0) {
! 480: free(hv);
! 481: return FALSE;
! 482: }
! 483: hv[1][1] = (m[1][3] - hv[1][3] * hv[0][2]) / hv[1][0];
! 484: hv[1][2] = m[1][4] / hv[1][0];
! 485:
! 486: for (i = 2; i <= n - 1; i++) {
! 487: hv[i][3] = m[i][1] - m[i][0] * hv[i - 2][1];
! 488: hv[i][0] = m[i][2] - m[i][0] * hv[i - 2][2] - hv[i][3] * hv[i - 1][1];
! 489: if (hv[i][0] == 0) {
! 490: free(hv);
! 491: return FALSE;
! 492: }
! 493: hv[i][1] = (m[i][3] - hv[i][3] * hv[i - 1][2]) / hv[i][0];
! 494: hv[i][2] = m[i][4] / hv[i][0];
! 495: }
! 496:
! 497: hv[0][4] = 0;
! 498: hv[1][4] = r[0] / hv[0][0];
! 499: for (i = 1; i <= n - 1; i++) {
! 500: hv[i + 1][4] = (r[i] - m[i][0] * hv[i - 1][4] - hv[i][3] * hv[i][4]) / hv[i][0];
! 501: }
! 502:
! 503: x[n - 1] = hv[n][4];
! 504: x[n - 2] = hv[n - 1][4] - hv[n - 2][1] * x[n - 1];
! 505: for (i = n - 3; i >= 0; i--)
! 506: x[i] = hv[i + 1][4] - hv[i][1] * x[i + 1] - hv[i][2] * x[i + 2];
! 507:
! 508: free(hv);
! 509: return TRUE;
! 510: }
! 511:
! 512:
! 513: /*
! 514: * Calculation of approximation cubic splines
! 515: * Input: x[i], y[i], weights z[i]
! 516: *
! 517: * Returns matrix of spline coefficients
! 518: */
! 519: static spline_coeff *cp_approx_spline(plot, first_point, num_points)
! 520: struct curve_points *plot;
! 521: int first_point; /* where to start in plot->points */
! 522: int num_points; /* to determine end in plot->points */
! 523: {
! 524: spline_coeff *sc;
! 525: five_diag *m;
! 526: int xaxis = plot->x_axis;
! 527: int yaxis = plot->y_axis;
! 528: double *r, *x, *h, *xp, *yp;
! 529: /* HBB 980308: added 'GPHUGE' tag */
! 530: struct coordinate GPHUGE *this_points;
! 531: int i;
! 532:
! 533: sc = (spline_coeff *) gp_alloc((num_points) * sizeof(spline_coeff),
! 534: "spline matrix");
! 535:
! 536: if (num_points < 4)
! 537: int_error("Can't calculate approximation splines, need at least 4 points", NO_CARET);
! 538:
! 539: this_points = (plot->points) + first_point;
! 540:
! 541: for (i = 0; i <= num_points - 1; i++)
! 542: if (this_points[i].z <= 0)
! 543: int_error("Can't calculate approximation splines, all weights have to be > 0", NO_CARET);
! 544:
! 545: m = (five_diag *) gp_alloc((num_points - 2) * sizeof(five_diag), "spline help matrix");
! 546:
! 547: r = (double *) gp_alloc((num_points - 2) * sizeof(double), "spline right side");
! 548: x = (double *) gp_alloc((num_points - 2) * sizeof(double), "spline solution vector");
! 549: h = (double *) gp_alloc((num_points - 1) * sizeof(double), "spline help vector");
! 550:
! 551: xp = (double *) gp_alloc((num_points) * sizeof(double), "x pos");
! 552: yp = (double *) gp_alloc((num_points) * sizeof(double), "y pos");
! 553:
! 554: /* KB 981107: With logarithmic axis first convert back to linear scale */
! 555:
! 556: if (log_array[xaxis]) {
! 557: for (i = 0; i <= num_points - 1; i++)
! 558: xp[i] = exp(this_points[i].x * log_base_array[xaxis]);
! 559: } else {
! 560: for (i = 0; i <= num_points - 1; i++)
! 561: xp[i] = this_points[i].x;
! 562: }
! 563: if (log_array[yaxis]) {
! 564: for (i = 0; i <= num_points - 1; i++)
! 565: yp[i] = exp(this_points[i].y * log_base_array[yaxis]);
! 566: } else {
! 567: for (i = 0; i <= num_points - 1; i++)
! 568: yp[i] = this_points[i].y;
! 569: }
! 570:
! 571: for (i = 0; i <= num_points - 2; i++)
! 572: h[i] = xp[i + 1] - xp[i];
! 573:
! 574: /* set up the matrix and the vector */
! 575:
! 576: for (i = 0; i <= num_points - 3; i++) {
! 577: r[i] = 3 * ((yp[i + 2] - yp[i + 1]) / h[i + 1]
! 578: - (yp[i + 1] - yp[i]) / h[i]);
! 579:
! 580: if (i < 2)
! 581: m[i][0] = 0;
! 582: else
! 583: m[i][0] = 6 / this_points[i].z / h[i - 1] / h[i];
! 584:
! 585: if (i < 1)
! 586: m[i][1] = 0;
! 587: else
! 588: m[i][1] = h[i] - 6 / this_points[i].z / h[i] * (1 / h[i - 1] + 1 / h[i])
! 589: - 6 / this_points[i + 1].z / h[i] * (1 / h[i] + 1 / h[i + 1]);
! 590:
! 591: m[i][2] = 2 * (h[i] + h[i + 1])
! 592: + 6 / this_points[i].z / h[i] / h[i]
! 593: + 6 / this_points[i + 1].z * (1 / h[i] + 1 / h[i + 1]) * (1 / h[i] + 1 / h[i + 1])
! 594: + 6 / this_points[i + 2].z / h[i + 1] / h[i + 1];
! 595:
! 596: if (i > num_points - 4)
! 597: m[i][3] = 0;
! 598: else
! 599: m[i][3] = h[i + 1] - 6 / this_points[i + 1].z / h[i + 1] * (1 / h[i] + 1 / h[i + 1])
! 600: - 6 / this_points[i + 2].z / h[i + 1] * (1 / h[i + 1] + 1 / h[i + 2]);
! 601:
! 602: if (i > num_points - 5)
! 603: m[i][4] = 0;
! 604: else
! 605: m[i][4] = 6 / this_points[i + 2].z / h[i + 1] / h[i + 2];
! 606: }
! 607:
! 608: /* solve the matrix */
! 609: if (!solve_five_diag(m, r, x, num_points - 2)) {
! 610: free(h);
! 611: free(x);
! 612: free(r);
! 613: free(m);
! 614: free(xp);
! 615: free(yp);
! 616: int_error("Can't calculate approximation splines", NO_CARET);
! 617: }
! 618: sc[0][2] = 0;
! 619: for (i = 1; i <= num_points - 2; i++)
! 620: sc[i][2] = x[i - 1];
! 621: sc[num_points - 1][2] = 0;
! 622:
! 623: sc[0][0] = yp[0] + 2 / this_points[0].z / h[0] * (sc[0][2] - sc[1][2]);
! 624: for (i = 1; i <= num_points - 2; i++)
! 625: sc[i][0] = yp[i] - 2 / this_points[i].z *
! 626: (sc[i - 1][2] / h[i - 1]
! 627: - sc[i][2] * (1 / h[i - 1] + 1 / h[i])
! 628: + sc[i + 1][2] / h[i]);
! 629: sc[num_points - 1][0] = yp[num_points - 1]
! 630: - 2 / this_points[num_points - 1].z / h[num_points - 2]
! 631: * (sc[num_points - 2][2] - sc[num_points - 1][2]);
! 632:
! 633: for (i = 0; i <= num_points - 2; i++) {
! 634: sc[i][1] = (sc[i + 1][0] - sc[i][0]) / h[i]
! 635: - h[i] / 3 * (sc[i + 1][2] + 2 * sc[i][2]);
! 636: sc[i][3] = (sc[i + 1][2] - sc[i][2]) / 3 / h[i];
! 637: }
! 638:
! 639: free(h);
! 640: free(x);
! 641: free(r);
! 642: free(m);
! 643: free(xp);
! 644: free(yp);
! 645:
! 646: return (sc);
! 647: }
! 648:
! 649:
! 650: /*
! 651: * Calculation of cubic splines
! 652: *
! 653: * This can be treated as a special case of approximation cubic splines, with
! 654: * all weights -> infinity.
! 655: *
! 656: * Returns matrix of spline coefficients
! 657: */
! 658: static spline_coeff *cp_tridiag(plot, first_point, num_points)
! 659: struct curve_points *plot;
! 660: int first_point, num_points;
! 661: {
! 662: spline_coeff *sc;
! 663: tri_diag *m;
! 664: int xaxis = plot->x_axis;
! 665: int yaxis = plot->y_axis;
! 666: double *r, *x, *h, *xp, *yp;
! 667: /* HBB 980308: added 'GPHUGE' tag */
! 668: struct coordinate GPHUGE *this_points;
! 669: int i;
! 670:
! 671: if (num_points < 3)
! 672: int_error("Can't calculate splines, need at least 3 points", NO_CARET);
! 673:
! 674: this_points = (plot->points) + first_point;
! 675:
! 676: sc = (spline_coeff *) gp_alloc((num_points) * sizeof(spline_coeff), "spline matrix");
! 677: m = (tri_diag *) gp_alloc((num_points - 2) * sizeof(tri_diag), "spline help matrix");
! 678:
! 679: r = (double *) gp_alloc((num_points - 2) * sizeof(double), "spline right side");
! 680: x = (double *) gp_alloc((num_points - 2) * sizeof(double), "spline solution vector");
! 681: h = (double *) gp_alloc((num_points - 1) * sizeof(double), "spline help vector");
! 682:
! 683: xp = (double *) gp_alloc((num_points) * sizeof(double), "x pos");
! 684: yp = (double *) gp_alloc((num_points) * sizeof(double), "y pos");
! 685:
! 686: /* KB 981107: With logarithmic axis first convert back to linear scale */
! 687:
! 688: if (log_array[xaxis]) {
! 689: for (i = 0; i <= num_points - 1; i++)
! 690: xp[i] = exp(this_points[i].x * log_base_array[xaxis]);
! 691: } else {
! 692: for (i = 0; i <= num_points - 1; i++)
! 693: xp[i] = this_points[i].x;
! 694: }
! 695: if (log_array[yaxis]) {
! 696: for (i = 0; i <= num_points - 1; i++)
! 697: yp[i] = exp(this_points[i].y * log_base_array[yaxis]);
! 698: } else {
! 699: for (i = 0; i <= num_points - 1; i++)
! 700: yp[i] = this_points[i].y;
! 701: }
! 702:
! 703: for (i = 0; i <= num_points - 2; i++)
! 704: h[i] = xp[i + 1] - xp[i];
! 705:
! 706: /* set up the matrix and the vector */
! 707:
! 708: for (i = 0; i <= num_points - 3; i++) {
! 709: r[i] = 3 * ((yp[i + 2] - yp[i + 1]) / h[i + 1]
! 710: - (yp[i + 1] - yp[i]) / h[i]);
! 711:
! 712: if (i < 1)
! 713: m[i][0] = 0;
! 714: else
! 715: m[i][0] = h[i];
! 716:
! 717: m[i][1] = 2 * (h[i] + h[i + 1]);
! 718:
! 719: if (i > num_points - 4)
! 720: m[i][2] = 0;
! 721: else
! 722: m[i][2] = h[i + 1];
! 723: }
! 724:
! 725: /* solve the matrix */
! 726: if (!solve_tri_diag(m, r, x, num_points - 2)) {
! 727: free(h);
! 728: free(x);
! 729: free(r);
! 730: free(m);
! 731: free(xp);
! 732: free(yp);
! 733: int_error("Can't calculate cubic splines", NO_CARET);
! 734: }
! 735: sc[0][2] = 0;
! 736: for (i = 1; i <= num_points - 2; i++)
! 737: sc[i][2] = x[i - 1];
! 738: sc[num_points - 1][2] = 0;
! 739:
! 740: for (i = 0; i <= num_points - 1; i++)
! 741: sc[i][0] = yp[i];
! 742:
! 743: for (i = 0; i <= num_points - 2; i++) {
! 744: sc[i][1] = (sc[i + 1][0] - sc[i][0]) / h[i]
! 745: - h[i] / 3 * (sc[i + 1][2] + 2 * sc[i][2]);
! 746: sc[i][3] = (sc[i + 1][2] - sc[i][2]) / 3 / h[i];
! 747: }
! 748:
! 749: free(h);
! 750: free(x);
! 751: free(r);
! 752: free(m);
! 753: free(xp);
! 754: free(yp);
! 755:
! 756: return (sc);
! 757: }
! 758:
! 759: static void do_cubic(plot, sc, first_point, num_points, dest)
! 760: struct curve_points *plot; /* still containes old plot->points */
! 761: spline_coeff *sc; /* generated by cp_tridiag */
! 762: int first_point; /* where to start in plot->points */
! 763: int num_points; /* to determine end in plot->points */
! 764: struct coordinate *dest; /* where to put the interpolated data */
! 765: {
! 766: double xdiff, temp, x, y;
! 767: int i, l;
! 768: int xaxis = plot->x_axis;
! 769: int yaxis = plot->y_axis;
! 770: /* HBB 980308: added 'GPHUGE' tag */
! 771: struct coordinate GPHUGE *this_points;
! 772:
! 773: /* min and max in internal (eg logged) co-ordinates. We update
! 774: * these, then update the external extrema in user co-ordinates
! 775: * at the end.
! 776: */
! 777:
! 778: double ixmin, ixmax, iymin, iymax;
! 779: double sxmin, sxmax, symin, symax; /* starting values of above */
! 780:
! 781: if (log_array[xaxis]) {
! 782: ixmin = sxmin = log(min_array[xaxis]) / log_base_array[xaxis];
! 783: ixmax = sxmax = log(max_array[xaxis]) / log_base_array[xaxis];
! 784: } else {
! 785: ixmin = sxmin = min_array[xaxis];
! 786: ixmax = sxmax = max_array[xaxis];
! 787: }
! 788:
! 789: if (log_array[yaxis]) {
! 790: iymin = symin = log(min_array[yaxis]) / log_base_array[yaxis];
! 791: iymax = symax = log(max_array[yaxis]) / log_base_array[yaxis];
! 792: } else {
! 793: iymin = symin = min_array[yaxis];
! 794: iymax = symax = max_array[yaxis];
! 795: }
! 796:
! 797:
! 798: this_points = (plot->points) + first_point;
! 799:
! 800: l = 0;
! 801:
! 802: xdiff = (this_points[num_points - 1].x - this_points[0].x) / (samples - 1);
! 803:
! 804: for (i = 0; i < samples; i++) {
! 805: x = this_points[0].x + i * xdiff;
! 806:
! 807: while ((x >= this_points[l + 1].x) && (l < num_points - 2))
! 808: l++;
! 809:
! 810: /* KB 981107: With logarithmic x axis the values were converted back to linear */
! 811: /* scale before calculating the coefficients. Use exponential for log x values. */
! 812:
! 813: if (log_array[xaxis]) {
! 814: temp = exp(x * log_base_array[xaxis]) - exp(this_points[l].x * log_base_array[xaxis]);
! 815: y = ((sc[l][3] * temp + sc[l][2]) * temp + sc[l][1]) * temp + sc[l][0];
! 816: } else {
! 817: temp = x - this_points[l].x;
! 818: y = ((sc[l][3] * temp + sc[l][2]) * temp + sc[l][1]) * temp + sc[l][0];
! 819: }
! 820: /* With logarithmic y axis, we need to convert from linear to log scale now. */
! 821: if (log_array[yaxis]) {
! 822: if (y > 0.)
! 823: y = log(y) / log_base_array[yaxis];
! 824: else
! 825: y = symin - (symax - symin);
! 826: }
! 827: dest[i].type = INRANGE;
! 828: STORE_AND_FIXUP_RANGE(dest[i].x, x, dest[i].type, ixmin, ixmax, auto_array[xaxis], NOOP, continue);
! 829: STORE_AND_FIXUP_RANGE(dest[i].y, y, dest[i].type, iymin, iymax, auto_array[yaxis], NOOP, NOOP);
! 830:
! 831: dest[i].xlow = dest[i].xhigh = dest[i].x;
! 832: dest[i].ylow = dest[i].yhigh = dest[i].y;
! 833:
! 834: dest[i].z = -1;
! 835:
! 836: }
! 837:
! 838: UPDATE_RANGE(ixmax > sxmax, max_array[xaxis], ixmax, xaxis);
! 839: UPDATE_RANGE(ixmin < sxmin, min_array[xaxis], ixmin, xaxis);
! 840: UPDATE_RANGE(iymax > symax, max_array[yaxis], iymax, yaxis);
! 841: UPDATE_RANGE(iymin < symin, min_array[yaxis], iymin, yaxis);
! 842:
! 843: }
! 844:
! 845: /*
! 846: * This is the main entry point used. As stated in the header, it is fine,
! 847: * but I'm not too happy with it.
! 848: */
! 849:
! 850: void gen_interp(plot)
! 851: struct curve_points *plot;
! 852: {
! 853:
! 854: spline_coeff *sc;
! 855: double *bc;
! 856: struct coordinate *new_points;
! 857: int i, curves;
! 858: int first_point, num_points;
! 859:
! 860: curves = num_curves(plot);
! 861: new_points = (struct coordinate *) gp_alloc((samples + 1) * curves * sizeof(struct coordinate), "interpolation table");
! 862:
! 863: first_point = 0;
! 864: for (i = 0; i < curves; i++) {
! 865: num_points = next_curve(plot, &first_point);
! 866: switch (plot->plot_smooth) {
! 867: case CSPLINES:
! 868: sc = cp_tridiag(plot, first_point, num_points);
! 869: do_cubic(plot, sc, first_point, num_points,
! 870: new_points + i * (samples + 1));
! 871: free(sc);
! 872: break;
! 873: case ACSPLINES:
! 874: sc = cp_approx_spline(plot, first_point, num_points);
! 875: do_cubic(plot, sc, first_point, num_points,
! 876: new_points + i * (samples + 1));
! 877: free(sc);
! 878: break;
! 879:
! 880: case BEZIER:
! 881: case SBEZIER:
! 882: bc = cp_binomial(num_points);
! 883: do_bezier(plot, bc, first_point, num_points,
! 884: new_points + i * (samples + 1));
! 885: free((char *) bc);
! 886: break;
! 887: default: /* keep gcc -Wall quiet */
! 888: ;
! 889: }
! 890: new_points[(i + 1) * (samples + 1) - 1].type = UNDEFINED;
! 891: first_point += num_points;
! 892: }
! 893:
! 894: free(plot->points);
! 895: plot->points = new_points;
! 896: plot->p_max = curves * (samples + 1);
! 897: plot->p_count = plot->p_max - 1;
! 898:
! 899: return;
! 900: }
! 901:
! 902: /*
! 903: * sort_points
! 904: *
! 905: * sort data succession for further evaluation by plot_splines, etc.
! 906: * This routine is mainly introduced for compilers *NOT* supporting the
! 907: * UNIX qsort() routine. You can then easily replace it by more convenient
! 908: * stuff for your compiler.
! 909: * (MGR 1992)
! 910: */
! 911:
! 912: static int compare_points(p1, p2)
! 913: struct coordinate *p1;
! 914: struct coordinate *p2;
! 915: {
! 916: if (p1->x > p2->x)
! 917: return (1);
! 918: if (p1->x < p2->x)
! 919: return (-1);
! 920: return (0);
! 921: }
! 922:
! 923: void sort_points(plot)
! 924: struct curve_points *plot;
! 925: {
! 926: int first_point, num_points;
! 927:
! 928: first_point = 0;
! 929: while ((num_points = next_curve(plot, &first_point)) > 0) {
! 930: /* Sort this set of points, does qsort handle 1 point correctly? */
! 931: qsort((char *) (plot->points + first_point), num_points,
! 932: sizeof(struct coordinate), (sortfunc) compare_points);
! 933: first_point += num_points;
! 934: }
! 935: return;
! 936: }
! 937:
! 938:
! 939: /*
! 940: * cp_implode() if averaging is selected this function computes the new
! 941: * entries and shortens the whole thing to the necessary
! 942: * size
! 943: * MGR Addendum
! 944: */
! 945:
! 946: void cp_implode(cp)
! 947: struct curve_points *cp;
! 948: {
! 949: int first_point, num_points;
! 950: int i, j, k;
! 951: double x, y, sux, slx, suy, sly;
! 952: enum coord_type dot;
! 953:
! 954:
! 955: j = 0;
! 956: first_point = 0;
! 957: while ((num_points = next_curve(cp, &first_point)) > 0) {
! 958: k = 0;
! 959: for (i = first_point; i < first_point + num_points; i++) {
! 960: if (!k) {
! 961: x = cp->points[i].x;
! 962: y = cp->points[i].y;
! 963: sux = cp->points[i].xhigh;
! 964: slx = cp->points[i].xlow;
! 965: suy = cp->points[i].yhigh;
! 966: sly = cp->points[i].ylow;
! 967: dot = INRANGE;
! 968: if (cp->points[i].type != INRANGE)
! 969: dot = UNDEFINED; /* This means somthing other than usual *//* just signal to check if INRANGE */
! 970: k = 1;
! 971: } else if (cp->points[i].x == x) {
! 972: y += cp->points[i].y;
! 973: sux += cp->points[i].xhigh;
! 974: slx += cp->points[i].xlow;
! 975: suy += cp->points[i].yhigh;
! 976: sly += cp->points[i].ylow;
! 977: if (cp->points[i].type != INRANGE)
! 978: dot = UNDEFINED;
! 979: k++;
! 980: } else {
! 981: cp->points[j].x = x;
! 982: cp->points[j].y = y / (double) k;
! 983: cp->points[j].xhigh = sux / (double) k;
! 984: cp->points[j].xlow = slx / (double) k;
! 985: cp->points[j].yhigh = suy / (double) k;
! 986: cp->points[j].ylow = sly / (double) k;
! 987: cp->points[j].type = INRANGE;
! 988: if (dot != INRANGE) {
! 989: if ((cp->points[j].x > xmax) || (cp->points[j].x < xmin))
! 990: cp->points[j].type = OUTRANGE;
! 991: else if (!autoscale_ly) {
! 992: if ((cp->points[j].y > ymax) || (cp->points[j].y < ymin))
! 993: cp->points[j].type = OUTRANGE;
! 994: } else
! 995: cp->points[j].type = INRANGE;
! 996: }
! 997: j++; /* next valid entry */
! 998: k = 0; /* to read */
! 999: i--; /* from this (-> last after for(;;)) entry */
! 1000: }
! 1001: }
! 1002: if (k) {
! 1003: cp->points[j].x = x;
! 1004: cp->points[j].y = y / (double) k;
! 1005: cp->points[j].xhigh = sux / (double) k;
! 1006: cp->points[j].xlow = slx / (double) k;
! 1007: cp->points[j].yhigh = suy / (double) k;
! 1008: cp->points[j].ylow = sly / (double) k;
! 1009: cp->points[j].type = INRANGE;
! 1010: if (dot != INRANGE) {
! 1011: if ((cp->points[j].x > xmax) || (cp->points[j].x < xmin))
! 1012: cp->points[j].type = OUTRANGE;
! 1013: else if (!autoscale_ly) {
! 1014: if ((cp->points[j].y > ymax) || (cp->points[j].y < ymin))
! 1015: cp->points[j].type = OUTRANGE;
! 1016: } else
! 1017: cp->points[j].type = INRANGE;
! 1018: }
! 1019: j++; /* next valid entry */
! 1020: }
! 1021: /* insert invalid point to separate curves */
! 1022: if (j < cp->p_count) {
! 1023: cp->points[j].type = UNDEFINED;
! 1024: j++;
! 1025: }
! 1026: first_point += num_points;
! 1027: } /* end while */
! 1028: cp->p_count = j;
! 1029: cp_extend(cp, j);
! 1030: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>