PLplot  5.10.0
plbox.c
Go to the documentation of this file.
00001 //      Routines for drawing axes & box around the current viewport.
00002 //
00003 // Copyright (C) 2004  Joao Cardoso
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 #define STRING_LEN         40
00026 #define FORMAT_LEN         10
00027 #define TEMP_LEN           30
00028 #define N_EDGE_SEGMENTS    50
00029 
00030 static PLFLT xlog[8] =
00031 {
00032     0.301030, 0.477121, 0.602060, 0.698970,
00033     0.778151, 0.845098, 0.903090, 0.954243
00034 };
00035 
00036 // Static function prototypes
00037 
00038 static void
00039 plxybx( const char *opt, const char *label, PLINT axis, PLFLT wx1, PLFLT wy1,
00040         PLFLT wx2, PLFLT wy2, PLFLT vmin, PLFLT vmax,
00041         PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits );
00042 
00043 static void
00044 plzbx( const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
00045        PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin, PLFLT vmax,
00046        PLFLT tick, PLINT nsub, PLINT *digits );
00047 
00048 static void
00049 plxytx( PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
00050         PLFLT disp, PLFLT pos, PLFLT just, const char *text );
00051 
00052 static void
00053 plztx( const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
00054        PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text );
00055 
00056 static void
00057 plform( PLINT axis, PLFLT value, PLINT scale, PLINT prec, char *result, PLINT len, PLBOOL ll, PLBOOL lf, PLBOOL lo );
00058 
00059 static void
00060 grid_box( const char *xopt, PLFLT xtick1, PLINT nxsub1,
00061           const char *yopt, PLFLT ytick1, PLINT nysub1 );
00062 
00063 static void
00064 label_box( const char *xopt, PLFLT xtick1, const char *yopt, PLFLT ytick1 );
00065 
00066 static void
00067 plP_default_label_log( PLINT axis, PLFLT value, char *string, PLINT len, void *data );
00068 
00069 static void
00070 plP_default_label_log_fixed( PLINT axis, PLFLT value, char *string, PLINT len, void *data );
00071 
00072 static void
00073 plP_default_label( PLINT axis, PLFLT value, char *string, PLINT len, void *data );
00074 
00075 static const char *
00076 plgesc_string( void );
00077 
00078 //--------------------------------------------------------------------------
00079 // void plbox()
00080 //
00081 // This draws a box around the current viewport, complete with axes, ticks,
00082 // numeric labels, and grids, according to input specification.  Just a
00083 // front-end to plaxes(), which allows arbitrary placement of coordinate
00084 // axes when plotted (here the origin is at 0,0).  See the documentation for
00085 // plaxes() for more info.
00086 //--------------------------------------------------------------------------
00087 
00088 void
00089 c_plbox( const char *xopt, PLFLT xtick, PLINT nxsub,
00090          const char *yopt, PLFLT ytick, PLINT nysub )
00091 {
00092     c_plaxes( 0.0, 0.0, xopt, xtick, nxsub, yopt, ytick, nysub );
00093 }
00094 
00095 //--------------------------------------------------------------------------
00096 // void plaxes()
00097 //
00098 // This draws a box around the current viewport, complete with axes,
00099 // ticks, numeric labels, and grids, according to input specification.
00100 //
00101 // x0 and y0 specify the origin of the axes.
00102 //
00103 // xopt and yopt are character strings which define the box as follows:
00104 //
00105 // a: Draw axis (X is horizontal line Y=0, Y is vertical line X=0)
00106 // b: Draw bottom (X) or left (Y) frame of box
00107 // c: Draw top (X) or right (Y) frame of box
00108 // d: Interpret axis as a date/time when writing labels
00109 // f: Always use fixed point numeric labels
00110 // g: Draws a grid at the major tick interval
00111 // h: Draws a grid at the minor tick interval
00112 // i: Inverts tick marks
00113 // l: Logarithmic axes, major ticks at decades, minor ticks at units
00114 // n: Write numeric label at conventional location
00115 // m: Write numeric label at unconventional location
00116 // o: Label text is generated by a user-defined function
00117 // t: Draw major tick marks
00118 // s: Draw minor tick marks
00119 // u: like b (including all side effects such as tick marks and numerical
00120 // labels for those) except exclude drawing the edge.
00121 // w: like c (including all side effects such as tick marks and numerical
00122 // labels for those) except exclude drawing the edge.
00123 // v: (for Y only) Label vertically
00124 // x: like t (including the side effect of the numerical labels for the major
00125 // ticks) except exclude drawing the major and minor tick marks.
00126 //
00127 // xtick, ytick are the major tick intervals required, zero for
00128 // automatic selection
00129 //
00130 // nxsub, nysub are the number of subtick intervals in a major tick
00131 // interval
00132 //--------------------------------------------------------------------------
00133 
00134 void
00135 c_plaxes( PLFLT x0, PLFLT y0,
00136           const char *xopt, PLFLT xtick, PLINT nxsub,
00137           const char *yopt, PLFLT ytick, PLINT nysub )
00138 {
00139     PLBOOL lax, lbx, lcx, ldx, lgx, lix, llx, lsx, ltx, lux, lwx, lxx;
00140     PLBOOL lay, lby, lcy, ldy, lgy, liy, lly, lsy, lty, luy, lwy, lxy;
00141     PLINT  xmajor, xminor, ymajor, yminor;
00142     PLINT  i, i1x, i2x, i3x, i4x, i1y, i2y, i3y, i4y;
00143     PLINT  nxsub1, nysub1;
00144     PLINT  lxmin, lxmax, lymin, lymax;
00145     PLINT  pxmin, pxmax, pymin, pymax;
00146     PLINT  vppxmi, vppxma, vppymi, vppyma;
00147     PLFLT  xtick1, ytick1, vpwxmi, vpwxma, vpwymi, vpwyma;
00148     PLFLT  vpwxmin, vpwxmax, vpwymin, vpwymax;
00149     PLFLT  xp0, yp0, tn, tp, temp;
00150     PLFLT  factor, tstart;
00151 
00152     if ( plsc->level < 3 )
00153     {
00154         plabort( "plbox: Please set up window first" );
00155         return;
00156     }
00157 
00158 // Open the clip limits to the subpage limits
00159 
00160     plP_gclp( &lxmin, &lxmax, &lymin, &lymax );
00161     plP_gphy( &pxmin, &pxmax, &pymin, &pymax );
00162     plP_sclp( pxmin, pxmax, pymin, pymax );
00163 
00164     vppxmi = plsc->vppxmi;
00165     vppxma = plsc->vppxma;
00166     vppymi = plsc->vppymi;
00167     vppyma = plsc->vppyma;
00168 
00169     if ( plsc->if_boxbb )
00170     {
00171         // Bounding-box limits for the box in mm before corrections
00172         // for decorations are applied.
00173         plsc->boxbb_xmin = plsc->vppxmi / plsc->xpmm;
00174         plsc->boxbb_xmax = plsc->vppxma / plsc->xpmm;
00175         plsc->boxbb_ymin = plsc->vppymi / plsc->ypmm;
00176         plsc->boxbb_ymax = plsc->vppyma / plsc->ypmm;
00177     }
00178 
00179 // Set plot options from input
00180 
00181     lax = plP_stsearch( xopt, 'a' );
00182     lbx = plP_stsearch( xopt, 'b' );
00183     lcx = plP_stsearch( xopt, 'c' );
00184     ldx = plP_stsearch( xopt, 'd' );
00185     lgx = plP_stsearch( xopt, 'g' );
00186     lix = plP_stsearch( xopt, 'i' );
00187     llx = plP_stsearch( xopt, 'l' );
00188     lsx = plP_stsearch( xopt, 's' );
00189     ltx = plP_stsearch( xopt, 't' );
00190     lux = plP_stsearch( xopt, 'u' );
00191     lwx = plP_stsearch( xopt, 'w' );
00192     lxx = plP_stsearch( xopt, 'x' );
00193 
00194     lay = plP_stsearch( yopt, 'a' );
00195     lby = plP_stsearch( yopt, 'b' );
00196     lcy = plP_stsearch( yopt, 'c' );
00197     ldy = plP_stsearch( yopt, 'd' );
00198     lgy = plP_stsearch( yopt, 'g' );
00199     liy = plP_stsearch( yopt, 'i' );
00200     lly = plP_stsearch( yopt, 'l' );
00201     lsy = plP_stsearch( yopt, 's' );
00202     lty = plP_stsearch( yopt, 't' );
00203     luy = plP_stsearch( yopt, 'u' );
00204     lwy = plP_stsearch( yopt, 'w' );
00205     lxy = plP_stsearch( yopt, 'x' );
00206 
00207 // Tick and subtick sizes in device coords
00208 
00209     xmajor = MAX( ROUND( plsc->majht * plsc->ypmm ), 1 );
00210     ymajor = MAX( ROUND( plsc->majht * plsc->xpmm ), 1 );
00211     xminor = MAX( ROUND( plsc->minht * plsc->ypmm ), 1 );
00212     yminor = MAX( ROUND( plsc->minht * plsc->xpmm ), 1 );
00213 
00214     nxsub1 = nxsub;
00215     nysub1 = nysub;
00216     xtick1 = llx ? 1.0 : xtick;
00217     ytick1 = lly ? 1.0 : ytick;
00218 
00219     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
00220 // vpwxmi always numerically less than vpwxma, and
00221 // similarly for vpwymi
00222     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
00223     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
00224     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
00225     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
00226 
00227 // Plot axes only if they are inside viewport.
00228     lax = lax && vpwymi < y0 && y0 < vpwyma;
00229     lay = lay && vpwxmi < x0 && x0 < vpwxma;
00230 
00231 // Calculate tick spacing
00232 
00233     if ( ltx || lgx || lxx )
00234         pldtik( vpwxmi, vpwxma, &xtick1, &nxsub1, ldx );
00235 
00236     if ( lty || lgy || lxy )
00237         pldtik( vpwymi, vpwyma, &ytick1, &nysub1, ldy );
00238 // n.b. large change; xtick1, nxsub1, ytick1, nysub1 always positive.
00239 
00240 // Set up tick variables
00241 
00242     if ( lix )
00243     {
00244         i1x = xminor;
00245         i2x = 0;
00246         i3x = xmajor;
00247         i4x = 0;
00248     }
00249     else
00250     {
00251         i1x = 0;
00252         i2x = xminor;
00253         i3x = 0;
00254         i4x = xmajor;
00255     }
00256 
00257     if ( liy )
00258     {
00259         i1y = yminor;
00260         i2y = 0;
00261         i3y = ymajor;
00262         i4y = 0;
00263     }
00264     else
00265     {
00266         i1y = 0;
00267         i2y = yminor;
00268         i3y = 0;
00269         i4y = ymajor;
00270     }
00271 
00272     if ( plsc->if_boxbb )
00273     {
00274         // Carefully follow logic below (and above) for the case where
00275         // an inverted major tick mark is written (in the X direction
00276         // for a Y axis and vice versa).  Ignore minor tick marks
00277         // which are assumed to be smaller.  Ignore axes and grids
00278         // which are all contained within the viewport.
00279         if ( lix && ( lbx || lux ) && ( ltx && !lxx ) )
00280             plsc->boxbb_ymin -= xmajor / plsc->ypmm;
00281         if ( liy && ( lcy || lwy ) && ( lty && !lxy ) )
00282             plsc->boxbb_xmax += ymajor / plsc->xpmm;
00283         if ( lix && ( lcx || lwx ) && ( ltx && !lxx ) )
00284             plsc->boxbb_ymax += xmajor / plsc->ypmm;
00285         if ( liy && ( lby || luy ) && ( lty && !lxy ) )
00286             plsc->boxbb_xmin -= ymajor / plsc->xpmm;
00287     }
00288     else
00289     {
00290 // Draw the bottom frame of the box
00291 
00292         if ( lbx || lux )
00293         {
00294             if ( !lux )
00295             {
00296                 plP_movphy( vppxmi, vppymi );
00297                 plP_draphy( vppxma, vppymi );
00298             }
00299             if ( ltx && !lxx )
00300             {
00301                 if ( ldx )
00302                 {
00303                     pldtfac( vpwxmi, vpwxma, &factor, &tstart );
00304                     tp = xtick1 * ( floor( ( vpwxmi - tstart ) / xtick1 ) ) + tstart;
00305                 }
00306                 else
00307                     tp = xtick1 * floor( vpwxmi / xtick1 );
00308                 for (;; )
00309                 {
00310                     tn = tp + xtick1;
00311                     if ( lsx )
00312                     {
00313                         if ( llx )
00314                         {
00315                             for ( i = 0; i <= 7; i++ )
00316                             {
00317                                 temp = tp + xlog[i];
00318                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00319                                     plxtik( plP_wcpcx( temp ), vppymi, i1x, i2x );
00320                             }
00321                         }
00322                         else
00323                         {
00324                             for ( i = 1; i <= nxsub1 - 1; i++ )
00325                             {
00326                                 temp = tp + i * xtick1 / nxsub1;
00327                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00328                                     plxtik( plP_wcpcx( temp ), vppymi, i1x, i2x );
00329                             }
00330                         }
00331                     }
00332                     if ( !BETW( tn, vpwxmi, vpwxma ) )
00333                         break;
00334                     plxtik( plP_wcpcx( tn ), vppymi, i3x, i4x );
00335                     tp = tn;
00336                 }
00337             }
00338         }
00339 
00340 // Draw the right-hand frame of box
00341 
00342         if ( lcy || lwy )
00343         {
00344             if ( !lwy )
00345             {
00346                 plP_movphy( vppxma, vppymi );
00347                 plP_draphy( vppxma, vppyma );
00348             }
00349             if ( lty && !lxy )
00350             {
00351                 if ( ldy )
00352                 {
00353                     pldtfac( vpwymi, vpwyma, &factor, &tstart );
00354                     tp = ytick1 * ( floor( ( vpwymi - tstart ) / ytick1 ) ) + tstart;
00355                 }
00356                 else
00357                     tp = ytick1 * floor( vpwymi / ytick1 );
00358                 for (;; )
00359                 {
00360                     tn = tp + ytick1;
00361                     if ( lsy )
00362                     {
00363                         if ( lly )
00364                         {
00365                             for ( i = 0; i <= 7; i++ )
00366                             {
00367                                 temp = tp + xlog[i];
00368                                 if ( BETW( temp, vpwymi, vpwyma ) )
00369                                     plytik( vppxma, plP_wcpcy( temp ), i2y, i1y );
00370                             }
00371                         }
00372                         else
00373                         {
00374                             for ( i = 1; i <= nysub1 - 1; i++ )
00375                             {
00376                                 temp = tp + i * ytick1 / nysub1;
00377                                 if ( BETW( temp, vpwymi, vpwyma ) )
00378                                     plytik( vppxma, plP_wcpcy( temp ), i2y, i1y );
00379                             }
00380                         }
00381                     }
00382                     if ( !BETW( tn, vpwymi, vpwyma ) )
00383                         break;
00384                     plytik( vppxma, plP_wcpcy( tn ), i4y, i3y );
00385                     tp = tn;
00386                 }
00387             }
00388         }
00389 
00390 // Draw the top frame of the box
00391 
00392         if ( lcx || lwx )
00393         {
00394             if ( !lwx )
00395             {
00396                 plP_movphy( vppxma, vppyma );
00397                 plP_draphy( vppxmi, vppyma );
00398             }
00399             if ( ltx && !lxx )
00400             {
00401                 if ( ldx )
00402                 {
00403                     pldtfac( vpwxmi, vpwxma, &factor, &tstart );
00404                     tp = xtick1 * ( floor( ( vpwxma - tstart ) / xtick1 ) + 1 ) + tstart;
00405                 }
00406                 else
00407                     tp = xtick1 * ( floor( vpwxma / xtick1 ) + 1 );
00408                 for (;; )
00409                 {
00410                     tn = tp - xtick1;
00411                     if ( lsx )
00412                     {
00413                         if ( llx )
00414                         {
00415                             for ( i = 7; i >= 0; i-- )
00416                             {
00417                                 temp = tn + xlog[i];
00418                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00419                                     plxtik( plP_wcpcx( temp ), vppyma, i2x, i1x );
00420                             }
00421                         }
00422                         else
00423                         {
00424                             for ( i = nxsub1 - 1; i >= 1; i-- )
00425                             {
00426                                 temp = tn + i * xtick1 / nxsub1;
00427                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00428                                     plxtik( plP_wcpcx( temp ), vppyma, i2x, i1x );
00429                             }
00430                         }
00431                     }
00432                     if ( !BETW( tn, vpwxmi, vpwxma ) )
00433                         break;
00434                     plxtik( plP_wcpcx( tn ), vppyma, i4x, i3x );
00435                     tp = tn;
00436                 }
00437             }
00438         }
00439 
00440 // Draw the left-hand frame of box
00441 
00442         if ( lby || luy )
00443         {
00444             if ( !luy )
00445             {
00446                 plP_movphy( vppxmi, vppyma );
00447                 plP_draphy( vppxmi, vppymi );
00448             }
00449             if ( lty && !lxy )
00450             {
00451                 if ( ldy )
00452                 {
00453                     pldtfac( vpwymi, vpwyma, &factor, &tstart );
00454                     tp = ytick1 * ( floor( ( vpwyma - tstart ) / ytick1 ) + 1 ) + tstart;
00455                 }
00456                 else
00457                     tp = ytick1 * ( floor( vpwyma / ytick1 ) + 1 );
00458                 for (;; )
00459                 {
00460                     tn = tp - ytick1;
00461                     if ( lsy )
00462                     {
00463                         if ( lly )
00464                         {
00465                             for ( i = 7; i >= 0; i-- )
00466                             {
00467                                 temp = tn + xlog[i];
00468                                 if ( BETW( temp, vpwymi, vpwyma ) )
00469                                     plytik( vppxmi, plP_wcpcy( temp ), i1y, i2y );
00470                             }
00471                         }
00472                         else
00473                         {
00474                             for ( i = nysub1 - 1; i >= 1; i-- )
00475                             {
00476                                 temp = tn + i * ytick1 / nysub1;
00477                                 if ( BETW( temp, vpwymi, vpwyma ) )
00478                                     plytik( vppxmi, plP_wcpcy( temp ), i1y, i2y );
00479                             }
00480                         }
00481                     }
00482                     if ( !BETW( tn, vpwymi, vpwyma ) )
00483                         break;
00484                     plytik( vppxmi, plP_wcpcy( tn ), i3y, i4y );
00485                     tp = tn;
00486                 }
00487             }
00488         }
00489 
00490         // Draw the horizontal axis.
00491         if ( lax )
00492         {
00493             // Convert world coordinates to physical
00494             yp0 = plP_wcpcy( y0 );
00495             plP_movphy( vppxmi, (PLINT) yp0 );
00496             plP_draphy( vppxma, (PLINT) yp0 );
00497             if ( ltx && !lxx )
00498             {
00499                 tp = xtick1 * floor( vpwxmi / xtick1 );
00500                 for (;; )
00501                 {
00502                     tn = tp + xtick1;
00503                     if ( lsx )
00504                     {
00505                         if ( llx )
00506                         {
00507                             for ( i = 0; i <= 7; i++ )
00508                             {
00509                                 temp = tp + xlog[i];
00510                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00511                                     plxtik( plP_wcpcx( temp ), (PLINT) yp0, xminor, xminor );
00512                             }
00513                         }
00514                         else
00515                         {
00516                             for ( i = 1; i <= nxsub1 - 1; i++ )
00517                             {
00518                                 temp = tp + i * xtick1 / nxsub1;
00519                                 if ( BETW( temp, vpwxmi, vpwxma ) )
00520                                     plxtik( plP_wcpcx( temp ), (PLINT) yp0, xminor, xminor );
00521                             }
00522                         }
00523                     }
00524                     if ( !BETW( tn, vpwxmi, vpwxma ) )
00525                         break;
00526                     plxtik( plP_wcpcx( tn ), (PLINT) yp0, xmajor, xmajor );
00527                     tp = tn;
00528                 }
00529             }
00530         }
00531 
00532         // Draw the vertical axis.
00533         if ( lay )
00534         {
00535             // Convert world coordinates to physical
00536             xp0 = plP_wcpcx( x0 );
00537             plP_movphy( (PLINT) xp0, vppymi );
00538             plP_draphy( (PLINT) xp0, vppyma );
00539             if ( lty && !lxy )
00540             {
00541                 tp = ytick1 * floor( vpwymi / ytick1 );
00542                 for (;; )
00543                 {
00544                     tn = tp + ytick1;
00545                     if ( lsy )
00546                     {
00547                         if ( lly )
00548                         {
00549                             for ( i = 0; i <= 7; i++ )
00550                             {
00551                                 temp = tp + xlog[i];
00552                                 if ( BETW( temp, vpwymi, vpwyma ) )
00553                                     plytik( (PLINT) xp0, plP_wcpcy( temp ), yminor, yminor );
00554                             }
00555                         }
00556                         else
00557                         {
00558                             for ( i = 1; i <= nysub1 - 1; i++ )
00559                             {
00560                                 temp = tp + i * ytick1 / nysub1;
00561                                 if ( BETW( temp, vpwymi, vpwyma ) )
00562                                     plytik( (PLINT) xp0, plP_wcpcy( temp ), yminor, yminor );
00563                             }
00564                         }
00565                     }
00566                     if ( !BETW( tn, vpwymi, vpwyma ) )
00567                         break;
00568                     plytik( (PLINT) xp0, plP_wcpcy( tn ), ymajor, ymajor );
00569                     tp = tn;
00570                 }
00571             }
00572         }
00573 
00574         // Draw grids.
00575         grid_box( xopt, xtick1, nxsub1, yopt, ytick1, nysub1 );
00576     }
00577 
00578     // Write labels.
00579     label_box( xopt, xtick1, yopt, ytick1 );
00580 
00581 // Restore the clip limits to viewport edge
00582 
00583     plP_sclp( lxmin, lxmax, lymin, lymax );
00584 }
00585 
00586 //--------------------------------------------------------------------------
00587 // void plbox3()
00588 //
00589 // This is the 3-d analogue of plbox().
00590 //--------------------------------------------------------------------------
00591 
00592 void
00593 c_plbox3( const char *xopt, const char *xlabel, PLFLT xtick, PLINT nxsub,
00594           const char *yopt, const char *ylabel, PLFLT ytick, PLINT nysub,
00595           const char *zopt, const char *zlabel, PLFLT ztick, PLINT nzsub )
00596 {
00597     PLFLT dx, dy, tx, ty, ux, uy;
00598     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00599     PLFLT cxx, cxy, cyx, cyy, cyz;
00600     PLINT ln;
00601     PLINT *zbflg, *zbcol;
00602     PLFLT *zbwidth;
00603     PLFLT *zbtck;
00604     PLINT xdigmax, xdigits;
00605     PLINT ydigmax, ydigits;
00606     PLINT zdigmax, zdigits;
00607 
00608     if ( plsc->level < 3 )
00609     {
00610         plabort( "plbox3: Please set up window first" );
00611         return;
00612     }
00613 
00614     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
00615     plP_gdom( &xmin, &xmax, &ymin, &ymax );
00616     plP_grange( &zscale, &zmin, &zmax );
00617 
00618     plgxax( &xdigmax, &xdigits );
00619     plgyax( &ydigmax, &ydigits );
00620     plgzax( &zdigmax, &zdigits );
00621 
00622     xdigits = xdigmax;
00623     ydigits = ydigmax;
00624     zdigits = zdigmax;
00625 
00626 // We have to wait until after the plot is drawn to draw back
00627 // grid so store this stuff.
00628 
00629     plP_gzback( &zbflg, &zbcol, &zbtck, &zbwidth );
00630     *zbflg = plP_stsearch( zopt, 'd' );
00631     if ( *zbflg )
00632     {
00633         *zbtck   = ztick;       // save tick spacing
00634         *zbcol   = plsc->icol0; // and color
00635         *zbwidth = plsc->width; // and line width
00636     }
00637 
00638     if ( cxx >= 0.0 && cxy <= 0.0 )
00639     {
00640         ln = plP_stsearch( xopt, 'n' );
00641         tx = plP_w3wcx( xmin, ymin, zmin );
00642         ty = plP_w3wcy( xmin, ymin, zmin );
00643         ux = plP_w3wcx( xmax, ymin, zmin );
00644         uy = plP_w3wcy( xmax, ymin, zmin );
00645         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00646             xmin, xmax, xtick, nxsub, 0, &xdigits );
00647 
00648         dx = ux - tx;
00649         dy = uy - ty;
00650         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00651             plP_w3wcy( xmax, ymin, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00652 
00653         tx = plP_w3wcx( xmin, ymax, zmin );
00654         ty = plP_w3wcy( xmin, ymax, zmin );
00655         ux = plP_w3wcx( xmin, ymin, zmin );
00656         uy = plP_w3wcy( xmin, ymin, zmin );
00657         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00658             ymax, ymin, ytick, nysub, ln, &ydigits );
00659 
00660         dx = ux - tx;
00661         dy = uy - ty;
00662 // restore zdigits to initial value for second call
00663         zdigits = zdigmax;
00664         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00665             plP_w3wcy( xmin, ymax, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00666     }
00667     else if ( cxx <= 0.0 && cxy <= 0.0 )
00668     {
00669         ln = plP_stsearch( yopt, 'n' );
00670         tx = plP_w3wcx( xmin, ymax, zmin );
00671         ty = plP_w3wcy( xmin, ymax, zmin );
00672         ux = plP_w3wcx( xmin, ymin, zmin );
00673         uy = plP_w3wcy( xmin, ymin, zmin );
00674         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00675             ymax, ymin, ytick, nysub, 0, &ydigits );
00676 
00677         dx = ux - tx;
00678         dy = uy - ty;
00679         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00680             plP_w3wcy( xmin, ymin, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00681 
00682         tx = plP_w3wcx( xmax, ymax, zmin );
00683         ty = plP_w3wcy( xmax, ymax, zmin );
00684         ux = plP_w3wcx( xmin, ymax, zmin );
00685         uy = plP_w3wcy( xmin, ymax, zmin );
00686         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00687             xmax, xmin, xtick, nxsub, ln, &xdigits );
00688 
00689         dx = ux - tx;
00690         dy = uy - ty;
00691 // restore zdigits to initial value for second call
00692         zdigits = zdigmax;
00693         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00694             plP_w3wcy( xmax, ymax, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00695     }
00696     else if ( cxx <= 0.0 && cxy >= 0.0 )
00697     {
00698         ln = plP_stsearch( xopt, 'n' );
00699         tx = plP_w3wcx( xmax, ymax, zmin );
00700         ty = plP_w3wcy( xmax, ymax, zmin );
00701         ux = plP_w3wcx( xmin, ymax, zmin );
00702         uy = plP_w3wcy( xmin, ymax, zmin );
00703         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00704             xmax, xmin, xtick, nxsub, 0, &xdigits );
00705 
00706         dx = ux - tx;
00707         dy = uy - ty;
00708         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00709             plP_w3wcy( xmin, ymax, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00710 
00711         tx = plP_w3wcx( xmax, ymin, zmin );
00712         ty = plP_w3wcy( xmax, ymin, zmin );
00713         ux = plP_w3wcx( xmax, ymax, zmin );
00714         uy = plP_w3wcy( xmax, ymax, zmin );
00715         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00716             ymin, ymax, ytick, nysub, ln, &ydigits );
00717 
00718         dx = ux - tx;
00719         dy = uy - ty;
00720 // restore zdigits to initial value for second call
00721         zdigits = zdigmax;
00722         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00723             plP_w3wcy( xmax, ymin, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00724     }
00725     else if ( cxx >= 0.0 && cxy >= 0.0 )
00726     {
00727         ln = plP_stsearch( yopt, 'n' );
00728         tx = plP_w3wcx( xmax, ymin, zmin );
00729         ty = plP_w3wcy( xmax, ymin, zmin );
00730         ux = plP_w3wcx( xmax, ymax, zmin );
00731         uy = plP_w3wcy( xmax, ymax, zmin );
00732         plxybx( yopt, ylabel, PL_X_AXIS, tx, ty, ux, uy,
00733             ymin, ymax, ytick, nysub, 0, &ydigits );
00734 
00735         dx = ux - tx;
00736         dy = uy - ty;
00737         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00738             plP_w3wcy( xmax, ymax, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00739 
00740         tx = plP_w3wcx( xmin, ymin, zmin );
00741         ty = plP_w3wcy( xmin, ymin, zmin );
00742         ux = plP_w3wcx( xmax, ymin, zmin );
00743         uy = plP_w3wcy( xmax, ymin, zmin );
00744         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00745             xmin, xmax, xtick, nxsub, ln, &xdigits );
00746 
00747         dx = ux - tx;
00748         dy = uy - ty;
00749 // restore zdigits to initial value for second call
00750         zdigits = zdigmax;
00751         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00752             plP_w3wcy( xmin, ymin, zmax ), zmin, zmax, ztick, nzsub, &zdigits );
00753     }
00754     plsxax( xdigmax, xdigits );
00755     plsyax( ydigmax, ydigits );
00756     plszax( zdigmax, zdigits );
00757 }
00758 
00759 //--------------------------------------------------------------------------
00760 // Support routines for 3d box draw.
00761 //--------------------------------------------------------------------------
00762 
00763 //--------------------------------------------------------------------------
00764 // void plxybx()
00765 //
00766 // This draws a sloping line from (wx1,wy1) to (wx2,wy2) which represents an
00767 // axis of a 3-d graph with data values from "vmin" to "vmax". Depending on
00768 // "opt", vertical ticks and/or subticks are placed on the line at major tick
00769 // interval "tick" with "nsub" subticks between major ticks. If "tick" and/or
00770 // "nsub" is zero, automatic tick positions are computed
00771 //
00772 // b: Draw box boundary
00773 // f: Always use fixed point numeric labels
00774 // i: Inverts tick marks (i.e. drawn downwards)
00775 // l: Logarithmic axes, major ticks at decades, minor ticks at units
00776 // n: Write numeric label
00777 // o: Use custom label function
00778 // t: Draw major tick marks
00779 // s: Draw minor tick marks
00780 // u: Write label on line
00781 //--------------------------------------------------------------------------
00782 
00783 static void
00784 plxybx( const char *opt, const char *label, PLINT axis, PLFLT wx1, PLFLT wy1,
00785         PLFLT wx2, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
00786         PLFLT tick, PLINT nsub, PLINT PL_UNUSED( nolast ), PLINT *digits )
00787 {
00788     static char string[STRING_LEN];
00789     PLINT       lb, ld, lf, li, ll, ln, ls, lt, lu, lo;
00790     PLINT       major, minor, mode, prec, scale;
00791     PLINT       i, i1, i2, i3, i4;
00792     PLINT       nsub1;
00793     PLFLT       pos, tn, tp, temp, height, tick1, vmin, vmax;
00794 // Note that 'tspace' is the minimim distance away (in fractional number
00795 // of ticks) from the boundary that an X or Y numerical label can be drawn.
00796     PLFLT      dwx, dwy, lambda, tcrit, tspace = 0.1;
00797     const char * esc_string = plgesc_string();
00798 
00799     vmin = ( vmax_in > vmin_in ) ? vmin_in : vmax_in;
00800     vmax = ( vmax_in > vmin_in ) ? vmax_in : vmin_in;
00801 
00802     dwx = wx2 - wx1;
00803     dwy = wy2 - wy1;
00804 
00805 // Tick and subtick sizes in device coords
00806 
00807     major = MAX( ROUND( plsc->majht * plsc->ypmm ), 1 );
00808     minor = MAX( ROUND( plsc->minht * plsc->ypmm ), 1 );
00809 
00810     tick1 = tick;
00811     nsub1 = nsub;
00812 
00813     lb = plP_stsearch( opt, 'b' );
00814     ld = plP_stsearch( opt, 'd' );
00815     lf = plP_stsearch( opt, 'f' );
00816     li = plP_stsearch( opt, 'i' );
00817     ll = plP_stsearch( opt, 'l' );
00818     ln = plP_stsearch( opt, 'n' );
00819     ls = plP_stsearch( opt, 's' );
00820     lt = plP_stsearch( opt, 't' );
00821     lu = plP_stsearch( opt, 'u' );
00822     lo = plP_stsearch( opt, 'o' );
00823 
00824     if ( lu )
00825         plxytx( wx1, wy1, wx2, wy2, 3.2, 0.5, 0.5, label );
00826     if ( !lb )
00827         return;
00828 
00829     if ( ll )
00830         tick1 = ( vmax > vmin ) ? 1.0 : -1.0;
00831     if ( lt )
00832         pldtik( vmin, vmax, &tick1, &nsub1, ld );
00833 
00834     if ( li )
00835     {
00836         i1 = minor;
00837         i2 = 0;
00838         i3 = major;
00839         i4 = 0;
00840     }
00841     else
00842     {
00843         i1 = 0;
00844         i2 = minor;
00845         i3 = 0;
00846         i4 = major;
00847     }
00848 
00849 // Draw the line
00850 
00851     plP_movwor( wx1, wy1 );
00852     plP_drawor( wx2, wy2 );
00853     if ( lt )
00854     {
00855         tp = tick1 * floor( vmin / tick1 );
00856         for (;; )
00857         {
00858             tn = tp + tick1;
00859             if ( ls )
00860             {
00861                 if ( ll )
00862                 {
00863                     for ( i = 0; i <= 7; i++ )
00864                     {
00865                         temp = tp + xlog[i];
00866                         if ( BETW( temp, vmin, vmax ) )
00867                         {
00868                             lambda = ( vmax_in > vmin_in ) ?
00869                                      ( temp - vmin ) / ( vmax - vmin ) :
00870                                      ( vmax - temp ) / ( vmax - vmin );
00871                             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00872                                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ),
00873                                 i1, i2 );
00874                         }
00875                     }
00876                 }
00877                 else
00878                 {
00879                     for ( i = 1; i <= nsub1 - 1; i++ )
00880                     {
00881                         temp = tp + i * ( tn - tp ) / nsub1;
00882                         if ( BETW( temp, vmin, vmax ) )
00883                         {
00884                             lambda = ( vmax_in > vmin_in ) ?
00885                                      ( temp - vmin ) / ( vmax - vmin ) :
00886                                      ( vmax - temp ) / ( vmax - vmin );
00887                             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00888                                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ),
00889                                 i1, i2 );
00890                         }
00891                     }
00892                 }
00893             }
00894             temp = tn;
00895             if ( !BETW( temp, vmin, vmax ) )
00896                 break;
00897 
00898             lambda = ( vmax_in > vmin_in ) ?
00899                      ( temp - vmin ) / ( vmax - vmin ) :
00900                      ( vmax - temp ) / ( vmax - vmin );
00901             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00902                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ), i3, i4 );
00903             tp = tn;
00904         }
00905     }
00906 
00907 
00908 // Label the line
00909 
00910     if ( ln && lt )
00911     {
00912         pldprec( vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale );
00913         pos    = 1.0;
00914         height = 3.2;
00915         tcrit  = tspace * tick1;
00916         tp     = tick1 * ( 1. + floor( vmin / tick1 ) );
00917         for ( tn = tp; BETW( tn, vmin, vmax ); tn += tick1 )
00918         {
00919             if ( BETW( tn, vmin + tcrit, vmax - tcrit ) )
00920             {
00921                 plform( axis, tn, scale, prec, string, STRING_LEN, ll, lf, lo );
00922                 pos = ( vmax_in > vmin_in ) ?
00923                       ( tn - vmin ) / ( vmax - vmin ) :
00924                       ( vmax - tn ) / ( vmax - vmin );
00925                 plxytx( wx1, wy1, wx2, wy2, 1.5, pos, 0.5, string );
00926             }
00927         }
00928         *digits = 2;
00929         if ( !ll && !lo && mode )
00930         {
00931             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) scale, esc_string );
00932             plxytx( wx1, wy1, wx2, wy2, height, 1.0, 0.5, string );
00933         }
00934     }
00935 }
00936 
00937 //--------------------------------------------------------------------------
00938 // void plxytx()
00939 //
00940 // Prints out text along a sloping axis joining world coordinates
00941 // (wx1,wy1) to (wx2,wy2). Parameters are as for plmtext.
00942 //--------------------------------------------------------------------------
00943 
00944 static void
00945 plxytx( PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
00946         PLFLT disp, PLFLT pos, PLFLT just, const char *text )
00947 {
00948     PLINT x, y, refx, refy;
00949     PLFLT shift, cc, ss, wx, wy;
00950     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
00951     PLFLT dispx, dispy;
00952     PLFLT chrdef, chrht;
00953 
00954     cc   = plsc->wmxscl * ( wx2 - wx1 );
00955     ss   = plsc->wmyscl * ( wy2 - wy1 );
00956     diag = sqrt( cc * cc + ss * ss );
00957     cc  /= diag;
00958     ss  /= diag;
00959     wx   = wx1 + pos * ( wx2 - wx1 );
00960     wy   = wy1 + pos * ( wy2 - wy1 );
00961 
00962     xform[0] = cc;
00963     xform[1] = 0.0;
00964     xform[2] = ss;
00965     xform[3] = 1.0;
00966 
00967     xdv = plP_wcdcx( wx );
00968     ydv = plP_wcdcy( wy );
00969 
00970     dispx = 0.;
00971     dispy = -disp;
00972 
00973     plgchr( &chrdef, &chrht );
00974     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
00975 
00976     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
00977     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
00978     refxmm = xmm - shift * xform[0];
00979     refymm = ymm - shift * xform[2];
00980 
00981     x    = plP_mmpcx( xmm );
00982     y    = plP_mmpcy( ymm );
00983     refx = plP_mmpcx( refxmm );
00984     refy = plP_mmpcy( refymm );
00985 
00986     plP_text( 0, just, xform, x, y, refx, refy, text );
00987 }
00988 
00989 //--------------------------------------------------------------------------
00990 // void plzbx()
00991 //
00992 // This draws a vertical line from (wx,wy1) to (wx,wy2) which represents the
00993 // vertical axis of a 3-d graph with data values from "vmin" to "vmax".
00994 // Depending on "opt", ticks and/or subticks are placed on the line at major
00995 // tick interval "tick" with "nsub" subticks between major ticks. If "tick"
00996 // and/or "nsub" is zero, automatic tick positions are computed
00997 //
00998 // b: Draws left-hand axis
00999 // c: Draws right-hand axis
01000 // f: Always use fixed point numeric labels
01001 // i: Inverts tick marks (i.e. drawn to the left)
01002 // l: Logarithmic axes, major ticks at decades, minor ticks at units
01003 // m: Write numeric label on right axis
01004 // n: Write numeric label on left axis
01005 // o: Use custom label function
01006 // s: Draw minor tick marks
01007 // t: Draw major tick marks
01008 // u: Writes left-hand label
01009 // v: Writes right-hand label
01010 //--------------------------------------------------------------------------
01011 
01012 static void
01013 plzbx( const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
01014        PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
01015        PLFLT tick, PLINT nsub, PLINT *digits )
01016 {
01017     static char string[STRING_LEN];
01018     PLINT       lb, lc, ld, lf, li, ll, lm, ln, ls, lt, lu, lv, lo;
01019     PLINT       i, mode, prec, scale;
01020     PLINT       nsub1, lstring;
01021     PLFLT       pos, tn, tp, temp, height, tick1;
01022     PLFLT       dwy, lambda, diag, major, minor, xmajor, xminor;
01023     PLFLT       ymajor, yminor, dxm, dym, vmin, vmax;
01024     const char  * esc_string = plgesc_string();
01025 
01026     vmin = ( vmax_in > vmin_in ) ? vmin_in : vmax_in;
01027     vmax = ( vmax_in > vmin_in ) ? vmax_in : vmin_in;
01028 
01029     dwy = wy2 - wy1;
01030 
01031 // Tick and subtick sizes in device coords
01032 
01033     major = plsc->majht;
01034     minor = plsc->minht;
01035 
01036     tick1 = tick;
01037     nsub1 = nsub;
01038 
01039     lb = plP_stsearch( opt, 'b' );
01040     lc = plP_stsearch( opt, 'c' );
01041     ld = plP_stsearch( opt, 'd' );
01042     lf = plP_stsearch( opt, 'f' );
01043     li = plP_stsearch( opt, 'i' );
01044     ll = plP_stsearch( opt, 'l' );
01045     lm = plP_stsearch( opt, 'm' );
01046     ln = plP_stsearch( opt, 'n' );
01047     ls = plP_stsearch( opt, 's' );
01048     lt = plP_stsearch( opt, 't' );
01049     lu = plP_stsearch( opt, 'u' );
01050     lv = plP_stsearch( opt, 'v' );
01051     lo = plP_stsearch( opt, 'o' );
01052 
01053     if ( lu && !right )
01054         plztx( "h", dx, dy, wx, wy1, wy2, 5.0, 0.5, 0.5, label );
01055 
01056     if ( lv && right )
01057         plztx( "h", dx, dy, wx, wy1, wy2, -5.0, 0.5, 0.5, label );
01058 
01059     if ( right && !lc )
01060         return;
01061 
01062     if ( !right && !lb )
01063         return;
01064 
01065     if ( ll )
01066         tick1 = 1.0;
01067 
01068     if ( lt )
01069         pldtik( vmin, vmax, &tick1, &nsub1, ld );
01070 
01071     if ( ( li && !right ) || ( !li && right ) )
01072     {
01073         minor = -minor;
01074         major = -major;
01075     }
01076 
01077     dxm  = dx * plsc->wmxscl;
01078     dym  = dy * plsc->wmyscl;
01079     diag = sqrt( dxm * dxm + dym * dym );
01080 
01081     xminor = minor * dxm / diag;
01082     xmajor = major * dxm / diag;
01083     yminor = minor * dym / diag;
01084     ymajor = major * dym / diag;
01085 
01086 // Draw the line
01087 
01088     plP_movwor( wx, wy1 );
01089     plP_drawor( wx, wy2 );
01090     if ( lt )
01091     {
01092         tp = tick1 * floor( vmin / tick1 );
01093         for (;; )
01094         {
01095             tn = tp + tick1;
01096             if ( ls )
01097             {
01098                 if ( ll )
01099                 {
01100                     for ( i = 0; i <= 7; i++ )
01101                     {
01102                         temp = tp + xlog[i];
01103                         if ( BETW( temp, vmin, vmax ) )
01104                         {
01105                             lambda = ( vmax_in > vmin_in ) ?
01106                                      ( temp - vmin ) / ( vmax - vmin ) :
01107                                      ( vmax - temp ) / ( vmax - vmin );
01108                             plstik( plP_wcmmx( wx ),
01109                                 plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01110                                 xminor, yminor );
01111                         }
01112                     }
01113                 }
01114                 else
01115                 {
01116                     for ( i = 1; i <= nsub1 - 1; i++ )
01117                     {
01118                         temp = tp + i * tick1 / nsub1;
01119                         if ( BETW( temp, vmin, vmax ) )
01120                         {
01121                             lambda = ( vmax_in > vmin_in ) ?
01122                                      ( temp - vmin ) / ( vmax - vmin ) :
01123                                      ( vmax - temp ) / ( vmax - vmin );
01124                             plstik( plP_wcmmx( wx ),
01125                                 plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01126                                 xminor, yminor );
01127                         }
01128                     }
01129                 }
01130             }
01131             temp = tn;
01132             if ( !BETW( temp, vmin, vmax ) )
01133                 break;
01134             lambda = ( vmax_in > vmin_in ) ?
01135                      ( temp - vmin ) / ( vmax - vmin ) :
01136                      ( vmax - temp ) / ( vmax - vmin );
01137             plstik( plP_wcmmx( wx ), plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01138                 xmajor, ymajor );
01139             tp = tn;
01140         }
01141     }
01142 
01143 
01144 // Label the line
01145 
01146     if ( ( ln || lm ) && lt )
01147     {
01148         pldprec( vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale );
01149         *digits = 0;
01150         tp      = tick1 * floor( vmin / tick1 );
01151         for ( tn = tp + tick1; BETW( tn, vmin, vmax ); tn += tick1 )
01152         {
01153             plform( PL_Z_AXIS, tn, scale, prec, string, STRING_LEN, ll, lf, lo );
01154             pos = ( vmax_in > vmin_in ) ?
01155                   ( tn - vmin ) / ( vmax - vmin ) :
01156                   ( vmax - tn ) / ( vmax - vmin );
01157             if ( ln && !right )
01158                 plztx( "v", dx, dy, wx, wy1, wy2, 0.5, pos, 1.0, string );
01159 
01160             if ( lm && right )
01161                 plztx( "v", dx, dy, wx, wy1, wy2, -0.5, pos, 0.0, string );
01162 
01163             lstring = (PLINT) strlen( string );
01164             *digits = MAX( *digits, lstring );
01165         }
01166         if ( !ll && !lo && mode )
01167         {
01168             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) scale, esc_string );
01169             pos    = 1.15;
01170             height = 0.5;
01171             if ( ln && !right )
01172             {
01173                 plztx( "v", dx, dy, wx, wy1, wy2, height, pos, 0.5, string );
01174             }
01175             if ( lm && right )
01176             {
01177                 plztx( "v", dx, dy, wx, wy1, wy2,
01178                     (PLFLT) -height, pos, 0.5, string );
01179             }
01180         }
01181     }
01182 }
01183 
01184 //--------------------------------------------------------------------------
01185 // void plztx()
01186 //
01187 // Prints out text along a vertical axis for a 3d plot joining
01188 // world coordinates (wx,wy1) to (wx,wy2).
01189 //--------------------------------------------------------------------------
01190 
01191 static void
01192 plztx( const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
01193        PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text )
01194 {
01195     PLINT refx = 0, refy = 0, x = 0, y = 0, vert = 0;
01196     PLFLT shift, cc, ss, wy;
01197     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
01198     PLFLT dispx, dispy;
01199     PLFLT chrdef, chrht;
01200 
01201     cc   = plsc->wmxscl * dx;
01202     ss   = plsc->wmyscl * dy;
01203     diag = sqrt( cc * cc + ss * ss );
01204     cc  /= diag;
01205     ss  /= diag;
01206     wy   = wy1 + pos * ( wy2 - wy1 );
01207 
01208     if ( plP_stsearch( opt, 'v' ) )
01209         vert = 0;
01210     else if ( plP_stsearch( opt, 'h' ) )
01211         vert = 1;
01212 
01213     if ( vert )
01214     {
01215         xform[0] = 0.0;
01216         xform[1] = -cc;
01217         xform[2] = 1.0;
01218         xform[3] = -ss;
01219     }
01220     else
01221     {
01222         xform[0] = cc;
01223         xform[1] = 0.0;
01224         xform[2] = ss;
01225         xform[3] = 1.0;
01226     }
01227 
01228     xdv = plP_wcdcx( wx );
01229     ydv = plP_wcdcy( wy );
01230 
01231     dispx = -disp * cc;
01232     dispy = -disp * ss;
01233 
01234     plgchr( &chrdef, &chrht );
01235     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
01236 
01237     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
01238     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
01239     refxmm = xmm - shift * xform[0];
01240     refymm = ymm - shift * xform[2];
01241 
01242     x    = plP_mmpcx( xmm );
01243     y    = plP_mmpcy( ymm );
01244     refx = plP_mmpcx( refxmm );
01245     refy = plP_mmpcy( refymm );
01246 
01247     plP_text( 0, just, xform, x, y, refx, refy, text );
01248 }
01249 
01250 //--------------------------------------------------------------------------
01251 // void grid_box()
01252 //
01253 // Draws grids at tick locations (major and/or minor).
01254 //
01255 // Note that 'tspace' is the minimim distance away (in fractional number
01256 // of ticks or subticks) from the boundary a grid line can be drawn.  If
01257 // you are too close, it looks bad.
01258 //--------------------------------------------------------------------------
01259 
01260 static void
01261 grid_box( const char *xopt, PLFLT xtick1, PLINT nxsub1,
01262           const char *yopt, PLFLT ytick1, PLINT nysub1 )
01263 {
01264     PLINT lgx, lhx, llx, ldx;
01265     PLINT lgy, lhy, lly, ldy;
01266     PLFLT vpwxmi, vpwxma, vpwymi, vpwyma;
01267     PLFLT vpwxmin, vpwxmax, vpwymin, vpwymax;
01268     PLFLT tn, temp, tcrit, tspace = 0.1;
01269     PLFLT tstart, factor;
01270     PLINT i;
01271 
01272 // Set plot options from input
01273 
01274     lgx = plP_stsearch( xopt, 'g' );
01275     lhx = plP_stsearch( xopt, 'h' );
01276     llx = plP_stsearch( xopt, 'l' );
01277     ldx = plP_stsearch( xopt, 'd' );
01278 
01279     lgy = plP_stsearch( yopt, 'g' );
01280     lhy = plP_stsearch( yopt, 'h' );
01281     lly = plP_stsearch( yopt, 'l' );
01282     ldy = plP_stsearch( yopt, 'd' );
01283 
01284     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
01285 // n.b. large change; vpwxmi always numerically less than vpwxma, and
01286 // similarly for vpwymi
01287     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
01288     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
01289     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
01290     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
01291 
01292 // Draw grid in x direction.
01293 
01294     if ( lgx )
01295     {
01296         if ( ldx )
01297         {
01298             pldtfac( vpwxmi, vpwxma, &factor, &tstart );
01299             tn = xtick1 * ( floor( ( vpwxmi - tstart ) / xtick1 ) ) + tstart;
01300         }
01301         else
01302         {
01303             tn = xtick1 * floor( vpwxmi / xtick1 );
01304         }
01305         for (; tn <= vpwxma; tn += xtick1 )
01306         {
01307             if ( lhx )
01308             {
01309                 if ( llx )
01310                 {
01311                     PLFLT otemp = tn;
01312                     for ( i = 0; i <= 7; i++ )
01313                     {
01314                         temp  = tn + xlog[i];
01315                         tcrit = ( temp - otemp ) * tspace;
01316                         otemp = temp;
01317                         if ( BETW( temp, vpwxmi + tcrit, vpwxma - tcrit ) )
01318                             pljoin( temp, vpwymi, temp, vpwyma );
01319                     }
01320                 }
01321                 else
01322                 {
01323                     for ( i = 1; i <= nxsub1 - 1; i++ )
01324                     {
01325                         temp  = tn + i * xtick1 / nxsub1;
01326                         tcrit = xtick1 / nxsub1 * tspace;
01327                         if ( BETW( temp, vpwxmi + tcrit, vpwxma - tcrit ) )
01328                             pljoin( temp, vpwymi, temp, vpwyma );
01329                     }
01330                 }
01331             }
01332             tcrit = xtick1 * tspace;
01333             if ( BETW( tn, vpwxmi + tcrit, vpwxma - tcrit ) )
01334                 pljoin( tn, vpwymi, tn, vpwyma );
01335         }
01336     }
01337 
01338 // Draw grid in y direction
01339 
01340     if ( lgy )
01341     {
01342         if ( ldy )
01343         {
01344             pldtfac( vpwymi, vpwyma, &factor, &tstart );
01345             tn = ytick1 * ( floor( ( vpwymi - tstart ) / ytick1 ) ) + tstart;
01346         }
01347         else
01348         {
01349             tn = ytick1 * floor( vpwymi / ytick1 );
01350         }
01351         for (; tn <= vpwyma; tn += ytick1 )
01352         {
01353             if ( lhy )
01354             {
01355                 if ( lly )
01356                 {
01357                     PLFLT otemp = tn;
01358                     for ( i = 0; i <= 7; i++ )
01359                     {
01360                         temp  = tn + xlog[i];
01361                         tcrit = ( temp - otemp ) * tspace;
01362                         otemp = temp;
01363                         if ( BETW( temp, vpwymi + tcrit, vpwyma - tcrit ) )
01364                             pljoin( vpwxmi, temp, vpwxma, temp );
01365                     }
01366                 }
01367                 else
01368                 {
01369                     for ( i = 1; i <= nysub1 - 1; i++ )
01370                     {
01371                         temp  = tn + i * ytick1 / nysub1;
01372                         tcrit = ytick1 / nysub1 * tspace;
01373                         if ( BETW( temp, vpwymi + tcrit, vpwyma - tcrit ) )
01374                             pljoin( vpwxmi, temp, vpwxma, temp );
01375                     }
01376                 }
01377             }
01378             tcrit = ytick1 * tspace;
01379             if ( BETW( tn, vpwymi + tcrit, vpwyma - tcrit ) )
01380                 pljoin( vpwxmi, tn, vpwxma, tn );
01381         }
01382     }
01383 }
01384 
01385 //--------------------------------------------------------------------------
01386 // void label_box()
01387 //
01388 // Writes numeric labels on side(s) of box.
01389 //--------------------------------------------------------------------------
01390 
01391 static void
01392 label_box( const char *xopt, PLFLT xtick1, const char *yopt, PLFLT ytick1 )
01393 {
01394     static char string[STRING_LEN];
01395     PLBOOL      ldx, lfx, lix, llx, lmx, lnx, ltx, lox, lxx;
01396     PLBOOL      ldy, lfy, liy, lly, lmy, lny, lty, lvy, loy, lxy;
01397     PLFLT       vpwxmi, vpwxma, vpwymi, vpwyma;
01398     PLFLT       vpwxmin, vpwxmax, vpwymin, vpwymax;
01399     PLFLT       tn, tp, offset;
01400     PLFLT       factor, tstart;
01401     const char  *timefmt = NULL;
01402     PLFLT       default_mm, char_height_mm, height_mm;
01403     PLFLT       string_length_mm = 0.0, pos_mm = 0.0;
01404 
01405     // Assume label data is for placement of exponents if no custom
01406     // label function is provided.
01407     PLBOOL custom_exponent_placement = !plsc->label_func && plsc->label_data;
01408 
01409     // pos, height, and just are unnecessarily set to quiet
01410     // -O3 -Wuninitialized warnings that are obvious false alarms from
01411     // the clarity of the code associated with the true or false
01412     // result for custom_exponent_placement.
01413     PLFLT      pos          = 0.0, height = 0.0, just = 0.0;
01414     const char * esc_string = plgesc_string();
01415 
01416     plgchr( &default_mm, &char_height_mm );
01417 
01418 // Set plot options from input
01419 
01420     ldx = plP_stsearch( xopt, 'd' );
01421     lfx = plP_stsearch( xopt, 'f' );
01422     lix = plP_stsearch( xopt, 'i' );
01423     llx = plP_stsearch( xopt, 'l' );
01424     lmx = plP_stsearch( xopt, 'm' );
01425     lnx = plP_stsearch( xopt, 'n' );
01426     ltx = plP_stsearch( xopt, 't' );
01427     lox = plP_stsearch( xopt, 'o' );
01428     lxx = plP_stsearch( xopt, 'x' );
01429 
01430     ldy = plP_stsearch( yopt, 'd' );
01431     lfy = plP_stsearch( yopt, 'f' );
01432     liy = plP_stsearch( yopt, 'i' );
01433     lly = plP_stsearch( yopt, 'l' );
01434     lmy = plP_stsearch( yopt, 'm' );
01435     lny = plP_stsearch( yopt, 'n' );
01436     lty = plP_stsearch( yopt, 't' );
01437     lvy = plP_stsearch( yopt, 'v' );
01438     loy = plP_stsearch( yopt, 'o' );
01439     lxy = plP_stsearch( yopt, 'x' );
01440 
01441     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
01442 // vpwxmi always numerically less than vpwxma, and
01443 // similarly for vpwymi
01444     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
01445     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
01446     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
01447     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
01448 
01449     // Write label(s) for horizontal axes.
01450     if ( ( lmx || lnx ) && ( ltx || lxx ) )
01451     {
01452         PLINT xmode, xprec, xdigmax, xdigits, xscale;
01453 
01454         plgxax( &xdigmax, &xdigits );
01455         pldprec( vpwxmi, vpwxma, xtick1, lfx, &xmode, &xprec, xdigmax, &xscale );
01456         timefmt = plP_gtimefmt();
01457 
01458         if ( ldx )
01459         {
01460             pldtfac( vpwxmi, vpwxma, &factor, &tstart );
01461             tp = xtick1 * ( 1. + floor( ( vpwxmi - tstart ) / xtick1 ) ) + tstart;
01462         }
01463         else
01464         {
01465             tp = xtick1 * ( 1. + floor( vpwxmi / xtick1 ) );
01466         }
01467         height = lix ? 1.75 : 1.5;
01468         if ( plsc->if_boxbb )
01469         {
01470             // For horizontal axes, height of zero corresponds to
01471             // character centred on edge so should add 0.5 to height
01472             // to obtain bounding box edge in direction away from
01473             // edge.  However, experimentally found 0.7 gave a better
01474             // looking result.
01475             height_mm = ( height + 0.7 ) * char_height_mm;
01476             if ( lnx )
01477                 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi /
01478                     plsc->ypmm - height_mm );
01479             if ( lmx )
01480                 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
01481                     plsc->ypmm + height_mm );
01482         }
01483 
01484         for ( tn = tp; BETW( tn, vpwxmi, vpwxma ); tn += xtick1 )
01485         {
01486             if ( ldx )
01487             {
01488                 strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
01489             }
01490             else
01491             {
01492                 plform( PL_X_AXIS, tn, xscale, xprec, string, STRING_LEN, llx, lfx, lox );
01493             }
01494             pos = ( vpwxmax > vpwxmin ) ?
01495                   ( tn - vpwxmi ) / ( vpwxma - vpwxmi ) :
01496                   ( vpwxma - tn ) / ( vpwxma - vpwxmi );
01497             if ( plsc->if_boxbb )
01498             {
01499                 string_length_mm = plstrl( string );
01500                 pos_mm           = ( plsc->vppxmi + pos *
01501                                      ( plsc->vppxma - plsc->vppxmi ) ) /
01502                                    plsc->xpmm;
01503             }
01504             if ( lnx )
01505             {
01506                 // Bottom axis.
01507                 if ( plsc->if_boxbb )
01508                 {
01509                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
01510                         pos_mm - 0.5 * string_length_mm );
01511                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
01512                         pos_mm + 0.5 * string_length_mm );
01513                 }
01514                 else
01515                 {
01516                     plmtex( "b", height, pos, 0.5, string );
01517                 }
01518             }
01519             if ( lmx )
01520             {
01521                 // Top axis.
01522                 if ( plsc->if_boxbb )
01523                 {
01524                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
01525                         pos_mm - 0.5 * string_length_mm );
01526                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
01527                         pos_mm + 0.5 * string_length_mm );
01528                 }
01529                 else
01530                 {
01531                     plmtex( "t", height, pos, 0.5, string );
01532                 }
01533             }
01534         }
01535         xdigits = 2;
01536         plsxax( xdigmax, xdigits );
01537 
01538         // Write separate exponential label if mode = 1.
01539 
01540         if ( !llx && !ldx && !lox && xmode )
01541         {
01542             if ( custom_exponent_placement )
01543             {
01544                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
01545                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
01546                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
01547             }
01548             else
01549             {
01550                 height = 3.2;
01551                 pos    = 1.0;
01552                 just   = 0.5;
01553             }
01554             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) xscale, esc_string );
01555             if ( lnx )
01556             {
01557                 // Bottom axis exponent.
01558                 if ( plsc->if_boxbb )
01559                 {
01560                     // For horizontal axes, height of zero corresponds
01561                     // to character centred on edge so should add 0.5
01562                     // to height to obtain bounding box edge in
01563                     // direction away from edge if no exponent.  Add
01564                     // an additional offset to make exponent fit.
01565                     height_mm        = ( height + 0.9 ) * char_height_mm;
01566                     plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi /
01567                         plsc->ypmm - height_mm );
01568                     string_length_mm = plstrl( string );
01569                     pos_mm           = ( plsc->vppxmi + pos *
01570                                          ( plsc->vppxma - plsc->vppxmi ) ) /
01571                                        plsc->xpmm;
01572                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
01573                         pos_mm - 0.5 * string_length_mm );
01574                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
01575                         pos_mm + 0.5 * string_length_mm );
01576                 }
01577                 else
01578                 {
01579                     plmtex( "b", height, pos, just, string );
01580                 }
01581             }
01582             if ( lmx )
01583             {
01584                 // Top axis exponent.
01585                 if ( plsc->if_boxbb )
01586                 {
01587                     // For horizontal axes, height of zero corresponds
01588                     // to character centred on edge so should add 0.5
01589                     // to height to obtain bounding box edge in
01590                     // direction away from edge if no exponent.  Add
01591                     // an additional offset to make exponent fit.
01592                     height_mm        = ( height + 1.4 ) * char_height_mm;
01593                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
01594                         plsc->ypmm + height_mm );
01595                     string_length_mm = plstrl( string );
01596                     pos_mm           = ( plsc->vppxmi + pos *
01597                                          ( plsc->vppxma - plsc->vppxmi ) ) /
01598                                        plsc->xpmm;
01599                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
01600                         pos_mm - 0.5 * string_length_mm );
01601                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
01602                         pos_mm + 0.5 * string_length_mm );
01603                 }
01604                 else
01605                 {
01606                     plmtex( "t", height, pos, just, string );
01607                 }
01608             }
01609         }
01610     }
01611 
01612     // Write label(s) for vertical axes.
01613 
01614     if ( ( lmy || lny ) && ( lty || lxy ) )
01615     {
01616         PLINT ymode, yprec, ydigmax, ydigits, yscale;
01617 
01618         plgyax( &ydigmax, &ydigits );
01619         pldprec( vpwymi, vpwyma, ytick1, lfy, &ymode, &yprec, ydigmax, &yscale );
01620 
01621         ydigits = 0;
01622         if ( ldy )
01623         {
01624             pldtfac( vpwymi, vpwyma, &factor, &tstart );
01625             tp = ytick1 * ( 1. + floor( ( vpwymi - tstart ) / ytick1 ) ) + tstart;
01626         }
01627         else
01628         {
01629             tp = ytick1 * ( 1. + floor( vpwymi / ytick1 ) );
01630         }
01631         for ( tn = tp; BETW( tn, vpwymi, vpwyma ); tn += ytick1 )
01632         {
01633             if ( ldy )
01634             {
01635                 strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
01636             }
01637             else
01638             {
01639                 plform( PL_Y_AXIS, tn, yscale, yprec, string, STRING_LEN, lly, lfy, loy );
01640             }
01641             pos = ( vpwymax > vpwymin ) ?
01642                   ( tn - vpwymi ) / ( vpwyma - vpwymi ) :
01643                   ( vpwyma - tn ) / ( vpwyma - vpwymi );
01644             if ( lny )
01645             {
01646                 if ( lvy )
01647                 {
01648                     // Left axis with text written perpendicular to edge.
01649                     height = liy ? 1.0 : 0.5;
01650                     if ( plsc->if_boxbb )
01651                     {
01652                         // For vertical axes with text written
01653                         // perpendicular to edge, height of zero
01654                         // corresponds character centred on edge so
01655                         // should add 0.5 to height to obtain bounding
01656                         // box edge in direction away from edge, and
01657                         // that value apparently works.
01658                         height_mm        = ( height + 0.0 ) * char_height_mm;
01659                         string_length_mm = plstrl( string );
01660                         plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
01661                             plsc->xpmm - height_mm - string_length_mm );
01662                         pos_mm = ( plsc->vppymi + pos *
01663                                    ( plsc->vppyma - plsc->vppymi ) ) /
01664                                  plsc->ypmm;
01665                         // Expected offset is 0.5, but adjust to improve
01666                         // look of result.
01667                         plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
01668                             pos_mm - 0.6 * char_height_mm );
01669                         plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
01670                             pos_mm + 0.7 * char_height_mm );
01671                     }
01672                     else
01673                     {
01674                         plmtex( "lv", height, pos, 1.0, string );
01675                     }
01676                 }
01677                 else
01678                 {
01679                     // Left axis with text written parallel to edge.
01680                     height = liy ? 1.75 : 1.5;
01681                     if ( plsc->if_boxbb )
01682                     {
01683                         // For vertical axes with text written
01684                         // parallel to edge, height of zero
01685                         // corresponds to character centred on edge so
01686                         // should add 0.5 to height to obtain bounding
01687                         // box edge in direction away from edge,
01688                         // However, experimentally found 0.8 gave a
01689                         // better looking result.
01690                         height_mm        = ( height + 0.8 ) * char_height_mm;
01691                         plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
01692                             plsc->xpmm - height_mm );
01693                         pos_mm = ( plsc->vppymi + pos *
01694                                    ( plsc->vppyma - plsc->vppymi ) ) /
01695                                  plsc->ypmm;
01696                         string_length_mm = plstrl( string );
01697                         plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
01698                             pos_mm - 0.5 * string_length_mm );
01699                         plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
01700                             pos_mm + 0.5 * string_length_mm );
01701                     }
01702                     else
01703                     {
01704                         plmtex( "l", height, pos, 0.5, string );
01705                     }
01706                 }
01707             }
01708             if ( lmy )
01709             {
01710                 if ( lvy )
01711                 {
01712                     // Right axis with text written perpendicular to edge.
01713                     height = liy ? 1.0 : 0.5;
01714                     if ( plsc->if_boxbb )
01715                     {
01716                         // For vertical axes with text written
01717                         // perpendicular to edge, height of zero
01718                         // corresponds character centred on edge so
01719                         // should add 0.5 to height to obtain bounding
01720                         // box edge in direction away from edge, and
01721                         // that value apparently works.
01722                         height_mm        = ( height + 0.0 ) * char_height_mm;
01723                         string_length_mm = plstrl( string );
01724                         plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
01725                             plsc->xpmm + height_mm + string_length_mm );
01726                         pos_mm = ( plsc->vppymi + pos *
01727                                    ( plsc->vppyma - plsc->vppymi ) ) /
01728                                  plsc->ypmm;
01729                         // Expected offset is 0.5, but adjust to improve
01730                         // look of result.
01731                         plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
01732                             pos_mm - 0.6 * char_height_mm );
01733                         plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
01734                             pos_mm + 0.7 * char_height_mm );
01735                     }
01736                     else
01737                     {
01738                         plmtex( "rv", height, pos, 0.0, string );
01739                     }
01740                 }
01741                 else
01742                 {
01743                     // Right axis with text written parallel to edge.
01744                     height = liy ? 1.75 : 1.5;
01745                     if ( plsc->if_boxbb )
01746                     {
01747                         // For vertical axes with text written
01748                         // parallel to edge, height of zero
01749                         // corresponds to character centred on edge so
01750                         // should add 0.5 to height to obtain bounding
01751                         // box edge in direction away from edge,
01752                         // However, experimentally found 0.8 gave a
01753                         // better looking result.
01754                         height_mm        = ( height + 0.8 ) * char_height_mm;
01755                         plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
01756                             plsc->xpmm + height_mm );
01757                         pos_mm = ( plsc->vppymi + pos *
01758                                    ( plsc->vppyma - plsc->vppymi ) ) /
01759                                  plsc->ypmm;
01760                         string_length_mm = plstrl( string );
01761                         plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
01762                             pos_mm - 0.5 * string_length_mm );
01763                         plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
01764                             pos_mm + 0.5 * string_length_mm );
01765                     }
01766                     else
01767                     {
01768                         plmtex( "r", height, pos, 0.5, string );
01769                     }
01770                 }
01771             }
01772             ydigits = MAX( ydigits, (PLINT) strlen( string ) );
01773         }
01774         if ( !lvy )
01775             ydigits = 2;
01776 
01777         plsyax( ydigmax, ydigits );
01778 
01779         // Write separate exponential label if mode = 1.
01780 
01781         if ( !lly && !ldy && !loy && ymode )
01782         {
01783             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) yscale, esc_string );
01784             if ( custom_exponent_placement )
01785             {
01786                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
01787                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
01788                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
01789             }
01790             if ( lvy )
01791             {
01792                 offset = 0.1;  // more space to clear labels in "v" mode
01793             }
01794             else
01795             {
01796                 offset = 0.02;
01797             }
01798             // Left axis exponent
01799             if ( lny )
01800             {
01801                 if ( !custom_exponent_placement )
01802                 {
01803                     height = 3.2;
01804                     pos    = 1.0 + offset;
01805                     just   = 0.5;
01806                 }
01807                 if ( plsc->if_boxbb )
01808                 {
01809                     // For horizontal axes, height of zero corresponds
01810                     // to character centred on edge so should add 0.5
01811                     // to height to obtain bounding box edge in
01812                     // direction away from edge if no exponent.  Add
01813                     // an additional offset to make exponent fit.
01814                     height_mm        = ( height + 1.4 ) * char_height_mm;
01815                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
01816                         plsc->ypmm + height_mm );
01817                     string_length_mm = plstrl( string );
01818                     pos_mm           = ( plsc->vppxmi + pos *
01819                                          ( plsc->vppxma - plsc->vppxmi ) ) /
01820                                        plsc->xpmm;
01821                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
01822                         pos_mm - string_length_mm );
01823                 }
01824                 else
01825                 {
01826                     if ( lvy )
01827                     {
01828                         plmtex( "lv", height, pos, just, string );
01829                     }
01830                     else
01831                     {
01832                         plmtex( "l", height, pos, just, string );
01833                     }
01834                 }
01835             }
01836             // Right axis exponent.
01837             if ( lmy )
01838             {
01839                 if ( !custom_exponent_placement )
01840                 {
01841                     height = 3.4;   // Extra space for superscript
01842                     pos    = 1.0 + offset;
01843                     just   = 0.5;
01844                 }
01845                 if ( plsc->if_boxbb )
01846                 {
01847                     // For horizontal axes, height of zero corresponds
01848                     // to character centred on edge so should add 0.5
01849                     // to height to obtain bounding box edge in
01850                     // direction away from edge if no exponent.  Add
01851                     // an additional offset to make exponent fit.
01852                     height_mm        = ( height + 1.4 ) * char_height_mm;
01853                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
01854                         plsc->ypmm + height_mm );
01855                     string_length_mm = plstrl( string );
01856                     pos_mm           = ( plsc->vppxmi + pos *
01857                                          ( plsc->vppxma - plsc->vppxmi ) ) /
01858                                        plsc->xpmm;
01859                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmin,
01860                         pos_mm + string_length_mm );
01861                 }
01862                 else
01863                 {
01864                     if ( lvy )
01865                     {
01866                         plmtex( "rv", height, pos, just, string );
01867                     }
01868                     else
01869                     {
01870                         plmtex( "r", height, pos, just, string );
01871                     }
01872                 }
01873             }
01874         }
01875     }
01876 }
01877 
01878 //--------------------------------------------------------------------------
01879 // void label_box_custom()
01880 //
01881 // Writes numeric labels on side(s) of box in custom locations
01882 //--------------------------------------------------------------------------
01883 
01884 void
01885 label_box_custom( const char *xopt, PLINT n_xticks, const PLFLT *xticks, const char *yopt, PLINT n_yticks, const PLFLT *yticks )
01886 {
01887     static char string[STRING_LEN];
01888     PLBOOL      ldx, lfx, lix, llx, lmx, lnx, ltx, lox, lxx;
01889     PLBOOL      ldy, lfy, liy, lly, lmy, lny, lty, lvy, loy, lxy;
01890     PLFLT       vpwxmi, vpwxma, vpwymi, vpwyma;
01891     PLFLT       vpwxmin, vpwxmax, vpwymin, vpwymax;
01892     PLFLT       tn, offset;
01893     const char  *timefmt;
01894     PLINT       i;
01895     PLINT       xdigmax, xdigits, xdigmax_old, xdigits_old;
01896     PLINT       ydigmax, ydigits, ydigmax_old, ydigits_old;
01897     PLINT       lxmin, lxmax, lymin, lymax;
01898     PLINT       pxmin, pxmax, pymin, pymax;
01899     PLFLT       default_mm, char_height_mm, height_mm;
01900     PLFLT       string_length_mm = 0.0, pos_mm = 0.0;
01901 
01902     // Assume label data is for placement of exponents if no custom
01903     // label function is provided.
01904     PLBOOL custom_exponent_placement = !plsc->label_func && plsc->label_data;
01905 
01906     // pos, height, and just are unnecessarily set to quiet
01907     // -O3 -Wuninitialized warnings that are obvious false alarms from
01908     // the clarity of the code associated with the true or false
01909     // result for custom_exponent_placement.
01910     PLFLT      pos          = 0.0, height = 0.0, just = 0.0;
01911     const char * esc_string = plgesc_string();
01912 
01913     plgchr( &default_mm, &char_height_mm );
01914 
01915     // Save some parameters
01916     plgxax( &xdigmax, &xdigits );
01917     plgyax( &ydigmax, &ydigits );
01918     xdigmax_old = xdigmax;
01919     xdigits_old = xdigits;
01920     ydigmax_old = ydigmax;
01921     ydigits_old = ydigits;
01922 
01923 // Open the clip limits to the subpage limits
01924 
01925     plP_gclp( &lxmin, &lxmax, &lymin, &lymax );
01926     plP_gphy( &pxmin, &pxmax, &pymin, &pymax );
01927     plP_sclp( pxmin, pxmax, pymin, pymax );
01928 
01929 // Set plot options from input
01930 
01931     ldx = plP_stsearch( xopt, 'd' );
01932     lfx = plP_stsearch( xopt, 'f' );
01933     lix = plP_stsearch( xopt, 'i' );
01934     llx = plP_stsearch( xopt, 'l' );
01935     lmx = plP_stsearch( xopt, 'm' );
01936     lnx = plP_stsearch( xopt, 'n' );
01937     ltx = plP_stsearch( xopt, 't' );
01938     lox = plP_stsearch( xopt, 'o' );
01939     lxx = plP_stsearch( xopt, 'x' );
01940 
01941     ldy = plP_stsearch( yopt, 'd' );
01942     lfy = plP_stsearch( yopt, 'f' );
01943     liy = plP_stsearch( yopt, 'i' );
01944     lly = plP_stsearch( yopt, 'l' );
01945     lmy = plP_stsearch( yopt, 'm' );
01946     lny = plP_stsearch( yopt, 'n' );
01947     lty = plP_stsearch( yopt, 't' );
01948     lvy = plP_stsearch( yopt, 'v' );
01949     loy = plP_stsearch( yopt, 'o' );
01950     lxy = plP_stsearch( yopt, 'x' );
01951 
01952     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
01953 // n.b. large change; vpwxmi always numerically less than vpwxma, and
01954 // similarly for vpwymi
01955     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
01956     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
01957     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
01958     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
01959 
01960     if ( plsc->if_boxbb )
01961     {
01962         PLINT xmajor = MAX( ROUND( plsc->majht * plsc->ypmm ), 1 );
01963         PLINT ymajor = MAX( ROUND( plsc->majht * plsc->xpmm ), 1 );
01964         // Bounding-box limits for the box in mm before corrections
01965         // for decorations are applied.
01966         plsc->boxbb_xmin = plsc->vppxmi / plsc->xpmm;
01967         plsc->boxbb_xmax = plsc->vppxma / plsc->xpmm;
01968         plsc->boxbb_ymin = plsc->vppymi / plsc->ypmm;
01969         plsc->boxbb_ymax = plsc->vppyma / plsc->ypmm;
01970         // Carefully follow logic below for the case where
01971         // an inverted major tick mark is written (in the X direction
01972         // for a Y axis and vice versa).  Ignore minor tick marks
01973         // which are assumed to be smaller.
01974         if ( lix && ( lmx || lnx ) && ( ltx && !lxx ) )
01975         {
01976             plsc->boxbb_ymin -= xmajor / plsc->ypmm;
01977             plsc->boxbb_ymax += xmajor / plsc->ypmm;
01978         }
01979         if ( liy && ( lmy || lny ) && ( lty && !lxy ) )
01980         {
01981             plsc->boxbb_xmin -= ymajor / plsc->xpmm;
01982             plsc->boxbb_xmax += ymajor / plsc->xpmm;
01983         }
01984     }
01985     // Write label(s) for horizontal axes.
01986 
01987     if ( ( lmx || lnx ) && ( ltx || lxx ) )
01988     {
01989         PLINT xmode, xprec, xscale;
01990         PLFLT x_spacing, x_spacing_tmp;
01991 
01992         // Determine spacing between ticks
01993         // Use the x-size of the window
01994         x_spacing = vpwxma - vpwxmi;
01995         if ( n_xticks > 1 )
01996         {
01997             // Use the smallest space between ticks
01998             for ( i = 1; i < n_xticks; i++ )
01999             {
02000                 x_spacing_tmp = fabs( xticks[i] - xticks[i - 1] );
02001                 x_spacing     = MIN( x_spacing, x_spacing_tmp );
02002             }
02003         }
02004 
02005         plgxax( &xdigmax, &xdigits );
02006         pldprec( vpwxmi, vpwxma, x_spacing, lfx, &xmode, &xprec, xdigmax, &xscale );
02007         timefmt = plP_gtimefmt();
02008 
02009         height = lix ? 1.75 : 1.5;
02010         if ( plsc->if_boxbb )
02011         {
02012             // For horizontal axes, height of zero corresponds to
02013             // character centred on edge so should add 0.5 to height
02014             // to obtain bounding box edge in direction away from
02015             // edge.  However, experimentally found 0.7 gave a better
02016             // looking result.
02017             height_mm = ( height + 0.7 ) * char_height_mm;
02018             if ( lnx )
02019                 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi /
02020                     plsc->ypmm - height_mm );
02021             if ( lmx )
02022                 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
02023                     plsc->ypmm + height_mm );
02024         }
02025         // Loop through all of the tick marks
02026         for ( i = 0; i < n_xticks; i++ )
02027         {
02028             tn = xticks[i];
02029             if ( BETW( tn, vpwxmi, vpwxma ) )
02030             {
02031                 if ( !lxx && !plsc->if_boxbb )
02032                 {
02033                     plwxtik( tn, vpwymin, FALSE, !lix );
02034                     plwxtik( tn, vpwymax, FALSE, lix );
02035                 }
02036                 if ( ldx )
02037                 {
02038                     strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
02039                 }
02040                 else
02041                 {
02042                     plform( PL_X_AXIS, tn, xscale, xprec, string, STRING_LEN, llx, lfx, lox );
02043                 }
02044                 pos = ( vpwxmax > vpwxmin ) ?
02045                       ( tn - vpwxmi ) / ( vpwxma - vpwxmi ) :
02046                       ( vpwxma - tn ) / ( vpwxma - vpwxmi );
02047                 if ( plsc->if_boxbb )
02048                 {
02049                     string_length_mm = plstrl( string );
02050                     pos_mm           = ( plsc->vppxmi + pos *
02051                                          ( plsc->vppxma - plsc->vppxmi ) ) /
02052                                        plsc->xpmm;
02053                 }
02054                 if ( lnx )
02055                 {
02056                     // Bottom axis.
02057                     if ( plsc->if_boxbb )
02058                     {
02059                         plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
02060                             pos_mm - 0.5 * string_length_mm );
02061                         plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
02062                             pos_mm + 0.5 * string_length_mm );
02063                     }
02064                     else
02065                     {
02066                         plmtex( "b", height, pos, 0.5, string );
02067                     }
02068                 }
02069                 if ( lmx )
02070                 {
02071                     // Top axis.
02072                     if ( plsc->if_boxbb )
02073                     {
02074                         plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
02075                             pos_mm - 0.5 * string_length_mm );
02076                         plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
02077                             pos_mm + 0.5 * string_length_mm );
02078                     }
02079                     else
02080                     {
02081                         plmtex( "t", height, pos, 0.5, string );
02082                     }
02083                 }
02084             }
02085         }
02086         xdigits = 2;
02087         plsxax( xdigmax, xdigits );
02088 
02089         // Write separate exponential label if mode = 1.
02090 
02091         if ( !llx && !ldx && !lox && xmode )
02092         {
02093             if ( custom_exponent_placement )
02094             {
02095                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
02096                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
02097                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
02098             }
02099             else
02100             {
02101                 height = 3.2;
02102                 pos    = 1.0;
02103                 just   = 0.5;
02104             }
02105             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) xscale, esc_string );
02106             if ( lnx )
02107             {
02108                 // Bottom axis exponent.
02109                 if ( plsc->if_boxbb )
02110                 {
02111                     // For horizontal axes, height of zero corresponds
02112                     // to character centred on edge so should add 0.5
02113                     // to height to obtain bounding box edge in
02114                     // direction away from edge if no exponent.  Add
02115                     // an additional offset to make exponent fit.
02116                     height_mm        = ( height + 0.9 ) * char_height_mm;
02117                     plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi /
02118                         plsc->ypmm - height_mm );
02119                     string_length_mm = plstrl( string );
02120                     pos_mm           = ( plsc->vppxmi + pos *
02121                                          ( plsc->vppxma - plsc->vppxmi ) ) /
02122                                        plsc->xpmm;
02123                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
02124                         pos_mm - 0.5 * string_length_mm );
02125                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
02126                         pos_mm + 0.5 * string_length_mm );
02127                 }
02128                 else
02129                 {
02130                     plmtex( "b", height, pos, just, string );
02131                 }
02132             }
02133             if ( lmx )
02134             {
02135                 // Top axis exponent.
02136                 if ( plsc->if_boxbb )
02137                 {
02138                     // For horizontal axes, height of zero corresponds
02139                     // to character centred on edge so should add 0.5
02140                     // to height to obtain bounding box edge in
02141                     // direction away from edge if no exponent.  Add
02142                     // an additional offset to make exponent fit.
02143                     height_mm        = ( height + 1.4 ) * char_height_mm;
02144                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
02145                         plsc->ypmm + height_mm );
02146                     string_length_mm = plstrl( string );
02147                     pos_mm           = ( plsc->vppxmi + pos *
02148                                          ( plsc->vppxma - plsc->vppxmi ) ) /
02149                                        plsc->xpmm;
02150                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
02151                         pos_mm - 0.5 * string_length_mm );
02152                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmax,
02153                         pos_mm + 0.5 * string_length_mm );
02154                 }
02155                 else
02156                 {
02157                     plmtex( "t", height, pos, just, string );
02158                 }
02159             }
02160         }
02161     }
02162 
02163     // Write label(s) for vertical axes.
02164     if ( ( lmy || lny ) && ( lty || lxy ) )
02165     {
02166         PLINT ymode, yprec, yscale;
02167         PLFLT y_spacing, y_spacing_tmp;
02168 
02169         // Determine spacing between ticks
02170         // Use the y-size of the window
02171         y_spacing = vpwyma - vpwymi;
02172         if ( n_yticks > 1 )
02173         {
02174             // Use the smallest space between ticks
02175             for ( i = 1; i < n_yticks; i++ )
02176             {
02177                 y_spacing_tmp = fabs( yticks[i] - yticks[i - 1] );
02178                 y_spacing     = MIN( y_spacing, y_spacing_tmp );
02179             }
02180         }
02181 
02182         plgyax( &ydigmax, &ydigits );
02183         pldprec( vpwymi, vpwyma, y_spacing, lfy, &ymode, &yprec, ydigmax, &yscale );
02184         timefmt = plP_gtimefmt();
02185 
02186         ydigits = 0;
02187         for ( i = 0; i < n_yticks; i++ )
02188         {
02189             tn = yticks[i];
02190             if ( BETW( tn, vpwymi, vpwyma ) )
02191             {
02192                 if ( !lxy && !plsc->if_boxbb )
02193                 {
02194                     plwytik( vpwxmin, tn, FALSE, !liy );
02195                     plwytik( vpwxmax, tn, FALSE, liy );
02196                 }
02197                 if ( ldy )
02198                 {
02199                     strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
02200                 }
02201                 else
02202                 {
02203                     plform( PL_Y_AXIS, tn, yscale, yprec, string, STRING_LEN, lly, lfy, loy );
02204                 }
02205                 pos = ( vpwymax > vpwymin ) ?
02206                       ( tn - vpwymi ) / ( vpwyma - vpwymi ) :
02207                       ( vpwyma - tn ) / ( vpwyma - vpwymi );
02208                 if ( lny )
02209                 {
02210                     if ( lvy )
02211                     {
02212                         // Left axis with text written perpendicular to edge.
02213                         height = liy ? 1.0 : 0.5;
02214                         if ( plsc->if_boxbb )
02215                         {
02216                             // For vertical axes with text written
02217                             // perpendicular to edge, height of zero
02218                             // corresponds character centred on edge so
02219                             // should add 0.5 to height to obtain bounding
02220                             // box edge in direction away from edge, and
02221                             // that value apparently works.
02222                             height_mm        = ( height + 0.0 ) * char_height_mm;
02223                             string_length_mm = plstrl( string );
02224                             plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
02225                                 plsc->xpmm - height_mm - string_length_mm );
02226                             pos_mm = ( plsc->vppymi + pos *
02227                                        ( plsc->vppyma - plsc->vppymi ) ) /
02228                                      plsc->ypmm;
02229                             // Expected offset is 0.5, but adjust to improve
02230                             // look of result.
02231                             plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
02232                                 pos_mm - 0.6 * char_height_mm );
02233                             plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
02234                                 pos_mm + 0.7 * char_height_mm );
02235                         }
02236                         else
02237                         {
02238                             plmtex( "lv", height, pos, 1.0, string );
02239                         }
02240                     }
02241                     else
02242                     {
02243                         // Left axis with text written parallel to edge.
02244                         height = liy ? 1.75 : 1.5;
02245                         if ( plsc->if_boxbb )
02246                         {
02247                             // For vertical axes with text written
02248                             // parallel to edge, height of zero
02249                             // corresponds to character centred on edge so
02250                             // should add 0.5 to height to obtain bounding
02251                             // box edge in direction away from edge,
02252                             // However, experimentally found 0.8 gave a
02253                             // better looking result.
02254                             height_mm        = ( height + 0.8 ) * char_height_mm;
02255                             plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi /
02256                                 plsc->xpmm - height_mm );
02257                             pos_mm = ( plsc->vppymi + pos *
02258                                        ( plsc->vppyma - plsc->vppymi ) ) /
02259                                      plsc->ypmm;
02260                             string_length_mm = plstrl( string );
02261                             plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
02262                                 pos_mm - 0.5 * string_length_mm );
02263                             plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
02264                                 pos_mm + 0.5 * string_length_mm );
02265                         }
02266                         else
02267                         {
02268                             plmtex( "l", height, pos, 0.5, string );
02269                         }
02270                     }
02271                 }
02272                 if ( lmy )
02273                 {
02274                     if ( lvy )
02275                     {
02276                         // Right axis with text written perpendicular to edge.
02277                         height = liy ? 1.0 : 0.5;
02278                         if ( plsc->if_boxbb )
02279                         {
02280                             // For vertical axes with text written
02281                             // perpendicular to edge, height of zero
02282                             // corresponds character centred on edge so
02283                             // should add 0.5 to height to obtain bounding
02284                             // box edge in direction away from edge, and
02285                             // that value apparently works.
02286                             height_mm        = ( height + 0.0 ) * char_height_mm;
02287                             string_length_mm = plstrl( string );
02288                             plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
02289                                 plsc->xpmm + height_mm + string_length_mm );
02290                             pos_mm = ( plsc->vppymi + pos *
02291                                        ( plsc->vppyma - plsc->vppymi ) ) /
02292                                      plsc->ypmm;
02293                             // Expected offset is 0.5, but adjust to improve
02294                             // look of result.
02295                             plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
02296                                 pos_mm - 0.6 * char_height_mm );
02297                             plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
02298                                 pos_mm + 0.7 * char_height_mm );
02299                         }
02300                         else
02301                         {
02302                             plmtex( "rv", height, pos, 0.0, string );
02303                         }
02304                     }
02305                     else
02306                     {
02307                         // Right axis with text written parallel to edge.
02308                         height = liy ? 1.75 : 1.5;
02309                         if ( plsc->if_boxbb )
02310                         {
02311                             // For vertical axes with text written
02312                             // parallel to edge, height of zero
02313                             // corresponds to character centred on edge so
02314                             // should add 0.5 to height to obtain bounding
02315                             // box edge in direction away from edge,
02316                             // However, experimentally found 0.8 gave a
02317                             // better looking result.
02318                             height_mm        = ( height + 0.8 ) * char_height_mm;
02319                             plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma /
02320                                 plsc->xpmm + height_mm );
02321                             pos_mm = ( plsc->vppymi + pos *
02322                                        ( plsc->vppyma - plsc->vppymi ) ) /
02323                                      plsc->ypmm;
02324                             string_length_mm = plstrl( string );
02325                             plsc->boxbb_ymin = MIN( plsc->boxbb_ymin,
02326                                 pos_mm - 0.5 * string_length_mm );
02327                             plsc->boxbb_ymax = MAX( plsc->boxbb_ymax,
02328                                 pos_mm + 0.5 * string_length_mm );
02329                         }
02330                         else
02331                         {
02332                             plmtex( "r", height, pos, 0.5, string );
02333                         }
02334                     }
02335                 }
02336                 ydigits = MAX( ydigits, (PLINT) strlen( string ) );
02337             }
02338         }
02339         if ( !lvy )
02340             ydigits = 2;
02341 
02342         plsyax( ydigmax, ydigits );
02343 
02344         // Write separate exponential label if mode = 1.
02345 
02346         if ( !lly && !ldy && !loy && ymode )
02347         {
02348             snprintf( string, STRING_LEN, "(x10%su%d%sd)", esc_string, (int) yscale, esc_string );
02349             if ( custom_exponent_placement )
02350             {
02351                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
02352                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
02353                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
02354             }
02355             if ( lvy )
02356             {
02357                 offset = 0.1;  // more space to clear labels in "v" mode
02358             }
02359             else
02360             {
02361                 offset = 0.02;
02362             }
02363             // Left axis exponent.
02364             if ( lny )
02365             {
02366                 if ( !custom_exponent_placement )
02367                 {
02368                     height = 3.2;
02369                     pos    = 1.0 + offset;
02370                     just   = 0.5;
02371                 }
02372                 if ( plsc->if_boxbb )
02373                 {
02374                     // For horizontal axes, height of zero corresponds
02375                     // to character centred on edge so should add 0.5
02376                     // to height to obtain bounding box edge in
02377                     // direction away from edge if no exponent.  Add
02378                     // an additional offset to make exponent fit.
02379                     height_mm        = ( height + 1.4 ) * char_height_mm;
02380                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
02381                         plsc->ypmm + height_mm );
02382                     string_length_mm = plstrl( string );
02383                     pos_mm           = ( plsc->vppxmi + pos *
02384                                          ( plsc->vppxma - plsc->vppxmi ) ) /
02385                                        plsc->xpmm;
02386                     plsc->boxbb_xmin = MIN( plsc->boxbb_xmin,
02387                         pos_mm - string_length_mm );
02388                 }
02389                 else
02390                 {
02391                     if ( lvy )
02392                     {
02393                         plmtex( "lv", height, pos, just, string );
02394                     }
02395                     else
02396                     {
02397                         plmtex( "l", height, pos, just, string );
02398                     }
02399                 }
02400             }
02401             // Right axis exponent.
02402             if ( lmy )
02403             {
02404                 if ( !custom_exponent_placement )
02405                 {
02406                     height = 3.4;   // Extra space for superscript
02407                     pos    = 1.0 + offset;
02408                     just   = 0.5;
02409                 }
02410                 if ( plsc->if_boxbb )
02411                 {
02412                     // For horizontal axes, height of zero corresponds
02413                     // to character centred on edge so should add 0.5
02414                     // to height to obtain bounding box edge in
02415                     // direction away from edge if no exponent.  Add
02416                     // an additional offset to make exponent fit.
02417                     height_mm        = ( height + 1.4 ) * char_height_mm;
02418                     plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma /
02419                         plsc->ypmm + height_mm );
02420                     string_length_mm = plstrl( string );
02421                     pos_mm           = ( plsc->vppxmi + pos *
02422                                          ( plsc->vppxma - plsc->vppxmi ) ) /
02423                                        plsc->xpmm;
02424                     plsc->boxbb_xmax = MAX( plsc->boxbb_xmin,
02425                         pos_mm + string_length_mm );
02426                 }
02427                 else
02428                 {
02429                     if ( lvy )
02430                     {
02431                         plmtex( "rv", height, pos, just, string );
02432                     }
02433                     else
02434                     {
02435                         plmtex( "r", height, pos, just, string );
02436                     }
02437                 }
02438             }
02439         }
02440     }
02441 
02442     // Restore saved parameters
02443     plsxax( xdigmax_old, xdigits_old );
02444     plsyax( ydigmax_old, ydigits_old );
02445 
02446     // Restore the clip limits to viewport edge
02447     plP_sclp( lxmin, lxmax, lymin, lymax );
02448 }
02449 
02450 //--------------------------------------------------------------------------
02451 //
02452 // Default labeling functions for PLplot
02453 //
02454 // These are the functions which are used internally by PLplot under various
02455 // conditions.
02456 //
02457 // They have been separated out for use in other PLplot functions and
02458 // potential exposure in the PLplot API.
02459 //
02460 //--------------------------------------------------------------------------
02461 void plP_default_label_log( PLINT PL_UNUSED( axis ), PLFLT value, char *string, PLINT len, void * PL_UNUSED( data ) )
02462 {
02463     const char * esc_string = plgesc_string();
02464     // Exponential, i.e. 10^-1, 10^0, 10^1, etc
02465     snprintf( string, (size_t) len, "10%su%d", esc_string, (int) ROUND( value ) );
02466 }
02467 
02468 void plP_default_label_log_fixed( PLINT PL_UNUSED( axis ), PLFLT value, char *string, PLINT len, void * PL_UNUSED( data ) )
02469 {
02470     // Fixed point, i.e. .1, 1, 10, etc
02471 
02472     int exponent = ROUND( value );
02473 
02474     value = pow( 10.0, exponent );
02475     if ( exponent < 0 )
02476     {
02477         char form[FORMAT_LEN];
02478         snprintf( form, FORMAT_LEN, "%%.%df", ABS( exponent ) );
02479         snprintf( string, (size_t) len, form, value );
02480     }
02481     else
02482     {
02483         snprintf( string, (size_t) len, "%d", (int) value );
02484     }
02485 }
02486 
02487 void plP_default_label( PLINT PL_UNUSED( axis ), PLFLT value, char *string, PLINT len, void *data )
02488 {
02489     PLINT  scale, prec;
02490     PLINT  setpre, precis;
02491     char   form[FORMAT_LEN], temp[TEMP_LEN];
02492     double scale2;
02493 
02494     scale = ( (PLINT *) data )[0];
02495     prec  = ( (PLINT *) data )[1];
02496 
02497     plP_gprec( &setpre, &precis );
02498 
02499     if ( setpre )
02500         prec = precis;
02501 
02502     if ( scale )
02503         value /= pow( 10., (double) scale );
02504 
02505     // This is necessary to prevent labels like "-0.0" on some systems
02506 
02507     scale2 = pow( 10., prec );
02508     value  = floor( ( value * scale2 ) + .5 ) / scale2;
02509 
02510     snprintf( form, FORMAT_LEN, "%%.%df", (int) prec );
02511     snprintf( temp, TEMP_LEN, form, value );
02512     strncpy( string, temp, (size_t) ( len - 1 ) );
02513     string[len - 1] = '\0';
02514 }
02515 
02516 //--------------------------------------------------------------------------
02517 // void plform()
02518 //
02519 // Formats a PLFLT value in one of the following formats.
02520 //
02521 // If ll (logarithmic), then:
02522 //
02523 //    - If lf (fixed), then used fixed point notation, i.e. .1, 1, 10, etc,
02524 //      with unnecessary trailing .'s or 0's removed.
02525 //
02526 //    - If !lf (default), then use exponential notation, i.e. 10^-1, etc.
02527 //
02528 // If !ll (linear), then:
02529 //
02530 //    - If scale == 0, use fixed point format with "prec" places after the
02531 //      decimal point.
02532 //
02533 //    - If scale == 1, use scientific notation with one place before the
02534 //      decimal point and "prec" places after.  In this case, the value
02535 //      must be divided by 10^scale.
02536 //
02537 // The axis argument is included to support PLplot's custom axis labeling.  It
02538 // is passed on to the custom labeling function if it exists.  Otherwise, it
02539 // is ignored.
02540 //--------------------------------------------------------------------------
02541 
02542 static void
02543 plform( PLINT axis, PLFLT value, PLINT scale, PLINT prec, char *string, PLINT len, PLBOOL ll, PLBOOL lf, PLBOOL lo )
02544 {
02545     // Check to see if a custom labeling function is defined.  If not,
02546     // use default.
02547     if ( lo && plsc->label_func )
02548     {
02549         ( *plsc->label_func )( axis, value, string, len, plsc->label_data );
02550     }
02551     else
02552     {
02553         if ( lo )
02554         {
02555             plwarn( "Custom axis labels requested without a labeling function \
02556                     - using default." );
02557         }
02558         if ( ll )
02559         {
02560             // Logarithmic
02561 
02562             if ( lf )
02563             {
02564                 // Fixed point, i.e. .1, 1, 10, etc
02565                 plP_default_label_log_fixed( axis, value, string, len, NULL );
02566             }
02567             else
02568             {
02569                 // Exponential, i.e. 10^-1, 10^0, 10^1, etc
02570                 plP_default_label_log( axis, value, string, len, NULL );
02571             }
02572         }
02573         else
02574         {
02575             // Linear
02576             PLINT scale_prec[2] = { scale, prec };
02577             plP_default_label( axis, value, string, len, (void *) scale_prec );
02578         }
02579     }
02580 }
02581 
02582 //--------------------------------------------------------------------------
02583 // plslabelfunc
02584 //
02585 // Formats a PLFLT value in one of the following formats.
02586 //
02587 // label_func - A pointer to a function which will provide a string to use
02588 //              as the label for the given floating point value.
02589 //              Pass this as NULL to clear the custom function and reset it to
02590 //              the default PLplot labeling function.
02591 //
02592 // label_data - Extra data to pass to the label function.
02593 //
02594 // The label_func function arguments are, in order:
02595 //
02596 // axis: PL_X_AXIS, PL_Y_AXIS or PL_Z_AXIS to indicate which axis is being
02597 //       labeled
02598 // value: The value at this position on the axis
02599 // string: The resulting label string should be stored here
02600 // data: A pointer to whatever extra information the custom plotting function
02601 //       requires
02602 //
02603 //--------------------------------------------------------------------------
02604 void
02605 c_plslabelfunc( void ( *label_func )( PLINT, PLFLT, char *, PLINT, PLPointer ), PLPointer label_data )
02606 {
02607     plsc->label_func = label_func;
02608     plsc->label_data = label_data;
02609 }
02610 
02611 static const char *
02612 plgesc_string( void )
02613 {
02614     static const char *esc_strings = { "!\0#\0$\0%\0&\0*\0@\0^\0~\0" };
02615     int d;
02616     // Follow plgesc logic here which is to set the default escape
02617     // if plsc->esc is in its initial state.
02618     if ( plsc->esc == '\0' )
02619         plsc->esc = '#';
02620 
02621     switch ( plsc->esc )
02622     {
02623     case '!':
02624         d = 0;
02625         break;
02626     case '#':
02627         d = 1;
02628         break;
02629     case '$':
02630         d = 2;
02631         break;
02632     case '%':
02633         d = 3;
02634         break;
02635     case '&':
02636         d = 4;
02637         break;
02638     case '*':
02639         d = 5;
02640         break;
02641     case '@':
02642         d = 6;
02643         break;
02644     case '^':
02645         d = 7;
02646         break;
02647     case '~':
02648         d = 8;
02649         break;
02650     default:
02651         plwarn( "plgesc_string: Invalid escape character, assuming '#' instead" );
02652         d = 1;
02653         break;
02654     }
02655     return &( esc_strings[d * 2] );
02656 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines