This is auxil.m in view mode; [Download] [Up]
/*
* Auxiliary routines, all taken from xyplot (translated from Fortran to C).
*/
#include "defs.h"
#include <strings.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h> /* for exit() */
#include <appkit/Panel.h> /* for NXRunAlertPanel */
/*
* Count the number of labels on a given axis.
*/
void
count_labels(int *pn, double *pfirst, double min, double inc, double max)
{
int bottom, top, j;
double range, absinc, tol, guess;
if (inc != 0.0) {
*pn = 0;
bottom = (int)(min/inc) - 1;
top = (int)(max/inc) + 1;
range = ABS(max - min);
absinc = MIN(range, ABS(inc));
tol = absinc * (range + absinc) / 100.0;
for (j=top; j>=bottom; j--) {
guess = (double)j * inc;
if ( (max-guess)*(guess-min) >= -tol) {
*pn += 1;
*pfirst = guess;
}
}
}
else {
*pn = 0;
*pfirst = 0.0;
}
return;
}
/*
* Write a float into a string and see how many characters are to the left
* of the decimal point, how many total decimal characters there are, and
* how many characters there are in the exponent (if exponential notation).
*/
void
numstring(double x, int *nl, int *nd, int *ne)
{
char string[80];
double ax;
int i, nc, net;
ax = ABS(x);
i = ax;
if ((double)i==ax && ax<99999.0) {
sprintf(string, "%1d", (int)x);
}
else {
if (ax>=1.e-4 && ax<1.e5) {
if ( ((int)(x*10000.0) % 10000) == 0 )
sprintf(string, "%-6.0f", x); /* left-justify */
else if ( ((int)(x*10000.0) % 1000) == 0 )
sprintf(string, "%-7.1f", x);
else if ( ((int)(x*10000.0) % 100) == 0 )
sprintf(string, "%-8.2f", x);
else if ( ((int)(x*10000.0) % 10) == 0 )
sprintf(string, "%-9.3f", x);
else
/* sprintf(string, "%-10.4f", x); this can fail -- e.g., x=0.000718 */
sprintf(string, "%10.6f", x); /* will this always work? */
}
else {
sprintf(string, "%-#11.2e", x);
}
}
nc = strlen(string);
/* strip off blanks from the end of the string: */
while (string[nc-1] == ' ') {
string[--nc] = '\0';
}
nc = strlen(string);
/* nl = no. of characters left of the decimal point (including sign) */
*nl = 0;
for (i=nc-1; i>=0; i--) {
*nl += 1;
if (string[i] == '.') *nl = 0;
}
/* nd = no. of decimal characters (including decimal point, omitting
* trailing zeros)
*/
*nd = 0;
for (i=nc-1; i>=*nl; i--) {
*nd += 1;
if (string[i] == 'e' || string[i] == 'E') *nd = 0;
if (string[i] == '0' && *nd == 1) *nd = 0;
}
/* ne = no. of exponent characters (including the 'E' if any) */
*ne = 0;
for (i=*nl + *nd; i<nc; i++) {
if (string[i] == 'e' || string[i] == 'E') *ne = nc - i;
}
net = 0;
for (i = nc-1; i >= nc - *ne + 2; i--) {
if (string[i] != '0') net = 2 + nc - i;
}
*ne = net;
/* Some special cases where floating point numbers may be
* expressed as integers.
*/
if (*nd==1 && *ne==0) *nd = 1;
return;
}
/*
* See what the formatting would be if we go from min to max in
* steps of inc.
*/
void
autoformat(double min, double inc, double max, int *axformat)
{
int nlabels, i, nl, nd, ne;
double first, value;
*axformat = 0;
*(axformat + 1) = 0;
*(axformat + 2) = 0;
count_labels(&nlabels, &first, min, inc, max);
for (i=0; i<nlabels; i++) {
/* Special test here for what should be exact 0 (but isn't sometimes
* due to floating-point arithmetic.
*/
if (inc != 0.0 && fabs(first/inc + (double)i) < 1.0e-14) { /* ugly */
value = 0.0;
}
else {
value = first + inc*(double)i;
}
numstring(value, &nl, &nd, &ne);
if (*(axformat+2)==0 && ne!=0) {
*axformat = nl;
*(axformat+1) = nd;
*(axformat+2) = ne;
}
else {
*axformat = MAX(nl, *axformat);
*(axformat+1) = MAX(nd, *(axformat+1));
*(axformat+2) = MAX(ne, *(axformat+2));
}
}
return;
}
/*
* Put a float into a string with a specified format.
*/
void
handformat(float number, char *string, int *axformat)
{
int nl, nd, ne;
nl = *(axformat+0);
nd = *(axformat+1);
ne = *(axformat+2);
// if all axformat[i] are 0, return just a blank:
if (ne==0 && nd==0 && nl==0) {
sprintf(string, " ");
return;
}
// special case 0:
if (number == 0.0) {
sprintf(string, "%1d", 0);
return;
}
if (ne==0) {
if (nd==0) {
sprintf(string, "%*d", nl, (int)rint((double)number));
}
else
sprintf(string, "%*.*f", nl, nd-1, number);
}
else {
if (nd==0)
sprintf(string, "%*.*e", nl, nd, number);
else
sprintf(string, "%*.*e", ne+1, nd-1, number);
}
return;
}
/*
* Compute nice increment for linear plotting, given min and max.
*/
void
computeNiceLinInc(float *pmin, float *pmax, float *pinc)
{
float fmin = *pmin, fmax = *pmax, finc = (fmax - fmin)/5.0, x;
int n;
if (finc <= 0.0) {
fmin = (fmin>0.0? 0.9*fmin : 1.1*fmin);
fmax = (fmax>0.0? 1.1*fmax : 0.9*fmax);
finc = (fmax - fmin)/5.0;
// for safety:
if (finc < 0.0) {
n = NXRunAlertPanel("computeNiceLinInc",
"Impossible increment = %g.\n"
"I'm very confused "
"(Perhaps all data is being ignored -- no lines, no symbols)",
"Quit", "Continue", NULL, finc);
if (n==NX_ALERTDEFAULT)
exit(0);
else if (n==NX_ALERTALTERNATE) {
*pmin = 0.0;
*pmax = 1.0;
*pinc = 0.2;
return;
}
}
}
n = ( log10((double)finc) >= 0.0 ? (int)floor(log10((double)finc)) :
(int)ceil(log10((double)finc)) );
if (finc > 1.0) n++;
x = finc * (float)pow((double)10.0, (double)(-n));
finc = 0.1;
if (x > 0.1) finc = 0.2;
if (x > 0.2) finc = 0.25;
if (x > 0.25) finc = 0.5;
if (x > 0.5) finc = 1.0;
finc = finc * (float)pow((double)10.0, (double)n);
if (fmin < ((int)(fmin/finc))*finc) fmin = ((int)(fmin/finc - 1))*finc;
else fmin = ((int)(fmin/finc))*finc;
if (fmax > ((int)(fmax/finc))*finc) fmax = ((int)(fmax/finc + 1))*finc;
else fmax = ((int)(fmax/finc))*finc;
*pmin = fmin;
*pmax = fmax;
*pinc = finc;
return;
}
/*
* Compute a nice min and max for logarithmic plotting (we take increment=1).
*/
void
computeNiceLogInc(float *pmin, float *pmax, float *pinc)
{
float fmin, fmax, finc;
int n;
// for safety:
if (*pmin <= 0.0 || *pmax <= 0.0) {
n = NXRunAlertPanel("computeNiceLogInc",
"Impossible min/max = %g, %g.\n"
"I'm very confused "
"(Perhaps all data is being ignored -- no lines, no symbols)",
"Quit", "Continue", NULL, *pmin, *pmax);
if (n==NX_ALERTDEFAULT)
exit(0);
else if (n==NX_ALERTALTERNATE) {
*pmin = 1.0;
*pmax = 10.0;
*pinc = 1.0;
return;
}
}
fmin = (float)log10(*pmin);
fmax = (float)log10(*pmax);
finc = 1.0;
fmin = (float) floor((double)fmin);
fmax = (float) ceil((double)fmax);
if (fmin == fmax) {
fmin = fmin - 1.0;
fmax = fmax + 1.0;
}
*pmin = (float)pow((double)10.0, (double)fmin);
*pmax = (float)pow((double)10.0, (double)fmax);
*pinc = (float)pow((double)10.0, (double)finc);
return;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.