spline/0000700000175000017500000000000011353745662011312 5ustar daviddavidspline/utils.h0000600000175000017500000000275211305317723012621 0ustar daviddavid/************************************************************************ * utils.h -- various utilities * * * * A little RPN (Reverse Polish Notation) calculator, * * rudimentary emulating a HP 28S. * * * * rpncalc is (c) David Frey, 1993, 1994, 1995, 2009 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * ************************************************************************/ /* $Id: utils.h,v 1.1 1996/02/11 20:44:55 david Rel $ * $Log: utils.h,v $ * Revision 1.1 1996/02/11 20:44:55 david * Initial revision **/ void *xmalloc(size_t size); void *xrealloc(void *ptr, size_t size); char *gettextline(FILE *stream); spline/aspline.10000600000175000017500000000330410736676212013027 0ustar daviddavid.TH SPLINE 1 "January 1998" "Debian" "User's Reference Manual" \" -*- nroff -*- .SH NAME aspline \- Akima spline interpolation .SH SYNOPSIS .B aspline .RI "[-a " xstep "]" .RI "[-l " llim "]" .RI "[-u " ulim "]" .RI "[-n " n "]" .RI "{" file(s) "}" .SH DESCRIPTION .I aspline reads pairs of numbers from the indicated .I file(s) (or from stdin if no files were given) as abscissas and ordinates of a function. It produces a similar set, which is approximately equally spaced and includes the input set on standard output. The output is an .IR Akima -interpolated spline which has an continuous first derivative. The second derivate may be discontinuous, but the output does not wiggle as it would do with cubic splines. .PP Datasets are separated by blank lines. .SH OPTIONS .TP .BR "\-a \fIincr\fP" ", " "\-\-auto=\fIincr\fP" supply abscissas automatically, since they are missing from the input; spacing is given by the next argument, or is assumed to be 1, if next argument is not a number. .TP .BR "\-l \fIllim\fP" ", " "\-\-llimit=\fIllim\fP" set lower x-limit to .IR llim , .TP .BR "\-u \fIulim\fP" ", " "\-\-ulimit=\fIulim\fP" set upper x-limit to .IR ulim , .TP .BR "\-n \fIn\fP" ", " "\-\-points=\fIn\fP" space output points so that approx. .I n intervals occur between the lower and upper limit, .TP .BR "\-v\fP" be verbose, .TP .BR "\-h\fP" print help message on stderr and exit. .PP .SH SEE ALSO .BR spline (1), .BR gnuplot (1). .sp \fIH. Akima, A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures, Journal of Assc. for Comp. Mach., Vol. 17, No. 4, Oct. 1970, pp. 589\(em602\fP .PP .SH BUGS If you need a continuous second derivative, use .I spline from the plotutils package instead. spline/Makefile0000600000175000017500000000233611352002763012743 0ustar daviddavid# Makefile for aspline RM = rm -f CC = gcc CFLAGS = -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif CFLAGS += -Wall -Wstrict-prototypes -Wmissing-prototypes\ -Wmissing-declarations -Wbad-function-cast -Wnested-externs\ -Wcast-qual -Wcast-align -Wshadow -Wwrite-strings -Wpointer-arith\ -Wformat\ -Wfloat-equal\ -mfpmath=sse # -mfpmath=387 #DEFS = -D_GNU_SOURCE -DHAVE_GETLINE -DOLD_OUTPUT -DVERSION=\"1.2\" DEFS = -D_GNU_SOURCE -DHAVE_GETLINE -DVERSION=\"1.2\" LIBS = -lm INSTOPT= ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTOPT += -s endif BIN = aspline MAN = $(BIN).1 SRCS = utils.c OBJS = ${SRCS:.c=.o} prefix = /usr BINDIR = $(prefix)/bin MANDIR = $(prefix)/share/man/man1 all: $(BIN) .c.o: $(SRCS) $(CC) $(CFLAGS) $(DEFS) -c -o $@ $< $(BIN): $(SRCS) $(OBJS) $(BIN).c $(CC) $(CFLAGS) $(DEFS) -o $(BIN) $(BIN).c $(OBJS) $(LIBS) clean: $(RM) *.o *~ *.bak \#*\# errors core* a.out TAGS *.out distclean: clean $(RM) $(BIN) realclean: distclean -rcsclean install: $(MAN) $(BIN) install -d -g root -o root -m 755 $(BINDIR) $(MANDIR) install $(INSTOPT) -g root -o root -m 755 $(BIN) $(BINDIR) install -g root -o root -m 644 $(MAN) $(MANDIR) spline/aspline.c0000600000175000017500000003323411353745264013116 0ustar daviddavid/*************************************************************************** * aspline.c -- aspline does an Akima spline interpolation. * * * * spline is (c) David Frey, 1996, 1998, 1999, 2002, 2009 * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 2 of the License, or (at your * * option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation, * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include "utils.h" #define DXSTEP 1.0 #define INTERVALLS 100 const char *progname; double *x, *y; /* the values to interpolate */ int warranty(void); int usage(void); void insertpoint(const char *inname, double xv, double yv, int *n); void computelimits(int s, int e, double *llimit, double *ulimit); void calcspline(int n, int d, double xstep, double llimit, double ulimit, int calclimit); void readandcalcspline(FILE *infile, const char *inname, int d, double xstep, double llimit, double ulimit, int calclimit, int verbose, int *s); static struct option const long_options[] = { {"auto", optional_argument, 0, 'a'}, {"help", no_argument, 0, 'h'}, {"help", no_argument, 0, '?'}, {"llimit", required_argument, 0, 'l'}, {"ulimit", required_argument, 0, 'u'}, {"points", required_argument, 0, 'n'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"license", no_argument, 0, 'W'}, {"warranty", no_argument, 0, 'W'}, {0, 0, 0, 0 } }; int warranty(void) /* say that there is no warranty */ { printf("This program is free software; you can redistribute it and/or "\ "modify it\n"\ "under the terms of the GNU General Public License as published "\ "by the\n"\ "Free Software Foundation; either version 2 of the License, or "\ "(at your\n"\ "option) any later version.\n"\ "\n"\ "This program is distributed in the hope that it will be useful, "\ "but\n"\ "WITHOUT ANY WARRANTY; without even the implied warranty of "\ "MERCHANTABILITY\n"\ "or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public "\ "License\n"\ "for more details.\n"\ "\n"\ "You should have received a copy of the GNU General Public License "\ "along\n"\ "with this program; if not, write to the Free Software Foundation, "\ "Inc.,\n"\ "59 Temple Place Suite 330, Boston, MA 02111-1307 USA.\n"); exit(0); } int usage(void) /* print a short usage statement. */ { fprintf(stderr, "usage: %s [-hv][-a [xstep]][-l llimit][-u ulimit][-n points] "\ "{data-file(s)}\n\n",progname); fprintf(stderr, " -a, --auto supply abscissas automatically.\n"\ " -l, --llimit set lower x-limit.\n"\ " -u, --ulimit set upper x-limit.\n"\ " -n, --points space output points so that approx. "\ "n intervals\n"\ " occur between the lower and upper limit.\n"\ " -h, --help display this help and exit.\n"\ " -v, --verbose be verbose.\n"\ " -V, --version display version and copyright information and "\ "exit.\n"\ " -W, --warranty display licensing terms.\n"); exit(0); } void insertpoint(const char *inname, double xv, double yv, int *n) /* insert or drop the point if duplicate */ { int k; /* search the point */ k=0; while ((k < *n) && (xv > x[k])) k++; if (k == *n) { /* new point */ /* We malloc the first point explicitly, on some architectures an * malloc(NULL,...) != realloc(...) */ if (*n == 0) { x=xmalloc(sizeof(double)); y=xmalloc(sizeof(double)); } else { x=xrealloc(x, (*n+1)*sizeof(double)); y=xrealloc(y, (*n+1)*sizeof(double)); } x[*n]=xv; y[*n]=yv; (*n)++; } else if (fpclassify(xv - x[k]) == FP_ZERO) { /* duplicate */ fprintf(stderr, "%s:%s: duplicate abscissas found, sample (%g,%g), dropped.\n", progname, inname, xv,yv); } else { /* intermediate point. Insert it */ x=xrealloc(x, (*n+1)*sizeof(double)); y=xrealloc(y, (*n+1)*sizeof(double)); /* Move the points above */ memmove(&x[k+1],&x[k], (size_t)((*n-k)*sizeof(double))); memmove(&y[k+1],&y[k], (size_t)((*n-k)*sizeof(double))); x[k]=xv; y[k]=yv; (*n)++; } } void computelimits(int s, int e, double *llimit, double *ulimit) /* Compute minimum and maximum of the x-values */ { int i; *llimit=FLT_MAX; *ulimit=-FLT_MAX; for (i=s; i < e; i++) { if (x[i] < *llimit) *llimit=x[i]; if (x[i] > *ulimit) *ulimit=x[i]; } } void calcspline(int n, int d, double xstep, double llimit, double ulimit, int calclimit) /* Calculate the spline and output the result on stdout */ { if (n > 0) { /* we have data to process */ if (n == 1) { /* but only one point :( */ printf("%g %g\n", x[0], y[0]); } else if (n == 2) { /* wow, two points! */ double dx, dy, m; int i; dx=x[1]-x[0]; dy=y[1]-y[0]; /* 3rd step: output the coefficients for the subintervalls i=2..n-4 */ /* calculate the intermediate values */ if (calclimit) computelimits(0,n,&llimit, &ulimit); xstep=(ulimit-llimit)/d; m=dy/dx; /* dx != 0.0 asserted by insertpoint */ for (i=0; i <= d; i++) printf("%g %g\n", x[0]+i*xstep, y[0]+i*m*xstep); } else { /* now we have something to compute */ int i, p; /* n=no of points */ double *dx, *dy; /* x[i+1]-x[i], resp. y[i+1]-y[i] */ double *m, *t; /* the slopes */ double *C, *D; /* the coefficients */ /* Leading extrapolation points, actual values will be filled in later */ x=(double *)xrealloc(x, (n+4) * sizeof(double)); y=(double *)xrealloc(y, (n+4) * sizeof(double)); /* Move x[0] to x[2] */ memmove(&x[2],&x[0], (size_t)(n*sizeof(double))); memmove(&y[2],&y[0], (size_t)(n*sizeof(double))); n += 4; /* calculate coefficients of the spline (Akima interpolation itself) */ /* allocate the arrays * NB: There are some unused locations (dx[0]), * but this faciliates the indexing. */ dx=(double *)xmalloc(n * sizeof(double)); dy=(double *)xmalloc(n * sizeof(double)); m=(double *)xmalloc(n * sizeof(double)); t=(double *)xmalloc(n * sizeof(double)); /* a) Calculate the differences and the slopes m[i]. */ for (i=2; i < n-3; i++) { dx[i]=x[i+1] - x[i]; dy[i]=y[i+1] - y[i]; m[i] =dy[i]/dx[i]; /* dx != 0, asserted by insertpoint() */ } /* b) interpolate the missing points: */ x[1]=x[2] + x[3] - x[4]; dx[1]=x[2] - x[1]; y[1]=dx[1]*(m[3] - 2*m[2]) + y[2]; dy[1]=y[2] - y[1]; m[1]=dy[1]/dx[1]; x[0]=2*x[2] - x[4]; dx[0]=x[1] - x[0]; y[0]=dx[0]*(m[2] - 2*m[1]) + y[1]; dy[0]=y[1] - y[0]; m[0]=dy[0]/dx[0]; x[n-2]=x[n-3] + x[n-4] - x[n-5]; y[n-2]=(2*m[n-4] - m[n-5])*(x[n-2] - x[n-3l]) + y[n-3]; x[n-1]=2*x[n-3] - x[n-5]; y[n-1]=(2*m[n-3] - m[n-4])*(x[n-1] - x[n-2]) + y[n-2]; for (i=n-3; i < n-1; i++) { dx[i]=x[i+1] - x[i]; dy[i]=y[i+1] - y[i]; m[i]=dy[i]/dx[i]; } /* the first x slopes and the last y ones are extrapolated: */ t[0]=0.0; t[1]=0.0; /* not relevant */ for (i=2; i < n-2; i++) { double num, den; num=fabs(m[i+1] - m[i])*m[i-1] + fabs(m[i-1] - m[i-2])*m[i]; den=fabs(m[i+1] - m[i]) + fabs(m[i-1] - m[i-2]); if (fpclassify(den) != FP_ZERO) t[i]=num/den; else t[i]=0.0; } /* c) Allocate the polynom coefficients */ /* A=y_i B=t_i */ C=(double *)xmalloc(n * sizeof(double)); D=(double *)xmalloc(n * sizeof(double)); for (i=2; i < n-2; i++) { /* A[i]=y[i]; B[i]=t[i]; */ C[i]=(3*m[i] - 2*t[i] - t[i+1])/dx[i]; D[i]=(t[i] + t[i+1] - 2*m[i])/(dx[i]*dx[i]); } /* 3rd step: output the coefficients for the subintervalls i=2..n-4 */ /* calculate the intermediate values */ if (calclimit) computelimits(2,n-2,&llimit, &ulimit); xstep=(ulimit-llimit)/d; p=2; double xv; for(xv=llimit; xv= x[p]) { printf("%g %g\n", x[p], y[p]); p++; } /* skip the next interpolated point if it's too close to the current point */ if (((xv - x[p-1]) > xstep/100.0) && ((x[p] - xv) > xstep/100.0)) { double xd=(xv-x[p-1]); printf("%g %g\n", xv, y[p-1] + (t[p-1] + (C[p-1] + D[p-1]*xd)*xd)*xd); } } free(dx); free(dy); free(m); free(t); free(C); free(D); } } } void readandcalcspline(FILE *infile, const char *inname, int d, double xstep, double llimit, double ulimit, int calclimit, int verbose, int *s) /* s is the dataset number */ { int n, l; char *line; if (infile != stdin) { infile=fopen(inname, "r"); if (infile == NULL) { fprintf(stderr, "%s: can't open \"%s\": %s.\n", progname, inname, strerror(errno)); return; } } if (verbose) printf("# %s\n", inname); /* Read the points and build an array with the samples (using insertpoint()). */ n=0; l=0; x=NULL; y=NULL; line=NULL; do { char *il; if (line != NULL) free(line); line=gettextline(infile); il=line; l++; if (il != NULL) while (isspace(*il)) il++; if ((line == NULL) || (il[0] == '\0')) { if (n > 0) { if (*s > 0) printf("\n"); calcspline(n, d, xstep, llimit, ulimit, calclimit); (*s)++; free(x); free(y); x=y=NULL; n=0; } } else if (il[0] != '#') { int k; /* number of values */ double f1, f2; /* doubleing point numbers */ /* read point */ k=sscanf(line, "%lf %lf", &f1, &f2); if (k < 1) fprintf(stderr, "%s:%s:%d: parse error at '%s'\n", progname, inname, l, line); else if (k==1) insertpoint(inname, llimit+n*xstep,f1,&n); /* Auto xscale */ else insertpoint(inname,f1,f2,&n); } } while (line != NULL); if (infile != stdin) fclose(infile); } int main(int argc, char *argv[]) { int c; int i,d; double xstep, llimit, ulimit; /* x-spacing, lower limit, upper limit */ int calclimit, verbose; /* calculate limits, be verbose */ progname=strrchr(argv[0], '/'); if (progname == NULL) progname=argv[0]; else progname++; /* * These are mostly preliminary assignments, the actual values will * be calculated when evaluating the spline expression depending on */ verbose=0; calclimit=1; xstep=DXSTEP; llimit=ulimit=0.0; d=INTERVALLS; while ((c = getopt_long(argc, argv, "a:?hl:n:u:vVW", long_options, (int *)0)) != EOF) { switch (c) { case 0: break; case 'a': xstep=strtod(optarg, NULL); if (fpclassify(xstep) == FP_ZERO) xstep=DXSTEP; break; case 'l': llimit=strtod(optarg, NULL); calclimit=0; break; case 'h': case '?': usage(); break; case 'n': d=atoi(optarg); break; case 'u': ulimit=strtod(optarg, NULL); calclimit=0; break; case 'v': verbose++; break; case 'V': fprintf(stderr, "%s version %s\n" "Akima spline interpolation (c) 1996-1998 David Frey.\n" "This is free software; see the GNU General Public Licence version 2 or " "later\n" "for copying conditions.\n" "There is NO warranty. See %s --licence for details.\n", progname, VERSION, progname); return 0; break; case 'W': warranty(); break; default : break; } } if (ulimit < llimit) { double temp; temp=ulimit; ulimit=llimit; llimit=temp; } if (argc > optind) { int s; s=0; for (i=optind; i < argc; i++) { readandcalcspline(NULL, argv[i], d, xstep, llimit, ulimit, calclimit, verbose, &s); if ((s > 0) && (i < argc-1)) printf("\n"); s++; } } else { int s; s=0; readandcalcspline(stdin, "stdin", d, xstep, llimit, ulimit, calclimit, verbose, &s); } return 0; } spline/README0000600000175000017500000000036711351773671012201 0ustar daviddavidAkima spline interpolation aspline(1) interpolates an Akima-spline trough a series of given points. The Akima-spline interpolation approximates a manually drawn curve better than the ordinary splines, but the second derivation is not continuous. spline/utils.c0000600000175000017500000000416011351772523012613 0ustar daviddavid/************************************************************************ * utils.c -- various utilities * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * ************************************************************************/ #include #include #include #include #include "utils.h" #define LINEFRAGMENT 32 void *xmalloc(size_t size) /* safe malloc */ { void *ptr; ptr=malloc(size); if (ptr == NULL) { perror("xmalloc"); exit(1); } return ptr; } void *xrealloc(void *ptr, size_t size) { ptr=realloc(ptr, size); if (ptr == NULL) { perror("xrealloc"); exit(1); } return ptr; } char *gettextline(FILE *stream) /* Read a line of text without imposing an length limit */ /* From: Bison Manual */ { char *line; #ifdef HAVE_GETLINE line=NULL; size_t len=0; ssize_t nread; nread=getline(&line, &len, stream); if (nread > 0) { line[len-1]='\0'; /* remove leading \n */ } else if (nread == -1) { line=NULL; } #else int c; size_t i; line=xmalloc(LINEFRAGMENT+1); i=0; while (((c=fgetc(stream)) != EOF) && (c != '\n')) { if ((i > 0) && (i % LINEFRAGMENT) == 0) { line=xrealloc(line,i+LINEFRAGMENT+1); } line[i++]=(char)c; } line[i]='\0'; if (c == EOF) { free(line); line=NULL; } #endif return line; } spline/CREDITS0000600000175000017500000000020511353745431012323 0ustar daviddavidThe following people helped with code-snippets, ideas, discussions, testing and improvements: Henk Adam Dershowitz Stuart Prescott