1 // Functions dealing with viewports.
2 //
3 // Copyright (C) 2004 Joao Cardoso
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21
22 #include "plplotP.h"
23
24 static void
25 c_plenvi( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
26 PLINT just, PLINT axis, PLINT old );
27
28 //--------------------------------------------------------------------------
29 // void plenv()
30 //
31 // Simple interface for defining viewport and window.
32 //
33 // The "just" parameter control how the axes will be scaled:
34 //
35 // just=-1 : The scales will not be set, the user must set up the scale
36 // before calling plenv() using plsvpa(), plvasp() or other;
37 // just= 0 : The scales will be set up to optimize plot area;
38 // just= 1 : The scales will be the same;
39 // just= 2 : The axes will be equal, the plot box will be square.
40 //
41 // The "axis" parameter is interpreted as follows:
42 //
43 // axis=-2 : draw no box, no tick marks, no numeric tick labels, no axes.
44 // axis=-1 : draw box only.
45 // axis= 0 : Draw box, ticks, and numeric tick labels.
46 // axis= 1 : Also draw coordinate axes at X=0, and Y=0.
47 // axis= 2 : Also draw a grid at major tick positions in both coordinates.
48 // axis= 3 : Same as 2, but the grid will be also at the minor ticks.
49 // axis=10 : Same as 0 except Logarithmic X tick marks. (The X data have
50 // to be converted to logarithms separately.)
51 // axis=11 : Same as 1 except Logarithmic X tick marks. (The X data have
52 // to be converted to logarithms separately.)
53 // axis=12 : Same as 2 except Logarithmic X tick marks. (The X data have
54 // to be converted to logarithms separately.)
55 // axis=13 : Same as 12, but the grid will be also at the minor ticks.
56 // axis=20 : Same as 0 except Logarithmic Y tick marks. (The Y data have
57 // to be converted to logarithms separately.)
58 // axis=21 : Same as 1 except Logarithmic Y tick marks. (The Y data have
59 // to be converted to logarithms separately.)
60 // axis=22 : Same as 2 except Logarithmic Y tick marks. (The Y data have
61 // to be converted to logarithms separately.)
62 // axis=23 : Same as 22, but the grid will be also at the minor ticks.
63 // axis=30 : Same as 0 except Logarithmic X,Y tick marks. (The X,Y data have
64 // to be converted to logarithms separately.)
65 // axis=31 : Same as 1 except Logarithmic X,Y tick marks. (The X,Y data have
66 // to be converted to logarithms separately.)
67 // axis=32 : Same as 2 except Logarithmic X,Y tick marks. (The X,Y data have
68 // to be converted to logarithms separately.)
69 // axis=33 : Same as 32, but the grid will be also at the minor ticks.
70 // axis=40 : Same as 0 except date / time X tick marks.
71 // axis=41 : Same as 1 except date / time X tick marks.
72 // axis=42 : Same as 2 except date / time X tick marks.
73 // axis=43 : Same as 42, but the grid will be also at the minor ticks.
74 // axis=50 : Same as 0 except date / time Y tick marks.
75 // axis=51 : Same as 1 except date / time Y tick marks.
76 // axis=52 : Same as 2 except date / time Y tick marks.
77 // axis=53 : Same as 52, but the grid will be also at the minor ticks.
78 // axis=60 : Same as 0 except date / time X,Y tick marks.
79 // axis=61 : Same as 1 except date / time X,Y tick marks.
80 // axis=62 : Same as 2 except date / time X,Y tick marks.
81 // axis=63 : Same as 62, but the grid will be also at the minor ticks.
82 // axis=70 : Same as 0 except custom X,Y labels.
83 // axis=71 : Same as 1 except custom X,Y labels.
84 // axis=72 : Same as 2 except custom X,Y labels.
85 // axis=73 : Same as 72, but the grid will be also at the minor ticks.
86 //--------------------------------------------------------------------------
87
88 void
c_plenv(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax,PLINT just,PLINT axis)89 c_plenv( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
90 PLINT just, PLINT axis )
91 {
92 c_plenvi( xmin, xmax, ymin, ymax, just, axis, 1 );
93 }
94
95 //--------------------------------------------------------------------------
96 // void plenv0()
97 //
98 // same as plenv() above, but if in multiplot mode does not advance the subpage,
99 // instead clears it.
100 //--------------------------------------------------------------------------
101
102 void
c_plenv0(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax,PLINT just,PLINT axis)103 c_plenv0( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
104 PLINT just, PLINT axis )
105 {
106 c_plenvi( xmin, xmax, ymin, ymax, just, axis, 0 );
107 }
108
109
110 static void
c_plenvi(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax,PLINT just,PLINT axis,PLINT old)111 c_plenvi( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax,
112 PLINT just, PLINT axis, PLINT old )
113 {
114 PLFLT lb, rb, tb, bb, dx, dy;
115 PLFLT xsize, ysize, size, xscale, yscale, scale;
116 PLFLT spxmin, spxmax, spymin, spymax;
117 PLFLT vpxmin, vpxmax, vpymin, vpymax;
118
119 if ( plsc->level < 1 )
120 {
121 plabort( "plenv: Please call plinit first" );
122 return;
123 }
124 if ( xmin == xmax )
125 {
126 plabort( "plenv: Invalid xmin and xmax arguments" );
127 return;
128 }
129 if ( ymin == ymax )
130 {
131 plabort( "plenv: Invalid ymin and ymax arguments" );
132 return;
133 }
134 if ( just < -1 || just > 2 )
135 {
136 plabort( "plenv: Invalid just option" );
137 return;
138 }
139
140 if ( plsc->nsubx * plsc->nsuby == 1 ) // not multiplot mode
141 old = 1;
142
143 if ( old == 1 )
144 pladv( 0 );
145 else
146 plclear();
147
148 if ( just == 0 )
149 plvsta();
150 else if ( just == 1 )
151 {
152 lb = 8.0 * plsc->chrht;
153 rb = 5.0 * plsc->chrht;
154 tb = 5.0 * plsc->chrht;
155 bb = 5.0 * plsc->chrht;
156 dx = ABS( xmax - xmin );
157 dy = ABS( ymax - ymin );
158 plgspa( &spxmin, &spxmax, &spymin, &spymax );
159 xsize = spxmax - spxmin;
160 ysize = spymax - spymin;
161 xscale = dx / ( xsize - lb - rb );
162 yscale = dy / ( ysize - tb - bb );
163 scale = MAX( xscale, yscale );
164 vpxmin = MAX( lb, 0.5 * ( xsize - dx / scale ) );
165 vpxmax = vpxmin + ( dx / scale );
166 vpymin = MAX( bb, 0.5 * ( ysize - dy / scale ) );
167 vpymax = vpymin + ( dy / scale );
168 plsvpa( vpxmin, vpxmax, vpymin, vpymax );
169 }
170 else if ( just == 2 )
171 {
172 lb = 8.0 * plsc->chrht;
173 rb = 5.0 * plsc->chrht;
174 tb = 5.0 * plsc->chrht;
175 bb = 5.0 * plsc->chrht;
176 plgspa( &spxmin, &spxmax, &spymin, &spymax );
177 xsize = spxmax - spxmin;
178 ysize = spymax - spymin;
179 size = MIN( xsize - lb - rb, ysize - tb - bb );
180 dx = ( xsize - size - lb - rb ) / 2;
181 vpxmin = lb + dx;
182 vpxmax = vpxmin + size;
183 dy = ( ysize - size - bb - tb ) / 2;
184 vpymin = bb + dy;
185 vpymax = vpymin + size;
186 plsvpa( vpxmin, vpxmax, vpymin, vpymax );
187 }
188
189 plwind( xmin, xmax, ymin, ymax );
190
191 switch ( axis )
192 {
193 case -2:
194 break;
195 case -1:
196 plbox( "bc", (PLFLT) 0.0, 0, "bc", (PLFLT) 0.0, 0 );
197 break;
198 case 0:
199 plbox( "bcnst", (PLFLT) 0.0, 0, "bcnstv", (PLFLT) 0.0, 0 );
200 break;
201 case 1:
202 plbox( "abcnst", (PLFLT) 0.0, 0, "abcnstv", (PLFLT) 0.0, 0 );
203 break;
204 case 2:
205 plbox( "abcgnst", (PLFLT) 0.0, 0, "abcgnstv", (PLFLT) 0.0, 0 );
206 break;
207 case 3:
208 plbox( "abcgnsth", (PLFLT) 0.0, 0, "abcgnstvh", (PLFLT) 0.0, 0 );
209 break;
210 case 10:
211 plbox( "bclnst", (PLFLT) 0.0, 0, "bcnstv", (PLFLT) 0.0, 0 );
212 break;
213 case 11:
214 plbox( "abclnst", (PLFLT) 0.0, 0, "abcnstv", (PLFLT) 0.0, 0 );
215 break;
216 case 12:
217 plbox( "abcglnst", (PLFLT) 0.0, 0, "abcgnstv", (PLFLT) 0.0, 0 );
218 break;
219 case 13:
220 plbox( "abcglnsth", (PLFLT) 0.0, 0, "abcgnstvh", (PLFLT) 0.0, 0 );
221 break;
222 case 20:
223 plbox( "bcnst", (PLFLT) 0.0, 0, "bclnstv", (PLFLT) 0.0, 0 );
224 break;
225 case 21:
226 plbox( "abcnst", (PLFLT) 0.0, 0, "abclnstv", (PLFLT) 0.0, 0 );
227 break;
228 case 22:
229 plbox( "abcgnst", (PLFLT) 0.0, 0, "abcglnstv", (PLFLT) 0.0, 0 );
230 break;
231 case 23:
232 plbox( "abcgnsth", (PLFLT) 0.0, 0, "abcglnstvh", (PLFLT) 0.0, 0 );
233 break;
234 case 30:
235 plbox( "bclnst", (PLFLT) 0.0, 0, "bclnstv", (PLFLT) 0.0, 0 );
236 break;
237 case 31:
238 plbox( "abclnst", (PLFLT) 0.0, 0, "abclnstv", (PLFLT) 0.0, 0 );
239 break;
240 case 32:
241 plbox( "abcglnst", (PLFLT) 0.0, 0, "abcglnstv", (PLFLT) 0.0, 0 );
242 break;
243 case 33:
244 plbox( "abcglnsth", (PLFLT) 0.0, 0, "abcglnstvh", (PLFLT) 0.0, 0 );
245 break;
246 case 40:
247 plbox( "bcdnst", (PLFLT) 0.0, 0, "bcnstv", (PLFLT) 0.0, 0 );
248 break;
249 case 41:
250 plbox( "abcdnst", (PLFLT) 0.0, 0, "abcnstv", (PLFLT) 0.0, 0 );
251 break;
252 case 42:
253 plbox( "abcgdnst", (PLFLT) 0.0, 0, "abcgnstv", (PLFLT) 0.0, 0 );
254 break;
255 case 43:
256 plbox( "abcgdnsth", (PLFLT) 0.0, 0, "abcgnstvh", (PLFLT) 0.0, 0 );
257 break;
258 case 50:
259 plbox( "bcnst", (PLFLT) 0.0, 0, "bcdnstv", (PLFLT) 0.0, 0 );
260 break;
261 case 51:
262 plbox( "abcnst", (PLFLT) 0.0, 0, "abcdnstv", (PLFLT) 0.0, 0 );
263 break;
264 case 52:
265 plbox( "abcgnst", (PLFLT) 0.0, 0, "abcgdnstv", (PLFLT) 0.0, 0 );
266 break;
267 case 53:
268 plbox( "abcgnsth", (PLFLT) 0.0, 0, "abcgdnstvh", (PLFLT) 0.0, 0 );
269 break;
270 case 60:
271 plbox( "bcdnst", (PLFLT) 0.0, 0, "bcdnstv", (PLFLT) 0.0, 0 );
272 break;
273 case 61:
274 plbox( "abcdnst", (PLFLT) 0.0, 0, "abcdnstv", (PLFLT) 0.0, 0 );
275 break;
276 case 62:
277 plbox( "abcgdnst", (PLFLT) 0.0, 0, "abcgdnstv", (PLFLT) 0.0, 0 );
278 break;
279 case 63:
280 plbox( "abcgdnsth", (PLFLT) 0.0, 0, "abcgdnstvh", (PLFLT) 0.0, 0 );
281 break;
282 case 70:
283 plbox( "bcnost", (PLFLT) 0.0, 0, "bcnostv", (PLFLT) 0.0, 0 );
284 break;
285 case 71:
286 plbox( "abcnost", (PLFLT) 0.0, 0, "abcnostv", (PLFLT) 0.0, 0 );
287 break;
288 case 72:
289 plbox( "abcgnost", (PLFLT) 0.0, 0, "abcgnostv", (PLFLT) 0.0, 0 );
290 break;
291 case 73:
292 plbox( "abcgnosth", (PLFLT) 0.0, 0, "abcgnostvh", (PLFLT) 0.0, 0 );
293 break;
294 default:
295 plwarn( "plenv: Invalid axis argument" );
296 }
297 }
298
299 //--------------------------------------------------------------------------
300 // void plvsta()
301 //
302 // Defines a "standard" viewport with seven character heights for
303 // the left margin and four character heights everywhere else.
304 //--------------------------------------------------------------------------
305
306 void
c_plvsta(void)307 c_plvsta( void )
308 {
309 PLFLT xmin, xmax, ymin, ymax;
310 PLFLT lb, rb, tb, bb;
311
312 if ( plsc->level < 1 )
313 {
314 plabort( "plvsta: Please call plinit first" );
315 return;
316 }
317
318 // Find out position of subpage boundaries in millimetres, reduce by
319 // the desired border, and convert back into normalized subpage
320 // coordinates
321
322 lb = 8.0 * plsc->chrht;
323 rb = 5.0 * plsc->chrht;
324 tb = 5.0 * plsc->chrht;
325 bb = 5.0 * plsc->chrht;
326
327 xmin = plP_dcscx( plP_mmdcx( (PLFLT) ( plP_dcmmx( plsc->spdxmi ) + lb ) ) );
328 xmax = plP_dcscx( plP_mmdcx( (PLFLT) ( plP_dcmmx( plsc->spdxma ) - rb ) ) );
329 ymin = plP_dcscy( plP_mmdcy( (PLFLT) ( plP_dcmmy( plsc->spdymi ) + tb ) ) );
330 ymax = plP_dcscy( plP_mmdcy( (PLFLT) ( plP_dcmmy( plsc->spdyma ) - bb ) ) );
331
332 plvpor( xmin, xmax, ymin, ymax );
333 }
334
335 //--------------------------------------------------------------------------
336 // void plvpor()
337 //
338 // Creates a viewport with the specified normalized subpage coordinates.
339 //--------------------------------------------------------------------------
340
341 void
c_plvpor(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax)342 c_plvpor( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax )
343 {
344 if ( plsc->level < 1 )
345 {
346 plabort( "plvpor: Please call plinit first" );
347 return;
348 }
349 if ( ( xmin >= xmax ) || ( ymin >= ymax ) )
350 {
351 plabort( "plvpor: Invalid limits" );
352 return;
353 }
354 if ( ( plsc->cursub <= 0 ) || ( plsc->cursub > ( plsc->nsubx * plsc->nsuby ) ) )
355 {
356 plabort( "plvpor: Please call pladv or plenv to go to a subpage" );
357 return;
358 }
359
360 plsc->vpdxmi = plsc->spdxmi + ( plsc->spdxma - plsc->spdxmi ) * xmin;
361 plsc->vpdxma = plsc->spdxmi + ( plsc->spdxma - plsc->spdxmi ) * xmax;
362 plsc->vpdymi = plsc->spdymi + ( plsc->spdyma - plsc->spdymi ) * ymin;
363 plsc->vpdyma = plsc->spdymi + ( plsc->spdyma - plsc->spdymi ) * ymax;
364
365 plsc->vppxmi = plP_dcpcx( plsc->vpdxmi );
366 plsc->vppxma = plP_dcpcx( plsc->vpdxma );
367 plsc->vppymi = plP_dcpcy( plsc->vpdymi );
368 plsc->vppyma = plP_dcpcy( plsc->vpdyma );
369
370 plP_sclp( MAX( plsc->vppxmi, plsc->phyxmi ), MIN( plsc->vppxma, plsc->phyxma ),
371 MAX( plsc->vppymi, plsc->phyymi ), MIN( plsc->vppyma, plsc->phyyma ) );
372
373 plsc->level = 2;
374 }
375
376 //--------------------------------------------------------------------------
377 // void plvpas()
378 //
379 // Creates the largest viewport of the specified aspect ratio that fits
380 // within the specified normalized subpage coordinates.
381 //--------------------------------------------------------------------------
382
383 void
c_plvpas(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax,PLFLT aspect)384 c_plvpas( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax, PLFLT aspect )
385 {
386 PLFLT spxmin, spxmax, spymin, spymax;
387 PLFLT vpxmin, vpxmax, vpymin, vpymax;
388 PLFLT xsize, ysize, nxsize, nysize;
389 PLFLT xoffset, yoffset;
390
391 if ( plsc->level < 1 )
392 {
393 plabort( "plvpas: Please call plinit first" );
394 return;
395 }
396 if ( ( xmin >= xmax ) || ( ymin >= ymax ) )
397 {
398 plabort( "plvpas: Invalid limits" );
399 return;
400 }
401
402 if ( aspect <= 0.0 )
403 {
404 c_plvpor( xmin, xmax, ymin, ymax );
405 return;
406 }
407
408 plgspa( &spxmin, &spxmax, &spymin, &spymax );
409
410 xsize = spxmax - spxmin;
411 ysize = spymax - spymin;
412
413 xoffset = xsize * xmin;
414 yoffset = ysize * ymin;
415
416 spxmax = spxmin + xsize * xmax;
417 spxmin = spxmin + xsize * xmin;
418 spymax = spymin + ysize * ymax;
419 spymin = spymin + ysize * ymin;
420
421 // Adjust size for the requested edging
422 xsize = spxmax - spxmin;
423 ysize = spymax - spymin;
424
425 if ( aspect * xsize > ysize )
426 {
427 nxsize = ysize / aspect;
428 nysize = ysize;
429 }
430 else
431 {
432 nxsize = xsize;
433 nysize = xsize * aspect;
434 }
435
436 // center plot within page
437
438 vpxmin = 0.5 * ( xsize - nxsize ) + xoffset;
439 vpxmax = vpxmin + nxsize;
440 vpymin = 0.5 * ( ysize - nysize ) + yoffset;
441 vpymax = vpymin + nysize;
442
443 plsvpa( vpxmin, vpxmax, vpymin, vpymax );
444 }
445
446 //--------------------------------------------------------------------------
447 // void plvasp()
448 //
449 // Sets the edges of the viewport with the given aspect ratio, leaving
450 // room for labels.
451 //--------------------------------------------------------------------------
452
453 void
c_plvasp(PLFLT aspect)454 c_plvasp( PLFLT aspect )
455 {
456 PLFLT spxmin, spxmax, spymin, spymax;
457 PLFLT vpxmin, vpxmax, vpymin, vpymax;
458 PLFLT xsize, ysize, nxsize, nysize;
459 PLFLT lb, rb, tb, bb;
460
461 if ( plsc->level < 1 )
462 {
463 plabort( "plvasp: Please call plinit first" );
464 return;
465 }
466
467 lb = 8.0 * plsc->chrht;
468 rb = 5.0 * plsc->chrht;
469 tb = 5.0 * plsc->chrht;
470 bb = 5.0 * plsc->chrht;
471
472 plgspa( &spxmin, &spxmax, &spymin, &spymax );
473 xsize = spxmax - spxmin;
474 ysize = spymax - spymin;
475 xsize -= lb + rb; // adjust for labels
476 ysize -= bb + tb;
477 if ( aspect * xsize > ysize )
478 {
479 nxsize = ysize / aspect;
480 nysize = ysize;
481 }
482 else
483 {
484 nxsize = xsize;
485 nysize = xsize * aspect;
486 }
487
488 // center plot within page
489
490 vpxmin = .5 * ( xsize - nxsize ) + lb;
491 vpxmax = vpxmin + nxsize;
492 vpymin = .5 * ( ysize - nysize ) + bb;
493 vpymax = vpymin + nysize;
494
495 plsvpa( vpxmin, vpxmax, vpymin, vpymax );
496 }
497
498 //--------------------------------------------------------------------------
499 // void plsvpa()
500 //
501 // Sets the edges of the viewport to the specified absolute coordinates
502 // (mm), measured with respect to the current subpage boundaries.
503 //--------------------------------------------------------------------------
504
505 void
c_plsvpa(PLFLT xmin,PLFLT xmax,PLFLT ymin,PLFLT ymax)506 c_plsvpa( PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax )
507 {
508 PLFLT sxmin, symin;
509
510 if ( plsc->level < 1 )
511 {
512 plabort( "plsvpa: Please call plinit first" );
513 return;
514 }
515 if ( ( xmin >= xmax ) || ( ymin >= ymax ) )
516 {
517 plabort( "plsvpa: Invalid limits" );
518 return;
519 }
520 if ( ( plsc->cursub <= 0 ) || ( plsc->cursub > ( plsc->nsubx * plsc->nsuby ) ) )
521 {
522 plabort( "plsvpa: Please call pladv or plenv to go to a subpage" );
523 return;
524 }
525
526 sxmin = plP_dcmmx( plsc->spdxmi );
527 symin = plP_dcmmy( plsc->spdymi );
528
529 plsc->vpdxmi = plP_mmdcx( (PLFLT) ( sxmin + xmin ) );
530 plsc->vpdxma = plP_mmdcx( (PLFLT) ( sxmin + xmax ) );
531 plsc->vpdymi = plP_mmdcy( (PLFLT) ( symin + ymin ) );
532 plsc->vpdyma = plP_mmdcy( (PLFLT) ( symin + ymax ) );
533
534 plsc->vppxmi = plP_dcpcx( plsc->vpdxmi );
535 plsc->vppxma = plP_dcpcx( plsc->vpdxma );
536 plsc->vppymi = plP_dcpcy( plsc->vpdymi );
537 plsc->vppyma = plP_dcpcy( plsc->vpdyma );
538
539 plP_sclp( plP_dcpcx( plsc->vpdxmi ), plP_dcpcx( plsc->vpdxma ),
540 plP_dcpcy( plsc->vpdymi ), plP_dcpcy( plsc->vpdyma ) );
541
542 plsc->level = 2;
543 }
544