[BACK]Return to interpol.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/interpol.c, Revision 1.1.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>