home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Encyclopedia of Graphics File Formats Companion
/
GFF_CD.ISO
/
formats
/
ttddd
/
spec
/
t3d_doc
/
igensurf.zoo
/
src
/
calfunc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-10
|
17KB
|
717 lines
/* :ts=8 */
/* Copyright (c) 1986 Regents of the University of California */
#include <stdio.h>
#include <errno.h>
#include "calcomp.h"
#include "calc.h"
#define ALISTSIZ 6 /* maximum saved argument list */
typedef struct Activation_Tag {
char *Function_Name; /* function name */
struct Activation_Tag *Prev_Act; /* previous activation */
double *ArgTab; /* argument list */
unsigned long ArgFlags; /* computed argument flags */
Expression_T *Function; /* argument function */
} Activation_T; /* an activation record */
static Activation_T *Current_Act = NULL;
static double Func_Exec();
#define MAXLIB 64 /* maximum number of library functions */
static double l_if(), l_select(), l_rand();
static double l_floor(), l_ceil();
static double l_sqrt();
static double l_sin(), l_cos(), l_tan();
static double l_asin(), l_acos(), l_atan(), l_atan2();
static double l_exp(), l_log(), l_log10();
static double l_bezier(), l_bspline();
double l_noise3(), l_noise3a(), l_noise3b(), l_noise3c();
double l_hermite(), l_fnoise3();
/* functions must be listed alphabetically */
static Function_T LibFuncs[MAXLIB] = {
{ "acos", 1, ':', l_acos },
{ "asin", 1, ':', l_asin },
{ "atan", 1, ':', l_atan },
{ "atan2", 2, ':', l_atan2 },
{ "bezier", 5, ':', l_bezier },
{ "bspline", 5, ':', l_bspline },
{ "ceil", 1, ':', l_ceil },
{ "cos", 1, ':', l_cos },
{ "exp", 1, ':', l_exp },
{ "floor", 1, ':', l_floor },
{ "fnoise3", 3, ':', l_fnoise3 },
{ "hermite", 5, ':', l_hermite },
{ "if", 3, ':', l_if },
{ "log", 1, ':', l_log },
{ "log10", 1, ':', l_log10 },
{ "noise3", 3, ':', l_noise3 },
{ "noise3a", 3, ':', l_noise3a },
{ "noise3b", 3, ':', l_noise3b },
{ "noise3c", 3, ':', l_noise3c },
{ "rand", 1, ':', l_rand },
{ "select", 1, ':', l_select },
{ "sin", 1, ':', l_sin },
{ "sqrt", 1, ':', l_sqrt },
{ "tan", 1, ':', l_tan },
};
static int Nbr_LibFuncs = 24;
extern char *savestr(), *Emalloc();
extern Function_T *LibFunc_Lookup();
extern Variable_T *Get_Func_Arg();
#define Resolve(Expr) ( (Expr)->Node_Type == ET_Variable ? \
(Expr)->Value.Variable : Get_Func_Arg((Expr)->Value.Channel) )
int Func_Nbr_Args(Function_Name)
char *Function_Name;
/************************************************************************/
/* */
/* return # of arguments for function */
/* */
/************************************************************************/
{
Function_T *lp;
register Variable_T *vp;
if ((vp = Var_Lookup(Function_Name)) == NULL ||
vp->Expression == NULL ||
vp->Expression->Value.Kid->Node_Type != ET_Function) {
if ((lp = LibFunc_Lookup(Function_Name)) == NULL) return(0);
else return( (int) lp->Number_Args);
} else return(Nbr_Kids(vp->Expression->Value.Kid) - 1);
} /* Func_Nbr_Args */
double Func_Value(Function_Name, n, ArgTab)
char *Function_Name;
int n;
double *ArgTab;
/************************************************************************/
/* */
/* return a function value to the user */
/* */
/************************************************************************/
{
Activation_T Activation_Record;
register Variable_T *vp;
double rval;
/* push environment */
Activation_Record.Function_Name = Function_Name;
Activation_Record.Prev_Act = Current_Act;
Activation_Record.ArgTab = ArgTab;
Activation_Record.ArgFlags = (1L<<n)-1;
Activation_Record.Function = NULL;
Current_Act = &Activation_Record;
if ((vp = Var_Lookup(Function_Name)) == NULL ||
vp->Expression == NULL ||
vp->Expression->Value.Kid->Node_Type != ET_Function) {
rval = Func_Exec(Function_Name, vp);
} else {
rval = Expr_Value(vp->Expression->Value.Kid->Sibling);
}
Current_Act = Activation_Record.Prev_Act; /* pop environment */
return(rval);
} /* Func_Value */
void Func_Set(Function_Name, Number_Args, Assignment_Type, Func_Ptr)
char *Function_Name;
int Number_Args;
int Assignment_Type;
double (*Func_Ptr)();
/************************************************************************/
/* */
/* set a library function */
/* */
/************************************************************************/
{
register Function_T *Fp;
if ((Fp = LibFunc_Lookup(Function_Name)) == NULL) {
if (Nbr_LibFuncs >= MAXLIB) {
fprintf(stderr, "Too many library functions!\n");
exit(1);
}
for (Fp = &LibFuncs[Nbr_LibFuncs]; Fp > LibFuncs; Fp--)
if (strcmp(Fp[-1].Function_Name, Function_Name) > 0) {
Fp[0].Function_Name = Fp[-1].Function_Name;
Fp[0].Number_Args = Fp[-1].Number_Args;
Fp[0].Assignment_Type = Fp[-1].Assignment_Type;
Fp[0].Func_Ptr = Fp[-1].Func_Ptr;
} else break;
Nbr_LibFuncs++;
} /* if */
Fp[0].Function_Name = savestr(Function_Name);
Fp[0].Number_Args = Number_Args;
Fp[0].Assignment_Type = Assignment_Type;
Fp[0].Func_Ptr = Func_Ptr;
} /* Func_Set */
int Get_Nbr_Args()
/************************************************************************/
/* */
/* return number of available arguments */
/* */
/************************************************************************/
{
register int n;
if (Current_Act == NULL) return(0);
if (Current_Act->Function == NULL) {
for (n = 0; (1L<<n) & Current_Act->ArgFlags; n++) ;
return(n);
} /* if */
return(Nbr_Kids(Current_Act->Function) - 1);
} /* Get_Nbr_Args */
double Get_Argument(n)
register int n;
/************************************************************************/
/* */
/* return nth argument for active function */
/* */
/************************************************************************/
{
register Activation_T *actp = Current_Act;
Expression_T *Expr;
double aval;
if (actp == NULL || --n < 0) {
fprintf(stderr, "Bad call to Get_Argument!\n");
exit(1);
} /* if */
/* already computed? */
if (1L<<n & actp->ArgFlags) return(actp->ArgTab[n]);
if (actp->Function == NULL ||
(Expr = Expr_Kid(actp->Function, n+1)) == NULL) {
fprintf(stderr, "%s : too few arguments\n", actp->Function_Name);
exit(1);
} /* if */
Current_Act = actp->Prev_Act; /* pop environment */
aval = Expr_Value(Expr); /* compute argument */
Current_Act = actp; /* push back environment */
if (n < ALISTSIZ) { /* save value */
actp->ArgTab[n] = aval;
actp->ArgFlags |= 1L<<n;
}
return(aval);
} /* Get_Argument */
Variable_T *Get_Func_Arg(n)
int n;
/************************************************************************/
/* */
/* return function def for nth argument */
/* */
/************************************************************************/
{
register Activation_T *actp;
register Expression_T *Expr;
for (actp = Current_Act; actp != NULL; actp = actp->Prev_Act) {
if (n <= 0) break;
if (actp->Function == NULL) goto badarg;
if ((Expr = Expr_Kid(actp->Function, n)) == NULL) {
fprintf(stderr, "%s : too few arguments\n", actp->Function_Name);
exit(1);
} /* if */
if (Expr->Node_Type == ET_Variable) return(Expr->Value.Variable);
if (Expr->Node_Type != ET_Argument) goto badarg;
n = Expr->Value.Channel; /* try previous context */
} /* for */
fprintf(stderr, "Bad call to Get_Func_Arg!\n");
exit(1);
badarg:
fprintf(stderr, "%s : argument not a function\n", actp->Function_Name);
exit(1);
} /* Get_Func_Arg */
char *Get_Func_Arg_Name(n)
int n;
/************************************************************************/
/* */
/* return function name for nth argument */
/* */
/************************************************************************/
{
return(Get_Func_Arg(n)->Name);
} /* Get_Func_Arg_Name */
double EFunc_Function(Expr)
register Expression_T *Expr;
/************************************************************************/
/* */
/* evaluate a function */
/* */
/************************************************************************/
{
Activation_T act;
double alist[ALISTSIZ];
double rval;
register Variable_T *dp;
/* push environment */
dp = Resolve(Expr->Value.Kid);
act.Function_Name = dp->Name;
act.Prev_Act = Current_Act;
act.ArgTab = alist;
act.ArgFlags = 0;
act.Function = Expr;
Current_Act = &act;
if (dp->Expression == NULL ||
dp->Expression->Value.Kid->Node_Type != ET_Function) {
rval = Func_Exec(act.Function_Name, dp);
} else {
rval = Expr_Value(dp->Expression->Value.Kid->Sibling);
}
Current_Act = act.Prev_Act; /* pop environment */
return(rval);
} /* EFunc_Function */
Function_T *LibFunc_Lookup(Function_Name)
char *Function_Name;
/************************************************************************/
/* */
/* look up a library function */
/* */
/************************************************************************/
{
int upper, lower;
register int cm, i;
lower = 0;
upper = cm = Nbr_LibFuncs;
while ((i = (lower + upper) >> 1) != cm) {
cm = strcmp(Function_Name, LibFuncs[i].Function_Name);
if (cm > 0) lower = i;
else if (cm < 0) upper = i;
else return(&LibFuncs[i]);
cm = i;
} /* while */
return(NULL);
} /* LibFunc_Lookup */
static double Func_Exec(Function_Name, vp)
char *Function_Name;
register Variable_T *vp;
/************************************************************************/
/* */
/* execute library function */
/* */
/************************************************************************/
{
Variable_T dumdef;
double d;
int lasterrno;
if (vp == NULL) {
vp = &dumdef;
vp->Function = NULL;
} /* if */
if (
(
(vp->Function == NULL ||
strcmp(Function_Name, vp->Function->Function_Name)) &&
(vp->Function = LibFunc_Lookup(Function_Name)) == NULL
) || vp->Function->Func_Ptr == NULL
) {
fprintf(stderr, "%s : undefined function\n", Function_Name);
exit(1);
}
lasterrno = errno;
errno = 0;
d = (*vp->Function->Func_Ptr)();
#ifdef IEEE
if (!finite(d)) errno = EDOM;
#endif
if (errno) {
fprintf(stderr, "%s : bad call\n", Function_Name);
return(0.0);
}
errno = lasterrno;
return(d);
}
/*
* Library functions:
*/
static double l_if()
/************************************************************************/
/* */
/* if(cond, then, else) conditional expression */
/* cond evaluates true if greater than zero */
/* */
/************************************************************************/
{
if (Get_Argument(1) > 0.0) return(Get_Argument(2));
else return(Get_Argument(3));
} /* l_if */
static double l_select()
/************************************************************************/
/* */
/* return argument #(A1+1) */
/* */
/************************************************************************/
{
register int n;
n = Get_Argument(1) + .5;
if (n == 0) return( (double) (Get_Nbr_Args()-1) );
if (n < 1 || n > Get_Nbr_Args()-1) {
errno = EDOM;
return(0.0);
} /* if */
return(Get_Argument(n+1));
} /* l_select */
static double l_rand()
/************************************************************************/
/* */
/* random function between 0 and 1 */
/* */
/************************************************************************/
{
extern double floor();
double x;
x = Get_Argument(1);
x *= 1.0/(1.0 + x*x) + 2.71828182845904;
x += .785398163397447 - floor(x);
x = 1e5 / x;
return(x - floor(x));
} /* l_rand */
static double l_floor()
/************************************************************************/
/* */
/* return largest integer not greater than arg1 */
/* */
/************************************************************************/
{
extern double floor();
return(floor(Get_Argument(1)));
} /* l_floor */
static double l_ceil()
/************************************************************************/
/* */
/* return smallest integer not less than arg1 */
/* */
/************************************************************************/
{
extern double ceil();
return(ceil(Get_Argument(1)));
} /* l_ceil */
static double l_sqrt()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double sqrt();
return(sqrt(Get_Argument(1)));
} /* l_sqrt */
static double l_sin()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double sin();
return(sin(Get_Argument(1)));
} /* l_sin */
static double l_cos()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double cos();
return(cos(Get_Argument(1)));
} /* l_cos */
static double l_tan()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double tan();
return(tan(Get_Argument(1)));
} /* l_tan */
static double l_asin()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double asin();
return(asin(Get_Argument(1)));
} /* l_asin */
static double l_acos()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double acos();
return(acos(Get_Argument(1)));
} /* l_acos */
static double l_atan()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double atan();
return(atan(Get_Argument(1)));
} /* l_atan */
static double l_atan2()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double atan2();
return(atan2(Get_Argument(1), Get_Argument(2)));
} /* l_atan2 */
static double l_exp()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double exp();
return(exp(Get_Argument(1)));
} /* l_exp */
static double l_log()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double log();
return(log(Get_Argument(1)));
} /* l_log */
static double l_log10()
/************************************************************************/
/* */
/* */
/************************************************************************/
{
extern double log10();
return(log10(Get_Argument(1)));
} /* l_log10 */
static double l_bezier()
/************************************************************************/
/* */
/* The bezier function: */
/* */
/* b(P1, P2, P3, P4, t) = P1 * (1-t)^3 + */
/* P2 * 3 * t * (1-t)^2 + */
/* P3 * 3 * t^2 * (1-t) + */
/* P4 * t^3 */
/* */
/* Characteristics: */
/* */
/* b(0) = P0 db/dt(0) = 3(P2-P1) */
/* b(1) = P4 db/dt(1) = 3(P4-P3) */
/* */
/* ie. a bezier curve passes through P0 with a tangent in the direction */
/* of P1. It passes through P4 with a tangent from the direction of P3. */
/* */
/************************************************************************/
{
double t;
double Get_Argument();
t = Get_Argument(5);
return(Get_Argument(1) * (1.+t*(-3.+t*(3.-t))) +
Get_Argument(2) * 3.*t*(1.+t*(-2.+t)) +
Get_Argument(3) * 3.*t*t*(1.-t) +
Get_Argument(4) * t*t*t );
} /* l_bezier */
static double l_bspline()
/************************************************************************/
/* */
/* The bspline function. */
/* */
/************************************************************************/
{
double t;
double Get_Argument();
t = Get_Argument(5);
return(Get_Argument(1) * (1./6.+t*(-1./2.+t*(1./2.-1./6.*t))) +
Get_Argument(2) * (2./3.+t*t*(-1.+1./2.*t)) +
Get_Argument(3) * (1./6.+t*(1./2.+t*(1./2.-1./2.*t))) +
Get_Argument(4) * (1./6.*t*t*t) );
} /* l_bspline */