/* The routines in this file are copyright (c) 1987 by Helene (Lee) Taran. * Permission is granted for use and free distribution as long as the * original author's name is included with the code. */ #include "spline.h" #define ALTSIGN(n,x) ((n) % 2 ? (x) : -(x)) #define VECTOR(n) ((REAL_POINT *)calloc((n),sizeof(REAL_POINT))) #define MATRIX(n) ((double *)calloc((n)*(n),sizeof(double))) double G[MAXG]; /* vector of g values */ void *calloc(); /* Init_GValues should be called once before drawing any curves. Computes * the first MAXG number of Gn values using iteration to save time and * stack space. */ Init_GValues() { int n; G[0] = 0.0; G[1] = 1.0; for (n = 2; n < MAXG; n++) G[n] = (4 * G[n-1] - G[n-2]); } Print_GValues() /* only for debugging */ { int i; for (i = 0; i < MAXG; i++) printf("G[%d] = %lf\n",i,G[i]); } /* Init_OpenSpline_Matrices : allocates an initializes the L and D matrices * that are used to create open splines. */ Init_OpenSpline_Matrices(n,L,D) int n; /* size of each of the square matrices */ double *L; /* lower triangular matrix used in LDL^t decomposition */ double *D; /* diagonal matrix used in LDL^t decomposition */ { int row,col; for (row = 0; row < n; row++) for (col = 0; col < n; col++) { if (row == col) { /* assign values to the diagonal elements */ AssignValue(n,L,row,col,1.0); AssignValue(n,D,row,col, G[row+2]/G[row+1]); } else if (row < col) { /* assign values to the upper triangular region */ AssignValue(n,L,row,col,0.0); AssignValue(n,D,row,col,0.0); } else { /* assign values to the lower triangular region */ AssignValue(n,D,row,col,0.0); if (col < row-1) AssignValue(n,L,row,col,0.0); else AssignValue(n,L,row,col,G[row]/G[row+1]); } } } AssignValue(n,matrix,row,col, value) int n; /* dimension of NxN matrix */ double *matrix; /* by matrix that will obtain the value */ int row,col; /* where */ double value; /* value being assigned */ { /* each row is sequence of consequtive columns; first loc = 0,0 */ *(matrix + n * row + col) = value; } double Value(n,matrix,row,col) int n; /* dimension of NxN matrix */ double *matrix; /* by matrix that will obtain the value */ int row,col; /* where */ { /* each row is a sequence of consequtive columns; first loc = 0,0 */ return(*(matrix + n * row + col)); } double TValue(n,matrix,row,col) /* return the transpose value */ int n; /* dimension of NxN matrix */ double *matrix; /* by matrix that will obtain the value */ int row,col; /* where */ { return(*(matrix + n * col + row)); } Init_ClosedSpline_Matrices(n,L,D) int n; /* size of each of the square matrices */ double *L; /* lower triangular matrix used in LDL^t decomposition */ double *D; /* diagonal matrix used in LDL^t decomposition */ { int row,col; for (row = 0; row < n; row++) for (col =0; col < n; col++) { if (row == col) { /* assign diagonal values */ AssignValue(n,L,row,col,1.0); if (row == n-1) AssignValue(n,D,row,col, (G[row+2] - G[row] - ALTSIGN(row,1) * 2)/G[row+1]); else AssignValue(n,D,row,col,G[row+2]/G[row+1]); } else if (row < col) { /* assign to upper triangular region */ AssignValue(n,L,row,col,0.0); AssignValue(n,D,row,col,0.0); } else { /* assign to the lower triangular region */ AssignValue(n,D,row,col,0.0); if (row < n-1) if (col == row-1) AssignValue(n,L,row,col,G[row]/G[row+1]); else AssignValue(n,L,row,col,0.0); else if (col < n-2) AssignValue(n,L,row,col,ALTSIGN(col,-1)/G[col+2]); else AssignValue(n,L,row,col,(G[row]+ALTSIGN(col,-1))/G[row+1]); } } } PrintMatrix(n,matrix) /* for debugging only */ int n; double *matrix; { int row, col; for (row = 0; row < n; row++) { for (col = 0; col < n; col++) printf("%lf ",Value(n,matrix,row,col)); printf("\n"); } } /* solves for x in the equation LDL^t * x = b and puts the result in */ Solve(n,L,D,b) int n; /* number of elements in and */ double *L; /* lower triangular matrix : assumed to be initialized */ double *D; /* diagonal matrix assumed to be initialized */ REAL_POINT b[]; /* vector of known point values & result destination */ { int row, col; for (row = 1; row < n; row++) /* forward substitution */ for (col = 0; col < row; col++) { b[row].x -= (Value(n,L,row,col) * b[col].x); b[row].y -= (Value(n,L,row,col) * b[col].y); } b[n-1].x /= Value(n,D,n-1,n-1); b[n-1].y /= Value(n,D,n-1,n-1); for (row = n-2; row >= 0; row--) { /* back substitution */ b[row].x /= Value(n,D,row,row); b[row].y /= Value(n,D,row,row); for (col = row +1; col < n; col++ ) { b[row].x -= (TValue(n,L,row,col) * b[col].x); b[row].y -= (TValue(n,L,row,col) * b[col].y); } } } PrintPoint(p) REAL_POINT *p; { printf("%lf, %lf\n", p->x, p->y); } PrintVector(n,v) int n; REAL_POINT v[]; { int i; for (i = 0; i < n; i++) PrintPoint(&v[i]); printf("\n"); } FillVector(n,v,list,xadj,yadj) int n; /* size of vectors <= length of list */ REAL_POINT v[]; /* vector to receive the x,y values in list */ DLISTPTR list; /* first element to get the values from */ float xadj, yadj; /* how to adjust the x,y values (1 if no adjustment) */ { DLISTPTR tmp = list; int i; if (n > 0) { for (i = 0; i < n; i++) { v[i].x = xadj * (POINT(tmp)->x) ; v[i].y = yadj * (POINT(tmp)->y) ; tmp = NEXT(tmp); } } } /* ListVector : takes a vector of points and makes it into a list * can be passed to the any of the bspline drawing routines. */ DLISTPTR ListVector(n,v) int n; /* n <= length of */ REAL_POINT v[]; { DLISTPTR list = (DLISTPTR)calloc(1,sizeof(DLIST_ELEMENT)); DLISTPTR element; int i; Init_List(list); for (i = 0; i < n; i++) { element = (DLISTPTR)calloc(1,sizeof(DLIST_ELEMENT)); element->contents = &(v[i]); INSERT_LAST(element,list); /* insert in same order */ } return(list); } Draw_Open_Ispline(w,control_points) struct Window *w; DLISTPTR control_points; { int n = LENGTH(control_points) -2; DLISTPTR newpoints; REAL_POINT *b = VECTOR(n); double *L = MATRIX(n); double *D = MATRIX(n); FillVector(n, b, NEXT(FIRST(control_points)), 6.0, 6.0); b[0].x -= POINT(FIRST(control_points))->x ; b[0].y -= POINT(FIRST(control_points))->y ; b[n-1].x -= POINT(LAST(control_points))->x ; b[n-1].y -= POINT(LAST(control_points))->y ; Init_OpenSpline_Matrices(n,L,D); Solve(n,L,D,b); newpoints = ListVector(n,b); MOVE_FIRST(control_points,newpoints); MOVE_LAST(control_points, newpoints); Draw_Natural_Bspline(w,newpoints); MOVE_FIRST(newpoints,control_points); MOVE_LAST(newpoints,control_points); ClearList(newpoints,FALSE); free(newpoints); free(L); free(D); free(b); } Draw_Closed_Ispline(w,control_points) struct Window *w; DLISTPTR control_points; { int n = LENGTH(control_points); DLISTPTR newpoints; REAL_POINT *b = VECTOR(n); double *L = MATRIX(n); double *D = MATRIX(n); FillVector(n, b, FIRST(control_points), 6.0, 6.0); Init_ClosedSpline_Matrices(n,L,D); Solve(n,L,D,b); newpoints = ListVector(n,b); Draw_Closed_Bspline(w,newpoints); ClearList(newpoints,FALSE); free(newpoints); free(L); free(D); free(b); }