Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/spline/spline.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* spline.c - curve smoothing ported from edition 7 source */
#include <u.h>
#include <libc.h>
#include <bio.h>

#define NP 1000		/* max #  of points read */
#define INF 1.e37	/* default upper and lower limits */

struct proj { 
	int	lbf, ubf; 
	float	a, b, lb, ub, quant, mult, val[NP]; 
} x, y;

Biobuf	bout;
float	*diag, *r;
float	dx = 1.0;
float	ni = 100.0;
int	n;
int	auta;
int	periodic;
float	konst = 0.0;
float	zero = 0.0;

float rhs(int);
int spline(void);
void readin(Biobuf *bp);
void getlim(struct proj *);
void usage(void);

float
rhs(int i)
{
	int	i_;
	double	zz;
	i_ = i == n - 1 ? 0 : i;
	zz = (y.val[i] - y.val[i-1]) / (x.val[i] - x.val[i-1]);
	return(6 * ((y.val[i_+1] - y.val[i_]) / (x.val[i+1] - x.val[i]) - zz));
}


int
spline(void)
{
	float	d, s, u, v, hi, hi1;
	float	h;
	float	D2yi, D2yi1, D2yn1, x0, x1, yy, a;
	int	end;
	float	corr;
	int	i, j, m;
	if (n < 3) 
		return(0);
	if (periodic) 
		konst = 0;
	d = 1;
	r[0] = 0;
	s = periodic ? -1 : 0;
	for (i = 0; ++i < n - !periodic; ) {	/* triangularize */
		hi = x.val[i] - x.val[i-1];
		hi1 = i == n - 1 ? x.val[1] - x.val[0] : 
		    x.val[i+1] - x.val[i];
		if (hi1 * hi <= 0) 
			return(0);
		u = i == 1 ? zero : u - s * s / d;
		v = i == 1 ? zero : v - s * r[i-1] / d;
		r[i] = rhs(i) - hi * r[i-1] / d;
		s = -hi * s / d;
		a = 2 * (hi + hi1);
		if (i == 1) 
			a += konst * hi;
		if (i == n - 2) 
			a += konst * hi1;
		diag[i] = d = i == 1 ? a : 
		    a - hi * hi / d;
	}
	D2yi = D2yn1 = 0;
	for (i = n - !periodic; --i >= 0; ) {	/* back substitute */
		end = i == n - 1;
		hi1 = end ? x.val[1] - x.val[0] : 
		    x.val[i+1] - x.val[i];
		D2yi1 = D2yi;
		if (i > 0) {
			hi = x.val[i] - x.val[i-1];
			corr = end ? 2 * s + u : zero;
			D2yi = (r[i] - hi1 * D2yi1 - s * D2yn1 + end * v) / 
			    (diag[i] + corr);
			if (end) 
				D2yn1 = D2yi;
			if (i > 1) {
				a = 2 * (hi + hi1);
				if (i == 1) 
					a += konst * hi;
				if (i == n - 2) 
					a += konst * hi1;
				d = diag[i-1];
				s = -s * d / hi;
			}
		} else 
			D2yi = D2yn1;

		if (!periodic) {
			if (i == 0) 
				D2yi = konst * D2yi1;
			if (i == n - 2) 
				D2yi1 = konst * D2yi;
		}
		if (end) 
			continue;
		m = (hi1 > 0) ? ni : -ni;
		m = 1.001 * m * hi1 / (x.ub - x.lb);
		if (m <= 0) 
			m = 1;
		h = hi1 / m;
		for (j = m; j > 0 || i == 0 && j == 0; j--) {	/* interpolate */
			x0 = (m - j) * h / hi1;
			x1 = j * h / hi1;
			yy = D2yi * (x0 - x0 * x0 * x0) + D2yi1 * (x1 - x1 * x1 * x1);
			yy = y.val[i] * x0 + y.val[i+1] * x1 - hi1 * hi1 * yy / 6;
			Bprint(&bout, "%f ", x.val[i] + j * h);
			Bprint(&bout, "%f\n", yy);
		}
	}
	return(1);
}


void
readin(Biobuf *bp) 
{
	int num;
	char *p, *a[4];

	for (n = 0; n < NP && (p = Brdline(bp, '\n')) != nil; n++){
		p[Blinelen(bp)-1] = 0;
		if ((num = tokenize(p, a, nelem(a))) == 0)
			continue;
		if (num == 1 || auta){
			x.val[n] = n * dx * x.lb;
			y.val[n] = atof(a[0]);
		}
		if(num >= 2){
			x.val[n] = atof(a[0]);
			y.val[n] = atof(a[1]);
		}
	}
}


void
getlim(struct proj *p)
{
	int	i;
	for (i = 0; i < n; i++) {
		if (!p->lbf && p->lb > (p->val[i])) 
			p->lb = p->val[i];
		if (!p->ubf && p->ub < (p->val[i])) 
			p->ub = p->val[i]; 
	}
}


void
main(int argc, char *argv[])
{
	int i;
	char *p;
	Biobuf *bp, bin;

	x.lbf = x.ubf = y.lbf = y.ubf = 0;
	x.lb = INF;
	x.ub = -INF;
	y.lb = INF;
	y.ub = -INF;

	Binit(&bin, 0, OREAD);
	Binit(&bout, 1, OWRITE);

	ARGBEGIN{
		case 'a': 
			auta = 1;
			dx = 1;
			if ((p = ARGF()) != nil)
				dx = atof(p);
			break;
		case 'k': 
			konst = atof(EARGF(usage()));
			break;
		case 'n': 
			ni = atof(EARGF(usage()));
			break;
		case 'p':
			periodic = 1;
			break;
		case 'x':
			x.lbf = atof(EARGF(usage()));
			if ((p = ARGF()) != nil)
				x.ubf = atof(p);
			break;
	}ARGEND;
	if (auta && !x.lbf) 
		x.lb = 1;

	if (argc == 0)
		readin(&bin);
	else
		for(; argc--; argv++){
			if ((bp = Bopen(*argv, OREAD)) == nil){
				fprint(2, "%s: %s cannot open, %r", argv0, *argv);
				continue;
			}
			readin(bp);
			Bterm(bp);
		}

	getlim(&x);
	getlim(&y);

	if ((diag = malloc((n+1) * sizeof(dx))) == nil)
		sysfatal("no memory");
	if ((r = malloc((n+1) * sizeof(dx))) == nil)
		sysfatal("no memory");

	if (spline() == 0) 
		for (i = 0; i < n; i++) {
			Bprint(&bout, "%f ", x.val[i]);
			Bprint(&bout, "%f\n", y.val[i]); 
		}
	Bflush(&bout);
	Bterm(&bout);
	exits(0);
}

void
usage(void)
{
	fprint(2, "usage: %s [-a n] [-k n] [-n n] [-p] [-x lo [hi]]\n", argv0);
	exits("usage");
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].