racket/src/plot/plplot/pldtik.c
Matthew Flatt 514706446e overhaul plot organization
by moving needed C source to src/plot and building during `make',
 but stripping out the copies of gd, png, and zlib; instead, hook
 a dc<%>-based back end into plot
2010-11-06 16:54:29 -06:00

210 lines
6.2 KiB
C

/* $Id: pldtik.c,v 1.1 2004/03/01 20:54:51 cozmic Exp $
Determines tick spacing and mode (fixed or floating) of
numeric axis labels.
*/
#include "plplotP.h"
/*----------------------------------------------------------------------*\
* void pldtik()
*
* Determine tick spacing: works out a "nice" interval (if tick == 0) such
* that there are between 3 and 7.5 major tick intervals in the input
* range vmin to vmax. The recommended number of subticks is returned in
* "nsubt" unless the routine is entered with a non-zero value of "nsubt".
* n.b. big change: now returns only positive values of tick and nsubt
\*----------------------------------------------------------------------*/
void
pldtik(PLFLT vmin, PLFLT vmax, PLFLT *tick, PLINT *nsubt)
{
PLFLT t1, t2, tick_reasonable;
PLINT np, ns;
/* Magnitude of min/max difference to get tick spacing */
t1 = (PLFLT) log10(ABS(vmax - vmin));
np = (PLINT) floor(t1);
t1 = t1 - np;
/* Get tick spacing. */
if (t1 > 0.7781512503) {
t2 = 2.0;
ns = 4;
}
else if (t1 > 0.4771212549) {
t2 = 1.0;
ns = 5;
}
else if (t1 > 0.1760912591) {
t2 = 5.0;
ns = 5;
np = np - 1;
}
else {
t2 = 2.0;
ns = 4;
np = np - 1;
}
/* Now compute reasonable tick spacing */
tick_reasonable = t2 * pow(10.0, (double) np);
if (*tick == 0) {
*tick = t2 * pow(10.0, (double) np);
}
else {
*tick = ABS(*tick);
if(*tick < 1.e-4*tick_reasonable) {
plexit("pldtik: magnitude of specified tick spacing is much too small");
return;
}
}
if (*nsubt == 0)
*nsubt = ns;
*nsubt = ABS(*nsubt);
}
/*----------------------------------------------------------------------*\
* void pldprec()
*
* Determine precision: the output variable "mode" is set to 0 if labels
* are to be written in floating-point format, or to 1 if they are to be
* written in scientific format. For mode = 1, the exponent will be
* placed at:
*
* top left for vertical axis on left
* top right for vertical axis on right
* bottom right for horizontal axis
*
* The digmax flag can be set by the user, and represents the maximum
* number of digits a label may occupy including sign and decimal point.
* digmin, calculated internally, is the maximum number of digits
* labels at vmin and vmax would occupy if floating point.
* If digmax<0, it is disregarded,
* and if digmax=0 the default value is used. For digmax>0, mode=1 is
* chosen if there is insufficient room for the label within the specified
* # of digits (digmin > digfix, where digfix is determined from digmax with
* fuzz factors).
*
* In the case of mode=0, the actual # of digits will become too large
* when the magnitude of the labels become too large. The mode=1 case
* offers the greatest precision for the smallest field length.
*
* The determination of maximum length for fixed point quantities is
* complicated by the fact that very long fixed point representations look
* much worse than the same sized floating point representation. Further,
* a fixed point number with a large negative exponent will actually gain
* in precision when written as floating point. Thus we use certain fuzz
* factors to get 'digfix' from 'digmax', however it will always be true
* that digfix<=digmax.
*
* Finally, if 'digmax' is set, 'prec' is reduced in size if necessary so
* that the labels fit the requested field length, where prec is the number of
* places after the decimal place.
\*----------------------------------------------------------------------*/
#define MIN_FLTDIG 3 /* disregarded if fractional part is 0 */
#define MAX_FIXDIG_POS 6
#define MAX_FIXDIG_NEG 4
#define DIGMAX_DEF 5
void
pldprec(PLFLT vmin, PLFLT vmax, PLFLT tick, PLINT lf,
PLINT *mode, PLINT *prec, PLINT digmax, PLINT *scale)
{
PLFLT chosen, notchosen, vmod, t0;
PLINT msd, notmsd, np, digmin, digfix;
*mode = 0;
*scale = 0;
if (digmax == 0)
digmax = DIGMAX_DEF;
/* Choose vmin or vmax depending on magnitudes of vmin and vmax. */
chosen = (ABS(vmax) >= ABS(vmin))? vmax: vmin;
notchosen = (ABS(vmax) >= ABS(vmin))? vmin: vmax;
/* Magnitute of chosen to get number of significant digits */
if(ABS(chosen) > 0.) {
vmod = ABS(chosen);
t0 = (PLFLT) log10(vmod);
msd = (PLINT) floor(t0);
}
else {
/* this branch occurs only when 0. --- 0. range put in */
vmod = 1.;
t0 = (PLFLT) log10(vmod);
msd = (PLINT) floor(t0);
}
if(ABS(notchosen) > 0.)
notmsd = (PLINT) floor( (PLFLT) log10(ABS(notchosen)));
else
notmsd = msd;
/* Autoselect the mode flag */
/* 'digmin' is the minimum number of places taken up by the label */
if (msd >= 0) {
/* n.b. no decimal point in the minimal case */
digmin = msd + 1;
digfix = MAX_FIXDIG_POS;
if (digmax > 0)
digfix = MIN(digmax, MAX_FIXDIG_POS);
}
else {
/* adjust digmin to account for leading 0 and decimal point */
digmin = -msd + 2;
digfix = MAX_FIXDIG_NEG;
if (digmax > 0)
digfix = MIN(digmax, MAX_FIXDIG_NEG);
}
/* adjust digmin to account for sign on the chosen end of axis or sign on the
* nonchosen end of axis if notmsd = msd or (msd <= 0 and notmsd < 0)
* For the latter case the notchosen label starts with "-0."
* For checking for the latter case, the notmsd < 0 condition is redundant
* since notmsd <= msd always and the equal part is selected by the first
* condition.
*/
if(chosen < 0.||(notchosen < 0. && (notmsd == msd || msd <= 0)))
digmin = digmin + 1;
if (digmin > digfix && !lf) {
*mode = 1;
*scale = msd;
}
/* Establish precision. */
/* It must be fine enough to resolve the tick spacing */
np = (PLINT) floor(log10(ABS(tick)));
if (*mode != 0)
*prec = msd - np;
else
*prec = MAX(-np, 0);
/* One last hack required: if exponent < 0, i.e. number has leading '0.',
* it's better to change to floating point form if the number of digits
* is insufficient to represent the tick spacing.
*/
if (*mode == 0 && digmax > 0 && !lf) {
if (t0 < 0.0) {
if (digmax - 2 - *prec < 0) {
*mode = 1;
*scale = msd;
}
}
else
*prec = MAX(MIN(*prec, digmax - msd - 1), 0);
}
if (*mode != 0) {
*prec = msd - np;
*prec = MAX(MIN(*prec, MAX(digmax-1, MIN_FLTDIG)), 0);
}
}