home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *RCSid="$Id: interpol.c,v 1.17 1995/12/14 21:08:56 drd Exp $";
- #endif
-
- /*
- * C-Source file identification Header
- *
- * This file belongs to a project which is:
- *
- * done 1993 by MGR-Software, Asgard (Lars Hanke)
- * written by Lars Hanke
- *
- * Contact me via:
- *
- * InterNet: mgr@asgard.bo.open.de
- * FIDO: Lars Hanke @ 2:243/4802.22 (as long as they keep addresses)
- *
- **************************************************************************
- *
- * Project: gnuplot
- * Module:
- * File: interpol.c
- *
- * Revisor: Lars Hanke
- * Revised: 26/09/93
- * Revision: 1.0
- *
- **************************************************************************
- *
- * LEGAL
- * This module is part of gnuplot and distributed under whatever terms
- * gnuplot is or will be published, unless exclusive rights are claimed.
- *
- * DESCRIPTION
- * Supplies 2-D data interpolation and approximation routines
- *
- * IMPORTS
- * plot.h
- * - cp_extend()
- * - structs: curve_points, coordval, coordinate
- *
- * setshow.h
- * - samples, is_log_x, base_log_x, xmin, xmax, autoscale_lx
- * - plottypes
- *
- * proto.h
- * - solve_tri_diag()
- * - typedef tri_diag
- *
- * EXPORTS
- * gen_interp()
- * sort_points()
- * cp_implode()
- *
- * BUGS and TODO
- * I would really have liked to use Gershon Elbers contouring code for
- * all the stuff done here, but I failed. So I used my own code.
- * If somebody is able to consolidate Gershon's code for this purpose
- * a lot of gnuplot users would be very happy - due to memory problems.
- *
- **************************************************************************
- *
- * HISTORY
- * Changes:
- * Nov 24, 1995 Markus Schuh (M.Schuh@meteo.uni-koeln.de):
- * changed the algorithm for csplines
- * added algorithm for approximation csplines
- * copied point storage and range fix from plot2d.c
- *
- * Dec 12, 1995 David Denholm
- * oops - at the time this is called, stored co-ords are
- * internal (ie maybe log of data) but min/max are in
- * user co-ordinates.
- * Work with min and max of internal co-ords, and
- * check at the end whether external min and max need to
- * be increased. (since samples is typically 100 ; we
- * dont want to take more logs than necessary)
- * Also, need to take into account which axes are active
- *
- */
-
- #include <math.h>
- #include "plot.h"
- #include "setshow.h"
-
-
- /* in order to support multiple axes, and to
- * simplify ranging in parametric plots, we use
- * arrays to store some things. For 2d plots,
- * elements are z=0,y1=1,x1=2,z2=4,y2=5,x2=6
- * these are given symbolic names in plot.h
- */
-
- extern double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE];
- extern int auto_array[AXIS_ARRAY_SIZE];
- extern TBOOLEAN log_array[AXIS_ARRAY_SIZE];
- extern double base_array[AXIS_ARRAY_SIZE];
- extern double log_base_array[AXIS_ARRAY_SIZE];
-
-
- /* both min() and MIN() are defined by some compilers - grr ! */
- #define GPMIN(a,b) ((a)>(b) ? (b) : (a))
-
- #define Inc_c_token if (++c_token >= num_tokens) \
- int_error ("Syntax error", c_token);
-
-
- /*
- * IMHO, code is getting too cluttered with repeated chunks of
- * code. Some macros to simplify, I hope.
- *
- * do { } while(0) is comp.lang.c recommendation for complex macros
- * also means that break can be specified as an action, and it will
- *
- */
-
-
-
- /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
- * Do OUT_ACTION or UNDEF_ACTION as appropriate
- * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
- * VALUE must not be same as STORE
- */
-
- #define STORE_AND_FIXUP_RANGE(STORE, VALUE, TYPE, MIN, MAX, AUTO, OUT_ACTION, UNDEF_ACTION)\
- do { STORE=VALUE; \
- if (TYPE != INRANGE) break; /* dont set y range if x is outrange, for example */ \
- if ( VALUE<MIN ) \
- if (AUTO & 1) MIN=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; break; } \
- if ( VALUE>MAX ) \
- if (AUTO & 2) MAX=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; } \
- } while(0)
-
- #define UPDATE_RANGE(TEST,OLD,NEW,AXIS) \
- do { if (TEST) \
- if (log_array[AXIS]) OLD = pow(base_array[AXIS], NEW); \
- else OLD = NEW; }while(0)
-
- /* use this instead empty macro arguments to work around NeXT cpp bug */
- /* if this fails on any system, we might use ((void)0) */
-
- #define NOOP /* */
-
-
- #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
-
- #define spline_coeff_size 4
- typedef double spline_coeff[spline_coeff_size];
- typedef double five_diag[5];
-
- static double *cp_binomial __P((struct curve_points *cp));
- static double s_pow __P((double base, unsigned int exponent));
- static void eval_bezier __P((struct curve_points *cp, double sr, coordval *px, coordval *py, double *c));
- static void do_bezier __P((struct curve_points *cp, double *bc));
- static spline_coeff *cp_tridiag __P((struct curve_points *plot));
- static int solve_five_diag __P((five_diag m[], double r[], double x[], int n));
- static spline_coeff *cp_approx_spline __P((struct curve_points *plot));
- static void do_cubic __P((struct curve_points *plot, spline_coeff *sc));
- static int compare_points __P((struct coordinate *p1, struct coordinate *p2));
-
- /*
- * build up a cntr_struct list from curve_points
- * this funtion is only used for the alternate entry point to
- * Gershon's code and thus commented out
-
- static struct cntr_struct *conv2cntr(struct curve_points *plot)
- {
- int i;
- struct cntr_struct *c,*oc;
-
- if(!plot) return(NULL);
- oc=NULL;
- for (i=plot->p_count-1;i >= 0; i--){
- c=(struct cntr_struct *)alloc(sizeof(struct cntr_struct),"Spline list");
- c->next=oc;
- c->X=plot->points[i].x;
- c->Y=plot->points[i].y;
- oc=c;
- }
-
- return(c);
- }
- */
-
- /*
- * cp_binomial() computes the binomial coefficients needed for BEZIER stuff
- * and stores them into an array which is hooked to sdat.
- * (MGR 1992)
- */
- static double *cp_binomial(cp)
- struct curve_points *cp;
- {
- register double *coeff;
- register int n,k;
- int e;
-
- e=cp->p_count; /* well we're going from k=0 to k=p_count-1 */
- coeff=(double *)alloc(e*sizeof(double),"bezier coefficients");
-
- n=cp->p_count-1;
- e=n/2;
- coeff[0]=1.0;
-
- for(k=0;k<e;k++)
- coeff[k+1] = coeff[k] * ((double)(n-k))/((double)(k+1));
-
- for(k=n;k>=e;k--) coeff[k] = coeff[n-k];
-
- return(coeff);
- }
-
- /* This is a subfunction of do_bezier() for BEZIER style computations.
- * It is passed the stepration (STEP/MAXSTEPS) and the addresses of
- * the double values holding the next x and y coordinates.
- * (MGR 1992)
- */
-
- /*
- * well, this routine runs faster with the 68040 striptease FPU
- * and it handles zeroes correctly - there had been some trouble with TC
- */
-
- #ifdef AMIGA_SC_6_1
- __inline
- #endif
- static double s_pow(base, exponent)
- double base;
- unsigned int exponent;
- {
- int i;
- double x,y;
-
- static int spoken=0;
-
- if(exponent==0) return(1.0);
- if(base==0.0) return(0.0);
- x=base;
- for(i=1;i<exponent;i++) x*=base;
-
- /* consider i in binary = abcd
- * x^i = x^(8a+4b+2c+d) = x^8a * x^4b * x^2b * x^d
- * = a?x^2^2^2:1 * b?x^2^2:1 + ...
- * so for each bit in exponent, square x, multiplying it into accumulator
- *
- * - probably not clear - that's why I'm comparing the two versions !
- */
-
- if (!spoken) {
- fprintf(stderr, "Please note that s_pow in interpol.c is comparing two algorithms.\nThis message will be taken out (I hope) before release\n");
- spoken=1;
- }
-
- y=1;
- while (exponent)
- {
- if (exponent&1)
- y *= base;
- base *= base;
- exponent >>= 1; /* if exponent was signed, this could be trouble ! */
- }
-
- if (fabs(x-y) > 0.001)
- fprintf(stderr, "uh oh - div got s_pow wrong in interpol.c : %f != %f\n", y, x);
-
- return(x);
- }
-
- static void eval_bezier(cp,sr,px,py,c)
- struct curve_points *cp;
- double sr;
- coordval *px;
- coordval *py;
- double *c;
- {
- int i;
- int n=cp->p_count-1;
- double lx=0.0, ly=0.0;
- double sr_to_the_i = 1.0;
- double dsr_to_the_di = s_pow(1-sr, n);
- double reciprocal_dsr = 1.0/(1-sr);
-
- for(i=0;i<=n;i++){
- double u = c[i] * sr_to_the_i * s_pow(1-sr,n-i);
- lx+=cp->points[i].x*u;
- ly+=cp->points[i].y*u;
- sr_to_the_i *= sr;
- dsr_to_the_di *= reciprocal_dsr;
- }
-
- *px = lx;
- *py = ly;
- }
-
- /*
- * generate a new set of coordinates representing the bezier curve and
- * set it to the plot
- */
-
- static void do_bezier(cp,bc)
- struct curve_points *cp;
- double *bc;
- {
- struct coordinate *s_tbl;
- int i;
- double x,y;
- int xaxis = cp->x_axis;
- int yaxis = cp->y_axis;
-
- /* min and max in internal (eg logged) co-ordinates. We update
- * these, then update the external extrema in user co-ordinates
- * at the end.
- */
-
- double ixmin,ixmax,iymin,iymax;
- double sxmin,sxmax,symin,symax; /* starting values of above */
-
- if (log_array[xaxis])
- {
- ixmin = sxmin = log(min_array[xaxis]) / log_base_array[xaxis];
- ixmax = sxmax = log(max_array[xaxis]) / log_base_array[xaxis];
- }
- else
- {
- ixmin = sxmin = min_array[xaxis];
- ixmax = sxmax = max_array[xaxis];
- }
-
- if (log_array[yaxis])
- {
- iymin = symin = log(min_array[yaxis]) / log_base_array[yaxis];
- iymax = symax = log(max_array[yaxis]) / log_base_array[yaxis];
- }
- else
- {
- iymin = symin = min_array[yaxis];
- iymax = symax = max_array[yaxis];
- }
-
- s_tbl=(struct coordinate *)alloc(samples*sizeof(struct coordinate),"bezier table");
-
- for(i=0;i<samples;i++){
- eval_bezier(cp,(double)i/(double)(samples-1),&x,&y,bc);
-
- /* now we have to store the points and adjust the ranges */
-
- s_tbl[i].type=INRANGE;
- STORE_AND_FIXUP_RANGE(s_tbl[i].x, x, s_tbl[i].type, ixmin, ixmax, auto_array[xaxis], NOOP, continue );
- STORE_AND_FIXUP_RANGE(s_tbl[i].y, y, s_tbl[i].type, iymin, iymax, auto_array[yaxis], NOOP, NOOP );
-
- s_tbl[i].xlow = s_tbl[i].xhigh = s_tbl[i].x;
- s_tbl[i].ylow = s_tbl[i].yhigh = s_tbl[i].y;
-
- s_tbl[i].z = -1;
- }
- free((char *)cp->points);
- cp->points=s_tbl;
- cp->p_count=samples;
- cp->p_max=samples;
-
-
- UPDATE_RANGE(ixmax > sxmax, max_array[xaxis], ixmax, xaxis);
- UPDATE_RANGE(ixmin < sxmin, min_array[xaxis], ixmin, xaxis);
- UPDATE_RANGE(iymax > symax, max_array[yaxis], iymax, yaxis);
- UPDATE_RANGE(iymin < symin, min_array[yaxis], iymin, yaxis);
- }
-
- /*
- * call contouring routines -- main entry
- */
-
- /*
- * it should be like this, but it doesn't run. If you find out why,
- * contact me: mgr@asgard.bo.open.de or Lars Hanke 2:243/4802.22@fidonet
- *
- * Well, all this had originally been inside contour.c, so maybe links
- * to functions and of contour.c are broken.
- *
-
- --> this denotes comment nests
-
- void gen_interp(struct curve_points *plot)
- {
- struct cntr_struct *my_cntr = NULL;
- struct gnuplot_contours *save_list = contour_list;
-
- int i;
- double x;
- double *bc;
- int num_pts = num_approx_pts;
-
- hermit_table=NULL;
- contour_list=NULL;
- my_cntr=conv2cntr(plot);
- if(!my_cntr) return;
-
- switch(plot->plot_smooth){
- case CSPLINES: calc_hermit_table();
- interp_kind=INTERP_CUBIC;
- break;
- case BEZIER:
- case SBEZIER: bc=cp_binomial(plot);
- do_bezier(plot,bc);
- free((char *)bc);
- --> no break
- default: free_contour(my_cntr);
- return;
- }
-
- num_approx_pts=samples/(plot->p_count);
-
- --> could not find any place where x_min to y_max were used, so I set
- --> them to zero
-
- put_contour(my_cntr,0,0,0,0,0,OPEN_CONTOUR);
-
- free(plot->points);
-
- plot->p_max=contour_list->num_pts;
- plot->p_count=contour_list->num_pts;
- plot->points=contour_list->coords;
- free(contour_list);
- contour_list=save_list;
- num_approx_pts=num_pts;
-
- if(hermit_table){
- free(hermit_table);
- hermit_table=NULL;
- }
- free_contour(my_cntr);
-
- for(i=0;i<plot->p_count;i++){
- x=(is_log_x)? pow(base_log_x,plot->points[i].x) : plot->points[i].x;
- if((x >= xmin) && (x <= xmax)) plot->points[i].type=INRANGE;
- else plot->points[i].type=OUTRANGE;
- }
-
- }
- *
- * end of unused entry point to Gershon's code
- *
- */
-
- /*
- * Solve five diagonal linear system equation. The five diagonal matrix is
- * defined via matrix M, right side is r, and solution X i.e. M * X = R.
- * Size of system given in n. Return TRUE if solution exist.
- * G. Engeln-Muellges/ F.Reutter:
- * "Formelsammlung zur Numerischen Mathematik mit Standard-FORTRAN-Programmen"
- * ISBN 3-411-01677-9
- *
- * / m02 m03 m04 0 0 0 0 . . . \ / x0 \ / r0 \
- * I m11 m12 m13 m14 0 0 0 . . . I I x1 I I r1 I
- * I m20 m21 m22 m23 m24 0 0 . . . I * I x2 I = I r2 I
- * I 0 m30 m31 m32 m33 m34 0 . . . I I x3 I I r3 I
- * . . . . . . . . . . . .
- * \ m(n-3)0 m(n-2)1 m(n-1)2 / \x(n-1)/ \r(n-1)/
- *
- */
- static int solve_five_diag(m, r, x, n)
- five_diag m[];
- double r[], x[];
- int n;
- {
- five_diag *hv;
- int i;
-
- hv=(five_diag *)alloc((n+1)*sizeof(five_diag),"five_diag help vars");
-
- hv[0][0] = m[0][2];
- if ( hv[0][0] == 0 ){
- free(hv);
- return FALSE;
- }
- hv[0][1] = m[0][3] / hv[0][0];
- hv[0][2] = m[0][4] / hv[0][0];
-
- hv[1][3] = m[1][1];
- hv[1][0] = m[1][2] - hv[1][3]*hv[0][1];
- if ( hv[1][0] == 0 ){
- free(hv);
- return FALSE;
- }
- hv[1][1] = (m[1][3] - hv[1][3]*hv[0][2]) / hv[1][0];
- hv[1][2] = m[1][4] / hv[1][0];
-
- for( i=2; i<=n-1; i++){
- hv[i][3] = m[i][1] - m[i][0]*hv[i-2][1];
- hv[i][0] = m[i][2] - m[i][0]*hv[i-2][2] - hv[i][3]*hv[i-1][1];
- if ( hv[i][0] == 0 ){
- free(hv);
- return FALSE;
- }
- hv[i][1] = (m[i][3] - hv[i][3]*hv[i-1][2]) / hv[i][0];
- hv[i][2] = m[i][4] / hv[i][0];
- }
-
- hv[0][4] = 0;
- hv[1][4] = r[0] / hv[0][0];
- for( i=1; i<=n-1; i++)
- hv[i+1][4] = ( r[i] - m[i][0]*hv[i-1][4] - hv[i][3]*hv[i][4] ) / hv[i][0];
-
- x[n-1] = hv[n][4];
- x[n-2] = hv[n-1][4] - hv[n-2][1]*x[n-1];
- for( i=n-3; i>=0; i--)
- x[i] = hv[i+1][4] - hv[i][1]*x[i+1] - hv[i][2]*x[i+2];
-
- free(hv);
- return TRUE;
- }
-
- /*
- * Calculation of approximation cubic splines
- * Input: x[i], y[i], weights z[i]
- *
- * Returns matrix of spline coefficients
- */
- static spline_coeff *cp_approx_spline(plot)
- struct curve_points *plot;
- {
- spline_coeff *sc;
- five_diag *m;
- double *r, *x, *h;
-
- int i;
-
- sc=(spline_coeff *)alloc((plot->p_count)*sizeof(spline_coeff),"spline matrix");
-
- if (plot->p_count < 3)
- int_error("Can't calculate approximation splines, need more than 3 points", NO_CARET);
-
- for( i=0; i<=plot->p_count-1; i++)
- if (plot->points[i].z <=0)
- int_error("Can't calculate approximation splines, all weights have to be > 0", NO_CARET);
-
- m = (five_diag *)alloc((plot->p_count-2)*sizeof(five_diag),"spline help matrix");
-
- r = (double *)alloc((plot->p_count-2)*sizeof(double),"spline right side");
- x = (double *)alloc((plot->p_count-2)*sizeof(double),"spline solution vector");
- h = (double *)alloc((plot->p_count-1)*sizeof(double),"spline help vector");
-
- for( i=0; i<=plot->p_count-2; i++)
- h[i] = plot->points[i+1].x - plot->points[i].x;
-
- /* set up the matrix and the vector*/
-
- for( i=0; i<=plot->p_count-3; i++){
- r[i] = 3*((plot->points[i+2].y-plot->points[i+1].y)/h[i+1]
- -(plot->points[i+1].y-plot->points[i].y)/h[i]);
-
- if ( i < 2 )
- m[i][0] = 0;
- else
- m[i][0] = 6 / plot->points[i].z / h[i-1] / h[i];
-
- if ( i < 1 )
- m[i][1] = 0;
- else
- m[i][1] = h[i] - 6 / plot->points[i].z / h[i] * ( 1/h[i-1] + 1/h[i])
- - 6 / plot->points[i+1].z / h[i] * ( 1/h[i] + 1/h[i+1]);
-
- m[i][2] = 2 * ( h[i] + h[i+1] )
- + 6 / plot->points[i].z / h[i] / h[i]
- + 6 / plot->points[i+1].z * ( 1/h[i] + 1/h[i+1] ) * ( 1/h[i] + 1/h[i+1] )
- + 6 / plot->points[i+2].z / h[i+1] / h[i+1];
-
- if ( i > plot->p_count-4 )
- m[i][3] = 0;
- else
- m[i][3] = h[i+1] - 6 / plot->points[i+1].z / h[i+1] * ( 1/h[i] + 1/h[i+1] )
- - 6 / plot->points[i+2].z / h[i+1] * ( 1/h[i+1] + 1/h[i+2] );
-
- if ( i > plot->p_count-5 )
- m[i][4] = 0;
- else
- m[i][4] = 6 / plot->points[i+2].z / h[i+1] / h[i+2];
- }
-
- /* solve the matrix */
- if (!solve_five_diag(m, r, x, plot->p_count-2)){
- free(h);
- free(x);
- free(r);
- free(m);
- int_error("Can't calculate approximation splines", NO_CARET);
- }
-
- sc[0][2] = 0;
- for( i=1; i<=plot->p_count-2; i++ )
- sc[i][2] = x[i-1];
- sc[plot->p_count-1][2] = 0;
-
- sc[0][0] = plot->points[0].y + 2 / plot->points[0].z / h[0] * ( sc[0][2] - sc[1][2] );
- for( i=1; i<=plot->p_count-2; i++ )
- sc[i][0] = plot->points[i].y - 2 / plot->points[i].z *
- ( sc[i-1][2] / h[i-1]
- - sc[i][2] * ( 1/h[i-1] + 1/h[i] )
- + sc[i+1][2] / h[i] );
- sc[plot->p_count-1][0] = plot->points[plot->p_count-1].y
- - 2 / plot->points[plot->p_count-1].z / h[plot->p_count-2]
- * ( sc[plot->p_count-2][2] - sc[plot->p_count-1][2] );
-
- for( i=0; i<=plot->p_count-2; i++ ){
- sc[i][1] = ( sc[i+1][0] - sc[i][0] ) / h[i]
- - h[i] / 3 * ( sc[i+1][2] + 2 * sc[i][2] );
- sc[i][3] = ( sc[i+1][2] - sc[i][2] ) / 3 / h[i];
- }
-
- free(h);
- free(x);
- free(r);
- free(m);
-
- return(sc);
- }
-
- /*
- * Calculation of cubic splines
- * Input: x[i], y[i]
- * This can be treated as a special case of approximation cubic splines, with
- * all weights -> infinity.
- *
- * Returns matrix of spline coefficients
- */
- static spline_coeff *cp_tridiag(plot)
- struct curve_points *plot;
- {
- spline_coeff *sc;
- tri_diag *m;
- double *r, *x, *h;
-
- int i;
-
- sc=(spline_coeff *)alloc((plot->p_count)*sizeof(spline_coeff),"spline matrix");
-
- m = (tri_diag *)alloc((plot->p_count-2)*sizeof(tri_diag),"spline help matrix");
-
- r = (double *)alloc((plot->p_count-2)*sizeof(double),"spline right side");
- x = (double *)alloc((plot->p_count-2)*sizeof(double),"spline solution vector");
- h = (double *)alloc((plot->p_count-1)*sizeof(double),"spline help vector");
-
- for( i=0; i<=plot->p_count-2; i++)
- h[i] = plot->points[i+1].x - plot->points[i].x;
-
- /* set up the matrix and the vector*/
-
- for( i=0; i<=plot->p_count-3; i++){
- r[i] = 3*((plot->points[i+2].y-plot->points[i+1].y)/h[i+1]
- -(plot->points[i+1].y-plot->points[i].y)/h[i]);
-
- if ( i < 1 )
- m[i][0] = 0;
- else
- m[i][0] = h[i];
-
- m[i][1] = 2 * ( h[i] + h[i+1] );
-
- if ( i > plot->p_count-4 )
- m[i][2] = 0;
- else
- m[i][2] = h[i+1];
- }
-
- /* solve the matrix */
- if (!solve_tri_diag(m, r, x, plot->p_count-2)){
- free(h);
- free(x);
- free(r);
- free(m);
- int_error("Can't calculate cubic splines", NO_CARET);
- }
-
- sc[0][2] = 0;
- for( i=1; i<=plot->p_count-2; i++ )
- sc[i][2] = x[i-1];
- sc[plot->p_count-1][2] = 0;
-
- for( i=0; i<=plot->p_count-1; i++ )
- sc[i][0] = plot->points[i].y;
-
- for( i=0; i<=plot->p_count-2; i++ ){
- sc[i][1] = ( sc[i+1][0] - sc[i][0] ) / h[i]
- - h[i] / 3 * ( sc[i+1][2] + 2 * sc[i][2] );
- sc[i][3] = ( sc[i+1][2] - sc[i][2] ) / 3 / h[i];
- }
-
- free(h);
- free(x);
- free(r);
- free(m);
-
- return(sc);
- }
-
- static void do_cubic(plot,sc)
- struct curve_points *plot;
- spline_coeff *sc;
- {
- struct coordinate *s_tbl;
- double xdiff,temp,x,y;
- int i,l;
- int xaxis = plot->x_axis;
- int yaxis = plot->y_axis;
-
- /* min and max in internal (eg logged) co-ordinates. We update
- * these, then update the external extrema in user co-ordinates
- * at the end.
- */
-
- double ixmin,ixmax,iymin,iymax;
- double sxmin,sxmax,symin,symax; /* starting values of above */
-
- if (log_array[xaxis])
- {
- ixmin = sxmin = log(min_array[xaxis]) / log_base_array[xaxis];
- ixmax = sxmax = log(max_array[xaxis]) / log_base_array[xaxis];
- }
- else
- {
- ixmin = sxmin = min_array[xaxis];
- ixmax = sxmax = max_array[xaxis];
- }
-
- if (log_array[yaxis])
- {
- iymin = symin = log(min_array[yaxis]) / log_base_array[yaxis];
- iymax = symax = log(max_array[yaxis]) / log_base_array[yaxis];
- }
- else
- {
- iymin = symin = min_array[yaxis];
- iymax = symax = max_array[yaxis];
- }
-
- s_tbl=(struct coordinate *)alloc(samples*sizeof(struct coordinate),"spline table");
-
- l = 0;
-
- xdiff = (plot->points[plot->p_count-1].x -plot->points[0].x)/(samples-1);
-
- for(i = 0; i < samples; i++) {
- x = plot->points[0].x + i*xdiff;
-
- while((x >= plot->points[l+1].x) && (l < plot->p_count-2)) l++;
-
- temp = x - plot->points[l].x;
-
- y = ((sc[l][3]*temp+sc[l][2])*temp+sc[l][1])*temp+sc[l][0];
-
- s_tbl[i].type=INRANGE;
- STORE_AND_FIXUP_RANGE(s_tbl[i].x, x, s_tbl[i].type, ixmin, ixmax, auto_array[xaxis], NOOP, continue );
- STORE_AND_FIXUP_RANGE(s_tbl[i].y, y, s_tbl[i].type, iymin, iymax, auto_array[yaxis], NOOP, NOOP );
-
- s_tbl[i].xlow = s_tbl[i].xhigh = s_tbl[i].x;
- s_tbl[i].ylow = s_tbl[i].yhigh = s_tbl[i].y;
-
- s_tbl[i].z = -1;
-
- }
-
- free(plot->points);
- plot->points = s_tbl;
- plot->p_count = samples;
- plot->p_max = samples;
-
- UPDATE_RANGE(ixmax > sxmax, max_array[xaxis], ixmax, xaxis);
- UPDATE_RANGE(ixmin < sxmin, min_array[xaxis], ixmin, xaxis);
- UPDATE_RANGE(iymax > symax, max_array[yaxis], iymax, yaxis);
- UPDATE_RANGE(iymin < symin, min_array[yaxis], iymin, yaxis);
- }
-
- /*
- * This is the main entry point used. As stated in the header, it is fine,
- * but I'm not too happy with it.
- */
-
- void gen_interp(plot)
- struct curve_points *plot;
- {
-
- spline_coeff *sc;
- double *bc;
-
- switch(plot->plot_smooth){
- case CSPLINES:
- sc=cp_tridiag(plot);
- do_cubic(plot,sc);
- free(sc);
- break;
- case ACSPLINES:
- sc=cp_approx_spline(plot);
- do_cubic(plot,sc);
- free(sc);
- break;
-
- case BEZIER:
- case SBEZIER: bc=cp_binomial(plot);
- do_bezier(plot,bc);
- free((char *)bc);
- break;
- default: /* keep gcc -Wall quiet */
- ;
- }
-
- return;
-
- }
-
- /* sort_points
- * sort data succession for further evaluation by plot_splines, etc.
- * This routine is mainly introduced for compilers *NOT* supporting the
- * UNIX qsort() routine. You can then easily replace it by more convenient
- * stuff for your compiler.
- * (MGR 1992)
- */
-
- static int compare_points(p1,p2)
- struct coordinate *p1;
- struct coordinate *p2;
- {
- if(p1->x > p2->x) return(1);
- if(p1->x < p2->x) return(-1);
- return(0);
- }
-
- void sort_points(plot)
- struct curve_points *plot;
- {
- qsort((char *)(plot->points), plot->p_count, sizeof(struct coordinate),
- (sortfunc)compare_points);
- }
-
- /*
- * cp_implode() if averaging is selected this function computes the new
- * entries and shortens the whole thing to the necessary
- * size
- * MGR Addendum
- */
-
- void cp_implode(cp)
- struct curve_points *cp;
- {
- int i,j,k;
- double x,y,sux,slx,suy,sly;
- enum coord_type dot;
-
- k=0;
- j=0;
- for(i=0;i<cp->p_count;i++){
- if(!k){
- x=cp->points[i].x;
- y=cp->points[i].y;
- sux=cp->points[i].xhigh;
- slx=cp->points[i].xlow;
- suy=cp->points[i].yhigh;
- sly=cp->points[i].ylow;
- dot=INRANGE;
- if(cp->points[i].type!=INRANGE) dot=UNDEFINED;
- k=1;
- } else if(cp->points[i].x==x){
- y+=cp->points[i].y;
- sux+=cp->points[i].xhigh;
- slx+=cp->points[i].xlow;
- suy+=cp->points[i].yhigh;
- sly+=cp->points[i].ylow;
- if(cp->points[i].type!=INRANGE) dot=UNDEFINED;
- k++;
- } else {
- cp->points[j].x=x;
- cp->points[j].y=y/(double)k;
- cp->points[j].xhigh=sux/(double)k;
- cp->points[j].xlow=slx/(double)k;
- cp->points[j].yhigh=suy/(double)k;
- cp->points[j].ylow=sly/(double)k;
- cp->points[j].type=INRANGE;
- if(dot!=INRANGE){
- if((cp->points[j].x>xmax) || (cp->points[j].x<xmin))
- cp->points[j].type=OUTRANGE;
- else if(!autoscale_ly){
- if((cp->points[j].y>ymax) || (cp->points[j].y<ymin))
- cp->points[j].type=OUTRANGE;
- } else cp->points[j].type=INRANGE;
- }
- j++; /* next valid entry */
- k=0; /* to read */
- i--; /* from this (-> last after for(;;)) entry */
- }
- }
- if(k){
- cp->points[j].x=x;
- cp->points[j].y=y/(double)k;
- cp->points[j].xhigh=sux/(double)k;
- cp->points[j].xlow=slx/(double)k;
- cp->points[j].yhigh=suy/(double)k;
- cp->points[j].ylow=sly/(double)k;
- cp->points[j].type=INRANGE;
- if(dot!=INRANGE){
- if((cp->points[j].x>xmax) || (cp->points[j].x<xmin))
- cp->points[j].type=OUTRANGE;
- else if(!autoscale_ly){
- if((cp->points[j].y>ymax) || (cp->points[j].y<ymin))
- cp->points[j].type=OUTRANGE;
- } else cp->points[j].type=INRANGE;
- }
- j++; /* next valid entry */
- }
- cp->p_count=j;
- cp_extend(cp,j);
- }
-