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