PLplot 5.9.6
plbox.c
00001 /* $Id$
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 General Library 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) edge of frame
00097  * c: Draw top (X) or right (Y) edge of frame
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  * v: (for Y only) Label vertically
00110  *
00111  * xtick, ytick are the major tick intervals required, zero for
00112  * automatic selection
00113  *
00114  * nxsub, nysub are the number of subtick intervals in a major tick
00115  * interval
00116  \*--------------------------------------------------------------------------*/
00117 
00118 void
00119 c_plaxes( PLFLT x0, PLFLT y0,
00120           const char *xopt, PLFLT xtick, PLINT nxsub,
00121           const char *yopt, PLFLT ytick, PLINT nysub )
00122 {
00123     PLBOOL lax, lbx, lcx, ldx, lgx, lix, llx, lsx, ltx;
00124     PLBOOL lay, lby, lcy, ldy, lgy, liy, lly, lsy, lty;
00125     PLINT  xmajor, xminor, ymajor, yminor;
00126     PLINT  i, i1x, i2x, i3x, i4x, i1y, i2y, i3y, i4y;
00127     PLINT  nxsub1, nysub1;
00128     PLINT  lxmin, lxmax, lymin, lymax;
00129     PLINT  pxmin, pxmax, pymin, pymax;
00130     PLINT  vppxmi, vppxma, vppymi, vppyma;
00131     PLFLT  xtick1, ytick1, vpwxmi, vpwxma, vpwymi, vpwyma;
00132     PLFLT  vpwxmin, vpwxmax, vpwymin, vpwymax;
00133     PLFLT  xp0, yp0, tn, tp, temp;
00134     PLFLT  factor, tstart;
00135 
00136     if ( plsc->level < 3 )
00137     {
00138         plabort( "plbox: Please set up window first" );
00139         return;
00140     }
00141 
00142 /* Open the clip limits to the subpage limits */
00143 
00144     plP_gclp( &lxmin, &lxmax, &lymin, &lymax );
00145     plP_gphy( &pxmin, &pxmax, &pymin, &pymax );
00146     plP_sclp( pxmin, pxmax, pymin, pymax );
00147 
00148     vppxmi = plsc->vppxmi;
00149     vppxma = plsc->vppxma;
00150     vppymi = plsc->vppymi;
00151     vppyma = plsc->vppyma;
00152 
00153 /* Convert world coordinates to physical */
00154 
00155     xp0 = plP_wcpcx( x0 );
00156     yp0 = plP_wcpcy( y0 );
00157 
00158 /* Set plot options from input */
00159 
00160     lax = plP_stsearch( xopt, 'a' );
00161     lbx = plP_stsearch( xopt, 'b' );
00162     lcx = plP_stsearch( xopt, 'c' );
00163     ldx = plP_stsearch( xopt, 'd' );
00164     lgx = plP_stsearch( xopt, 'g' );
00165     lix = plP_stsearch( xopt, 'i' );
00166     llx = plP_stsearch( xopt, 'l' );
00167     lsx = plP_stsearch( xopt, 's' );
00168     ltx = plP_stsearch( xopt, 't' );
00169 
00170     lay = plP_stsearch( yopt, 'a' );
00171     lby = plP_stsearch( yopt, 'b' );
00172     lcy = plP_stsearch( yopt, 'c' );
00173     ldy = plP_stsearch( yopt, 'd' );
00174     lgy = plP_stsearch( yopt, 'g' );
00175     liy = plP_stsearch( yopt, 'i' );
00176     lly = plP_stsearch( yopt, 'l' );
00177     lsy = plP_stsearch( yopt, 's' );
00178     lty = plP_stsearch( yopt, 't' );
00179 
00180 /* Tick and subtick sizes in device coords */
00181 
00182     xmajor = MAX( ROUND( plsc->majht * plsc->ypmm ), 1 );
00183     ymajor = MAX( ROUND( plsc->majht * plsc->xpmm ), 1 );
00184     xminor = MAX( ROUND( plsc->minht * plsc->ypmm ), 1 );
00185     yminor = MAX( ROUND( plsc->minht * plsc->xpmm ), 1 );
00186 
00187     nxsub1 = nxsub;
00188     nysub1 = nysub;
00189     xtick1 = llx ? 1.0 : xtick;
00190     ytick1 = lly ? 1.0 : ytick;
00191 
00192     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
00193 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
00194  * similarly for vpwymi */
00195     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
00196     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
00197     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
00198     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
00199 
00200     lax = lax && vpwymi < y0 && y0 < vpwyma;
00201     lay = lay && vpwxmi < x0 && x0 < vpwxma;
00202 
00203 /* Calculate tick spacing */
00204 
00205     if ( ltx || lgx )
00206         pldtik( vpwxmi, vpwxma, &xtick1, &nxsub1, ldx );
00207 
00208     if ( lty || lgy )
00209         pldtik( vpwymi, vpwyma, &ytick1, &nysub1, ldy );
00210 /* n.b. large change; xtick1, nxsub1, ytick1, nysub1 always positive. */
00211 
00212 /* Set up tick variables */
00213 
00214     if ( lix )
00215     {
00216         i1x = xminor;
00217         i2x = 0;
00218         i3x = xmajor;
00219         i4x = 0;
00220     }
00221     else
00222     {
00223         i1x = 0;
00224         i2x = xminor;
00225         i3x = 0;
00226         i4x = xmajor;
00227     }
00228 
00229     if ( liy )
00230     {
00231         i1y = yminor;
00232         i2y = 0;
00233         i3y = ymajor;
00234         i4y = 0;
00235     }
00236     else
00237     {
00238         i1y = 0;
00239         i2y = yminor;
00240         i3y = 0;
00241         i4y = ymajor;
00242     }
00243 
00244 /* Draw the bottom edge of the box */
00245 
00246     if ( lbx )
00247     {
00248         plP_movphy( vppxmi, vppymi );
00249         plP_draphy( vppxma, vppymi );
00250         if ( ltx )
00251         {
00252             if ( ldx )
00253             {
00254                 pldtfac( vpwxmi, vpwxma, &factor, &tstart );
00255                 tp = xtick1 * ( floor( ( vpwxmi - tstart ) / xtick1 ) ) + tstart;
00256             }
00257             else
00258                 tp = xtick1 * floor( vpwxmi / xtick1 );
00259             for (;; )
00260             {
00261                 tn = tp + xtick1;
00262                 if ( lsx )
00263                 {
00264                     if ( llx )
00265                     {
00266                         for ( i = 0; i <= 7; i++ )
00267                         {
00268                             temp = tp + xlog[i];
00269                             if ( BETW( temp, vpwxmi, vpwxma ) )
00270                                 plxtik( plP_wcpcx( temp ), vppymi, i1x, i2x );
00271                         }
00272                     }
00273                     else
00274                     {
00275                         for ( i = 1; i <= nxsub1 - 1; i++ )
00276                         {
00277                             temp = tp + i * xtick1 / nxsub1;
00278                             if ( BETW( temp, vpwxmi, vpwxma ) )
00279                                 plxtik( plP_wcpcx( temp ), vppymi, i1x, i2x );
00280                         }
00281                     }
00282                 }
00283                 if ( !BETW( tn, vpwxmi, vpwxma ) )
00284                     break;
00285                 plxtik( plP_wcpcx( tn ), vppymi, i3x, i4x );
00286                 tp = tn;
00287             }
00288         }
00289     }
00290 
00291 /* Draw right-hand edge of box */
00292 
00293     if ( lcy )
00294     {
00295         plP_movphy( vppxma, vppymi );
00296         plP_draphy( vppxma, vppyma );
00297         if ( lty )
00298         {
00299             if ( ldy )
00300             {
00301                 pldtfac( vpwymi, vpwyma, &factor, &tstart );
00302                 tp = ytick1 * ( floor( ( vpwymi - tstart ) / ytick1 ) ) + tstart;
00303             }
00304             else
00305                 tp = ytick1 * floor( vpwymi / ytick1 );
00306             for (;; )
00307             {
00308                 tn = tp + ytick1;
00309                 if ( lsy )
00310                 {
00311                     if ( lly )
00312                     {
00313                         for ( i = 0; i <= 7; i++ )
00314                         {
00315                             temp = tp + xlog[i];
00316                             if ( BETW( temp, vpwymi, vpwyma ) )
00317                                 plytik( vppxma, plP_wcpcy( temp ), i2y, i1y );
00318                         }
00319                     }
00320                     else
00321                     {
00322                         for ( i = 1; i <= nysub1 - 1; i++ )
00323                         {
00324                             temp = tp + i * ytick1 / nysub1;
00325                             if ( BETW( temp, vpwymi, vpwyma ) )
00326                                 plytik( vppxma, plP_wcpcy( temp ), i2y, i1y );
00327                         }
00328                     }
00329                 }
00330                 if ( !BETW( tn, vpwymi, vpwyma ) )
00331                     break;
00332                 plytik( vppxma, plP_wcpcy( tn ), i4y, i3y );
00333                 tp = tn;
00334             }
00335         }
00336     }
00337 
00338 /* Draw the top edge of the box */
00339 
00340     if ( lcx )
00341     {
00342         plP_movphy( vppxma, vppyma );
00343         plP_draphy( vppxmi, vppyma );
00344         if ( ltx )
00345         {
00346             if ( ldx )
00347             {
00348                 pldtfac( vpwxmi, vpwxma, &factor, &tstart );
00349                 tp = xtick1 * ( floor( ( vpwxma - tstart ) / xtick1 ) + 1 ) + tstart;
00350             }
00351             else
00352                 tp = xtick1 * ( floor( vpwxma / xtick1 ) + 1 );
00353             for (;; )
00354             {
00355                 tn = tp - xtick1;
00356                 if ( lsx )
00357                 {
00358                     if ( llx )
00359                     {
00360                         for ( i = 7; i >= 0; i-- )
00361                         {
00362                             temp = tn + xlog[i];
00363                             if ( BETW( temp, vpwxmi, vpwxma ) )
00364                                 plxtik( plP_wcpcx( temp ), vppyma, i2x, i1x );
00365                         }
00366                     }
00367                     else
00368                     {
00369                         for ( i = nxsub1 - 1; i >= 1; i-- )
00370                         {
00371                             temp = tn + i * xtick1 / nxsub1;
00372                             if ( BETW( temp, vpwxmi, vpwxma ) )
00373                                 plxtik( plP_wcpcx( temp ), vppyma, i2x, i1x );
00374                         }
00375                     }
00376                 }
00377                 if ( !BETW( tn, vpwxmi, vpwxma ) )
00378                     break;
00379                 plxtik( plP_wcpcx( tn ), vppyma, i4x, i3x );
00380                 tp = tn;
00381             }
00382         }
00383     }
00384 
00385 /* Draw left-hand edge of box */
00386 
00387     if ( lby )
00388     {
00389         plP_movphy( vppxmi, vppyma );
00390         plP_draphy( vppxmi, vppymi );
00391         if ( lty )
00392         {
00393             if ( ldy )
00394             {
00395                 pldtfac( vpwymi, vpwyma, &factor, &tstart );
00396                 tp = ytick1 * ( floor( ( vpwymi - tstart ) / ytick1 ) + 1 ) + tstart;
00397             }
00398             else
00399                 tp = ytick1 * ( floor( vpwyma / ytick1 ) + 1 );
00400             for (;; )
00401             {
00402                 tn = tp - ytick1;
00403                 if ( lsy )
00404                 {
00405                     if ( lly )
00406                     {
00407                         for ( i = 7; i >= 0; i-- )
00408                         {
00409                             temp = tn + xlog[i];
00410                             if ( BETW( temp, vpwymi, vpwyma ) )
00411                                 plytik( vppxmi, plP_wcpcy( temp ), i1y, i2y );
00412                         }
00413                     }
00414                     else
00415                     {
00416                         for ( i = nysub1 - 1; i >= 1; i-- )
00417                         {
00418                             temp = tn + i * ytick1 / nysub1;
00419                             if ( BETW( temp, vpwymi, vpwyma ) )
00420                                 plytik( vppxmi, plP_wcpcy( temp ), i1y, i2y );
00421                         }
00422                     }
00423                 }
00424                 if ( !BETW( tn, vpwymi, vpwyma ) )
00425                     break;
00426                 plytik( vppxmi, plP_wcpcy( tn ), i3y, i4y );
00427                 tp = tn;
00428             }
00429         }
00430     }
00431 
00432 /* Draw the horizontal axis */
00433 
00434     if ( lax )
00435     {
00436         plP_movphy( vppxmi, (PLINT) yp0 );
00437         plP_draphy( vppxma, (PLINT) yp0 );
00438         if ( ltx )
00439         {
00440             tp = xtick1 * floor( vpwxmi / xtick1 );
00441             for (;; )
00442             {
00443                 tn = tp + xtick1;
00444                 if ( lsx )
00445                 {
00446                     if ( llx )
00447                     {
00448                         for ( i = 0; i <= 7; i++ )
00449                         {
00450                             temp = tp + xlog[i];
00451                             if ( BETW( temp, vpwxmi, vpwxma ) )
00452                                 plxtik( plP_wcpcx( temp ), (PLINT) yp0, xminor, xminor );
00453                         }
00454                     }
00455                     else
00456                     {
00457                         for ( i = 1; i <= nxsub1 - 1; i++ )
00458                         {
00459                             temp = tp + i * xtick1 / nxsub1;
00460                             if ( BETW( temp, vpwxmi, vpwxma ) )
00461                                 plxtik( plP_wcpcx( temp ), (PLINT) yp0, xminor, xminor );
00462                         }
00463                     }
00464                 }
00465                 if ( !BETW( tn, vpwxmi, vpwxma ) )
00466                     break;
00467                 plxtik( plP_wcpcx( tn ), (PLINT) yp0, xmajor, xmajor );
00468                 tp = tn;
00469             }
00470         }
00471     }
00472 
00473 /* Draw the vertical axis */
00474 
00475     if ( lay )
00476     {
00477         plP_movphy( (PLINT) xp0, vppymi );
00478         plP_draphy( (PLINT) xp0, vppyma );
00479         if ( lty )
00480         {
00481             tp = ytick1 * floor( vpwymi / ytick1 );
00482             for (;; )
00483             {
00484                 tn = tp + ytick1;
00485                 if ( lsy )
00486                 {
00487                     if ( lly )
00488                     {
00489                         for ( i = 0; i <= 7; i++ )
00490                         {
00491                             temp = tp + xlog[i];
00492                             if ( BETW( temp, vpwymi, vpwyma ) )
00493                                 plytik( (PLINT) xp0, plP_wcpcy( temp ), yminor, yminor );
00494                         }
00495                     }
00496                     else
00497                     {
00498                         for ( i = 1; i <= nysub1 - 1; i++ )
00499                         {
00500                             temp = tp + i * ytick1 / nysub1;
00501                             if ( BETW( temp, vpwymi, vpwyma ) )
00502                                 plytik( (PLINT) xp0, plP_wcpcy( temp ), yminor, yminor );
00503                         }
00504                     }
00505                 }
00506                 if ( !BETW( tn, vpwymi, vpwyma ) )
00507                     break;
00508                 plytik( (PLINT) xp0, plP_wcpcy( tn ), ymajor, ymajor );
00509                 tp = tn;
00510             }
00511         }
00512     }
00513 
00514 /* Draw grids */
00515 
00516     grid_box( xopt, xtick1, nxsub1, yopt, ytick1, nysub1 );
00517 
00518 /* Write labels */
00519 
00520     label_box( xopt, xtick1, yopt, ytick1 );
00521 
00522 /* Restore the clip limits to viewport edge */
00523 
00524     plP_sclp( lxmin, lxmax, lymin, lymax );
00525 }
00526 
00527 /*--------------------------------------------------------------------------*\
00528  * void plbox3()
00529  *
00530  * This is the 3-d analogue of plbox().
00531  \*--------------------------------------------------------------------------*/
00532 
00533 void
00534 c_plbox3( const char *xopt, const char *xlabel, PLFLT xtick, PLINT nsubx,
00535           const char *yopt, const char *ylabel, PLFLT ytick, PLINT nsuby,
00536           const char *zopt, const char *zlabel, PLFLT ztick, PLINT nsubz )
00537 {
00538     PLFLT dx, dy, tx, ty, ux, uy;
00539     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00540     PLFLT cxx, cxy, cyx, cyy, cyz;
00541     PLINT ln;
00542     PLINT *zbflg, *zbcol, *zbwidth;
00543     PLFLT *zbtck;
00544     PLINT xdigmax, xdigits;
00545     PLINT ydigmax, ydigits;
00546     PLINT zdigmax, zdigits;
00547 
00548     if ( plsc->level < 3 )
00549     {
00550         plabort( "plbox3: Please set up window first" );
00551         return;
00552     }
00553 
00554     plP_gw3wc( &cxx, &cxy, &cyx, &cyy, &cyz );
00555     plP_gdom( &xmin, &xmax, &ymin, &ymax );
00556     plP_grange( &zscale, &zmin, &zmax );
00557 
00558     plgxax( &xdigmax, &xdigits );
00559     plgyax( &ydigmax, &ydigits );
00560     plgzax( &zdigmax, &zdigits );
00561 
00562     xdigits = xdigmax;
00563     ydigits = ydigmax;
00564     zdigits = zdigmax;
00565 
00566 /* We have to wait until after the plot is drawn to draw back */
00567 /* grid so store this stuff. */
00568 
00569     plP_gzback( &zbflg, &zbcol, &zbtck, &zbwidth );
00570     *zbflg = plP_stsearch( zopt, 'd' );
00571     if ( *zbflg )
00572     {
00573         *zbtck   = ztick;       /* save tick spacing */
00574         *zbcol   = plsc->icol0; /* and color */
00575         *zbwidth = plsc->width; /* and line width */
00576     }
00577 
00578     if ( cxx >= 0.0 && cxy <= 0.0 )
00579     {
00580         ln = plP_stsearch( xopt, 'n' );
00581         tx = plP_w3wcx( xmin, ymin, zmin );
00582         ty = plP_w3wcy( xmin, ymin, zmin );
00583         ux = plP_w3wcx( xmax, ymin, zmin );
00584         uy = plP_w3wcy( xmax, ymin, zmin );
00585         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00586             xmin, xmax, xtick, nsubx, 0, &xdigits );
00587 
00588         dx = ux - tx;
00589         dy = uy - ty;
00590         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00591             plP_w3wcy( xmax, ymin, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00592 
00593         tx = plP_w3wcx( xmin, ymax, zmin );
00594         ty = plP_w3wcy( xmin, ymax, zmin );
00595         ux = plP_w3wcx( xmin, ymin, zmin );
00596         uy = plP_w3wcy( xmin, ymin, zmin );
00597         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00598             ymax, ymin, ytick, nsuby, ln, &ydigits );
00599 
00600         dx = ux - tx;
00601         dy = uy - ty;
00602 /* restore zdigits to initial value for second call */
00603         zdigits = zdigmax;
00604         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00605             plP_w3wcy( xmin, ymax, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00606     }
00607     else if ( cxx <= 0.0 && cxy <= 0.0 )
00608     {
00609         ln = plP_stsearch( yopt, 'n' );
00610         tx = plP_w3wcx( xmin, ymax, zmin );
00611         ty = plP_w3wcy( xmin, ymax, zmin );
00612         ux = plP_w3wcx( xmin, ymin, zmin );
00613         uy = plP_w3wcy( xmin, ymin, zmin );
00614         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00615             ymax, ymin, ytick, nsuby, 0, &ydigits );
00616 
00617         dx = ux - tx;
00618         dy = uy - ty;
00619         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00620             plP_w3wcy( xmin, ymin, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00621 
00622         tx = plP_w3wcx( xmax, ymax, zmin );
00623         ty = plP_w3wcy( xmax, ymax, zmin );
00624         ux = plP_w3wcx( xmin, ymax, zmin );
00625         uy = plP_w3wcy( xmin, ymax, zmin );
00626         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00627             xmax, xmin, xtick, nsubx, ln, &xdigits );
00628 
00629         dx = ux - tx;
00630         dy = uy - ty;
00631 /* restore zdigits to initial value for second call */
00632         zdigits = zdigmax;
00633         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00634             plP_w3wcy( xmax, ymax, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00635     }
00636     else if ( cxx <= 0.0 && cxy >= 0.0 )
00637     {
00638         ln = plP_stsearch( xopt, 'n' );
00639         tx = plP_w3wcx( xmax, ymax, zmin );
00640         ty = plP_w3wcy( xmax, ymax, zmin );
00641         ux = plP_w3wcx( xmin, ymax, zmin );
00642         uy = plP_w3wcy( xmin, ymax, zmin );
00643         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00644             xmax, xmin, xtick, nsubx, 0, &xdigits );
00645 
00646         dx = ux - tx;
00647         dy = uy - ty;
00648         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00649             plP_w3wcy( xmin, ymax, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00650 
00651         tx = plP_w3wcx( xmax, ymin, zmin );
00652         ty = plP_w3wcy( xmax, ymin, zmin );
00653         ux = plP_w3wcx( xmax, ymax, zmin );
00654         uy = plP_w3wcy( xmax, ymax, zmin );
00655         plxybx( yopt, ylabel, PL_Y_AXIS, tx, ty, ux, uy,
00656             ymin, ymax, ytick, nsuby, ln, &ydigits );
00657 
00658         dx = ux - tx;
00659         dy = uy - ty;
00660 /* restore zdigits to initial value for second call */
00661         zdigits = zdigmax;
00662         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00663             plP_w3wcy( xmax, ymin, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00664     }
00665     else if ( cxx >= 0.0 && cxy >= 0.0 )
00666     {
00667         ln = plP_stsearch( yopt, 'n' );
00668         tx = plP_w3wcx( xmax, ymin, zmin );
00669         ty = plP_w3wcy( xmax, ymin, zmin );
00670         ux = plP_w3wcx( xmax, ymax, zmin );
00671         uy = plP_w3wcy( xmax, ymax, zmin );
00672         plxybx( yopt, ylabel, PL_X_AXIS, tx, ty, ux, uy,
00673             ymin, ymax, ytick, nsuby, 0, &ydigits );
00674 
00675         dx = ux - tx;
00676         dy = uy - ty;
00677         plzbx( zopt, zlabel, 1, dx, dy, ux, uy,
00678             plP_w3wcy( xmax, ymax, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00679 
00680         tx = plP_w3wcx( xmin, ymin, zmin );
00681         ty = plP_w3wcy( xmin, ymin, zmin );
00682         ux = plP_w3wcx( xmax, ymin, zmin );
00683         uy = plP_w3wcy( xmax, ymin, zmin );
00684         plxybx( xopt, xlabel, PL_X_AXIS, tx, ty, ux, uy,
00685             xmin, xmax, xtick, nsubx, ln, &xdigits );
00686 
00687         dx = ux - tx;
00688         dy = uy - ty;
00689 /* restore zdigits to initial value for second call */
00690         zdigits = zdigmax;
00691         plzbx( zopt, zlabel, 0, dx, dy, tx, ty,
00692             plP_w3wcy( xmin, ymin, zmax ), zmin, zmax, ztick, nsubz, &zdigits );
00693     }
00694     plsxax( xdigmax, xdigits );
00695     plsyax( ydigmax, ydigits );
00696     plszax( zdigmax, zdigits );
00697 }
00698 
00699 /*--------------------------------------------------------------------------*\
00700  * Support routines for 3d box draw.
00701  \*--------------------------------------------------------------------------*/
00702 
00703 /*--------------------------------------------------------------------------*\
00704  * void plxybx()
00705  *
00706  * This draws a sloping line from (wx1,wy1) to (wx2,wy2) which represents an
00707  * axis of a 3-d graph with data values from "vmin" to "vmax". Depending on
00708  * "opt", vertical ticks and/or subticks are placed on the line at major tick
00709  * interval "tick" with "nsub" subticks between major ticks. If "tick" and/or
00710  * "nsub" is zero, automatic tick positions are computed
00711  *
00712  * b: Draw box boundary
00713  * f: Always use fixed point numeric labels
00714  * i: Inverts tick marks (i.e. drawn downwards)
00715  * l: Logarithmic axes, major ticks at decades, minor ticks at units
00716  * n: Write numeric label
00717  * o: Use custom label function
00718  * t: Draw major tick marks
00719  * s: Draw minor tick marks
00720  * u: Write label on line
00721  \*--------------------------------------------------------------------------*/
00722 
00723 static void
00724 plxybx( const char *opt, const char *label, PLINT axis, PLFLT wx1, PLFLT wy1,
00725         PLFLT wx2, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
00726         PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits )
00727 {
00728     static char string[STRING_LEN];
00729     PLINT       lb, ld, lf, li, ll, ln, ls, lt, lu, lo;
00730     PLINT       major, minor, mode, prec, scale;
00731     PLINT       i, i1, i2, i3, i4;
00732     PLINT       nsub1;
00733     PLFLT       pos, tn, tp, temp, height, tick1, vmin, vmax;
00734 /* Note that 'tspace' is the minimim distance away (in fractional number
00735  * of ticks) from the boundary that an X or Y numerical label can be drawn. */
00736     PLFLT dwx, dwy, lambda, tcrit, tspace = 0.1;
00737 
00738     vmin = ( vmax_in > vmin_in ) ? vmin_in : vmax_in;
00739     vmax = ( vmax_in > vmin_in ) ? vmax_in : vmin_in;
00740 
00741     dwx = wx2 - wx1;
00742     dwy = wy2 - wy1;
00743 
00744 /* Tick and subtick sizes in device coords */
00745 
00746     major = MAX( ROUND( plsc->majht * plsc->ypmm ), 1 );
00747     minor = MAX( ROUND( plsc->minht * plsc->ypmm ), 1 );
00748 
00749     tick1 = tick;
00750     nsub1 = nsub;
00751 
00752     lb = plP_stsearch( opt, 'b' );
00753     ld = plP_stsearch( opt, 'd' );
00754     lf = plP_stsearch( opt, 'f' );
00755     li = plP_stsearch( opt, 'i' );
00756     ll = plP_stsearch( opt, 'l' );
00757     ln = plP_stsearch( opt, 'n' );
00758     ls = plP_stsearch( opt, 's' );
00759     lt = plP_stsearch( opt, 't' );
00760     lu = plP_stsearch( opt, 'u' );
00761     lo = plP_stsearch( opt, 'o' );
00762 
00763     if ( lu )
00764         plxytx( wx1, wy1, wx2, wy2, 3.2, 0.5, 0.5, label );
00765     if ( !lb )
00766         return;
00767 
00768     if ( ll )
00769         tick1 = ( vmax > vmin ) ? 1.0 : -1.0;
00770     if ( lt )
00771         pldtik( vmin, vmax, &tick1, &nsub1, ld );
00772 
00773     if ( li )
00774     {
00775         i1 = minor;
00776         i2 = 0;
00777         i3 = major;
00778         i4 = 0;
00779     }
00780     else
00781     {
00782         i1 = 0;
00783         i2 = minor;
00784         i3 = 0;
00785         i4 = major;
00786     }
00787 
00788 /* Draw the line */
00789 
00790     plP_movwor( wx1, wy1 );
00791     plP_drawor( wx2, wy2 );
00792     if ( lt )
00793     {
00794         tp = tick1 * floor( vmin / tick1 );
00795         for (;; )
00796         {
00797             tn = tp + tick1;
00798             if ( ls )
00799             {
00800                 if ( ll )
00801                 {
00802                     for ( i = 0; i <= 7; i++ )
00803                     {
00804                         temp = tp + xlog[i];
00805                         if ( BETW( temp, vmin, vmax ) )
00806                         {
00807                             lambda = ( vmax_in > vmin_in ) ?
00808                                      ( temp - vmin ) / ( vmax - vmin ) :
00809                                      ( vmax - temp ) / ( vmax - vmin );
00810                             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00811                                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ),
00812                                 i1, i2 );
00813                         }
00814                     }
00815                 }
00816                 else
00817                 {
00818                     for ( i = 1; i <= nsub1 - 1; i++ )
00819                     {
00820                         temp = tp + i * ( tn - tp ) / nsub1;
00821                         if ( BETW( temp, vmin, vmax ) )
00822                         {
00823                             lambda = ( vmax_in > vmin_in ) ?
00824                                      ( temp - vmin ) / ( vmax - vmin ) :
00825                                      ( vmax - temp ) / ( vmax - vmin );
00826                             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00827                                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ),
00828                                 i1, i2 );
00829                         }
00830                     }
00831                 }
00832             }
00833             temp = tn;
00834             if ( !BETW( temp, vmin, vmax ) )
00835                 break;
00836 
00837             lambda = ( vmax_in > vmin_in ) ?
00838                      ( temp - vmin ) / ( vmax - vmin ) :
00839                      ( vmax - temp ) / ( vmax - vmin );
00840             plxtik( plP_wcpcx( (PLFLT) ( wx1 + lambda * dwx ) ),
00841                 plP_wcpcy( (PLFLT) ( wy1 + lambda * dwy ) ), i3, i4 );
00842             tp = tn;
00843         }
00844     }
00845 
00846 
00847 /* Label the line */
00848 
00849     if ( ln && lt )
00850     {
00851         pldprec( vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale );
00852         pos    = 1.0;
00853         height = 3.2;
00854         tcrit  = tspace * tick1;
00855         tp     = tick1 * ( 1. + floor( vmin / tick1 ) );
00856         for ( tn = tp; BETW( tn, vmin, vmax ); tn += tick1 )
00857         {
00858             if ( BETW( tn, vmin + tcrit, vmax - tcrit ) )
00859             {
00860                 plform( axis, tn, scale, prec, string, STRING_LEN, ll, lf, lo );
00861                 pos = ( vmax_in > vmin_in ) ?
00862                       ( tn - vmin ) / ( vmax - vmin ) :
00863                       ( vmax - tn ) / ( vmax - vmin );
00864                 plxytx( wx1, wy1, wx2, wy2, 1.5, pos, 0.5, string );
00865             }
00866         }
00867         *digits = 2;
00868         if ( !ll && !lo && mode )
00869         {
00870             snprintf( string, STRING_LEN, "(x10#u%d#d)", (int) scale );
00871             plxytx( wx1, wy1, wx2, wy2, height, 1.0, 0.5, string );
00872         }
00873     }
00874 }
00875 
00876 /*--------------------------------------------------------------------------*\
00877  * void plxytx()
00878  *
00879  * Prints out text along a sloping axis joining world coordinates
00880  * (wx1,wy1) to (wx2,wy2). Parameters are as for plmtext.
00881  \*--------------------------------------------------------------------------*/
00882 
00883 static void
00884 plxytx( PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
00885         PLFLT disp, PLFLT pos, PLFLT just, const char *text )
00886 {
00887     PLINT x, y, refx, refy;
00888     PLFLT shift, cc, ss, wx, wy;
00889     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
00890     PLFLT dispx, dispy;
00891     PLFLT chrdef, chrht;
00892 
00893     cc   = plsc->wmxscl * ( wx2 - wx1 );
00894     ss   = plsc->wmyscl * ( wy2 - wy1 );
00895     diag = sqrt( cc * cc + ss * ss );
00896     cc  /= diag;
00897     ss  /= diag;
00898     wx   = wx1 + pos * ( wx2 - wx1 );
00899     wy   = wy1 + pos * ( wy2 - wy1 );
00900 
00901     xform[0] = cc;
00902     xform[1] = 0.0;
00903     xform[2] = ss;
00904     xform[3] = 1.0;
00905 
00906     xdv = plP_wcdcx( wx );
00907     ydv = plP_wcdcy( wy );
00908 
00909     dispx = 0.;
00910     dispy = -disp;
00911 
00912     plgchr( &chrdef, &chrht );
00913     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
00914 
00915     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
00916     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
00917     refxmm = xmm - shift * xform[0];
00918     refymm = ymm - shift * xform[2];
00919 
00920     x    = plP_mmpcx( xmm );
00921     y    = plP_mmpcy( ymm );
00922     refx = plP_mmpcx( refxmm );
00923     refy = plP_mmpcy( refymm );
00924 
00925     plP_text( 0, just, xform, x, y, refx, refy, text );
00926 }
00927 
00928 /*--------------------------------------------------------------------------*\
00929  * void plzbx()
00930  *
00931  * This draws a vertical line from (wx,wy1) to (wx,wy2) which represents the
00932  * vertical axis of a 3-d graph with data values from "vmin" to "vmax".
00933  * Depending on "opt", ticks and/or subticks are placed on the line at major
00934  * tick interval "tick" with "nsub" subticks between major ticks. If "tick"
00935  * and/or "nsub" is zero, automatic tick positions are computed
00936  *
00937  * b: Draws left-hand axis
00938  * c: Draws right-hand axis
00939  * f: Always use fixed point numeric labels
00940  * i: Inverts tick marks (i.e. drawn to the left)
00941  * l: Logarithmic axes, major ticks at decades, minor ticks at units
00942  * m: Write numeric label on right axis
00943  * n: Write numeric label on left axis
00944  * o: Use custom label function
00945  * s: Draw minor tick marks
00946  * t: Draw major tick marks
00947  * u: Writes left-hand label
00948  * v: Writes right-hand label
00949  \*--------------------------------------------------------------------------*/
00950 
00951 static void
00952 plzbx( const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
00953        PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
00954        PLFLT tick, PLINT nsub, PLINT *digits )
00955 {
00956     static char string[STRING_LEN];
00957     PLINT       lb, lc, ld, lf, li, ll, lm, ln, ls, lt, lu, lv, lo;
00958     PLINT       i, mode, prec, scale;
00959     PLINT       nsub1, lstring;
00960     PLFLT       pos, tn, tp, temp, height, tick1;
00961     PLFLT       dwy, lambda, diag, major, minor, xmajor, xminor;
00962     PLFLT       ymajor, yminor, dxm, dym, vmin, vmax;
00963 
00964     vmin = ( vmax_in > vmin_in ) ? vmin_in : vmax_in;
00965     vmax = ( vmax_in > vmin_in ) ? vmax_in : vmin_in;
00966 
00967     dwy = wy2 - wy1;
00968 
00969 /* Tick and subtick sizes in device coords */
00970 
00971     major = plsc->majht;
00972     minor = plsc->minht;
00973 
00974     tick1 = tick;
00975     nsub1 = nsub;
00976 
00977     lb = plP_stsearch( opt, 'b' );
00978     lc = plP_stsearch( opt, 'c' );
00979     ld = plP_stsearch( opt, 'd' );
00980     lf = plP_stsearch( opt, 'f' );
00981     li = plP_stsearch( opt, 'i' );
00982     ll = plP_stsearch( opt, 'l' );
00983     lm = plP_stsearch( opt, 'm' );
00984     ln = plP_stsearch( opt, 'n' );
00985     ls = plP_stsearch( opt, 's' );
00986     lt = plP_stsearch( opt, 't' );
00987     lu = plP_stsearch( opt, 'u' );
00988     lv = plP_stsearch( opt, 'v' );
00989     lo = plP_stsearch( opt, 'o' );
00990 
00991     if ( lu && !right )
00992         plztx( "h", dx, dy, wx, wy1, wy2, 5.0, 0.5, 0.5, label );
00993 
00994     if ( lv && right )
00995         plztx( "h", dx, dy, wx, wy1, wy2, -5.0, 0.5, 0.5, label );
00996 
00997     if ( right && !lc )
00998         return;
00999 
01000     if ( !right && !lb )
01001         return;
01002 
01003     if ( ll )
01004         tick1 = 1.0;
01005 
01006     if ( lt )
01007         pldtik( vmin, vmax, &tick1, &nsub1, ld );
01008 
01009     if ( ( li && !right ) || ( !li && right ) )
01010     {
01011         minor = -minor;
01012         major = -major;
01013     }
01014 
01015     dxm  = dx * plsc->wmxscl;
01016     dym  = dy * plsc->wmyscl;
01017     diag = sqrt( dxm * dxm + dym * dym );
01018 
01019     xminor = minor * dxm / diag;
01020     xmajor = major * dxm / diag;
01021     yminor = minor * dym / diag;
01022     ymajor = major * dym / diag;
01023 
01024 /* Draw the line */
01025 
01026     plP_movwor( wx, wy1 );
01027     plP_drawor( wx, wy2 );
01028     if ( lt )
01029     {
01030         tp = tick1 * floor( vmin / tick1 );
01031         for (;; )
01032         {
01033             tn = tp + tick1;
01034             if ( ls )
01035             {
01036                 if ( ll )
01037                 {
01038                     for ( i = 0; i <= 7; i++ )
01039                     {
01040                         temp = tp + xlog[i];
01041                         if ( BETW( temp, vmin, vmax ) )
01042                         {
01043                             lambda = ( vmax_in > vmin_in ) ?
01044                                      ( temp - vmin ) / ( vmax - vmin ) :
01045                                      ( vmax - temp ) / ( vmax - vmin );
01046                             plstik( plP_wcmmx( wx ),
01047                                 plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01048                                 xminor, yminor );
01049                         }
01050                     }
01051                 }
01052                 else
01053                 {
01054                     for ( i = 1; i <= nsub1 - 1; i++ )
01055                     {
01056                         temp = tp + i * tick1 / nsub1;
01057                         if ( BETW( temp, vmin, vmax ) )
01058                         {
01059                             lambda = ( vmax_in > vmin_in ) ?
01060                                      ( temp - vmin ) / ( vmax - vmin ) :
01061                                      ( vmax - temp ) / ( vmax - vmin );
01062                             plstik( plP_wcmmx( wx ),
01063                                 plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01064                                 xminor, yminor );
01065                         }
01066                     }
01067                 }
01068             }
01069             temp = tn;
01070             if ( !BETW( temp, vmin, vmax ) )
01071                 break;
01072             lambda = ( vmax_in > vmin_in ) ?
01073                      ( temp - vmin ) / ( vmax - vmin ) :
01074                      ( vmax - temp ) / ( vmax - vmin );
01075             plstik( plP_wcmmx( wx ), plP_wcmmy( (PLFLT) ( wy1 + lambda * dwy ) ),
01076                 xmajor, ymajor );
01077             tp = tn;
01078         }
01079     }
01080 
01081 
01082 /* Label the line */
01083 
01084     if ( ( ln || lm ) && lt )
01085     {
01086         pldprec( vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale );
01087         *digits = 0;
01088         tp      = tick1 * floor( vmin / tick1 );
01089         for ( tn = tp + tick1; BETW( tn, vmin, vmax ); tn += tick1 )
01090         {
01091             plform( PL_Z_AXIS, tn, scale, prec, string, STRING_LEN, ll, lf, lo );
01092             pos = ( vmax_in > vmin_in ) ?
01093                   ( tn - vmin ) / ( vmax - vmin ) :
01094                   ( vmax - tn ) / ( vmax - vmin );
01095             if ( ln && !right )
01096                 plztx( "v", dx, dy, wx, wy1, wy2, 0.5, pos, 1.0, string );
01097 
01098             if ( lm && right )
01099                 plztx( "v", dx, dy, wx, wy1, wy2, -0.5, pos, 0.0, string );
01100 
01101             lstring = strlen( string );
01102             *digits = MAX( *digits, lstring );
01103         }
01104         if ( !ll && !lo && mode )
01105         {
01106             snprintf( string, STRING_LEN, "(x10#u%d#d)", (int) scale );
01107             pos    = 1.15;
01108             height = 0.5;
01109             if ( ln && !right )
01110             {
01111                 plztx( "v", dx, dy, wx, wy1, wy2, height, pos, 0.5, string );
01112             }
01113             if ( lm && right )
01114             {
01115                 plztx( "v", dx, dy, wx, wy1, wy2,
01116                     (PLFLT) -height, pos, 0.5, string );
01117             }
01118         }
01119     }
01120 }
01121 
01122 /*--------------------------------------------------------------------------*\
01123  * void plztx()
01124  *
01125  * Prints out text along a vertical axis for a 3d plot joining
01126  * world coordinates (wx,wy1) to (wx,wy2).
01127  \*--------------------------------------------------------------------------*/
01128 
01129 static void
01130 plztx( const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
01131        PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text )
01132 {
01133     PLINT refx = 0, refy = 0, x = 0, y = 0, vert = 0;
01134     PLFLT shift, cc, ss, wy;
01135     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
01136     PLFLT dispx, dispy;
01137     PLFLT chrdef, chrht;
01138 
01139     cc   = plsc->wmxscl * dx;
01140     ss   = plsc->wmyscl * dy;
01141     diag = sqrt( cc * cc + ss * ss );
01142     cc  /= diag;
01143     ss  /= diag;
01144     wy   = wy1 + pos * ( wy2 - wy1 );
01145 
01146     if ( plP_stsearch( opt, 'v' ) )
01147         vert = 0;
01148     else if ( plP_stsearch( opt, 'h' ) )
01149         vert = 1;
01150 
01151     if ( vert )
01152     {
01153         xform[0] = 0.0;
01154         xform[1] = -cc;
01155         xform[2] = 1.0;
01156         xform[3] = -ss;
01157     }
01158     else
01159     {
01160         xform[0] = cc;
01161         xform[1] = 0.0;
01162         xform[2] = ss;
01163         xform[3] = 1.0;
01164     }
01165 
01166     xdv = plP_wcdcx( wx );
01167     ydv = plP_wcdcy( wy );
01168 
01169     dispx = -disp * cc;
01170     dispy = -disp * ss;
01171 
01172     plgchr( &chrdef, &chrht );
01173     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
01174 
01175     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
01176     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
01177     refxmm = xmm - shift * xform[0];
01178     refymm = ymm - shift * xform[2];
01179 
01180     x    = plP_mmpcx( xmm );
01181     y    = plP_mmpcy( ymm );
01182     refx = plP_mmpcx( refxmm );
01183     refy = plP_mmpcy( refymm );
01184 
01185     plP_text( 0, just, xform, x, y, refx, refy, text );
01186 }
01187 
01188 /*--------------------------------------------------------------------------*\
01189  * void grid_box()
01190  *
01191  * Draws grids at tick locations (major and/or minor).
01192  *
01193  * Note that 'tspace' is the minimim distance away (in fractional number
01194  * of ticks or subticks) from the boundary a grid line can be drawn.  If
01195  * you are too close, it looks bad.
01196  \*--------------------------------------------------------------------------*/
01197 
01198 static void
01199 grid_box( const char *xopt, PLFLT xtick1, PLINT nxsub1,
01200           const char *yopt, PLFLT ytick1, PLINT nysub1 )
01201 {
01202     PLINT lgx, lhx, llx;
01203     PLINT lgy, lhy, lly;
01204     PLFLT vpwxmi, vpwxma, vpwymi, vpwyma;
01205     PLFLT vpwxmin, vpwxmax, vpwymin, vpwymax;
01206     PLFLT tn, temp, tcrit, tspace = 0.1;
01207     PLINT i;
01208 
01209 /* Set plot options from input */
01210 
01211     lgx = plP_stsearch( xopt, 'g' );
01212     lhx = plP_stsearch( xopt, 'h' );
01213     llx = plP_stsearch( xopt, 'l' );
01214 
01215     lgy = plP_stsearch( yopt, 'g' );
01216     lhy = plP_stsearch( yopt, 'h' );
01217     lly = plP_stsearch( yopt, 'l' );
01218 
01219     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
01220 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
01221  * similarly for vpwymi */
01222     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
01223     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
01224     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
01225     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
01226 
01227 /* Draw grid in x direction. */
01228 
01229     if ( lgx )
01230     {
01231         for ( tn = xtick1 * floor( vpwxmi / xtick1 );
01232               tn <= vpwxma; tn += xtick1 )
01233         {
01234             if ( lhx )
01235             {
01236                 if ( llx )
01237                 {
01238                     PLFLT otemp = tn;
01239                     for ( i = 0; i <= 7; i++ )
01240                     {
01241                         temp  = tn + xlog[i];
01242                         tcrit = ( temp - otemp ) * tspace;
01243                         otemp = temp;
01244                         if ( BETW( temp, vpwxmi + tcrit, vpwxma - tcrit ) )
01245                             pljoin( temp, vpwymi, temp, vpwyma );
01246                     }
01247                 }
01248                 else
01249                 {
01250                     for ( i = 1; i <= nxsub1 - 1; i++ )
01251                     {
01252                         temp  = tn + i * xtick1 / nxsub1;
01253                         tcrit = xtick1 / nxsub1 * tspace;
01254                         if ( BETW( temp, vpwxmi + tcrit, vpwxma - tcrit ) )
01255                             pljoin( temp, vpwymi, temp, vpwyma );
01256                     }
01257                 }
01258             }
01259             tcrit = xtick1 * tspace;
01260             if ( BETW( tn, vpwxmi + tcrit, vpwxma - tcrit ) )
01261                 pljoin( tn, vpwymi, tn, vpwyma );
01262         }
01263     }
01264 
01265 /* Draw grid in y direction */
01266 
01267     if ( lgy )
01268     {
01269         tn = ytick1 * floor( vpwymi / ytick1 + tspace );
01270         for ( tn = ytick1 * floor( vpwymi / ytick1 );
01271               tn <= vpwyma; tn += ytick1 )
01272         {
01273             if ( lhy )
01274             {
01275                 if ( lly )
01276                 {
01277                     PLFLT otemp = tn;
01278                     for ( i = 0; i <= 7; i++ )
01279                     {
01280                         temp  = tn + xlog[i];
01281                         tcrit = ( temp - otemp ) * tspace;
01282                         otemp = temp;
01283                         if ( BETW( temp, vpwymi + tcrit, vpwyma - tcrit ) )
01284                             pljoin( vpwxmi, temp, vpwxma, temp );
01285                     }
01286                 }
01287                 else
01288                 {
01289                     for ( i = 1; i <= nysub1 - 1; i++ )
01290                     {
01291                         temp  = tn + i * ytick1 / nysub1;
01292                         tcrit = ytick1 / nysub1 * tspace;
01293                         if ( BETW( temp, vpwymi + tcrit, vpwyma - tcrit ) )
01294                             pljoin( vpwxmi, temp, vpwxma, temp );
01295                     }
01296                 }
01297             }
01298             tcrit = ytick1 * tspace;
01299             if ( BETW( tn, vpwymi + tcrit, vpwyma - tcrit ) )
01300                 pljoin( vpwxmi, tn, vpwxma, tn );
01301         }
01302     }
01303 }
01304 
01305 /*--------------------------------------------------------------------------*\
01306  * void label_box()
01307  *
01308  * Writes numeric labels on side(s) of box.
01309  \*--------------------------------------------------------------------------*/
01310 
01311 static void
01312 label_box( const char *xopt, PLFLT xtick1, const char *yopt, PLFLT ytick1 )
01313 {
01314     static char string[STRING_LEN];
01315     PLBOOL      ldx, lfx, lix, llx, lmx, lnx, ltx, lox;
01316     PLBOOL      ldy, lfy, liy, lly, lmy, lny, lty, lvy, loy;
01317     PLFLT       vpwxmi, vpwxma, vpwymi, vpwyma;
01318     PLFLT       vpwxmin, vpwxmax, vpwymin, vpwymax;
01319     PLFLT       pos, tn, tp, offset, height, just;
01320     PLFLT       factor, tstart;
01321     const char  *timefmt;
01322 
01323 /* Set plot options from input */
01324 
01325     ldx = plP_stsearch( xopt, 'd' );
01326     lfx = plP_stsearch( xopt, 'f' );
01327     lix = plP_stsearch( xopt, 'i' );
01328     llx = plP_stsearch( xopt, 'l' );
01329     lmx = plP_stsearch( xopt, 'm' );
01330     lnx = plP_stsearch( xopt, 'n' );
01331     ltx = plP_stsearch( xopt, 't' );
01332     lox = plP_stsearch( xopt, 'o' );
01333 
01334     ldy = plP_stsearch( yopt, 'd' );
01335     lfy = plP_stsearch( yopt, 'f' );
01336     liy = plP_stsearch( yopt, 'i' );
01337     lly = plP_stsearch( yopt, 'l' );
01338     lmy = plP_stsearch( yopt, 'm' );
01339     lny = plP_stsearch( yopt, 'n' );
01340     lty = plP_stsearch( yopt, 't' );
01341     lvy = plP_stsearch( yopt, 'v' );
01342     loy = plP_stsearch( yopt, 'o' );
01343 
01344     plP_xgvpw( &vpwxmin, &vpwxmax, &vpwymin, &vpwymax );
01345 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
01346  * similarly for vpwymi */
01347     vpwxmi = ( vpwxmax > vpwxmin ) ? vpwxmin : vpwxmax;
01348     vpwxma = ( vpwxmax > vpwxmin ) ? vpwxmax : vpwxmin;
01349     vpwymi = ( vpwymax > vpwymin ) ? vpwymin : vpwymax;
01350     vpwyma = ( vpwymax > vpwymin ) ? vpwymax : vpwymin;
01351 
01352 /* Write horizontal label(s) */
01353 
01354     if ( ( lmx || lnx ) && ltx )
01355     {
01356         PLINT xmode, xprec, xdigmax, xdigits, xscale;
01357 
01358         plgxax( &xdigmax, &xdigits );
01359         pldprec( vpwxmi, vpwxma, xtick1, lfx, &xmode, &xprec, xdigmax, &xscale );
01360         timefmt = plP_gtimefmt();
01361 
01362         if ( ldx )
01363         {
01364             pldtfac( vpwxmi, vpwxma, &factor, &tstart );
01365             tp = xtick1 * ( 1. + floor( ( vpwxmi - tstart ) / xtick1 ) ) + tstart;
01366         }
01367         else
01368             tp = xtick1 * ( 1. + floor( vpwxmi / xtick1 ) );
01369         for ( tn = tp; BETW( tn, vpwxmi, vpwxma ); tn += xtick1 )
01370         {
01371             if ( ldx )
01372             {
01373                 strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
01374             }
01375             else
01376             {
01377                 plform( PL_X_AXIS, tn, xscale, xprec, string, STRING_LEN, llx, lfx, lox );
01378             }
01379             height = lix ? 1.75 : 1.5;
01380             pos    = ( vpwxmax > vpwxmin ) ?
01381                      ( tn - vpwxmi ) / ( vpwxma - vpwxmi ) :
01382                      ( vpwxma - tn ) / ( vpwxma - vpwxmi );
01383             if ( lnx )
01384                 plmtex( "b", height, pos, 0.5, string );
01385             if ( lmx )
01386                 plmtex( "t", height, pos, 0.5, string );
01387         }
01388         xdigits = 2;
01389         plsxax( xdigmax, xdigits );
01390 
01391         /* Write separate exponential label if mode = 1. */
01392 
01393         if ( !llx && !ldx && !lox && xmode )
01394         {
01395             /* Assume label data is for placement of exponents if no custom
01396              * label function is provided. */
01397             if ( plsc->label_data )
01398             {
01399                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
01400                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
01401                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
01402             }
01403             else
01404             {
01405                 height = 3.2;
01406                 pos    = 1.0;
01407                 just   = 0.5;
01408             }
01409             snprintf( string, STRING_LEN, "(x10#u%d#d)", (int) xscale );
01410             if ( lnx )
01411                 plmtex( "b", height, pos, just, string );
01412             if ( lmx )
01413                 plmtex( "t", height, pos, just, string );
01414         }
01415     }
01416 
01417 /* Write vertical label(s) */
01418 
01419     if ( ( lmy || lny ) && lty )
01420     {
01421         PLINT ymode, yprec, ydigmax, ydigits, yscale;
01422 
01423         plgyax( &ydigmax, &ydigits );
01424         pldprec( vpwymi, vpwyma, ytick1, lfy, &ymode, &yprec, ydigmax, &yscale );
01425 
01426         ydigits = 0;
01427         if ( ldy )
01428         {
01429             pldtfac( vpwymi, vpwyma, &factor, &tstart );
01430             tp = ytick1 * ( 1. + floor( ( vpwymi - tstart ) / ytick1 ) ) + tstart;
01431         }
01432         else
01433             tp = ytick1 * ( 1. + floor( vpwymi / ytick1 ) );
01434         for ( tn = tp; BETW( tn, vpwymi, vpwyma ); tn += ytick1 )
01435         {
01436             if ( ldy )
01437             {
01438                 strfqsas( string, STRING_LEN, timefmt, (double) tn, plsc->qsasconfig );
01439             }
01440             else
01441             {
01442                 plform( PL_Y_AXIS, tn, yscale, yprec, string, STRING_LEN, lly, lfy, loy );
01443             }
01444             pos = ( vpwymax > vpwymin ) ?
01445                   ( tn - vpwymi ) / ( vpwyma - vpwymi ) :
01446                   ( vpwyma - tn ) / ( vpwyma - vpwymi );
01447             if ( lny )
01448             {
01449                 if ( lvy )
01450                 {
01451                     height = liy ? 1.0 : 0.5;
01452                     plmtex( "lv", height, pos, 1.0, string );
01453                 }
01454                 else
01455                 {
01456                     height = liy ? 1.75 : 1.5;
01457                     plmtex( "l", height, pos, 0.5, string );
01458                 }
01459             }
01460             if ( lmy )
01461             {
01462                 if ( lvy )
01463                 {
01464                     height = liy ? 1.0 : 0.5;
01465                     plmtex( "rv", height, pos, 0.0, string );
01466                 }
01467                 else
01468                 {
01469                     height = liy ? 1.75 : 1.5;
01470                     plmtex( "r", height, pos, 0.5, string );
01471                 }
01472             }
01473             ydigits = MAX( ydigits, (PLINT) strlen( string ) );
01474         }
01475         if ( !lvy )
01476             ydigits = 2;
01477 
01478         plsyax( ydigmax, ydigits );
01479 
01480         /* Write separate exponential label if mode = 1. */
01481 
01482         if ( !lly && !ldy && !loy && ymode )
01483         {
01484             snprintf( string, STRING_LEN, "(x10#u%d#d)", (int) yscale );
01485             if ( plsc->label_data )
01486             {
01487                 height = ( (PLLabelDefaults *) plsc->label_data )->exp_label_disp;
01488                 pos    = ( (PLLabelDefaults *) plsc->label_data )->exp_label_pos;
01489                 just   = ( (PLLabelDefaults *) plsc->label_data )->exp_label_just;
01490             }
01491             else
01492             {
01493                 offset = 0.02;
01494                 height = 2.0;
01495                 if ( lny )
01496                 {
01497                     pos  = 0.0 - offset;
01498                     just = 1.0;
01499                 }
01500                 if ( lmy )
01501                 {
01502                     pos  = 1.0 + offset;
01503                     just = 0.0;
01504                 }
01505             }
01506             plmtex( "t", height, pos, just, string );
01507         }
01508     }
01509 }
01510 
01511 /*--------------------------------------------------------------------------*\
01512  * void plform()
01513  *
01514  * Formats a PLFLT value in one of the following formats.
01515  *
01516  * If ll (logarithmic), then:
01517  *
01518  *    - If lf (fixed), then used fixed point notation, i.e. .1, 1, 10, etc,
01519  *  with unnecessary trailing .'s or 0's removed.
01520  *
01521  *    - If !lf (default), then use exponential notation, i.e. 10^-1, etc.
01522  *
01523  * If !ll (linear), then:
01524  *
01525  *    - If scale == 0, use fixed point format with "prec" places after the
01526  *  decimal point.
01527  *
01528  *    - If scale == 1, use scientific notation with one place before the
01529  *  decimal point and "prec" places after.  In this case, the value
01530  *  must be divided by 10^scale.
01531  *
01532  * The axis argument is included to support PLplot's custom axis labeling.  It
01533  * is passed on to the custom labeling function if it exists.  Otherwise, it
01534  * is ignored.
01535  \*--------------------------------------------------------------------------*/
01536 
01537 static void
01538 plform( PLINT axis, PLFLT value, PLINT scale, PLINT prec, char *string, PLINT len, PLBOOL ll, PLBOOL lf, PLBOOL lo )
01539 {
01540     /* Check to see if a custom labeling function is defined.  If not, */
01541     if ( lo && plsc->label_func )
01542     {
01543         ( *plsc->label_func )( axis, value, string, len, plsc->label_data );
01544     }
01545     else
01546     {
01547         if ( lo )
01548         {
01549             plwarn( "Custom axis labels requested without a labeling function \
01550                     - using default." );
01551         }
01552         if ( ll )
01553         {
01554             /* Logarithmic */
01555 
01556             if ( lf )
01557             {
01558                 /* Fixed point, i.e. .1, 1, 10, etc */
01559 
01560                 int exponent = ROUND( value );
01561 
01562                 value = pow( 10.0, exponent );
01563                 if ( exponent < 0 )
01564                 {
01565                     char form[FORMAT_LEN];
01566                     snprintf( form, FORMAT_LEN, "%%.%df", ABS( exponent ) );
01567                     snprintf( string, len, form, value );
01568                 }
01569                 else
01570                 {
01571                     snprintf( string, len, "%d", (int) value );
01572                 }
01573             }
01574             else
01575             {
01576                 /* Exponential, i.e. 10^-1, 10^0, 10^1, etc */
01577 
01578                 snprintf( string, len, "10#u%d", (int) ROUND( value ) );
01579             }
01580         }
01581         else
01582         {
01583             /* Linear */
01584 
01585             PLINT  setpre, precis;
01586             char   form[FORMAT_LEN], temp[TEMP_LEN];
01587             double scale2;
01588 
01589             plP_gprec( &setpre, &precis );
01590 
01591             if ( setpre )
01592                 prec = precis;
01593 
01594             if ( scale )
01595                 value /= pow( 10., (double) scale );
01596 
01597             /* This is necessary to prevent labels like "-0.0" on some systems */
01598 
01599             scale2 = pow( 10., prec );
01600             value  = floor( ( value * scale2 ) + .5 ) / scale2;
01601 
01602             snprintf( form, FORMAT_LEN, "%%.%df", (int) prec );
01603             snprintf( temp, TEMP_LEN, form, value );
01604             strncpy( string, temp, len - 1 );
01605             string[len - 1] = '\0';
01606         }
01607     }
01608 }
01609 
01610 /*--------------------------------------------------------------------------*\
01611  * plslabelfunc
01612  *
01613  * Formats a PLFLT value in one of the following formats.
01614  *
01615  * label_func - A pointer to a function which will provide a string to use
01616  *              as the label for the given floating point value.
01617  *              Pass this as NULL to clear the custom function and reset it to
01618  *              the default PLplot labeling function.
01619  *
01620  * label_data - Extra data to pass to the label function.
01621  *
01622  * The label_func function arguments are, in order:
01623  *
01624  * axis: PL_X_AXIS, PL_Y_AXIS or PL_Z_AXIS to indicate which axis is being
01625  *       labeled
01626  * value: The value at this position on the axis
01627  * string: The resulting label string should be stored here
01628  * data: A pointer to whatever extra information the custom plotting function
01629  *       requires
01630  *
01631  \*--------------------------------------------------------------------------*/
01632 void
01633 c_plslabelfunc( void ( *label_func )( PLINT, PLFLT, char *, PLINT, PLPointer ), PLPointer label_data )
01634 {
01635     plsc->label_func = label_func;
01636     plsc->label_data = label_data;
01637 }
 All Data Structures Files Functions