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