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

plbox.c

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

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