• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

pldtik.c

Go to the documentation of this file.
00001 // $Id: pldtik.c 11680 2011-03-27 17:57:51Z airwin $
00002 //
00003 //      Determines tick spacing and mode (fixed or floating) of
00004 //      numeric axis labels.
00005 //
00006 // Copyright (C) 2004  Alan W. Irwin
00007 //
00008 // This file is part of PLplot.
00009 //
00010 // PLplot is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Library General Public License as published
00012 // by the Free Software Foundation; either version 2 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // PLplot is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Library General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Library General Public License
00021 // along with PLplot; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 
00025 #include "plplotP.h"
00026 
00027 //--------------------------------------------------------------------------
00028 // void pldtik()
00029 //
00030 // Determine tick spacing: works out a "nice" interval (if tick == 0) such
00031 // that there are between 3 and 7.5 major tick intervals in the input
00032 // range vmin to vmax.  The recommended number of subticks is returned in
00033 // "nsubt" unless the routine is entered with a non-zero value of "nsubt".
00034 // n.b. big change: now returns only positive values of tick and nsubt
00035 //--------------------------------------------------------------------------
00036 
00037 void
00038 pldtik( PLFLT vmin, PLFLT vmax, PLFLT *tick, PLINT *nsubt, PLBOOL ld )
00039 {
00040     PLFLT t1, t2, tick_reasonable;
00041     PLINT np, ns;
00042     PLFLT factor;
00043 
00044 
00045     if ( ld )
00046     {
00047         // Check suitable units for tick spacing
00048         pldtfac( vmin, vmax, &factor, NULL );
00049 
00050         *tick = *tick / factor;
00051         vmin  = vmin / factor;
00052         vmax  = vmax / factor;
00053     }
00054 
00055 // Magnitude of min/max difference to get tick spacing
00056 
00057     t1 = (PLFLT) log10( ABS( vmax - vmin ) );
00058     np = (PLINT) floor( t1 );
00059     t1 = t1 - np;
00060 
00061 // Get tick spacing.
00062 
00063     if ( t1 > 0.7781512503 )
00064     {
00065         t2 = 2.0;
00066         ns = 4;
00067     }
00068     else if ( t1 > 0.4771212549 )
00069     {
00070         t2 = 1.0;
00071         ns = 5;
00072     }
00073     else if ( t1 > 0.1760912591 )
00074     {
00075         t2 = 5.0;
00076         ns = 5;
00077         np = np - 1;
00078     }
00079     else
00080     {
00081         t2 = 2.0;
00082         ns = 4;
00083         np = np - 1;
00084     }
00085 
00086 // Now compute reasonable tick spacing
00087 
00088     tick_reasonable = t2 * pow( 10.0, (double) np );
00089     if ( *tick == 0 )
00090     {
00091         *tick = t2 * pow( 10.0, (double) np );
00092     }
00093     else
00094     {
00095         *tick = ABS( *tick );
00096         if ( *tick < 1.e-4 * tick_reasonable )
00097         {
00098             plexit( "pldtik: magnitude of specified tick spacing is much too small" );
00099             return;
00100         }
00101     }
00102     if ( *nsubt == 0 )
00103         *nsubt = ns;
00104 
00105     *nsubt = ABS( *nsubt );
00106 
00107     if ( ld )
00108     {
00109         *tick = *tick * factor;
00110     }
00111 }
00112 
00113 //--------------------------------------------------------------------------
00114 // PLFLT pldtfac()
00115 //
00116 // Calculate factor to convert a date/time interval in seconds
00117 // into a more natural units (minutes, hours, days, week, years).
00118 // Also optionally calculate the sensible start time for counting ticks
00119 // from (e.g. beginning of day, beginning of year).
00120 // Used to calculate sensible tick and label spacings.
00121 //--------------------------------------------------------------------------
00122 void
00123 pldtfac( PLFLT vmin, PLFLT vmax, PLFLT *factor, PLFLT *start )
00124 {
00125     PLFLT diff;
00126     PLINT year, month, day, hour, min;
00127     PLFLT sec;
00128 
00129     diff = vmax - vmin;
00130 
00131     if ( start != NULL )
00132     {
00133         plbtime( &year, &month, &day, &hour, &min, &sec, vmin );
00134     }
00135 
00136     if ( diff < 3.0 * 60.0 )
00137     {
00138         // Seconds
00139         *factor = 1.0;
00140         if ( start != NULL )
00141         {
00142             sec = 0.;
00143             plctime( year, month, day, hour, min, sec, start );
00144         }
00145     }
00146     else if ( diff < 3.0 * 60.0 * 60.0 )
00147     {
00148         // Minutes
00149         *factor = 60.0;
00150         if ( start != NULL )
00151         {
00152             sec = 0.;
00153             min = 0;
00154             plctime( year, month, day, hour, min, sec, start );
00155         }
00156     }
00157     else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 )
00158     {
00159         // Hours
00160         *factor = 60.0 * 60.0;
00161         if ( start != NULL )
00162         {
00163             sec  = 0.;
00164             min  = 0;
00165             hour = 0;
00166             plctime( year, month, day, hour, min, sec, start );
00167         }
00168     }
00169     else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 * 7.0 )
00170     {
00171         // Days
00172         *factor = 60.0 * 60.0 * 24.0;
00173         if ( start != NULL )
00174         {
00175             sec  = 0.;
00176             min  = 0;
00177             hour = 0;
00178             plctime( year, month, day, hour, min, sec, start );
00179         }
00180     }
00181     else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 * 365 )
00182     {
00183         // Weeks
00184         *factor = 60.0 * 60.0 * 24.0 * 7.0;
00185         if ( start != NULL )
00186         {
00187             sec  = 0.;
00188             min  = 0;
00189             hour = 0;
00190             plctime( year, month, day, hour, min, sec, start );
00191         }
00192     }
00193     else
00194     {
00195         // Years
00196         *factor = 60.0 * 60.0 * 24.0 * 365.25;
00197         if ( start != NULL )
00198         {
00199             sec   = 0.;
00200             min   = 0;
00201             hour  = 0;
00202             day   = 0;
00203             month = 0;
00204             plctime( year, month, day, hour, min, sec, start );
00205         }
00206     }
00207 }
00208 
00209 //--------------------------------------------------------------------------
00210 // void pldprec()
00211 //
00212 // Determine precision: the output variable "mode" is set to 0 if labels
00213 // are to be written in floating-point format, or to 1 if they are to be
00214 // written in scientific format.  For mode = 1, the exponent will be
00215 // placed at:
00216 //
00217 //      top left        for vertical axis on left
00218 //      top right       for vertical axis on right
00219 //      bottom right    for horizontal axis
00220 //
00221 // The digmax flag can be set by the user, and represents the maximum
00222 // number of digits a label may occupy including sign and decimal point.
00223 // digmin, calculated internally, is the maximum number of digits
00224 // labels at vmin and vmax would occupy if floating point.
00225 // If digmax<0, it is disregarded,
00226 // and if digmax=0 the default value is used.  For digmax>0, mode=1 is
00227 // chosen if there is insufficient room for the label within the specified
00228 // # of digits (digmin > digfix, where digfix is determined from digmax with
00229 // fuzz factors).
00230 //
00231 // In the case of mode=0, the actual # of digits will become too large
00232 // when the magnitude of the labels become too large.  The mode=1 case
00233 // offers the greatest precision for the smallest field length.
00234 //
00235 // The determination of maximum length for fixed point quantities is
00236 // complicated by the fact that very long fixed point representations look
00237 // much worse than the same sized floating point representation.  Further,
00238 // a fixed point number with a large negative exponent will actually gain
00239 // in precision when written as floating point.  Thus we use certain fuzz
00240 // factors to get 'digfix' from 'digmax', however it will always be true
00241 // that digfix<=digmax.
00242 //
00243 // Finally, if 'digmax' is set, 'prec' is reduced in size if necessary so
00244 // that the labels fit the requested field length, where prec is the number of
00245 // places after the decimal place.
00246 //--------------------------------------------------------------------------
00247 
00248 #define MIN_FLTDIG    3         // disregarded if fractional part is 0
00249 #define DIGMAX_DEF    5
00250 
00251 void
00252 pldprec( PLFLT vmin, PLFLT vmax, PLFLT tick, PLINT lf,
00253          PLINT *mode, PLINT *prec, PLINT digmax, PLINT *scale )
00254 {
00255     PLFLT chosen, notchosen, vmod, t0;
00256     PLINT msd, notmsd, np, digmin, digfix;
00257 
00258     *mode  = 0;
00259     *scale = 0;
00260 
00261     // Default xdigmax, ydigmax and zdigmax set in c_plinit so this is
00262     // only an emergency measure in case of some internal PLplot
00263     // logic error.
00264     if ( digmax == 0 )
00265         digmax = DIGMAX_DEF;
00266     // No modification of digfix from digmax value.
00267     digfix = digmax;
00268 // Choose vmin or vmax depending on magnitudes of vmin and vmax.
00269     chosen    = ( ABS( vmax ) >= ABS( vmin ) ) ? vmax : vmin;
00270     notchosen = ( ABS( vmax ) >= ABS( vmin ) ) ? vmin : vmax;
00271 // Magnitute of chosen to get number of significant digits
00272 
00273     if ( ABS( chosen ) > 0. )
00274     {
00275         vmod = ABS( chosen );
00276         t0   = (PLFLT) log10( vmod );
00277         msd  = (PLINT) floor( t0 );
00278     }
00279     else
00280     {
00281         // this branch occurs only when 0. --- 0. range put in
00282         vmod = 1.;
00283         t0   = (PLFLT) log10( vmod );
00284         msd  = (PLINT) floor( t0 );
00285     }
00286 
00287     if ( ABS( notchosen ) > 0. )
00288         notmsd = (PLINT) floor( (PLFLT) log10( ABS( notchosen ) ) );
00289     else
00290         notmsd = msd;
00291     // Autoselect the mode flag
00292     // 'digmin' is the minimum number of places taken up by the label
00293 
00294     if ( msd >= 0 )
00295     {
00296         // n.b. no decimal point in the minimal case
00297         digmin = msd + 1;
00298     }
00299     else
00300     {
00301         // adjust digmin to account for leading 0 and decimal point
00302         digmin = -msd + 2;
00303     }
00304 // adjust digmin to account for sign on the chosen end of axis or sign on the
00305 // nonchosen end of axis if notmsd = msd or (msd <= 0 and notmsd < 0)
00306 // For the latter case the notchosen label starts with "-0."
00307 // For checking for the latter case, the notmsd < 0 condition is redundant
00308 // since notmsd <= msd always and the equal part is selected by the first
00309 // condition.
00310 //
00311     if ( chosen < 0. || ( notchosen < 0. && ( notmsd == msd || msd <= 0 ) ) )
00312         digmin = digmin + 1;
00313 
00314     if ( digmin > digfix && !lf )
00315     {
00316         *mode  = 1;
00317         *scale = msd;
00318     }
00319 
00320 // Establish precision.
00321 // It must be fine enough to resolve the tick spacing
00322 
00323     np = (PLINT) floor( log10( ABS( tick ) ) );
00324 
00325     if ( *mode != 0 )
00326         *prec = msd - np;
00327     else
00328         *prec = MAX( -np, 0 );
00329 
00330 // One last hack required: if exponent < 0, i.e. number has leading '0.',
00331 // it's better to change to floating point form if the number of digits
00332 // is insufficient to represent the tick spacing.
00333 //
00334     if ( *mode == 0 && digmax > 0 && !lf )
00335     {
00336         if ( t0 < 0.0 )
00337         {
00338             if ( digmax - 2 - *prec < 0 )
00339             {
00340                 *mode  = 1;
00341                 *scale = msd;
00342             }
00343         }
00344         else
00345             *prec = MAX( MIN( *prec, digmax - msd - 1 ), 0 );
00346     }
00347     if ( *mode != 0 )
00348     {
00349         *prec = msd - np;
00350         *prec = MAX( MIN( *prec, MAX( digmax - 1, MIN_FLTDIG ) ), 0 );
00351     }
00352 }

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1