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