Back to index

plt-scheme  4.2.1
pldtik.c
Go to the documentation of this file.
00001 /* $Id: pldtik.c,v 1.1 2004/03/01 20:54:51 cozmic Exp $
00002 
00003        Determines tick spacing and mode (fixed or floating) of
00004        numeric axis labels.
00005 */
00006 
00007 #include "plplotP.h"
00008 
00009 /*----------------------------------------------------------------------*\
00010  * void pldtik()
00011  *
00012  * Determine tick spacing: works out a "nice" interval (if tick == 0) such
00013  * that there are between 3 and 7.5 major tick intervals in the input
00014  * range vmin to vmax.  The recommended number of subticks is returned in
00015  * "nsubt" unless the routine is entered with a non-zero value of "nsubt".
00016  * n.b. big change: now returns only positive values of tick and nsubt
00017 \*----------------------------------------------------------------------*/
00018 
00019 void
00020 pldtik(PLFLT vmin, PLFLT vmax, PLFLT *tick, PLINT *nsubt)
00021 {
00022     PLFLT t1, t2, tick_reasonable;
00023     PLINT np, ns;
00024 
00025 /* Magnitude of min/max difference to get tick spacing */
00026 
00027     t1 = (PLFLT) log10(ABS(vmax - vmin));
00028     np = (PLINT) floor(t1);
00029     t1 = t1 - np;
00030 
00031 /* Get tick spacing. */
00032 
00033     if (t1 > 0.7781512503) {
00034        t2 = 2.0;
00035        ns = 4;
00036     }
00037     else if (t1 > 0.4771212549) {
00038        t2 = 1.0;
00039        ns = 5;
00040     }
00041     else if (t1 > 0.1760912591) {
00042        t2 = 5.0;
00043        ns = 5;
00044        np = np - 1;
00045     }
00046     else {
00047        t2 = 2.0;
00048        ns = 4;
00049        np = np - 1;
00050     }
00051 
00052 /* Now compute reasonable tick spacing */
00053 
00054     tick_reasonable = t2 * pow(10.0, (double) np);
00055     if (*tick == 0) {
00056        *tick = t2 * pow(10.0, (double) np);
00057     }
00058     else {
00059         *tick = ABS(*tick);
00060         if(*tick < 1.e-4*tick_reasonable) {
00061           plexit("pldtik: magnitude of specified tick spacing is much too small");
00062           return;
00063        }
00064     }
00065     if (*nsubt == 0)
00066        *nsubt = ns;
00067 
00068     *nsubt = ABS(*nsubt);
00069 }
00070 
00071 /*----------------------------------------------------------------------*\
00072  * void pldprec()
00073  *
00074  * Determine precision: the output variable "mode" is set to 0 if labels
00075  * are to be written in floating-point format, or to 1 if they are to be
00076  * written in scientific format.  For mode = 1, the exponent will be
00077  * placed at:
00078  *
00079  *     top left      for vertical axis on left
00080  *     top right     for vertical axis on right
00081  *     bottom right  for horizontal axis
00082  *
00083  * The digmax flag can be set by the user, and represents the maximum
00084  * number of digits a label may occupy including sign and decimal point.
00085  * digmin, calculated internally, is the maximum number of digits
00086  * labels at vmin and vmax would occupy if floating point.
00087  * If digmax<0, it is disregarded,
00088  * and if digmax=0 the default value is used.  For digmax>0, mode=1 is
00089  * chosen if there is insufficient room for the label within the specified
00090  * # of digits (digmin > digfix, where digfix is determined from digmax with
00091  * fuzz factors).
00092  *
00093  * In the case of mode=0, the actual # of digits will become too large
00094  * when the magnitude of the labels become too large.  The mode=1 case
00095  * offers the greatest precision for the smallest field length.
00096  *
00097  * The determination of maximum length for fixed point quantities is
00098  * complicated by the fact that very long fixed point representations look
00099  * much worse than the same sized floating point representation.  Further,
00100  * a fixed point number with a large negative exponent will actually gain
00101  * in precision when written as floating point.  Thus we use certain fuzz
00102  * factors to get 'digfix' from 'digmax', however it will always be true
00103  * that digfix<=digmax.
00104  *
00105  * Finally, if 'digmax' is set, 'prec' is reduced in size if necessary so
00106  * that the labels fit the requested field length, where prec is the number of 
00107  * places after the decimal place.
00108 \*----------------------------------------------------------------------*/
00109 
00110 #define MIN_FLTDIG   3      /* disregarded if fractional part is 0 */
00111 #define MAX_FIXDIG_POS      6
00112 #define MAX_FIXDIG_NEG      4
00113 #define DIGMAX_DEF   5
00114 
00115 void
00116 pldprec(PLFLT vmin, PLFLT vmax, PLFLT tick, PLINT lf, 
00117        PLINT *mode, PLINT *prec, PLINT digmax, PLINT *scale)
00118 {
00119     PLFLT chosen, notchosen, vmod, t0;
00120     PLINT msd, notmsd, np, digmin, digfix;
00121 
00122     *mode = 0;
00123     *scale = 0;
00124 
00125     if (digmax == 0)
00126        digmax = DIGMAX_DEF;
00127 
00128 /* Choose vmin or vmax depending on magnitudes of vmin and vmax. */
00129     chosen = (ABS(vmax) >= ABS(vmin))? vmax: vmin;
00130     notchosen = (ABS(vmax) >= ABS(vmin))? vmin: vmax;
00131 /* Magnitute of chosen to get number of significant digits */
00132 
00133     if(ABS(chosen) > 0.) {
00134         vmod = ABS(chosen);
00135         t0 = (PLFLT) log10(vmod);
00136         msd = (PLINT) floor(t0);
00137     }
00138     else {
00139 /* this branch occurs only when 0. --- 0. range put in */
00140         vmod = 1.;
00141         t0 = (PLFLT) log10(vmod);
00142         msd = (PLINT) floor(t0);
00143     }
00144         
00145     if(ABS(notchosen) > 0.)
00146        notmsd = (PLINT) floor( (PLFLT) log10(ABS(notchosen)));
00147     else
00148        notmsd = msd;
00149 /* Autoselect the mode flag */
00150 /* 'digmin' is the minimum number of places taken up by the label */
00151 
00152     if (msd >= 0) {
00153 /* n.b. no decimal point in the minimal case  */
00154        digmin = msd + 1;
00155        digfix = MAX_FIXDIG_POS;
00156        if (digmax > 0)
00157            digfix = MIN(digmax, MAX_FIXDIG_POS);
00158     }
00159     else {
00160 /* adjust digmin to account for leading 0 and decimal point */
00161        digmin = -msd + 2;
00162        digfix = MAX_FIXDIG_NEG;
00163        if (digmax > 0)
00164            digfix = MIN(digmax, MAX_FIXDIG_NEG);
00165     }
00166 /* adjust digmin to account for sign on the chosen end of axis or sign on the 
00167  * nonchosen end of axis if notmsd = msd or (msd <= 0 and notmsd < 0)
00168  * For the latter case the notchosen label starts with "-0."
00169  * For checking for the latter case, the notmsd < 0 condition is redundant
00170  * since notmsd <= msd always and the equal part is selected by the first
00171  * condition.
00172  */
00173     if(chosen < 0.||(notchosen < 0. && (notmsd == msd || msd <= 0)))
00174         digmin = digmin + 1;
00175 
00176     if (digmin > digfix && !lf) {
00177        *mode = 1;
00178        *scale = msd;
00179     }
00180 
00181 /* Establish precision.  */
00182 /* It must be fine enough to resolve the tick spacing */
00183 
00184     np = (PLINT) floor(log10(ABS(tick)));
00185 
00186     if (*mode != 0)
00187        *prec = msd - np;
00188     else
00189        *prec = MAX(-np, 0);
00190 
00191 /* One last hack required: if exponent < 0, i.e. number has leading '0.',
00192  * it's better to change to floating point form if the number of digits
00193  * is insufficient to represent the tick spacing.
00194 */
00195     if (*mode == 0 && digmax > 0 && !lf) {
00196        if (t0 < 0.0) {
00197            if (digmax - 2 - *prec < 0) {
00198               *mode = 1;
00199               *scale = msd;
00200            }
00201        }
00202        else
00203            *prec = MAX(MIN(*prec, digmax - msd - 1), 0);
00204     }
00205     if (*mode != 0) {
00206        *prec = msd - np;
00207        *prec = MAX(MIN(*prec, MAX(digmax-1, MIN_FLTDIG)), 0);
00208     }
00209 }