This is hutil.c in view mode; [Download] [Up]
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "hippo.h"
#include "hutil.h"
GLOB_QUAL const char hippoutil_c_rcsid[] = "$Id: hutil.c,v 5.0.2.1 1993/11/19 19:45:10 mfg Exp $";
#define FLT_EQUAL(x,y) ((float)fabs((x)-(y))<=2.0*((y)*FLT_EPSILON+FLT_MIN))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
/*
* Internal functions
*/
static float calcTicks(float size, float *magnitude);
/*
* Structures for the function registry.
*/
struct func_strt {
char name[FUNCNAMELEN+1];
void *func;
};
static struct func_strt f_list1[] = {
{ "h_cut_lt", (void *)h_cut_lt },
{ "h_cut_gt", (void *)h_cut_gt },
{ "h_cut_le", (void *)h_cut_le },
{ "h_cut_ge", (void *)h_cut_ge },
{ "h_cut_inside", (void *)h_cut_inside },
{ "h_cut_outside", (void *)h_cut_outside },
{ "h_cut_in_incl", (void *)h_cut_in_incl },
{ "h_cut_out_incl", (void *)h_cut_out_incl },
{ "", (void *)NULL } }; /* must terminate with NULL */
static struct func_strt *f_list2 = NULL;
static int func_list_l = 0;
/*
* Search for the function name, return its pointer.
* Return NULL if not found.
*/
void *h_fNameSrch(const char *fname)
{
int i = 0;
while( f_list1[i].func != NULL )
{
if (strncmp(f_list1[i].name,fname,FUNCNAMELEN) == 0)
return f_list1[i].func;
i++;
}
if (f_list2 != NULL)
{
i = 0;
while( f_list2[i].func != NULL )
{
if (strncmp(f_list2[i].name,fname,FUNCNAMELEN) == 0)
return f_list2[i].func;
i++;
}
}
return NULL;
}
/*
* Search for the function pointer, return its name if found.
*/
char *h_fPtrSrch(void *func)
{
int i = 0;
while( f_list1[i].func != NULL )
{
if (f_list1[i].func == func)
return f_list1[i].name;
i++;
}
if (f_list2 != NULL)
{
i = 0;
while( f_list2[i].func != NULL )
{
if (f_list2[i].func == func)
return f_list2[i].name;
i++;
}
}
return NULL;
}
/*
* Register the function on the registry.
*/
int h_func_reg(const char *fn, void *func)
{
int i=0;
char *sname;
void *sfunc;
if ((sname = h_fPtrSrch(func)) != NULL)
if (sname != fn)
{
h_error("h_funcReg: function name is in registry, but pointer does not match.");
return -1;
}
else
return 0;
if ((sfunc = h_fNameSrch(fn)) != NULL)
if (sfunc != func)
{
h_error("h_funcReg: function pointer is in registry, but name does not match.");
return -1;
}
else
return 0;
if (func_list_l == 0)
{
f_list2 = (struct func_strt *)
malloc( (size_t)5*sizeof(struct func_strt) );
if (f_list2 == NULL)
{
h_error("h_funcReg: Error allocating memory for function registry.");
return -1;
}
func_list_l = 5;
i = 0;
}
else
{
while( f_list2[i].func != NULL ) i++;
if (i==(func_list_l-1))
{
f_list2 = (struct func_strt *)
realloc( f_list2,
(size_t)(func_list_l+5)*sizeof(struct func_strt) );
if (f_list2 == NULL)
{
h_error("h_funcReg: Error reallocating memory for function registry");
return -1;
}
func_list_l += 5;
}
}
strncpy(f_list2[i].name,fn,FUNCNAMELEN);
f_list2[i].func = func;
strncpy(f_list2[i+1].name,"",FUNCNAMELEN);
f_list2[i+1].func = (void*)NULL;
return 0;
}
void h_adjustAxis( float *low, float *high, int nbins, int log )
{
int i;
int axis = 0;
float step, w, mag, range;
float mylow, myhigh;
#define N_NICE 6
#ifndef __STDC__
static
#endif
float nice[N_NICE] = { 1.0,2.0,2.5,4.0,5.0,7.5 };
if (*low >= *high)
{
if (*low < 0.0) *high = 0.0;
else if (*low > 0.0) *low = 0.0;
else
{
*low = -1.0;
*high = 1.0;
return;
}
}
if (nbins <= 0)
{
axis = 1;
nbins = 10;
}
/*
* Round the "bin width" to a nice number.
* If this is being done for an axis (ie nbins was 0), then
* we don't have to go > *high.
*/
w = (*high - *low)/((float)nbins);
mag = floor(log10(w));
i = 0;
do
{
step = nice[i] * pow(10.0,mag);
mylow = floor(*low/step) * step;
myhigh = mylow + step*nbins;
i++;
if (i>=N_NICE)
{
i = 0;
mag++;
}
}
while ( myhigh <= *high || FLT_EQUAL(*high,myhigh) );
range = myhigh - mylow;
if (axis && range < 1.1*(*high - *low)) range *= 1.1;
/*
* we now have decided on a range. Try to move low/high a little
* to end up on a nice number.
*
* first check if either end is near 0.0
*/
if (!log && *low >= 0.0 && range>(1.05* *high) )
{
*low = 0.0;
*high = range;
return;
}
if (*high<=0.0 && -range<(1.05* *low))
{
*high = 0.0;
*low = -range;
return;
}
/*
* try to round *low.
*/
i = N_NICE-1;
if (myhigh != 0.0)
mag = ceil(log10(fabs(myhigh)));
else
mag = ceil(log10(fabs(mylow)));
do
{
step = nice[i] * pow(10.0,mag);
mylow = floor(*low/step) * step;
myhigh = mylow + range;
i--;
if (i<0)
{
i = N_NICE-1;
mag--;
}
}
while ((log && mylow <= 0.0) || myhigh <= *high );
*low = mylow;
*high = myhigh;
}
#undef N_NICE
/*
* Hippo error message facility.
*/
void h_errmsg(const char *file, int line, const char *msg )
{
fprintf(stderr, "Error in hippo file %s, line %d :\n", file, line);
fprintf(stderr, " %s\n", msg );
}
/*
* Title expansion routine. Parse string for such things as
* %t, %x, %y, etc.
*/
char *h_expandLabel( char *dest, const char *src, int max, display disp )
{
int i,j=0;
int bind;
int l;
int k;
float del,del2;
char form[15];
l = strlen(src);
if (disp->tuple == NULL)
{
strncpy( dest, src, max );
return dest;
}
for (i=0; i<l && j<max; i++)
{
if (src[i] == '%')
{
i++;
switch (src[i])
{
case '%':
dest[j++] = '%';
break;
case 't': case 'T':
if (disp->tuple->title != NULL)
{
strncpy(&(dest[j]),disp->tuple->title,max-j-1);
j = strlen(dest);
}
break;
case 'x': case 'X':
if ((bind = disp->binding.x) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],max-j-1);
j = strlen(dest);
}
break;
case 'y': case 'Y':
if ((bind = disp->binding.y) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],max-j-1);
j = strlen(dest);
}
break;
case 'z': case 'Z':
if ((bind = disp->binding.z) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],max-j-1);
j = strlen(dest);
}
break;
case 'w': case 'W':
if ((bind = disp->binding.weight) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],max-j-1);
j = strlen(dest);
}
break;
case 'd': case 'D':
i++;
switch (src[i])
{
case 'x': case 'X':
/* The following code was neccessitated by a bug in 'g' format on the NeXT */
del = (disp->xAxis.high-disp->xAxis.low)
/(float)disp->bins.xAxis.nBins;
for (k=1; k<6; k++)
{
del2 = del*pow(10.0,(double)k);
if (del2 == 0.0) break;
if (fabs(((int)del2 - del2)/del2) < 2e-2) break;
}
sprintf(form,"%%1.%df",k);
sprintf(&dest[j],form,del);
j = strlen(dest);
break;
case 'y': case 'Y':
del = (disp->yAxis.high-disp->yAxis.low)
/(float)disp->bins.yAxis.nBins;
for (k=0; k<6; k++)
{
del2 = del*pow(10.0,(double)k);
if (del2 == 0.0) break;
if (fabs(((int)del2 - del2)/del2) < 2e-2) break;
}
sprintf(form,"%%1.%df",k);
sprintf(&dest[j],form,del);
j = strlen(dest);
break;
}
break;
case 'e': case 'E':
i++;
switch (src[i])
{
case 'x': case 'X':
if ((bind = disp->binding.xerror) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],
max-j-1);
j = strlen(dest);
}
break;
case 'y': case 'Y':
if ((bind = disp->binding.yerror) >= 0)
{
strncpy(&(dest[j]),disp->tuple->label[bind],
max-j-1);
j = strlen(dest);
}
break;
}
break;
}
}
else
dest[j++] = src[i];
}
if (j<max)
dest[j] = '\0';
else
dest[max-1] = '\0';
return dest;
}
/*
* Standard Cut functions.
*/
int h_cut_lt( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0] ][row] < param[1])
return 1;
else
return 0;
}
int h_cut_gt( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] > param[1] )
return 1;
else
return 0;
}
int h_cut_le( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] <= param[1] )
return 1;
else
return 0;
}
int h_cut_ge( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] >= param[1] )
return 1;
else
return 0;
}
int h_cut_inside( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] > param[1] &&
ntdata[(int) param[0]][row] < param[2])
return 1;
else
return 0;
}
int h_cut_outside( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] < param[1] ||
ntdata[(int) param[0]][row] > param[2])
return 1;
else
return 0;
}
int h_cut_in_incl( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] >= param[1] &&
ntdata[(int) param[0]][row] <= param[2])
return 1;
else
return 0;
}
int h_cut_out_incl( float **ntdata, int row, double param[] )
{
if (ntdata[(int) param[0]][row] <= param[1] ||
ntdata[(int) param[0]][row] >= param[2])
return 1;
else
return 0;
}
int doCuts( float **ntdata, int row, func_id cutlist )
{
typedef int (*cutfunc)(float **, int, double *);
func_id c = cutlist;
int result = 0;
while (c != NULL)
{
result += (*((cutfunc)c->funcPtr))(ntdata, row,
(double *)c->paramBlk );
c = c->next;
}
return result;
}
int genTicks(axis_t *thisaxis, int maxticks, int *nticks,
float *ticks, char labels[][10], float *pmag)
{
int i;
float magnitude,y=0.0,yr,startTick,tickSize;
char string[70];
char pstr[10];
int nLogTicks;
float logTicks[5];
float maglow, maghigh, magrng, magStep;
*nticks = 0;
if (thisaxis->low >= thisaxis->high)
{
h_error("h_plot: axis low > high");
sprintf(string,"low = %f, high = %f\n",thisaxis->low,
thisaxis->high);
h_error(string);
return -1;
}
if (!thisaxis->flags.log)
{
tickSize = calcTicks((thisaxis->high -
thisaxis->low), &magnitude);
startTick = ceil( thisaxis->low / tickSize) * tickSize;
if (fabs(magnitude) <= 3.0)
*pmag = 0.0;
else
{
if (startTick != 0.0)
*pmag = floor(log10(fabs(startTick)));
else
*pmag = magnitude;
}
sprintf(pstr,"%%1.%df",(int)MAX((*pmag-magnitude),0.0));
y = startTick;
while (y <= thisaxis->high || FLT_EQUAL(thisaxis->high,y))
{
if (*nticks >= maxticks)
{
h_error("Too many ticks along y axis.");
return -1;
}
yr = floor(y/pow(10.0,magnitude) + 0.5);
ticks[*nticks] = yr * pow(10.0,magnitude);
sprintf(labels[*nticks],pstr,yr*pow(10.0,magnitude-*pmag));
(*nticks)++;
y += tickSize;
}
if (fabs(magnitude) <= 3.0) magnitude = 0.0;
}
else
{
maghigh = ceil(log10(thisaxis->high)*(1.0-2.0*FLT_EPSILON));
maglow = floor(log10(thisaxis->low)*(1.0+2.0*FLT_EPSILON));
magrng = log10(thisaxis->high/thisaxis->low);
if (magrng <4.0)
{
nLogTicks = 3;
logTicks[0] = 1.0;
logTicks[1] = 2.0;
logTicks[2] = 5.0;
magStep = 1.0;
}
else if (magrng < 7.0)
{
nLogTicks = 2;
logTicks[0] = 1.0;
logTicks[1] = 2.0;
magStep = 1.0;
}
else
{
nLogTicks = 1;
logTicks[0] = 1.0;
magStep = 2.0;
}
if (nLogTicks > 1 && (fabs(maglow)>3 || fabs(maghigh)>3))
*pmag = maglow;
else
*pmag = 0.0;
magnitude = maglow;
i = 0;
while ((y=logTicks[i]*pow(10.0,magnitude)) <= thisaxis->high
|| FLT_EQUAL(thisaxis->high,y))
{
if (*nticks >= maxticks)
{
h_error("Too many ticks along y axis.");
return -1;
}
if (y >= thisaxis->low)
{
ticks[*nticks] = log10(y);
/*
* be careful: there is a bug in the NeXT (s)printf
* routine when you do, eg. printf("%1.0g",0.01);
*/
if ((magnitude-*pmag) > 4 || (magnitude-*pmag) < -3)
strcpy(pstr,"%1.0e");
else
sprintf(pstr,"%%1.%df",
(int)((magnitude-*pmag)>0?
0:-(magnitude-*pmag)));
sprintf(labels[*nticks],pstr,y*pow(10.0,-*pmag));
(*nticks)++;
}
i++;
if (i>=nLogTicks)
{
i = 0;
magnitude += magStep;
}
}
}
return 0;
}
#define MIN_TICKS 4
static float calcTicks(float size, float *magnitude)
{
static float goodTicks[] = {10.0, 5.0, 4.0, 2.0, 1.0};
float tickSize;
int tickIndex;
if (size <= 0.0)
{
h_error("calcTicks: size is <= 0");
size = fabs(size);
if (size == 0.0) size = 1.0;
}
*magnitude = floor(log10(size));
if (size/pow(10.0,*magnitude) < MIN_TICKS) (*magnitude)--;
/*
* now fit the max number of ticks into this range
*/
for (tickIndex = 0;
size / (tickSize=goodTicks[tickIndex]*pow(10.0,*magnitude) )
< MIN_TICKS;
tickIndex++);
if (tickIndex == 0)
(*magnitude)++;
return tickSize;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.