1 /* $Id: plbox.c,v 1.3 2007/05/08 09:09:37 rice Exp $
2 
3 	Routines for drawing axes & box around the current viewport.
4 
5    Copyright (C) 2004  Joao Cardoso
6    Copyright (C) 2004  Alan W. Irwin
7 
8    This file is part of PLplot.
9 
10    PLplot is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Library Public License as published
12    by the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    PLplot is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU Library General Public License for more details.
19 
20    You should have received a copy of the GNU Library General Public License
21    along with PLplot; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24 
25 #include "plplotP.h"
26 
27 static PLFLT xlog[8] =
28 {
29     0.301030, 0.477121, 0.602060, 0.698970,
30     0.778151, 0.845098, 0.903090, 0.954243
31 };
32 
33 /* Static function prototypes */
34 
35 static void
36 plxybx(const char *opt, const char *label, PLFLT wx1, PLFLT wy1,
37        PLFLT wx2, PLFLT wy2, PLFLT vmin, PLFLT vmax,
38        PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits);
39 
40 static void
41 plzbx(const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
42       PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin, PLFLT vmax,
43       PLFLT tick, PLINT nsub, PLINT *digits);
44 
45 static void
46 plxytx(PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
47        PLFLT disp, PLFLT pos, PLFLT just, const char *text);
48 
49 static void
50 plztx(const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
51       PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text);
52 
53 static void
54 plform(PLFLT value, PLINT scale, PLINT prec, char *result, PLINT ll, PLINT lf);
55 
56 static void
57 grid_box(const char *xopt, PLFLT xtick1, PLINT nxsub1,
58 	 const char *yopt, PLFLT ytick1, PLINT nysub1);
59 
60 static void
61 label_box(const char *xopt, PLFLT xtick1, const char *yopt, PLFLT ytick1);
62 
63 /*--------------------------------------------------------------------------*\
64  * void plbox()
65  *
66  * This draws a box around the current viewport, complete with axes, ticks,
67  * numeric labels, and grids, according to input specification.  Just a
68  * front-end to plaxes(), which allows arbitrary placement of coordinate
69  * axes when plotted (here the origin is at 0,0).  See the documentation for
70  * plaxes() for more info.
71 \*--------------------------------------------------------------------------*/
72 
73 void
c_plbox(const char * xopt,PLFLT xtick,PLINT nxsub,const char * yopt,PLFLT ytick,PLINT nysub)74 c_plbox(const char *xopt, PLFLT xtick, PLINT nxsub,
75 	const char *yopt, PLFLT ytick, PLINT nysub)
76 {
77     c_plaxes(0.0, 0.0, xopt, xtick, nxsub, yopt, ytick, nysub);
78 }
79 
80 /*--------------------------------------------------------------------------*\
81  * void plaxes()
82  *
83  * This draws a box around the current viewport, complete with axes,
84  * ticks, numeric labels, and grids, according to input specification.
85  *
86  * xx0 and yy0 specify the origin of the axes.
87  *
88  * xopt and yopt are character strings which define the box as follows:
89  *
90  * a: Draw axis (X is horizontal line Y=0, Y is vertical line X=0)
91  * b: Draw bottom (X) or left (Y) edge of frame
92  * c: Draw top (X) or right (Y) edge of frame
93  * f: Always use fixed point numeric labels
94  * g: Draws a grid at the major tick interval
95  * h: Draws a grid at the minor tick interval
96  * i: Inverts tick marks
97  * l: Logarithmic axes, major ticks at decades, minor ticks at units
98  * n: Write numeric label at conventional location
99  * m: Write numeric label at unconventional location
100  * t: Draw major tick marks
101  * s: Draw minor tick marks
102  * v: (for Y only) Label vertically
103  *
104  * xtick, ytick are the major tick intervals required, zero for
105  * automatic selection
106  *
107  * nxsub, nysub are the number of subtick intervals in a major tick
108  * interval
109 \*--------------------------------------------------------------------------*/
110 
111 void
c_plaxes(PLFLT xx0,PLFLT yy0,const char * xopt,PLFLT xtick,PLINT nxsub,const char * yopt,PLFLT ytick,PLINT nysub)112 c_plaxes(PLFLT xx0, PLFLT yy0,
113 	 const char *xopt, PLFLT xtick, PLINT nxsub,
114 	 const char *yopt, PLFLT ytick, PLINT nysub)
115 {
116     PLINT lax, lbx, lcx, lgx, lix, llx, lsx, ltx;
117     PLINT lay, lby, lcy, lgy, liy, lly, lsy, lty;
118     PLINT xmajor, xminor, ymajor, yminor;
119     PLINT i, i1x, i2x, i3x, i4x, i1y, i2y, i3y, i4y;
120     PLINT nxsub1, nysub1;
121     PLINT lxmin, lxmax, lymin, lymax;
122     PLINT pxmin, pxmax, pymin, pymax;
123     PLINT vppxmi, vppxma, vppymi, vppyma;
124     PLFLT xtick1, ytick1, vpwxmi, vpwxma, vpwymi, vpwyma;
125     PLFLT vpwxmin, vpwxmax, vpwymin, vpwymax;
126     PLFLT xp0, yp0, tn, tp, temp;
127 
128     if (plsc->level < 3) {
129 	plabort("plbox: Please set up window first");
130 	return;
131     }
132 
133 /* Open the clip limits to the subpage limits */
134 
135     plP_gclp(&lxmin, &lxmax, &lymin, &lymax);
136     plP_gphy(&pxmin, &pxmax, &pymin, &pymax);
137     plP_sclp(pxmin, pxmax, pymin, pymax);
138 
139     vppxmi = plsc->vppxmi;
140     vppxma = plsc->vppxma;
141     vppymi = plsc->vppymi;
142     vppyma = plsc->vppyma;
143 
144 /* Convert world coordinates to physical */
145 
146     xp0 = plP_wcpcx(xx0);
147     yp0 = plP_wcpcy(yy0);
148 
149 /* Set plot options from input */
150 
151     lax = plP_stsearch(xopt, 'a');
152     lbx = plP_stsearch(xopt, 'b');
153     lcx = plP_stsearch(xopt, 'c');
154     lgx = plP_stsearch(xopt, 'g');
155     lix = plP_stsearch(xopt, 'i');
156     llx = plP_stsearch(xopt, 'l');
157     lsx = plP_stsearch(xopt, 's');
158     ltx = plP_stsearch(xopt, 't');
159 
160     lay = plP_stsearch(yopt, 'a');
161     lby = plP_stsearch(yopt, 'b');
162     lcy = plP_stsearch(yopt, 'c');
163     lgy = plP_stsearch(yopt, 'g');
164     liy = plP_stsearch(yopt, 'i');
165     lly = plP_stsearch(yopt, 'l');
166     lsy = plP_stsearch(yopt, 's');
167     lty = plP_stsearch(yopt, 't');
168 
169 /* Tick and subtick sizes in device coords */
170 
171     xmajor = MAX(ROUND(plsc->majht * plsc->ypmm), 1);
172     ymajor = MAX(ROUND(plsc->majht * plsc->xpmm), 1);
173     xminor = MAX(ROUND(plsc->minht * plsc->ypmm), 1);
174     yminor = MAX(ROUND(plsc->minht * plsc->xpmm), 1);
175 
176     nxsub1 = nxsub;
177     nysub1 = nysub;
178     xtick1 = llx ? 1.0 : xtick;
179     ytick1 = lly ? 1.0 : ytick;
180 
181     plgvpw(&vpwxmin, &vpwxmax, &vpwymin, &vpwymax);
182 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
183  * similarly for vpwymi */
184     vpwxmi = (vpwxmax > vpwxmin) ? vpwxmin : vpwxmax;
185     vpwxma = (vpwxmax > vpwxmin) ? vpwxmax : vpwxmin;
186     vpwymi = (vpwymax > vpwymin) ? vpwymin : vpwymax;
187     vpwyma = (vpwymax > vpwymin) ? vpwymax : vpwymin;
188 
189     lax = lax && vpwymi < yy0 && yy0 < vpwyma ;
190     lay = lay && vpwxmi < xx0 && xx0 < vpwxma ;
191 
192 /* Calculate tick spacing */
193 
194     if (ltx || lgx)
195 	pldtik(vpwxmi, vpwxma, &xtick1, &nxsub1);
196 
197     if (lty || lgy)
198 	pldtik(vpwymi, vpwyma, &ytick1, &nysub1);
199 /* n.b. large change; xtick1, nxsub1, ytick1, nysub1 always positive. */
200 
201 /* Set up tick variables */
202 
203     if (lix) {
204 	i1x = xminor;
205 	i2x = 0;
206 	i3x = xmajor;
207 	i4x = 0;
208     }
209     else {
210 	i1x = 0;
211 	i2x = xminor;
212 	i3x = 0;
213 	i4x = xmajor;
214     }
215 
216     if (liy) {
217 	i1y = yminor;
218 	i2y = 0;
219 	i3y = ymajor;
220 	i4y = 0;
221     }
222     else {
223 	i1y = 0;
224 	i2y = yminor;
225 	i3y = 0;
226 	i4y = ymajor;
227     }
228 
229 /* Draw the bottom edge of the box */
230 
231     if (lbx) {
232 	plP_movphy(vppxmi, vppymi);
233 	if (ltx) {
234 	    tp = xtick1 * floor(vpwxmi / xtick1);
235 	    for (;;) {
236 		tn = tp + xtick1;
237 		if (lsx) {
238 		    if (llx) {
239 			for (i = 0; i <= 7; i++) {
240 			    temp = tp + xlog[i];
241 			    if (BETW(temp, vpwxmi, vpwxma))
242 				plxtik(plP_wcpcx(temp), vppymi, i1x, i2x);
243 			}
244 		    }
245 		    else {
246 			for (i = 1; i <= nxsub1 - 1; i++) {
247 			    temp = tp + i * xtick1 / nxsub1;
248 			    if (BETW(temp, vpwxmi, vpwxma))
249 				plxtik(plP_wcpcx(temp), vppymi, i1x, i2x);
250 			}
251 		    }
252 		}
253 		if (!BETW(tn, vpwxmi, vpwxma))
254 		    break;
255 		plxtik(plP_wcpcx(tn), vppymi, i3x, i4x);
256 		tp = tn;
257 	    }
258 	}
259 	plP_draphy(vppxma, vppymi);
260     }
261 
262 /* Draw right-hand edge of box */
263 
264     if (lcy) {
265 	plP_movphy(vppxma, vppymi);
266 	if (lty) {
267 	    tp = ytick1 * floor(vpwymi / ytick1);
268 	    for (;;) {
269 		tn = tp + ytick1;
270 		if (lsy) {
271 		    if (lly) {
272 			for (i = 0; i <= 7; i++) {
273 			    temp = tp + xlog[i];
274 			    if (BETW(temp, vpwymi, vpwyma))
275 				plytik(vppxma, plP_wcpcy(temp), i2y, i1y);
276 			}
277 		    }
278 		    else {
279 			for (i = 1; i <= nysub1 - 1; i++) {
280 			    temp = tp + i * ytick1 / nysub1;
281 			    if (BETW(temp, vpwymi, vpwyma))
282 				plytik(vppxma, plP_wcpcy(temp), i2y, i1y);
283 			}
284 		    }
285 		}
286 		if (!BETW(tn, vpwymi, vpwyma))
287 		    break;
288 		plytik(vppxma, plP_wcpcy(tn), i4y, i3y);
289 		tp = tn;
290 	    }
291 	}
292 	plP_draphy(vppxma, vppyma);
293     }
294 
295 /* Draw the top edge of the box */
296 
297     if (lcx) {
298 	plP_movphy(vppxma, vppyma);
299 	if (ltx) {
300 	    tp = xtick1 * (floor(vpwxma / xtick1) + 1);
301 	    for (;;) {
302 		tn = tp - xtick1;
303 		if (lsx) {
304 		    if (llx) {
305 			for (i = 7; i >= 0; i--) {
306 			    temp = tn + xlog[i];
307 			    if (BETW(temp, vpwxmi, vpwxma))
308 				plxtik(plP_wcpcx(temp), vppyma, i2x, i1x);
309 			}
310 		    }
311 		    else {
312 			for (i = nxsub1 - 1; i >= 1; i--) {
313 			    temp = tn + i * xtick1 / nxsub1;
314 			    if (BETW(temp, vpwxmi, vpwxma))
315 				plxtik(plP_wcpcx(temp), vppyma, i2x, i1x);
316 			}
317 		    }
318 		}
319 		if (!BETW(tn, vpwxmi, vpwxma))
320 		    break;
321 		plxtik(plP_wcpcx(tn), vppyma, i4x, i3x);
322 		tp = tn;
323 	    }
324 	}
325 	plP_draphy(vppxmi, vppyma);
326     }
327 
328 /* Draw left-hand edge of box */
329 
330     if (lby) {
331 	plP_movphy(vppxmi, vppyma);
332 	if (lty) {
333 	    tp = ytick1 * (floor(vpwyma / ytick1) + 1);
334 	    for (;;) {
335 		tn = tp - ytick1;
336 		if (lsy) {
337 		    if (lly) {
338 			for (i = 7; i >= 0; i--) {
339 			    temp = tn + xlog[i];
340 			    if (BETW(temp, vpwymi, vpwyma))
341 				plytik(vppxmi, plP_wcpcy(temp), i1y, i2y);
342 			}
343 		    }
344 		    else {
345 			for (i = nysub1 - 1; i >= 1; i--) {
346 			    temp = tn + i * ytick1 / nysub1;
347 			    if (BETW(temp, vpwymi, vpwyma))
348 				plytik(vppxmi, plP_wcpcy(temp), i1y, i2y);
349 			}
350 		    }
351 		}
352 		if (!BETW(tn, vpwymi, vpwyma))
353 		    break;
354 		plytik(vppxmi, plP_wcpcy(tn), i3y, i4y);
355 		tp = tn;
356 	    }
357 	}
358 	plP_draphy(vppxmi, vppymi);
359     }
360 
361 /* Draw the horizontal axis */
362 
363     if (lax) {
364 	plP_movphy(vppxmi, yp0);
365 	if (ltx) {
366 	    tp = xtick1 * floor(vpwxmi / xtick1);
367 	    for (;;) {
368 		tn = tp + xtick1;
369 		if (lsx) {
370 		    if (llx) {
371 			for (i = 0; i <= 7; i++) {
372 			    temp = tp + xlog[i];
373 			    if (BETW(temp, vpwxmi, vpwxma))
374 				plxtik(plP_wcpcx(temp), yp0, xminor, xminor);
375 			}
376 		    }
377 		    else {
378 			for (i = 1; i <= nxsub1 - 1; i++) {
379 			    temp = tp + i * xtick1 / nxsub1;
380 			    if (BETW(temp, vpwxmi, vpwxma))
381 				plxtik(plP_wcpcx(temp), yp0, xminor, xminor);
382 			}
383 		    }
384 		}
385 		if (!BETW(tn, vpwxmi, vpwxma))
386 		    break;
387 		plxtik(plP_wcpcx(tn), yp0, xmajor, xmajor);
388 		tp = tn;
389 	    }
390 	}
391 	plP_draphy(vppxma, yp0);
392     }
393 
394 /* Draw the vertical axis */
395 
396     if (lay) {
397 	plP_movphy(xp0, vppymi);
398 	if (lty) {
399 	    tp = ytick1 * floor(vpwymi / ytick1);
400 	    for (;;) {
401 		tn = tp + ytick1;
402 		if (lsy) {
403 		    if (lly) {
404 			for (i = 0; i <= 7; i++) {
405 			    temp = tp + xlog[i];
406 			    if (BETW(temp, vpwymi, vpwyma))
407 				plytik(xp0, plP_wcpcy(temp), yminor, yminor);
408 			}
409 		    }
410 		    else {
411 			for (i = 1; i <= nysub1 - 1; i++) {
412 			    temp = tp + i * ytick1 / nysub1;
413 			    if (BETW(temp, vpwymi, vpwyma))
414 				plytik(xp0, plP_wcpcy(temp), yminor, yminor);
415 			}
416 		    }
417 		}
418 		if (!BETW(tn, vpwymi, vpwyma))
419 		    break;
420 		plytik(xp0, plP_wcpcy(tn), ymajor, ymajor);
421 		tp = tn;
422 	    }
423 	}
424 	plP_draphy(xp0, vppyma);
425     }
426 
427 /* Draw grids */
428 
429     grid_box(xopt, xtick1, nxsub1, yopt, ytick1, nysub1);
430 
431 /* Write labels */
432 
433     label_box(xopt, xtick1, yopt, ytick1);
434 
435 /* Restore the clip limits to viewport edge */
436 
437     plP_sclp(lxmin, lxmax, lymin, lymax);
438 }
439 
440 /*--------------------------------------------------------------------------*\
441  * void plbox3()
442  *
443  * This is the 3-d analogue of plbox().
444 \*--------------------------------------------------------------------------*/
445 
446 void
c_plbox3(const char * xopt,const char * xlabel,PLFLT xtick,PLINT nsubx,const char * yopt,const char * ylabel,PLFLT ytick,PLINT nsuby,const char * zopt,const char * zlabel,PLFLT ztick,PLINT nsubz)447 c_plbox3(const char *xopt, const char *xlabel, PLFLT xtick, PLINT nsubx,
448 	 const char *yopt, const char *ylabel, PLFLT ytick, PLINT nsuby,
449 	 const char *zopt, const char *zlabel, PLFLT ztick, PLINT nsubz)
450 {
451     PLFLT dx, dy, tx, ty, ux, uy;
452     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
453     PLFLT cxx, cxy, cyx, cyy, cyz;
454     PLINT ln;
455     PLINT *zbflg, *zbcol, *zbwidth;
456     PLFLT *zbtck;
457     PLINT xdigmax, xdigits;
458     PLINT ydigmax, ydigits;
459     PLINT zdigmax, zdigits;
460 
461     if (plsc->level < 3) {
462 	plabort("plbox3: Please set up window first");
463 	return;
464     }
465 
466     plP_gw3wc(&cxx, &cxy, &cyx, &cyy, &cyz);
467     plP_gdom(&xmin, &xmax, &ymin, &ymax);
468     plP_grange(&zscale, &zmin, &zmax);
469 
470     plgxax(&xdigmax, &xdigits);
471     plgyax(&ydigmax, &ydigits);
472     plgzax(&zdigmax, &zdigits);
473 
474     xdigits = xdigmax;
475     ydigits = ydigmax;
476     zdigits = zdigmax;
477 
478 /* We have to wait until after the plot is drawn to draw back */
479 /* grid so store this stuff. */
480 
481     plP_gzback(&zbflg, &zbcol, &zbtck, &zbwidth);
482     *zbflg = plP_stsearch(zopt, 'd');
483     if (*zbflg) {
484 	*zbtck = ztick;		/* save tick spacing */
485 	*zbcol = plsc->icol0;	/* and color */
486 	*zbwidth = plsc->width;	/* and line width */
487     }
488 
489     if (cxx >= 0.0 && cxy <= 0.0) {
490 	ln = plP_stsearch(xopt, 'n');
491 	tx = plP_w3wcx(xmin, ymin, zmin);
492 	ty = plP_w3wcy(xmin, ymin, zmin);
493 	ux = plP_w3wcx(xmax, ymin, zmin);
494 	uy = plP_w3wcy(xmax, ymin, zmin);
495 	plxybx(xopt, xlabel, tx, ty, ux, uy,
496 	       xmin, xmax, xtick, nsubx, 0, &xdigits);
497 
498 	dx = ux - tx;
499 	dy = uy - ty;
500 	plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
501 	      plP_w3wcy(xmax, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
502 
503 	tx = plP_w3wcx(xmin, ymax, zmin);
504 	ty = plP_w3wcy(xmin, ymax, zmin);
505 	ux = plP_w3wcx(xmin, ymin, zmin);
506 	uy = plP_w3wcy(xmin, ymin, zmin);
507 	plxybx(yopt, ylabel, tx, ty, ux, uy,
508 	       ymax, ymin, ytick, nsuby, ln, &ydigits);
509 
510 	dx = ux - tx;
511 	dy = uy - ty;
512 /* restore zdigits to initial value for second call */
513         zdigits = zdigmax;
514 	plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
515 	      plP_w3wcy(xmin, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
516     }
517     else if (cxx <= 0.0 && cxy <= 0.0) {
518 	ln = plP_stsearch(yopt, 'n');
519 	tx = plP_w3wcx(xmin, ymax, zmin);
520 	ty = plP_w3wcy(xmin, ymax, zmin);
521 	ux = plP_w3wcx(xmin, ymin, zmin);
522 	uy = plP_w3wcy(xmin, ymin, zmin);
523 	plxybx(yopt, ylabel, tx, ty, ux, uy,
524 	       ymax, ymin, ytick, nsuby, 0, &ydigits);
525 
526 	dx = ux - tx;
527 	dy = uy - ty;
528 	plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
529 	      plP_w3wcy(xmin, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
530 
531 	tx = plP_w3wcx(xmax, ymax, zmin);
532 	ty = plP_w3wcy(xmax, ymax, zmin);
533 	ux = plP_w3wcx(xmin, ymax, zmin);
534 	uy = plP_w3wcy(xmin, ymax, zmin);
535 	plxybx(xopt, xlabel, tx, ty, ux, uy,
536 	       xmax, xmin, xtick, nsubx, ln, &xdigits);
537 
538 	dx = ux - tx;
539 	dy = uy - ty;
540 /* restore zdigits to initial value for second call */
541         zdigits = zdigmax;
542 	plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
543 	      plP_w3wcy(xmax, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
544     }
545     else if (cxx <= 0.0 && cxy >= 0.0) {
546 	ln = plP_stsearch(xopt, 'n');
547 	tx = plP_w3wcx(xmax, ymax, zmin);
548 	ty = plP_w3wcy(xmax, ymax, zmin);
549 	ux = plP_w3wcx(xmin, ymax, zmin);
550 	uy = plP_w3wcy(xmin, ymax, zmin);
551 	plxybx(xopt, xlabel, tx, ty, ux, uy,
552 	       xmax, xmin, xtick, nsubx, 0, &xdigits);
553 
554 	dx = ux - tx;
555 	dy = uy - ty;
556 	plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
557 	      plP_w3wcy(xmin, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
558 
559 	tx = plP_w3wcx(xmax, ymin, zmin);
560 	ty = plP_w3wcy(xmax, ymin, zmin);
561 	ux = plP_w3wcx(xmax, ymax, zmin);
562 	uy = plP_w3wcy(xmax, ymax, zmin);
563 	plxybx(yopt, ylabel, tx, ty, ux, uy,
564 	       ymin, ymax, ytick, nsuby, ln, &ydigits);
565 
566 	dx = ux - tx;
567 	dy = uy - ty;
568 /* restore zdigits to initial value for second call */
569         zdigits = zdigmax;
570 	plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
571 	      plP_w3wcy(xmax, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
572     }
573     else if (cxx >= 0.0 && cxy >= 0.0) {
574 	ln = plP_stsearch(yopt, 'n');
575 	tx = plP_w3wcx(xmax, ymin, zmin);
576 	ty = plP_w3wcy(xmax, ymin, zmin);
577 	ux = plP_w3wcx(xmax, ymax, zmin);
578 	uy = plP_w3wcy(xmax, ymax, zmin);
579 	plxybx(yopt, ylabel, tx, ty, ux, uy,
580 	       ymin, ymax, ytick, nsuby, 0, &ydigits);
581 
582 	dx = ux - tx;
583 	dy = uy - ty;
584 	plzbx(zopt, zlabel, 1, dx, dy, ux, uy,
585 	      plP_w3wcy(xmax, ymax, zmax), zmin, zmax, ztick, nsubz, &zdigits);
586 
587 	tx = plP_w3wcx(xmin, ymin, zmin);
588 	ty = plP_w3wcy(xmin, ymin, zmin);
589 	ux = plP_w3wcx(xmax, ymin, zmin);
590 	uy = plP_w3wcy(xmax, ymin, zmin);
591 	plxybx(xopt, xlabel, tx, ty, ux, uy,
592 	       xmin, xmax, xtick, nsubx, ln, &xdigits);
593 
594 	dx = ux - tx;
595 	dy = uy - ty;
596 /* restore zdigits to initial value for second call */
597         zdigits = zdigmax;
598 	plzbx(zopt, zlabel, 0, dx, dy, tx, ty,
599 	      plP_w3wcy(xmin, ymin, zmax), zmin, zmax, ztick, nsubz, &zdigits);
600     }
601     plsxax(xdigmax, xdigits);
602     plsyax(ydigmax, ydigits);
603     plszax(zdigmax, zdigits);
604 }
605 
606 /*--------------------------------------------------------------------------*\
607  * Support routines for 3d box draw.
608 \*--------------------------------------------------------------------------*/
609 
610 /*--------------------------------------------------------------------------*\
611  * void plxybx()
612  *
613  * This draws a sloping line from (wx1,wy1) to (wx2,wy2) which represents an
614  * axis of a 3-d graph with data values from "vmin" to "vmax". Depending on
615  * "opt", vertical ticks and/or subticks are placed on the line at major tick
616  * interval "tick" with "nsub" subticks between major ticks. If "tick" and/or
617  * "nsub" is zero, automatic tick positions are computed
618  *
619  * b: Draw box boundary
620  * f: Always use fixed point numeric labels
621  * i: Inverts tick marks (i.e. drawn downwards)
622  * l: Logarithmic axes, major ticks at decades, minor ticks at units
623  * n: Write numeric label
624  * t: Draw major tick marks
625  * s: Draw minor tick marks
626  * u: Write label on line
627 \*--------------------------------------------------------------------------*/
628 
629 static void
plxybx(const char * opt,const char * label,PLFLT wx1,PLFLT wy1,PLFLT wx2,PLFLT wy2,PLFLT vmin_in,PLFLT vmax_in,PLFLT tick,PLINT nsub,PLINT nolast,PLINT * digits)630 plxybx(const char *opt, const char *label, PLFLT wx1, PLFLT wy1,
631        PLFLT wx2, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
632        PLFLT tick, PLINT nsub, PLINT nolast, PLINT *digits)
633 {
634     static char string[40];
635     PLINT lb, lf, li, ll, ln, ls, lt, lu;
636     PLINT major, minor, mode, prec, scale;
637     PLINT i, i1, i2, i3, i4;
638     PLINT nsub1;
639     PLFLT pos, tn, tp, temp, height, tick1, vmin, vmax;
640 /* Note that 'tspace' is the minimim distance away (in fractional number
641  * of ticks) from the boundary that an X or Y numerical label can be drawn. */
642     PLFLT dwx, dwy, lambda, tcrit, tspace = 0.1;
643 
644     (void) nolast;			/* pmr: make it used */
645 
646     vmin = (vmax_in > vmin_in) ? vmin_in : vmax_in;
647     vmax = (vmax_in > vmin_in) ? vmax_in : vmin_in;
648 
649     dwx = wx2 - wx1;
650     dwy = wy2 - wy1;
651 
652 /* Tick and subtick sizes in device coords */
653 
654     major = MAX(ROUND(plsc->majht * plsc->ypmm), 1);
655     minor = MAX(ROUND(plsc->minht * plsc->ypmm), 1);
656 
657     tick1 = tick;
658     nsub1 = nsub;
659 
660     lb = plP_stsearch(opt, 'b');
661     lf = plP_stsearch(opt, 'f');
662     li = plP_stsearch(opt, 'i');
663     ll = plP_stsearch(opt, 'l');
664     ln = plP_stsearch(opt, 'n');
665     ls = plP_stsearch(opt, 's');
666     lt = plP_stsearch(opt, 't');
667     lu = plP_stsearch(opt, 'u');
668 
669     if (lu)
670 	plxytx(wx1, wy1, wx2, wy2, 3.2, 0.5, 0.5, label);
671     if (!lb)
672 	return;
673 
674     if (ll)
675 	tick1 = (vmax > vmin) ? 1.0 : -1.0 ;
676     if (lt)
677 	pldtik(vmin, vmax, &tick1, &nsub1);
678 
679     if (li) {
680 	i1 = minor;
681 	i2 = 0;
682 	i3 = major;
683 	i4 = 0;
684     }
685     else {
686 	i1 = 0;
687 	i2 = minor;
688 	i3 = 0;
689 	i4 = major;
690     }
691 
692 /* Draw the line */
693 
694     plP_movwor(wx1, wy1);
695     if (lt) {
696 	tp = tick1 * floor(vmin / tick1);
697 	for (;;) {
698 	    tn = tp + tick1;
699 	    if (ls) {
700 		if (ll) {
701 		    for (i = 0; i <= 7; i++) {
702 			temp = tp + xlog[i];
703 			if (BETW(temp, vmin, vmax)) {
704 			    lambda = (vmax_in > vmin_in)?
705 			       (temp - vmin) / (vmax - vmin):
706 			       (vmax - temp) / (vmax - vmin);
707 			    plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
708 				   plP_wcpcy((PLFLT) (wy1 + lambda * dwy)),
709 				   i1, i2);
710 			}
711 		    }
712 		}
713 		else {
714 		    for (i = 1; i <= nsub1 - 1; i++) {
715 			temp = tp + i * (tn - tp) / nsub1;
716 			if (BETW(temp, vmin, vmax)) {
717 			    lambda = (vmax_in > vmin_in)?
718 			       (temp - vmin) / (vmax - vmin):
719 			       (vmax - temp) / (vmax - vmin);
720 			    plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
721 				   plP_wcpcy((PLFLT) (wy1 + lambda * dwy)),
722 				   i1, i2);
723 			}
724 		    }
725 		}
726 	    }
727 	    temp = tn;
728 	    if (!BETW(temp, vmin, vmax))
729 		break;
730 
731 	    lambda = (vmax_in > vmin_in)?
732 	       (temp - vmin) / (vmax - vmin):
733 	       (vmax - temp) / (vmax - vmin);
734 	    plxtik(plP_wcpcx((PLFLT) (wx1 + lambda * dwx)),
735 		   plP_wcpcy((PLFLT) (wy1 + lambda * dwy)), i3, i4);
736 	    tp = tn;
737 	}
738     }
739 
740     plP_drawor(wx2, wy2);
741 
742 /* Label the line */
743 
744     if (ln && lt) {
745 	pldprec(vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale);
746 	pos = 1.0;
747 	height = 3.2;
748         tcrit = tspace*tick1;
749 	tp = tick1 * (1. + floor(vmin / tick1));
750 	for (tn = tp; BETW(tn, vmin, vmax); tn += tick1) {
751 	   if(BETW(tn, vmin+tcrit, vmax-tcrit)) {
752 	    plform(tn, scale, prec, string, ll, lf);
753 	    pos = (vmax_in > vmin_in)?
754 	       (tn - vmin) / (vmax - vmin):
755 	       (vmax - tn) / (vmax - vmin);
756 	    plxytx(wx1, wy1, wx2, wy2, 1.5, pos, 0.5, string);
757 	   }
758 	}
759 	*digits = 2;
760 	if (!ll && mode) {
761 	    sprintf(string, "(x10#u%d#d)", (int) scale);
762 	    plxytx(wx1, wy1, wx2, wy2, height, 1.0, 0.5, string);
763 	}
764     }
765 }
766 
767 /*--------------------------------------------------------------------------*\
768  * void plxytx()
769  *
770  * Prints out text along a sloping axis joining world coordinates
771  * (wx1,wy1) to (wx2,wy2). Parameters are as for plmtext.
772 \*--------------------------------------------------------------------------*/
773 
774 static void
plxytx(PLFLT wx1,PLFLT wy1,PLFLT wx2,PLFLT wy2,PLFLT disp,PLFLT pos,PLFLT just,const char * text)775 plxytx(PLFLT wx1, PLFLT wy1, PLFLT wx2, PLFLT wy2,
776        PLFLT disp, PLFLT pos, PLFLT just, const char *text)
777 {
778     PLINT x, y, refx, refy;
779     PLFLT shift, cc, ss, wx, wy;
780     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
781     PLFLT dispx, dispy;
782     PLFLT chrdef, chrht;
783 
784     cc = plsc->wmxscl * (wx2 - wx1);
785     ss = plsc->wmyscl * (wy2 - wy1);
786     diag = sqrt(cc * cc + ss * ss);
787     cc /= diag;
788     ss /= diag;
789     wx = wx1 + pos * (wx2 - wx1);
790     wy = wy1 + pos * (wy2 - wy1);
791 
792     xform[0] = cc;
793     xform[1] = 0.0;
794     xform[2] = ss;
795     xform[3] = 1.0;
796 
797     xdv = plP_wcdcx(wx);
798     ydv = plP_wcdcy(wy);
799 
800     dispx = 0.;
801     dispy = -disp;
802 
803     plgchr(&chrdef, &chrht);
804     shift = (just == 0.0) ? 0.0 : plstrl(text) * just;
805 
806     xmm = plP_dcmmx(xdv) + dispx * chrht;
807     ymm = plP_dcmmy(ydv) + dispy * chrht;
808     refxmm = xmm - shift * xform[0];
809     refymm = ymm - shift * xform[2];
810 
811     x = plP_mmpcx(xmm);
812     y = plP_mmpcy(ymm);
813     refx = plP_mmpcx(refxmm);
814     refy = plP_mmpcy(refymm);
815 
816     plP_text(0, just, xform, x, y, refx, refy, text);
817 }
818 
819 /*--------------------------------------------------------------------------*\
820  * void plzbx()
821  *
822  * This draws a vertical line from (wx,wy1) to (wx,wy2) which represents the
823  * vertical axis of a 3-d graph with data values from "vmin" to "vmax".
824  * Depending on "opt", ticks and/or subticks are placed on the line at major
825  * tick interval "tick" with "nsub" subticks between major ticks. If "tick"
826  * and/or "nsub" is zero, automatic tick positions are computed
827  *
828  * b: Draws left-hand axis
829  * c: Draws right-hand axis
830  * f: Always use fixed point numeric labels
831  * i: Inverts tick marks (i.e. drawn to the left)
832  * l: Logarithmic axes, major ticks at decades, minor ticks at units
833  * m: Write numeric label on right axis
834  * n: Write numeric label on left axis
835  * s: Draw minor tick marks
836  * t: Draw major tick marks
837  * u: Writes left-hand label
838  * v: Writes right-hand label
839 \*--------------------------------------------------------------------------*/
840 
841 static void
plzbx(const char * opt,const char * label,PLINT right,PLFLT dx,PLFLT dy,PLFLT wx,PLFLT wy1,PLFLT wy2,PLFLT vmin_in,PLFLT vmax_in,PLFLT tick,PLINT nsub,PLINT * digits)842 plzbx(const char *opt, const char *label, PLINT right, PLFLT dx, PLFLT dy,
843       PLFLT wx, PLFLT wy1, PLFLT wy2, PLFLT vmin_in, PLFLT vmax_in,
844       PLFLT tick, PLINT nsub, PLINT *digits)
845 {
846     static char string[40];
847     PLINT lb, lc, lf, li, ll, lm, ln, ls, lt, lu, lv;
848     PLINT i, mode, prec, scale;
849     PLINT nsub1, lstring;
850     PLFLT pos, tn, tp, temp, height, tick1;
851     PLFLT dwy, lambda, diag, major, minor, xmajor, xminor;
852     PLFLT ymajor, yminor, dxm, dym, vmin, vmax;
853 
854     vmin = (vmax_in > vmin_in) ? vmin_in : vmax_in;
855     vmax = (vmax_in > vmin_in) ? vmax_in : vmin_in;
856 
857     dwy = wy2 - wy1;
858 
859 /* Tick and subtick sizes in device coords */
860 
861     major = plsc->majht;
862     minor = plsc->minht;
863 
864     tick1 = tick;
865     nsub1 = nsub;
866 
867     lb = plP_stsearch(opt, 'b');
868     lc = plP_stsearch(opt, 'c');
869     lf = plP_stsearch(opt, 'f');
870     li = plP_stsearch(opt, 'i');
871     ll = plP_stsearch(opt, 'l');
872     lm = plP_stsearch(opt, 'm');
873     ln = plP_stsearch(opt, 'n');
874     ls = plP_stsearch(opt, 's');
875     lt = plP_stsearch(opt, 't');
876     lu = plP_stsearch(opt, 'u');
877     lv = plP_stsearch(opt, 'v');
878 
879     if (lu && !right)
880 	plztx("h", dx, dy, wx, wy1, wy2, 5.0, 0.5, 0.5, label);
881 
882     if (lv && right)
883 	plztx("h", dx, dy, wx, wy1, wy2, -5.0, 0.5, 0.5, label);
884 
885     if (right && !lc)
886 	return;
887 
888     if (!right && !lb)
889 	return;
890 
891     if (ll)
892 	tick1 = 1.0;
893 
894     if (lt)
895 	pldtik(vmin, vmax, &tick1, &nsub1);
896 
897     if ((li && !right) || (!li && right)) {
898 	minor = -minor;
899 	major = -major;
900     }
901 
902     dxm = dx * plsc->wmxscl;
903     dym = dy * plsc->wmyscl;
904     diag = sqrt(dxm * dxm + dym * dym);
905 
906     xminor = minor * dxm / diag;
907     xmajor = major * dxm / diag;
908     yminor = minor * dym / diag;
909     ymajor = major * dym / diag;
910 
911 /* Draw the line */
912 
913     plP_movwor(wx, wy1);
914     if (lt) {
915 	tp = tick1 * floor(vmin / tick1);
916 	for (;;) {
917 	    tn = tp + tick1;
918 	    if (ls) {
919 		if (ll) {
920 		    for (i = 0; i <= 7; i++) {
921 			temp = tp + xlog[i];
922 			if (BETW(temp, vmin, vmax)) {
923 			    lambda = (vmax_in > vmin_in)?
924 			       (temp - vmin) / (vmax - vmin):
925 			       (vmax - temp) / (vmax - vmin);
926 			    plstik(plP_wcmmx(wx),
927 				   plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
928 				   xminor, yminor);
929 			}
930 		    }
931 		}
932 		else {
933 		    for (i = 1; i <= nsub1 - 1; i++) {
934 			temp = tp + i * tick1 / nsub1;
935 			if (BETW(temp, vmin, vmax)) {
936 			    lambda = (vmax_in > vmin_in)?
937 			       (temp - vmin) / (vmax - vmin):
938 			       (vmax - temp) / (vmax - vmin);
939 			    plstik(plP_wcmmx(wx),
940 				   plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
941 				   xminor, yminor);
942 			}
943 		    }
944 		}
945 	    }
946 	    temp = tn;
947 	    if (!BETW(temp, vmin, vmax))
948 		break;
949 	    lambda = (vmax_in > vmin_in)?
950 	        (temp - vmin) / (vmax - vmin):
951 	        (vmax - temp) / (vmax - vmin);
952 	    plstik(plP_wcmmx(wx), plP_wcmmy((PLFLT) (wy1 + lambda * dwy)),
953 		   xmajor, ymajor);
954 	    tp = tn;
955 	}
956     }
957 
958     plP_drawor(wx, wy2);
959 
960 /* Label the line */
961 
962     if ((ln || lm) && lt) {
963 	pldprec(vmin, vmax, tick1, lf, &mode, &prec, *digits, &scale);
964 	*digits = 0;
965 	tp = tick1 * floor(vmin / tick1);
966 	for (tn = tp + tick1; BETW(tn, vmin, vmax); tn += tick1) {
967 	    plform(tn, scale, prec, string, ll, lf);
968 	    pos = (vmax_in > vmin_in)?
969 	        (tn - vmin) / (vmax - vmin):
970 	        (vmax - tn) / (vmax - vmin);
971 	    if (ln && !right)
972 		plztx("v", dx, dy, wx, wy1, wy2, 0.5, pos, 1.0, string);
973 
974 	    if (lm && right)
975 		plztx("v", dx, dy, wx, wy1, wy2, -0.5, pos, 0.0, string);
976 
977 	    lstring = strlen(string);
978 	    *digits = MAX(*digits, lstring);
979 	}
980 	if (!ll && mode) {
981 	    sprintf(string, "(x10#u%d#d)", (int) scale);
982 	    pos = 1.15;
983 	    height = 0.5;
984 	    if (ln && !right) {
985 		plztx("v", dx, dy, wx, wy1, wy2, height, pos, 0.5, string);
986 	    }
987 	    if (lm && right) {
988 		plztx("v", dx, dy, wx, wy1, wy2,
989 		      (PLFLT) -height, pos, 0.5, string);
990 	    }
991 	}
992     }
993 }
994 
995 /*--------------------------------------------------------------------------*\
996  * void plztx()
997  *
998  * Prints out text along a vertical axis for a 3d plot joining
999  * world coordinates (wx,wy1) to (wx,wy2).
1000 \*--------------------------------------------------------------------------*/
1001 
1002 static void
plztx(const char * opt,PLFLT dx,PLFLT dy,PLFLT wx,PLFLT wy1,PLFLT wy2,PLFLT disp,PLFLT pos,PLFLT just,const char * text)1003 plztx(const char *opt, PLFLT dx, PLFLT dy, PLFLT wx, PLFLT wy1,
1004       PLFLT wy2, PLFLT disp, PLFLT pos, PLFLT just, const char *text)
1005 {
1006     PLINT refx = 0, refy = 0, x = 0, y = 0, vert = 0;
1007     PLFLT shift, cc, ss, wy;
1008     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, xform[4], diag;
1009     PLFLT dispx, dispy;
1010     PLFLT chrdef, chrht;
1011 
1012     cc = plsc->wmxscl * dx;
1013     ss = plsc->wmyscl * dy;
1014     diag = sqrt(cc * cc + ss * ss);
1015     cc /= diag;
1016     ss /= diag;
1017     wy = wy1 + pos * (wy2 - wy1);
1018 
1019     if (plP_stsearch(opt, 'v'))
1020 	vert = 0;
1021     else if (plP_stsearch(opt, 'h'))
1022 	vert = 1;
1023 
1024     if (vert) {
1025 	xform[0] = 0.0;
1026 	xform[1] = -cc;
1027 	xform[2] = 1.0;
1028 	xform[3] = -ss;
1029     } else {
1030 	xform[0] = cc;
1031 	xform[1] = 0.0;
1032 	xform[2] = ss;
1033 	xform[3] = 1.0;
1034     }
1035 
1036     xdv = plP_wcdcx(wx);
1037     ydv = plP_wcdcy(wy);
1038 
1039     dispx = -disp * cc;
1040     dispy = -disp * ss;
1041 
1042     plgchr(&chrdef, &chrht);
1043     shift = (just == 0.0) ? 0.0 : plstrl(text) * just;
1044 
1045     xmm = plP_dcmmx(xdv) + dispx * chrht;
1046     ymm = plP_dcmmy(ydv) + dispy * chrht;
1047     refxmm = xmm - shift * xform[0];
1048     refymm = ymm - shift * xform[2];
1049 
1050     x = plP_mmpcx(xmm);
1051     y = plP_mmpcy(ymm);
1052     refx = plP_mmpcx(refxmm);
1053     refy = plP_mmpcy(refymm);
1054 
1055     plP_text(0, just, xform, x, y, refx, refy, text);
1056 }
1057 
1058 /*--------------------------------------------------------------------------*\
1059  * void grid_box()
1060  *
1061  * Draws grids at tick locations (major and/or minor).
1062  *
1063  * Note that 'tspace' is the minimim distance away (in fractional number
1064  * of ticks or subticks) from the boundary a grid line can be drawn.  If
1065  * you are too close, it looks bad.
1066 \*--------------------------------------------------------------------------*/
1067 
1068 static void
grid_box(const char * xopt,PLFLT xtick1,PLINT nxsub1,const char * yopt,PLFLT ytick1,PLINT nysub1)1069 grid_box(const char *xopt, PLFLT xtick1, PLINT nxsub1,
1070 	 const char *yopt, PLFLT ytick1, PLINT nysub1)
1071 {
1072     PLINT lgx, lhx, llx;
1073     PLINT lgy, lhy, lly;
1074     PLFLT vpwxmi, vpwxma, vpwymi, vpwyma;
1075     PLFLT vpwxmin, vpwxmax, vpwymin, vpwymax;
1076     PLFLT tn, temp, tcrit, tspace = 0.1;
1077     PLINT i;
1078 
1079 /* Set plot options from input */
1080 
1081     lgx = plP_stsearch(xopt, 'g');
1082     lhx = plP_stsearch(xopt, 'h');
1083     llx = plP_stsearch(xopt, 'l');
1084 
1085     lgy = plP_stsearch(yopt, 'g');
1086     lhy = plP_stsearch(yopt, 'h');
1087     lly = plP_stsearch(yopt, 'l');
1088 
1089     plgvpw(&vpwxmin, &vpwxmax, &vpwymin, &vpwymax);
1090 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
1091  * similarly for vpwymi */
1092     vpwxmi = (vpwxmax > vpwxmin) ? vpwxmin : vpwxmax;
1093     vpwxma = (vpwxmax > vpwxmin) ? vpwxmax : vpwxmin;
1094     vpwymi = (vpwymax > vpwymin) ? vpwymin : vpwymax;
1095     vpwyma = (vpwymax > vpwymin) ? vpwymax : vpwymin;
1096 
1097 /* Draw grid in x direction. */
1098 
1099     if (lgx) {
1100 	for (tn = xtick1 * floor(vpwxmi/xtick1);
1101 	     tn <= vpwxma; tn += xtick1) {
1102 	    if (lhx) {
1103 		if (llx) {
1104 		    PLFLT otemp = tn;
1105 		    for (i = 0; i <= 7; i++) {
1106 			temp = tn + xlog[i];
1107 			tcrit = (temp - otemp)*tspace;
1108 			otemp = temp;
1109 			if (BETW(temp, vpwxmi+tcrit, vpwxma-tcrit))
1110 			    pljoin(temp, vpwymi, temp, vpwyma);
1111 		    }
1112 		}
1113 		else {
1114 		    for (i = 1; i <= nxsub1 - 1; i++) {
1115 			temp = tn + i * xtick1 / nxsub1;
1116 			tcrit = xtick1 / nxsub1 * tspace;
1117 			if (BETW(temp, vpwxmi+tcrit, vpwxma-tcrit))
1118 			    pljoin(temp, vpwymi, temp, vpwyma);
1119 		    }
1120 		}
1121 	    }
1122 	    tcrit = xtick1*tspace;
1123 	    if (BETW(tn, vpwxmi+tcrit, vpwxma-tcrit))
1124 	        pljoin(tn, vpwymi, tn, vpwyma);
1125 	}
1126     }
1127 
1128 /* Draw grid in y direction */
1129 
1130     if (lgy) {
1131 	tn = ytick1 * floor(vpwymi / ytick1 + tspace);
1132 	for (tn = ytick1 * floor(vpwymi/ytick1);
1133 	     tn <= vpwyma; tn += ytick1) {
1134 	    if (lhy) {
1135 		if (lly) {
1136 		    PLFLT otemp = tn;
1137 		    for (i = 0; i <= 7; i++) {
1138 			temp = tn + xlog[i];
1139 			tcrit = (temp - otemp)*tspace;
1140 			otemp = temp;
1141 			if (BETW(temp, vpwymi+tcrit, vpwyma-tcrit))
1142 			    pljoin(vpwxmi, temp, vpwxma, temp);
1143 		    }
1144 		}
1145 		else {
1146 		    for (i = 1; i <= nysub1 - 1; i++) {
1147 			temp = tn + i * ytick1 / nysub1;
1148 			tcrit = ytick1 / nysub1 * tspace;
1149 			if (BETW(temp, vpwymi+tcrit, vpwyma-tcrit))
1150 			    pljoin(vpwxmi, temp, vpwxma, temp);
1151 		    }
1152 		}
1153 	    }
1154 	    tcrit = ytick1*tspace;
1155 	    if (BETW(tn, vpwymi+tcrit, vpwyma-tcrit))
1156 	    pljoin(vpwxmi, tn, vpwxma, tn);
1157 	}
1158     }
1159 }
1160 
1161 /*--------------------------------------------------------------------------*\
1162  * void label_box()
1163  *
1164  * Writes numeric labels on side(s) of box.
1165 \*--------------------------------------------------------------------------*/
1166 
1167 static void
label_box(const char * xopt,PLFLT xtick1,const char * yopt,PLFLT ytick1)1168 label_box(const char *xopt, PLFLT xtick1, const char *yopt, PLFLT ytick1)
1169 {
1170     static char string[40];
1171     PLINT lfx, lix, llx, lmx, lnx, ltx;
1172     PLINT lfy, liy, lly, lmy, lny, lty, lvy;
1173     PLFLT vpwxmi, vpwxma, vpwymi, vpwyma;
1174     PLFLT vpwxmin, vpwxmax, vpwymin, vpwymax;
1175     PLFLT pos, tn, tp, offset, height;
1176 
1177 /* Set plot options from input */
1178 
1179     lfx = plP_stsearch(xopt, 'f');
1180     lix = plP_stsearch(xopt, 'i');
1181     llx = plP_stsearch(xopt, 'l');
1182     lmx = plP_stsearch(xopt, 'm');
1183     lnx = plP_stsearch(xopt, 'n');
1184     ltx = plP_stsearch(xopt, 't');
1185 
1186     lfy = plP_stsearch(yopt, 'f');
1187     liy = plP_stsearch(yopt, 'i');
1188     lly = plP_stsearch(yopt, 'l');
1189     lmy = plP_stsearch(yopt, 'm');
1190     lny = plP_stsearch(yopt, 'n');
1191     lty = plP_stsearch(yopt, 't');
1192     lvy = plP_stsearch(yopt, 'v');
1193 
1194     plgvpw(&vpwxmin, &vpwxmax, &vpwymin, &vpwymax);
1195 /* n.b. large change; vpwxmi always numerically less than vpwxma, and
1196  * similarly for vpwymi */
1197     vpwxmi = (vpwxmax > vpwxmin) ? vpwxmin : vpwxmax;
1198     vpwxma = (vpwxmax > vpwxmin) ? vpwxmax : vpwxmin;
1199     vpwymi = (vpwymax > vpwymin) ? vpwymin : vpwymax;
1200     vpwyma = (vpwymax > vpwymin) ? vpwymax : vpwymin;
1201 
1202 /* Write horizontal label(s) */
1203 
1204     if ((lmx || lnx) && ltx) {
1205 	PLINT xmode, xprec, xdigmax, xdigits, xscale;
1206 
1207 	plgxax(&xdigmax, &xdigits);
1208 	pldprec(vpwxmi, vpwxma, xtick1, lfx, &xmode, &xprec, xdigmax, &xscale);
1209 
1210 	tp = xtick1 * (1. + floor(vpwxmi / xtick1));
1211 	for (tn = tp; BETW(tn, vpwxmi, vpwxma); tn += xtick1) {
1212 	    plform(tn, xscale, xprec, string, llx, lfx);
1213 	    height = lix ? 1.75 : 1.5;
1214 	    pos = (vpwxmax > vpwxmin)?
1215 	        (tn - vpwxmi) / (vpwxma - vpwxmi):
1216 	        (vpwxma - tn) / (vpwxma - vpwxmi);
1217   	    if (lnx)
1218 		plmtex("b", height, pos, 0.5, string);
1219 	    if (lmx)
1220 		plmtex("t", height, pos, 0.5, string);
1221 	}
1222 	xdigits = 2;
1223 	plsxax(xdigmax, xdigits);
1224 
1225     /* Write separate exponential label if mode = 1. */
1226 
1227 	if (!llx && xmode) {
1228 	    pos = 1.0;
1229 	    height = 3.2;
1230 	    sprintf(string, "(x10#u%d#d)", (int) xscale);
1231 	    if (lnx)
1232 		plmtex("b", height, pos, 0.5, string);
1233 	    if (lmx)
1234 		plmtex("t", height, pos, 0.5, string);
1235 	}
1236     }
1237 
1238 /* Write vertical label(s) */
1239 
1240     if ((lmy || lny) && lty) {
1241 	PLINT ymode, yprec, ydigmax, ydigits, yscale;
1242 
1243 	plgyax(&ydigmax, &ydigits);
1244 	pldprec(vpwymi, vpwyma, ytick1, lfy, &ymode, &yprec, ydigmax, &yscale);
1245 
1246 	ydigits = 0;
1247 	tp = ytick1 * (1. + floor(vpwymi / ytick1));
1248 	for (tn = tp; BETW(tn, vpwymi, vpwyma); tn += ytick1) {
1249 	    plform(tn, yscale, yprec, string, lly, lfy);
1250 	    pos = (vpwymax > vpwymin)?
1251 	        (tn - vpwymi) / (vpwyma - vpwymi):
1252 	        (vpwyma - tn) / (vpwyma - vpwymi);
1253 	    if (lny) {
1254 		if (lvy) {
1255 		    height = liy ? 1.0 : 0.5;
1256 		    plmtex("lv", height, pos, 1.0, string);
1257 		} else {
1258 		    height = liy ? 1.75 : 1.5;
1259 		    plmtex("l", height, pos, 0.5, string);
1260 		}
1261 	    }
1262 	    if (lmy) {
1263 		if (lvy) {
1264 		    height = liy ? 1.0 : 0.5;
1265 		    plmtex("rv", height, pos, 0.0, string);
1266 		} else {
1267 		    height = liy ? 1.75 : 1.5;
1268 		    plmtex("r", height, pos, 0.5, string);
1269 		}
1270 	    }
1271 	    ydigits = MAX(ydigits, (PLINT) strlen(string));
1272 	}
1273 	if (!lvy)
1274 	    ydigits = 2;
1275 
1276 	plsyax(ydigmax, ydigits);
1277 
1278     /* Write separate exponential label if mode = 1. */
1279 
1280 	if (!lly && ymode) {
1281 	    sprintf(string, "(x10#u%d#d)", (int) yscale);
1282 	    offset = 0.02;
1283 	    height = 2.0;
1284 	    if (lny) {
1285 		pos = 0.0 - offset;
1286 		plmtex("t", height, pos, 1.0, string);
1287 	    }
1288 	    if (lmy) {
1289 		pos = 1.0 + offset;
1290 		plmtex("t", height, pos, 0.0, string);
1291 	    }
1292 	}
1293     }
1294 }
1295 
1296 /*--------------------------------------------------------------------------*\
1297  * void plform()
1298  *
1299  * Formats a PLFLT value in one of the following formats.
1300  *
1301  * If ll (logarithmic), then:
1302  *
1303  *    -	If lf (fixed), then used fixed point notation, i.e. .1, 1, 10, etc,
1304  *	with unnecessary trailing .'s or 0's removed.
1305  *
1306  *    -	If !lf (default), then use exponential notation, i.e. 10^-1, etc.
1307  *
1308  * If !ll (linear), then:
1309  *
1310  *    - If scale == 0, use fixed point format with "prec" places after the
1311  *	decimal point.
1312  *
1313  *    -	If scale == 1, use scientific notation with one place before the
1314  *	decimal point and "prec" places after.  In this case, the value
1315  *	must be divided by 10^scale.
1316 \*--------------------------------------------------------------------------*/
1317 
1318 static void
plform(PLFLT value,PLINT scale,PLINT prec,char * string,PLINT ll,PLINT lf)1319 plform(PLFLT value, PLINT scale, PLINT prec, char *string, PLINT ll, PLINT lf)
1320 {
1321     if (ll) {
1322 
1323     /* Logarithmic */
1324 
1325 	if (lf) {
1326 
1327 	/* Fixed point, i.e. .1, 1, 10, etc */
1328 
1329 	    int exponent = ROUND(value);
1330 
1331 	    value = pow(10.0, exponent);
1332 	    if (exponent < 0) {
1333 		char form[10];
1334 		sprintf(form, "%%.%df", ABS(exponent));
1335 		sprintf(string, form, value);
1336 	    }
1337 	    else {
1338 		sprintf(string, "%d", (int) value);
1339 	    }
1340 	}
1341 	else {
1342 
1343 	/* Exponential, i.e. 10^-1, 10^0, 10^1, etc */
1344 
1345 	    sprintf(string, "10#u%d", (int) ROUND(value));
1346 	}
1347     }
1348     else {
1349 
1350     /* Linear */
1351 
1352 	PLINT setpre, precis;
1353 	char form[10], temp[30];
1354 	double scale2;
1355 
1356 	plP_gprec(&setpre, &precis);
1357 
1358 	if (setpre)
1359 	    prec = precis;
1360 
1361 	if (scale)
1362 	    value /= pow(10.,(double)scale);
1363 
1364     /* This is necessary to prevent labels like "-0.0" on some systems */
1365 
1366 	scale2 = pow(10., prec);
1367 	value = floor((value * scale2) + .5) / scale2;
1368 
1369 	sprintf(form, "%%.%df", (int) prec);
1370 	sprintf(temp, form, value);
1371 	strcpy(string, temp);
1372     }
1373 }
1374