1 /* $Id: plcore.c,v 1.14 2007/10/24 13:14:43 ajb Exp $
2
3 Central dispatch facility for PLplot.
4 Also contains the PLplot main data structures, external access
5 routines, and initialization calls.
6
7 This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
8
9
10 Copyright (C) 2004 Joao Cardoso
11 Copyright (C) 2004, 2005 Rafael Laboissiere
12 Copyright (C) 2004, 2006 Andrew Ross
13 Copyright (C) 2004 Andrew Roach
14 Copyright (C) 2005 Alan W. Irwin
15 Copyright (C) 2005 Thomas J. Duck
16
17 This file is part of PLplot.
18
19 PLplot is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Library Public License as published
21 by the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 PLplot is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU Library General Public License for more details.
28
29 You should have received a copy of the GNU Library General Public License
30 along with PLplot; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32
33 */
34
35 #define DEBUG
36
37 #define NEED_PLDEBUG
38 #include "plcore.h"
39
40 #ifdef ENABLE_DYNDRIVERS
41 #include <ltdl.h>
42 #endif
43
44 /*--------------------------------------------------------------------------*\
45 * Driver Interface
46 *
47 * These routines are the low-level interface to the driver -- all calls to
48 * driver functions must pass through here. For implementing driver-
49 * specific functions, the escape function is provided. The command stream
50 * gets duplicated to the plot buffer here.
51 *
52 * All functions that result in graphics actually being plotted (rather than
53 * just a change of state) are filtered as necessary before being passed on.
54 * The default settings do not require any filtering, i.e. PLplot physical
55 * coordinates are the same as the device physical coordinates (currently
56 * this can't be changed anyway), and a global view equal to the entire page
57 * is used.
58 *
59 * The reason one wants to put view-specific filtering here is that if
60 * enabled, the plot buffer should receive the unfiltered data stream. This
61 * allows a specific view to be used from an interactive device (e.g. TCL/TK
62 * driver) but be restored to the full view at any time merely by
63 * reprocessing the contents of the plot buffer.
64 *
65 * The metafile, on the other hand, *should* be affected by changes in the
66 * view, since this is a crucial editing capability. It is recommended that
67 * the initial metafile be created without a restricted global view, and
68 * modification of the view done on a per-plot basis as desired during
69 * subsequent processing.
70 *
71 \*--------------------------------------------------------------------------*/
72
73 enum {AT_BOP, DRAWING, AT_EOP};
74
75 /* Initialize device. */
76 /* The plot buffer must be called last. */
77
78 /* The following array of chars is used both here and in plsym.c for
79 * translating the Greek characters from the #g escape sequences into
80 * the Hershey and Unicode codings
81 */
82 const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
83
84 void
plP_init(void)85 plP_init(void)
86 {
87 plsc->page_status = AT_EOP;
88
89 (*plsc->dispatch_table->pl_init) ((struct PLStream_struct *) plsc);
90
91 if (plsc->plbuf_write)
92 plbuf_init(plsc);
93 }
94
95 /* End of page */
96 /* The plot buffer must be called first. */
97 /* Ignore instruction if already at eop. */
98
99 void
plP_eop(void)100 plP_eop(void)
101 {
102 int skip_driver_eop = 0;
103
104 if (plsc->page_status == AT_EOP)
105 return;
106
107 plsc->page_status = AT_EOP;
108
109 if (plsc->plbuf_write)
110 plbuf_eop(plsc);
111
112 /* Call user eop handler if present. */
113
114 if (plsc->eop_handler != NULL)
115 (*plsc->eop_handler) (plsc->eop_data, &skip_driver_eop);
116
117 if (!skip_driver_eop)
118 (*plsc->dispatch_table->pl_eop) ((struct PLStream_struct *) plsc);
119 }
120
121 /* Set up new page. */
122 /* The plot buffer must be called last. */
123 /* Ignore if already at bop. */
124 /* It's not actually necessary to be AT_EOP here, so don't check for it. */
125
126 void
plP_bop(void)127 plP_bop(void)
128 {
129 int skip_driver_bop = 0;
130
131 plP_subpInit();
132 if (plsc->page_status == AT_BOP)
133 return;
134
135 plsc->page_status = AT_BOP;
136 plsc->nplwin = 0;
137
138 /* Call user bop handler if present. */
139
140 if (plsc->bop_handler != NULL)
141 (*plsc->bop_handler) (plsc->bop_data, &skip_driver_bop);
142
143 if (!skip_driver_bop)
144 (*plsc->dispatch_table->pl_bop) ((struct PLStream_struct *) plsc);
145
146 if (plsc->plbuf_write)
147 plbuf_bop(plsc);
148 }
149
150 /* Tidy up device (flush buffers, close file, etc). */
151
152 void
plP_tidy(void)153 plP_tidy(void)
154 {
155 if (plsc->tidy) {
156 (*plsc->tidy) (plsc->tidy_data);
157 plsc->tidy = NULL;
158 plsc->tidy_data = NULL;
159 }
160
161 (*plsc->dispatch_table->pl_tidy) ((struct PLStream_struct *) plsc);
162
163 if (plsc->plbuf_write) {
164 plbuf_tidy(plsc);
165 }
166
167 plsc->OutFile = NULL;
168
169 }
170
171 /* Change state. */
172
173 void
plP_state(PLINT op)174 plP_state(PLINT op)
175 {
176 if (plsc->plbuf_write) plbuf_state(plsc, op);
177
178 (*plsc->dispatch_table->pl_state) ((struct PLStream_struct *) plsc, op);
179 }
180
181 /* Escape function, for driver-specific commands. */
182
183 void
plP_esc(PLINT op,void * ptr)184 plP_esc(PLINT op, void *ptr)
185 {
186 PLINT clpxmi, clpxma, clpymi, clpyma;
187 EscText* args;
188
189 /* The plot buffer must be called first */
190 if(plsc->plbuf_write) plbuf_esc(plsc, op, ptr);
191
192 /* Text coordinates must pass through the driver interface filter */
193 if(op==PLESC_HAS_TEXT && plsc->dev_unicode) {
194
195 /* Apply the driver interface filter */
196 if (plsc->difilt) {
197 args = (EscText*)ptr;
198 difilt(&(args->x),&(args->y),1,&clpxmi,&clpxma,&clpymi,&clpyma);
199 }
200 }
201
202 (*plsc->dispatch_table->pl_esc) ((struct PLStream_struct *) plsc, op, ptr);
203 }
204
205 /* Set up plot window parameters. */
206 /* The plot buffer must be called first */
207 /* Some drivers (metafile, Tk) need access to this data */
208
209 void
plP_swin(PLWindow * plwin)210 plP_swin(PLWindow *plwin)
211 {
212 PLWindow *w;
213 PLINT clpxmi, clpxma, clpymi, clpyma;
214
215 /* Provide plot buffer with unfiltered window data */
216
217 if (plsc->plbuf_write)
218 plbuf_esc(plsc, PLESC_SWIN, (void *) plwin);
219
220 w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
221
222 w->dxmi = plwin->dxmi;
223 w->dxma = plwin->dxma;
224 w->dymi = plwin->dymi;
225 w->dyma = plwin->dyma;
226
227 if (plsc->difilt) {
228 xscl[0] = plP_dcpcx(w->dxmi);
229 xscl[1] = plP_dcpcx(w->dxma);
230 yscl[0] = plP_dcpcy(w->dymi);
231 yscl[1] = plP_dcpcy(w->dyma);
232
233 difilt(xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma);
234
235 w->dxmi = plP_pcdcx(xscl[0]);
236 w->dxma = plP_pcdcx(xscl[1]);
237 w->dymi = plP_pcdcy(yscl[0]);
238 w->dyma = plP_pcdcy(yscl[1]);
239 }
240
241 w->wxmi = plwin->wxmi;
242 w->wxma = plwin->wxma;
243 w->wymi = plwin->wymi;
244 w->wyma = plwin->wyma;
245
246 /* If the driver wants to process swin commands, call it now */
247 /* It must use the filtered data, which it can get from *plsc */
248
249 if (plsc->dev_swin) {
250 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
251 PLESC_SWIN, NULL );
252 }
253 }
254
255 /*--------------------------------------------------------------------------*\
256 * Drawing commands.
257 \*--------------------------------------------------------------------------*/
258
259 /* Draw line between two points */
260 /* The plot buffer must be called first so it gets the unfiltered data */
261
262 void
plP_line(short * x,short * y)263 plP_line(short *x, short *y)
264 {
265 PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
266
267 plsc->page_status = DRAWING;
268
269 if (plsc->plbuf_write)
270 plbuf_line(plsc, x[0], y[0], x[1], y[1]);
271
272 if (plsc->difilt) {
273 for (i = 0; i < npts; i++) {
274 xscl[i] = x[i];
275 yscl[i] = y[i];
276 }
277 difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
278 plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
279 }
280 else {
281 grline(x, y, npts);
282 }
283 }
284
285 /* Draw polyline */
286 /* The plot buffer must be called first */
287
288 void
plP_polyline(short * x,short * y,PLINT npts)289 plP_polyline(short *x, short *y, PLINT npts)
290 {
291 PLINT i, clpxmi, clpxma, clpymi, clpyma;
292
293 plsc->page_status = DRAWING;
294
295 if (plsc->plbuf_write)
296 plbuf_polyline(plsc, x, y, npts);
297
298 if (plsc->difilt) {
299 for (i = 0; i < npts; i++) {
300 xscl[i] = x[i];
301 yscl[i] = y[i];
302 }
303 difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
304 plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
305 grpolyline);
306 }
307 else {
308 grpolyline(x, y, npts);
309 }
310 }
311
312 /* Fill polygon */
313 /* The plot buffer must be called first */
314 /* Here if the desired area fill capability isn't present, we mock up */
315 /* something in software */
316
317 static int foo;
318
319 void
plP_fill(short * x,short * y,PLINT npts)320 plP_fill(short *x, short *y, PLINT npts)
321 {
322 PLINT i, clpxmi, clpxma, clpymi, clpyma;
323
324 plsc->page_status = DRAWING;
325
326 if (plsc->plbuf_write) {
327 plsc->dev_npts = npts;
328 plsc->dev_x = x;
329 plsc->dev_y = y;
330 plbuf_esc(plsc, PLESC_FILL, NULL);
331 }
332
333 /* Account for driver ability to do fills */
334
335 if (plsc->patt == 0 && ! plsc->dev_fill0) {
336 if ( ! foo) {
337 plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
338 foo = 1;
339 }
340 plsc->patt = 8;
341 plpsty(plsc->patt);
342 }
343 if (plsc->dev_fill1) {
344 plsc->patt = -ABS(plsc->patt);
345 }
346
347 /* Perform fill. Here we MUST NOT allow the software fill to pass through the
348 driver interface filtering twice, else we get the infamous 2*rotation for
349 software fills on orientation swaps.
350 */
351
352 if (plsc->patt > 0)
353 plfill_soft(x, y, npts);
354
355 else {
356 if (plsc->difilt) {
357 for (i = 0; i < npts; i++) {
358 xscl[i] = x[i];
359 yscl[i] = y[i];
360 }
361 difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
362 plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
363 grfill);
364 }
365 else {
366 grfill(x, y, npts);
367 }
368 }
369 }
370
371 /* Account for driver ability to draw text itself */
372 /*
373 #define DEBUG_TEXT
374 */
375
376 #define hex2dec( a ) isdigit(a) ? a - 48 : (toupper(a) - 65) + 10
377
378 int text2num( const char *text, char end, PLUNICODE *num);
379 int text2fci( const char *text, unsigned char *hexdigit,
380 unsigned char *hexpower);
381
382
383 /*--------------------------------------------------------------------------*\
384 * int text2num( char *text, char end, PLUNICODE *num)
385 * char *text - pointer to the text to be parsed
386 * char end - end character (i.e. ')' or ']' to stop parsing
387 * PLUNICODE *num - pointer to an PLUNICODE to store the value
388 *
389 * Function takes a string, which can be either hex or decimal,
390 * and converts it into an PLUNICODE, stopping at either a null,
391 * or the character pointed to by 'end'. It is a bit brain-dead,
392 * and probably should make more checks, but it works.
393 \*--------------------------------------------------------------------------*/
394
text2num(const char * text,char end,PLUNICODE * num)395 int text2num( const char *text, char end, PLUNICODE *num)
396 {
397 int base=10;
398 unsigned short i=0;
399 *num=0;
400
401 if (text[1]=='x')
402 {
403 base=16;
404 i=2;
405 }
406
407 while ((text[i]!=end)&&(text[i]!=0))
408 {
409 *num*=base;
410 *num+=hex2dec(text[i]);
411 i++;
412 }
413 return(i);
414 }
415
416 /*--------------------------------------------------------------------------*\
417 * int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
418 * char *text - pointer to the text to be parsed
419 * unsigned char *hexdigit - pointer to hex value that is stored.
420 * unsigned char *hexpower - pointer to hex power (left shift) that is stored.
421 *
422 * Function takes a pointer to a string, which is looked up in a table
423 * to determine the corresponding FCI (font characterization integer)
424 * hex digit value and hex power (left shift). All matched strings
425 * start with "<" and end with the two characters "/>".
426 * If the lookup succeeds, hexdigit and hexpower are set to the appropriate
427 * values in the table, and the function returns the number of characters
428 * in text that are consumed by the matching string in the table lookup.
429 *
430 * If the lookup fails, hexdigit is set to 0, hexpower is set to and
431 * impossible value, and the function returns 0.
432 \*--------------------------------------------------------------------------*/
433
text2fci(const char * text,unsigned char * hexdigit,unsigned char * hexpower)434 int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower)
435 {
436 typedef struct
437 {
438 const char *ptext; /* pmr: const */
439 unsigned char hexdigit;
440 unsigned char hexpower;
441 unsigned char padding[6]; /* pmr: padding to align */
442 }
443 TextLookupTable;
444 /* This defines the various font control commands and the corresponding
445 * hexdigit and hexpower in the FCI.
446 */
447 #define N_TextLookupTable 10
448 const TextLookupTable lookup[N_TextLookupTable] = {
449 {"<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY, " "},
450 {"<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY, " "},
451 {"<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY, " "},
452 {"<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY, " "},
453 {"<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY, " "},
454 {"<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE, " "},
455 {"<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE, " "},
456 {"<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE, " "},
457 {"<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT, " "},
458 {"<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT, " "}
459 };
460 int i, length;
461 for (i=0; i<N_TextLookupTable; i++) {
462 length = strlen(lookup[i].ptext);
463 if (! strncmp(text, lookup[i].ptext, length)) {
464 *hexdigit = lookup[i].hexdigit;
465 *hexpower = lookup[i].hexpower;
466 return(length);
467 }
468 }
469 *hexdigit = 0;
470 *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
471 return(0);
472 }
473
474 PLUNICODE unicode_buffer[1024];
475
476 void
plP_text(PLINT base,PLFLT just,PLFLT * xform,PLINT x,PLINT y,PLINT refx,PLINT refy,const char * string)477 plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
478 PLINT refx, PLINT refy, const char *string)
479 {
480
481 if (plsc->dev_text) { /* Does the device render it's own text ? */
482 EscText args;
483 short len=0;
484 char skip;
485 unsigned short i,j;
486 PLUNICODE code;
487 unsigned char esc;
488 int idx;
489
490 args.base = base;
491 args.just = just;
492 args.xform = xform;
493 args.x = x;
494 args.y = y;
495 args.refx = refx;
496 args.refy = refy;
497 args.string = string;
498
499 if (plsc->dev_unicode) { /* Does the device also understand unicode? */
500 PLINT ig;
501 PLUNICODE fci, fcisave;
502 unsigned char hexdigit, hexpower;
503
504 /* Now process the text string */
505
506 if (string!=NULL) { /* If the string isn't blank, then we will
507 * continue
508 */
509
510 len=strlen(string); /* this length is only used in the loop
511 * counter, we will work out the length of
512 * the unicode string as we go */
513 plgesc(&esc);
514
515 /* At this stage we will do some translations into unicode, like
516 * conversion to Greek , and will save other translations such as
517 * superscript for the driver to do later on. As we move through
518 * the string and do the translations, we will get
519 * rid of the esc character sequence, just replacing it with
520 * unicode.
521 */
522
523 /* Obtain FCI (font characterization integer) for start of
524 * string. */
525 plgfci(&fci);
526 for (j=i=0;i<len;i++) { /* Walk through the string, and convert
527 * some stuff to unicode on the fly */
528 skip=0;
529
530 if (string[i]==esc) {
531 switch(string[i+1]) {
532 case '(': /* hershey code */
533 i+=2+text2num(&string[i+2],')',&code);
534 idx=plhershey2unicode(code);
535 /* momentarily switch to symbol font. */
536 fcisave = fci;
537 plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
538 unicode_buffer[j++]= fci;
539 unicode_buffer[j++] = \
540 (PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
541
542 /* if unicode_buffer[j-1] corresponds to the escape
543 * character must unescape it by appending one more.
544 * This will probably always be necessary since it is
545 * likely unicode_buffer will always have to contain
546 * escape characters that are interpreted by the device
547 * driver.
548 */
549 if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
550 fci = fcisave;
551 unicode_buffer[j]= fci;
552 skip=1;
553 break;
554
555 case '[': /* unicode */
556 i+=2+text2num(&string[i+2],']',&code);
557 /* momentarily switch to symbol font. */
558 fcisave = fci;
559 plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
560 unicode_buffer[j++]= fci;
561 unicode_buffer[j++]=code;
562 /* if unicode_buffer[j-1] corresponds to the escape
563 * character must unescape it by appending one more.
564 * This will probably always be necessary since it is
565 * likely unicode_buffer will always have to contain
566 * escape characters that are interpreted by the device
567 * driver.
568 */
569 if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
570 fci = fcisave;
571 unicode_buffer[j] = fci;
572 skip=1;
573 break;
574
575 case '<': /* change font*/
576 if ('0' <= string[i+2] && string[i+2] <= '9' ) {
577 i+=2+text2num(&string[i+2],'>', &code);
578 if (code & PL_FCI_MARK) {
579 /* code is a complete FCI (font characterization
580 * integer): change FCI to this value.
581 */
582 fci = code;
583 unicode_buffer[j]=fci;
584 skip=1;
585 }
586 else {
587 /* code is not complete FCI. Change
588 * FCI with hex power in rightmost hex
589 * digit and hex digit value in second rightmost
590 * hex digit.
591 */
592 hexdigit = (code >> 4) & PL_FCI_HEXDIGIT_MASK;
593 hexpower = code & PL_FCI_HEXPOWER_MASK;
594 plP_hex2fci(hexdigit, hexpower, &fci);
595 unicode_buffer[j]=fci;
596 skip=1;
597 }
598 }
599
600 else {
601 i+=text2fci(&string[i+1], &hexdigit, &hexpower);
602 if (hexpower < 7) {
603 plP_hex2fci(hexdigit, hexpower, &fci);
604 unicode_buffer[j]=fci;
605 skip=1;
606 }
607 }
608 break;
609
610 case 'f': /* Deprecated Hershey-style font change*/
611 case 'F': /* Deprecated Hershey-style font change*/
612 /* We implement an approximate response here so that
613 * reasonable results are obtained for unicode fonts,
614 * but this method is deprecated and the #<nnn> or
615 * #<command string> methods should be used instead
616 * to change unicode fonts in mid-string.
617 */
618 fci = PL_FCI_MARK;
619 if (string[i+2] == 'n') {
620 /* medium, upright, sans-serif */
621 plP_hex2fci(PL_FCI_SANS, PL_FCI_FAMILY, &fci);
622 } else if (string[i+2] == 'r') {
623 /* medium, upright, serif */
624 plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
625 } else if (string[i+2] == 'i') {
626 /* medium, italic, serif */
627 plP_hex2fci(PL_FCI_ITALIC, PL_FCI_STYLE, &fci);
628 plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
629 } else if (string[i+2] == 's') {
630 /* medium, upright, script */
631 plP_hex2fci(PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci);
632 } else
633 fci = PL_FCI_IMPOSSIBLE;
634
635 if (fci != PL_FCI_IMPOSSIBLE){
636 i+=2;
637 unicode_buffer[j] = fci;
638 skip = 1;
639 }
640 break;
641
642 case 'g': /* Greek font */
643 case 'G': /* Greek font */
644 /* Get the index in the lookup table
645 * 527 = upper case alpha displacement in Hershey Table
646 * 627 = lower case alpha displacement in Hershey Table
647 */
648 /* momentarily switch to symbol font. */
649 fcisave = fci;
650 plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
651 unicode_buffer[j++]= fci;
652 ig = plP_strpos(plP_greek_mnemonic, string[i+2]);
653 if (ig >= 0) {
654 if (ig >= 24)
655 ig = ig + 100 - 24;
656 idx=plhershey2unicode(ig+527);
657 unicode_buffer[j++] = \
658 (PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
659 i+=2;
660 skip=1; /* skip is set if we have copied something
661 * into the unicode table */
662 }
663 else {
664 /* Use "unknown" unicode character if string[i+2]
665 * is not in the Greek array.*/
666 unicode_buffer[j++]=(PLUNICODE)0x00;
667 i+=2;
668 skip=1; /* skip is set if we have copied something
669 * into the unicode table */
670 }
671 fci = fcisave;
672 unicode_buffer[j]= fci;
673 break;
674
675 }
676 }
677
678 if (skip==0) {
679 PLUNICODE unichar = 0;
680 #ifdef HAVE_LIBUNICODE
681 char* ptr = unicode_get_utf8 (string + i, &unichar);
682 #else
683 const char* ptr = utf8_to_ucs4 (string + i, &unichar);
684 #endif
685 if (ptr == NULL) {
686 char buf[80];
687 strncpy (buf, string, 30);
688 sprintf (buf, "UTF-8 string is malformed: %s%s",
689 buf, strlen (string) > 30 ? "[...]" : "");
690 plabort (buf);
691 }
692 unicode_buffer [j] = unichar;
693 i += ptr - (string + i) - 1;
694
695 /* Search for escesc (an unescaped escape) in the input
696 * string and adjust unicode_buffer accordingly).
697 */
698 if (unicode_buffer[j] == esc && string[i+1] == esc) {
699 i++;
700 unicode_buffer[++j] = esc;
701 }
702 }
703 j++;
704 }
705 if (j > 0) {
706 args.unicode_array_len=j; /* Much easier to set the length than
707 * work it out later :-) */
708 args.unicode_array=&unicode_buffer[0]; /* Get address of the
709 * unicode buffer (even
710 * though it is
711 * currently static) */
712 } else
713 /* Don't print anything, if there is no unicode to print! */
714 return;
715 }
716 }
717
718 if (plsc->dev_unicode) {
719 args.string=NULL; /* We are using unicode */
720 }
721 else {
722 args.string = string;
723 }
724
725 plP_esc(PLESC_HAS_TEXT, &args);
726 #ifndef DEBUG_TEXT
727 } else {
728 #endif
729 plstr(base, xform, refx, refy, string);
730 }
731 }
732
733 /* convert utf8 string to ucs4 unichar */
734 static const char *
utf8_to_ucs4(const char * ptr,PLUNICODE * unichar)735 utf8_to_ucs4(const char *ptr, PLUNICODE *unichar)
736 {
737 char tmp;
738 int isFirst = 1;
739 int cnt = 0;
740
741 do {
742 /* Get next character in string */
743 tmp = *ptr++;
744 if (isFirst) { /* First char in UTF8 sequence */
745 isFirst = 0;
746 /* Determine length of sequence */
747 if ((unsigned char)(tmp & 0x80) == 0x00) { /* single char */
748 *unichar = (unsigned int)tmp & 0x7F;
749 cnt = 0;
750 } else if ((unsigned char)(tmp & 0xE0) == 0xC0) { /* 2 chars */
751 *unichar = (unsigned int)tmp & 0x1F;
752 cnt = 1;
753 } else if ((unsigned char)(tmp & 0xF0) == 0xE0) { /* 3 chars */
754 *unichar = (unsigned char)tmp & 0x0F;
755 cnt = 2;
756 } else if ((unsigned char)(tmp & 0xF8) == 0xF0) { /* 4 chars */
757 *unichar = (unsigned char)tmp & 0x07;
758 cnt = 3;
759 } else if ((unsigned char)(tmp & 0xFC) == 0xF8) { /* 5 chars */
760 *unichar = (unsigned char)tmp & 0x03;
761 cnt = 4;
762 } else if ((unsigned char)(tmp & 0xFE) == 0xFC) { /* 6 chars */
763 *unichar = (unsigned char)tmp & 0x01;
764 cnt = 5;
765 } else { /* Malformed */
766 ptr = NULL;
767 cnt = 0;
768 }
769 } else { /* Subsequent char in UTF8 sequence */
770 if ((unsigned char)(tmp & 0xC0) == 0x80) {
771 *unichar = (*unichar << 6) | ((unsigned int)tmp & 0x3F);
772 cnt--;
773 } else { /* Malformed */
774 ptr = NULL;
775 cnt = 0;
776 }
777 }
778 } while (cnt > 0);
779 return (const char *) ptr;
780 }
781
782 /* convert ucs4 unichar to utf8 string */
783 int
ucs4_to_utf8(PLUNICODE unichar,char * ptr)784 ucs4_to_utf8(PLUNICODE unichar, char *ptr)
785 {
786 unsigned char *tmp;
787 int len;
788
789 tmp = (unsigned char *)ptr;
790
791 if ( (unichar & 0xffff80) == 0 ) { /* single byte */
792 *tmp = (unsigned char) unichar;
793 tmp++;
794 len = 1;
795 }
796 else if ( (unichar & 0xfff800) == 0) { /* two bytes */
797 *tmp = (unsigned char) 0xc0 | (unichar >> 6);
798 tmp++;
799 *tmp = (unsigned char) 0x80 | (unichar & 0x3f);
800 tmp++;
801 len = 2;
802 }
803 else if ( (unichar & 0xff0000) == 0) { /* three bytes */
804 *tmp = (unsigned char) 0xe0 | (unichar >> 12);
805 tmp++;
806 *tmp = (unsigned char) 0x80 | ((unichar >> 6) & 0x3f);
807 tmp++;
808 *tmp = (unsigned char) 0x80 | (unichar & 0x3f);
809 tmp++;
810 len = 3;
811 }
812 else if ( (unichar & 0xe0000) == 0){ /* four bytes */
813 *tmp = (unsigned char) 0xf0 | (unichar >> 18);
814 tmp++;
815 *tmp = (unsigned char) 0x80 | ((unichar >> 12) & 0x3f);
816 tmp++;
817 *tmp = (unsigned char) 0x80 | ((unichar >> 6) & 0x3f);
818 tmp++;
819 *tmp = (unsigned char) 0x80 | (unichar & 0x3f);
820 tmp++;
821 len = 4;
822 }
823 else { /* Illegal coding */
824 len = 0;
825 }
826 *tmp = '\0';
827
828 return len;
829 }
830
831 static void
grline(short * x,short * y,PLINT npts)832 grline(short *x, short *y, PLINT npts)
833 {
834 (void) npts; /* pmr: make it used */
835 (*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
836 x[0], y[0], x[1], y[1] );
837 }
838
839 static void
grpolyline(short * x,short * y,PLINT npts)840 grpolyline(short *x, short *y, PLINT npts)
841 {
842 (*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
843 x, y, npts );
844 }
845
846 static void
grfill(short * x,short * y,PLINT npts)847 grfill(short *x, short *y, PLINT npts)
848 {
849 plsc->dev_npts = npts;
850 plsc->dev_x = x;
851 plsc->dev_y = y;
852
853 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
854 PLESC_FILL, NULL );
855 }
856
857 /*--------------------------------------------------------------------------*\
858 * void difilt
859 *
860 * Driver interface filter -- passes all coordinates through a variety
861 * of filters. These include filters to change :
862 *
863 * - mapping of meta to physical coordinates
864 * - plot orientation
865 * - window into plot (zooms)
866 * - window into device (i.e set margins)
867 *
868 * The filters are applied in the order specified above. Because the
869 * orientation change comes first, subsequent window specifications affect
870 * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
871 * This is the only way that makes sense from a graphical interface
872 * (e.g. TCL/TK driver).
873 *
874 * Where appropriate, the page clip limits are modified.
875 \*--------------------------------------------------------------------------*/
876
877 void
difilt(PLINT * myxscl,PLINT * myyscl,PLINT npts,PLINT * clpxmi,PLINT * clpxma,PLINT * clpymi,PLINT * clpyma)878 difilt(PLINT *myxscl, PLINT *myyscl, PLINT npts,
879 PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
880 {
881 PLINT i, x, y;
882
883 /* Map meta coordinates to physical coordinates */
884
885 if (plsc->difilt & PLDI_MAP) {
886 for (i = 0; i < npts; i++) {
887 myxscl[i] = plsc->dimxax * myxscl[i] + plsc->dimxb;
888 myyscl[i] = plsc->dimyay * myyscl[i] + plsc->dimyb;
889 }
890 }
891
892 /* Change orientation */
893
894 if (plsc->difilt & PLDI_ORI) {
895 for (i = 0; i < npts; i++) {
896 x = plsc->dioxax * myxscl[i] + plsc->dioxay * myyscl[i] +
897 plsc->dioxb;
898 y = plsc->dioyax * myxscl[i] + plsc->dioyay * myyscl[i] +
899 plsc->dioyb;
900 myxscl[i] = x;
901 myyscl[i] = y;
902 }
903 }
904
905 /* Change window into plot space */
906
907 if (plsc->difilt & PLDI_PLT) {
908 for (i = 0; i < npts; i++) {
909 myxscl[i] = plsc->dipxax * myxscl[i] + plsc->dipxb;
910 myyscl[i] = plsc->dipyay * myyscl[i] + plsc->dipyb;
911 }
912 }
913
914 /* Change window into device space and set clip limits */
915 /* (this is the only filter that modifies them) */
916
917 if (plsc->difilt & PLDI_DEV) {
918 for (i = 0; i < npts; i++) {
919 myxscl[i] = plsc->didxax * myxscl[i] + plsc->didxb;
920 myyscl[i] = plsc->didyay * myyscl[i] + plsc->didyb;
921 }
922 *clpxmi = plsc->diclpxmi;
923 *clpxma = plsc->diclpxma;
924 *clpymi = plsc->diclpymi;
925 *clpyma = plsc->diclpyma;
926 }
927 else {
928 *clpxmi = plsc->phyxmi;
929 *clpxma = plsc->phyxma;
930 *clpymi = plsc->phyymi;
931 *clpyma = plsc->phyyma;
932 }
933 }
934
935 static void
sdifilt(short * myxscl,short * myyscl,PLINT npts,PLINT * clpxmi,PLINT * clpxma,PLINT * clpymi,PLINT * clpyma)936 sdifilt(short *myxscl, short *myyscl, PLINT npts,
937 PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
938 {
939 int i;
940 short x, y;
941
942 /* Map meta coordinates to physical coordinates */
943
944 if (plsc->difilt & PLDI_MAP) {
945 for (i = 0; i < npts; i++) {
946 myxscl[i] = plsc->dimxax * myxscl[i] + plsc->dimxb;
947 myyscl[i] = plsc->dimyay * myyscl[i] + plsc->dimyb;
948 }
949 }
950
951 /* Change orientation */
952
953 if (plsc->difilt & PLDI_ORI) {
954 for (i = 0; i < npts; i++) {
955 x = plsc->dioxax * myxscl[i] + plsc->dioxay * myyscl[i] + plsc->dioxb;
956 y = plsc->dioyax * myxscl[i] + plsc->dioyay * myyscl[i] + plsc->dioyb;
957 myxscl[i] = x;
958 myyscl[i] = y;
959 }
960 }
961
962 /* Change window into plot space */
963
964 if (plsc->difilt & PLDI_PLT) {
965 for (i = 0; i < npts; i++) {
966 myxscl[i] = plsc->dipxax * myxscl[i] + plsc->dipxb;
967 myyscl[i] = plsc->dipyay * myyscl[i] + plsc->dipyb;
968 }
969 }
970
971 /* Change window into device space and set clip limits */
972 /* (this is the only filter that modifies them) */
973
974 if (plsc->difilt & PLDI_DEV) {
975 for (i = 0; i < npts; i++) {
976 myxscl[i] = plsc->didxax * myxscl[i] + plsc->didxb;
977 myyscl[i] = plsc->didyay * myyscl[i] + plsc->didyb;
978 }
979 *clpxmi = plsc->diclpxmi;
980 *clpxma = plsc->diclpxma;
981 *clpymi = plsc->diclpymi;
982 *clpyma = plsc->diclpyma;
983 }
984 else {
985 *clpxmi = plsc->phyxmi;
986 *clpxma = plsc->phyxma;
987 *clpymi = plsc->phyymi;
988 *clpyma = plsc->phyyma;
989 }
990 }
991
992 /*--------------------------------------------------------------------------*\
993 * void pldi_ini
994 *
995 * Updates driver interface, making sure everything is in order.
996 * Even if filter is not being used, the defaults need to be set up.
997 \*--------------------------------------------------------------------------*/
998
999 static void
setdef_diplt(void)1000 setdef_diplt(void) /* pmr: fix prototype */
1001 {
1002 plsc->dipxmin = 0.0;
1003 plsc->dipxmax = 1.0;
1004 plsc->dipymin = 0.0;
1005 plsc->dipymax = 1.0;
1006 }
1007
1008 static void /* pmr: fix prototype */
setdef_didev(void)1009 setdef_didev(void)
1010 {
1011 plsc->mar = 0.0;
1012 plsc->aspect = 0.0;
1013 plsc->jx = 0.0;
1014 plsc->jy = 0.0;
1015 }
1016
1017 static void
setdef_diori(void)1018 setdef_diori(void) /* pmr: fix prototype */
1019 {
1020 plsc->diorot = 0.;
1021 }
1022
1023 static void
pldi_ini(void)1024 pldi_ini(void)
1025 {
1026 if (plsc->level >= 1) {
1027 if (plsc->difilt & PLDI_MAP) /* Coordinate mapping */
1028 calc_dimap();
1029
1030 if (plsc->difilt & PLDI_ORI) /* Orientation */
1031 calc_diori();
1032 else
1033 setdef_diori();
1034
1035 if (plsc->difilt & PLDI_PLT) /* Plot window */
1036 calc_diplt();
1037 else
1038 setdef_diplt();
1039
1040 if (plsc->difilt & PLDI_DEV) /* Device window */
1041 calc_didev();
1042 else
1043 setdef_didev();
1044 }
1045 }
1046
1047 /*--------------------------------------------------------------------------*\
1048 * void pldid2pc
1049 *
1050 * Converts input values from relative device coordinates to relative plot
1051 * coordinates. This function must be called when selecting a plot window
1052 * from a display driver, since the coordinates chosen by the user are
1053 * necessarily device-specific.
1054 \*--------------------------------------------------------------------------*/
1055
1056 void
pldid2pc(PLFLT * xmin,PLFLT * ymin,PLFLT * xmax,PLFLT * ymax)1057 pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
1058 {
1059 PLFLT pxmin, pymin, pxmax, pymax;
1060 PLFLT sxmin, symin, sxmax, symax;
1061 PLFLT rxmin, rymin, rxmax, rymax;
1062
1063 if (plsc->difilt & PLDI_DEV) {
1064
1065 pldebug("pldid2pc",
1066 "Relative device coordinates (in): %f, %f, %f, %f\n",
1067 *xmin, *ymin, *xmax, *ymax);
1068
1069 pxmin = plP_dcpcx(*xmin);
1070 pymin = plP_dcpcy(*ymin);
1071 pxmax = plP_dcpcx(*xmax);
1072 pymax = plP_dcpcy(*ymax);
1073
1074 sxmin = (pxmin - plsc->didxb) / plsc->didxax;
1075 symin = (pymin - plsc->didyb) / plsc->didyay;
1076 sxmax = (pxmax - plsc->didxb) / plsc->didxax;
1077 symax = (pymax - plsc->didyb) / plsc->didyay;
1078
1079 rxmin = plP_pcdcx(sxmin);
1080 rymin = plP_pcdcy(symin);
1081 rxmax = plP_pcdcx(sxmax);
1082 rymax = plP_pcdcy(symax);
1083
1084 *xmin = (rxmin < 0) ? 0 : rxmin;
1085 *xmax = (rxmax > 1) ? 1 : rxmax;
1086 *ymin = (rymin < 0) ? 0 : rymin;
1087 *ymax = (rymax > 1) ? 1 : rymax;
1088
1089 pldebug("pldid2pc",
1090 "Relative plot coordinates (out): %f, %f, %f, %f\n",
1091 rxmin, rymin, rxmax, rymax);
1092 }
1093 }
1094
1095 /*--------------------------------------------------------------------------*\
1096 * void pldip2dc
1097 *
1098 * Converts input values from relative plot coordinates to relative
1099 * device coordinates.
1100 \*--------------------------------------------------------------------------*/
1101
1102 void
pldip2dc(PLFLT * xmin,PLFLT * ymin,PLFLT * xmax,PLFLT * ymax)1103 pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
1104 {
1105 PLFLT pxmin, pymin, pxmax, pymax;
1106 PLFLT sxmin, symin, sxmax, symax;
1107 PLFLT rxmin, rymin, rxmax, rymax;
1108
1109 if (plsc->difilt & PLDI_DEV) {
1110
1111 pldebug("pldip2pc",
1112 "Relative plot coordinates (in): %f, %f, %f, %f\n",
1113 *xmin, *ymin, *xmax, *ymax);
1114
1115 pxmin = plP_dcpcx(*xmin);
1116 pymin = plP_dcpcy(*ymin);
1117 pxmax = plP_dcpcx(*xmax);
1118 pymax = plP_dcpcy(*ymax);
1119
1120 sxmin = pxmin * plsc->didxax + plsc->didxb;
1121 symin = pymin * plsc->didyay + plsc->didyb;
1122 sxmax = pxmax * plsc->didxax + plsc->didxb;
1123 symax = pymax * plsc->didyay + plsc->didyb;
1124
1125 rxmin = plP_pcdcx(sxmin);
1126 rymin = plP_pcdcy(symin);
1127 rxmax = plP_pcdcx(sxmax);
1128 rymax = plP_pcdcy(symax);
1129
1130 *xmin = (rxmin < 0) ? 0 : rxmin;
1131 *xmax = (rxmax > 1) ? 1 : rxmax;
1132 *ymin = (rymin < 0) ? 0 : rymin;
1133 *ymax = (rymax > 1) ? 1 : rymax;
1134
1135 pldebug("pldip2pc",
1136 "Relative device coordinates (out): %f, %f, %f, %f\n",
1137 rxmin, rymin, rxmax, rymax);
1138 }
1139 }
1140
1141 /*--------------------------------------------------------------------------*\
1142 * void plsdiplt
1143 *
1144 * Set window into plot space
1145 \*--------------------------------------------------------------------------*/
1146
1147 void
c_plsdiplt(PLFLT xmin,PLFLT ymin,PLFLT xmax,PLFLT ymax)1148 c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
1149 {
1150 plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
1151 plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
1152 plsc->dipymin = (ymin < ymax) ? ymin : ymax;
1153 plsc->dipymax = (ymin < ymax) ? ymax : ymin;
1154
1155 if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.) {
1156 plsc->difilt &= ~PLDI_PLT;
1157 return;
1158 }
1159
1160 plsc->difilt |= PLDI_PLT;
1161 pldi_ini();
1162 }
1163
1164 /*--------------------------------------------------------------------------*\
1165 * void plsdiplz
1166 *
1167 * Set window into plot space incrementally (zoom)
1168 \*--------------------------------------------------------------------------*/
1169
1170 void
c_plsdiplz(PLFLT xmin,PLFLT ymin,PLFLT xmax,PLFLT ymax)1171 c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
1172 {
1173 if (plsc->difilt & PLDI_PLT) {
1174 xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
1175 ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
1176 xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
1177 ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
1178 }
1179
1180 plsdiplt(xmin, ymin, xmax, ymax);
1181 }
1182
1183 /*--------------------------------------------------------------------------*\
1184 * void calc_diplt
1185 *
1186 * Calculate transformation coefficients to set window into plot space.
1187 *
1188 * Note: if driver has requested to handle these commands itself, we must
1189 * send the appropriate escape command. If the driver succeeds it will
1190 * cancel the filter operation. The command is deferred until this point
1191 * to ensure that the driver has been initialized.
1192 \*--------------------------------------------------------------------------*/
1193
1194 static void
calc_diplt(void)1195 calc_diplt(void)
1196 {
1197 PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
1198
1199 if (plsc->dev_di) {
1200 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
1201 PLESC_DI, NULL );
1202 }
1203
1204 if ( ! (plsc->difilt & PLDI_PLT))
1205 return;
1206
1207 pxmin = plP_dcpcx(plsc->dipxmin);
1208 pxmax = plP_dcpcx(plsc->dipxmax);
1209 pymin = plP_dcpcy(plsc->dipymin);
1210 pymax = plP_dcpcy(plsc->dipymax);
1211
1212 pxlen = pxmax - pxmin;
1213 pylen = pymax - pymin;
1214 pxlen = MAX(1, pxlen);
1215 pylen = MAX(1, pylen);
1216
1217 plsc->dipxax = plsc->phyxlen / (double) pxlen;
1218 plsc->dipyay = plsc->phyylen / (double) pylen;
1219 plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
1220 plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
1221 }
1222
1223 /*--------------------------------------------------------------------------*\
1224 * void plgdiplt
1225 *
1226 * Retrieve current window into plot space
1227 \*--------------------------------------------------------------------------*/
1228
1229 void
c_plgdiplt(PLFLT * p_xmin,PLFLT * p_ymin,PLFLT * p_xmax,PLFLT * p_ymax)1230 c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
1231 {
1232 *p_xmin = plsc->dipxmin;
1233 *p_xmax = plsc->dipxmax;
1234 *p_ymin = plsc->dipymin;
1235 *p_ymax = plsc->dipymax;
1236 }
1237
1238 /*--------------------------------------------------------------------------*\
1239 * void plsdidev
1240 *
1241 * Set window into device space using margin, aspect ratio, and
1242 * justification. If you want to just use the previous value for any of
1243 * these, just pass in the magic value PL_NOTSET.
1244 *
1245 * It is unlikely that one should ever need to change the aspect ratio
1246 * but it's in there for completeness.
1247 \*--------------------------------------------------------------------------*/
1248
1249 void
c_plsdidev(PLFLT mar,PLFLT aspect,PLFLT jx,PLFLT jy)1250 c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
1251 {
1252 plsetvar(plsc->mar, mar);
1253 plsetvar(plsc->aspect, aspect);
1254 plsetvar(plsc->jx, jx);
1255 plsetvar(plsc->jy, jy);
1256
1257 if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
1258 ! (plsc->difilt & PLDI_ORI)) {
1259 plsc->difilt &= ~PLDI_DEV;
1260 return;
1261 }
1262
1263 plsc->difilt |= PLDI_DEV;
1264 pldi_ini();
1265 }
1266
1267 /*--------------------------------------------------------------------------*\
1268 * void calc_didev
1269 *
1270 * Calculate transformation coefficients to set window into device space.
1271 * Calculates relative window bounds and calls plsdidxy to finish the job.
1272 \*--------------------------------------------------------------------------*/
1273
1274 static void
calc_didev(void)1275 calc_didev(void)
1276 {
1277 PLFLT lx, ly, aspect, aspdev;
1278 PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
1279 PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
1280
1281 if (plsc->dev_di) {
1282 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
1283 PLESC_DI, NULL );
1284 }
1285
1286 if ( ! (plsc->difilt & PLDI_DEV))
1287 return;
1288
1289 /* Calculate aspect ratio of physical device */
1290
1291 lx = plsc->phyxlen / plsc->xpmm;
1292 ly = plsc->phyylen / plsc->ypmm;
1293 aspdev = lx / ly;
1294
1295 if (plsc->difilt & PLDI_ORI)
1296 aspect = plsc->aspori;
1297 else
1298 aspect = plsc->aspect;
1299
1300 if (aspect <= 0.)
1301 aspect = plsc->aspdev;
1302
1303 /* Failsafe */
1304
1305 plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
1306 plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
1307 plsc->jx = (plsc->jx > 0.5) ? 0.5 : plsc->jx;
1308 plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
1309 plsc->jy = (plsc->jy > 0.5) ? 0.5 : plsc->jy;
1310 plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
1311
1312 /* Relative device coordinates that neutralize aspect ratio difference */
1313
1314 xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
1315 ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
1316
1317 xlen *= (1.0 - 2.*plsc->mar);
1318 ylen *= (1.0 - 2.*plsc->mar);
1319
1320 xmin = (1. - xlen) * (0.5 + plsc->jx);
1321 xmax = xmin + xlen;
1322
1323 ymin = (1. - ylen) * (0.5 + plsc->jy);
1324 ymax = ymin + ylen;
1325
1326 /* Calculate transformation coefficients */
1327
1328 pxmin = plP_dcpcx(xmin);
1329 pxmax = plP_dcpcx(xmax);
1330 pymin = plP_dcpcy(ymin);
1331 pymax = plP_dcpcy(ymax);
1332
1333 pxlen = pxmax - pxmin;
1334 pylen = pymax - pymin;
1335 pxlen = MAX(1, pxlen);
1336 pylen = MAX(1, pylen);
1337
1338 plsc->didxax = pxlen / (double) plsc->phyxlen;
1339 plsc->didyay = pylen / (double) plsc->phyylen;
1340 plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
1341 plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
1342
1343 /* Set clip limits to conform to new page size */
1344
1345 plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
1346 plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
1347 plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
1348 plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
1349 }
1350
1351 /*--------------------------------------------------------------------------*\
1352 * void plgdidev
1353 *
1354 * Retrieve current window into device space
1355 \*--------------------------------------------------------------------------*/
1356
1357 void
c_plgdidev(PLFLT * p_mar,PLFLT * p_aspect,PLFLT * p_jx,PLFLT * p_jy)1358 c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
1359 {
1360 *p_mar = plsc->mar;
1361 *p_aspect = plsc->aspect;
1362 *p_jx = plsc->jx;
1363 *p_jy = plsc->jy;
1364 }
1365
1366 /*--------------------------------------------------------------------------*\
1367 * void plsdiori
1368 *
1369 * Set plot orientation, specifying rotation in units of pi/2.
1370 \*--------------------------------------------------------------------------*/
1371
1372 void
c_plsdiori(PLFLT rot)1373 c_plsdiori(PLFLT rot)
1374 {
1375 plsc->diorot = rot;
1376 if (rot == 0.) {
1377 plsc->difilt &= ~PLDI_ORI;
1378 pldi_ini();
1379 return;
1380 }
1381
1382 plsc->difilt |= PLDI_ORI;
1383 pldi_ini();
1384 }
1385
1386 /*--------------------------------------------------------------------------*\
1387 * void calc_diori
1388 *
1389 * Calculate transformation coefficients to arbitrarily orient plot.
1390 * Preserve aspect ratios so the output doesn't suck.
1391 \*--------------------------------------------------------------------------*/
1392
1393 static void
calc_diori(void)1394 calc_diori(void)
1395 {
1396 PLFLT r11, r21, r12, r22, cost, sint;
1397 PLFLT xx0, yy0, lx, ly, aspect;
1398
1399 if (plsc->dev_di) {
1400 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
1401 PLESC_DI, NULL );
1402 }
1403
1404 if ( ! (plsc->difilt & PLDI_ORI))
1405 return;
1406
1407 /* Center point of rotation */
1408
1409 xx0 = (plsc->phyxma + plsc->phyxmi) / 2.;
1410 yy0 = (plsc->phyyma + plsc->phyymi) / 2.;
1411
1412 /* Rotation matrix */
1413
1414 r11 = cos(plsc->diorot * PI / 2.);
1415 r21 = sin(plsc->diorot * PI / 2.);
1416 r12 = -r21;
1417 r22 = r11;
1418
1419 cost = ABS(r11);
1420 sint = ABS(r21);
1421
1422 /* Flip aspect ratio as necessary. Grungy but I don't see a better way */
1423
1424 aspect = plsc->aspect;
1425 if (aspect == 0.)
1426 aspect = plsc->aspdev;
1427
1428 if (plsc->freeaspect)
1429 plsc->aspori = aspect;
1430 else
1431 plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
1432
1433 if ( ! (plsc->difilt & PLDI_DEV)) {
1434 plsc->difilt |= PLDI_DEV;
1435 setdef_didev();
1436 }
1437 calc_didev();
1438
1439 /* Compute scale factors */
1440
1441 lx = plsc->phyxlen;
1442 ly = plsc->phyylen;
1443
1444 /* Transformation coefficients */
1445
1446 plsc->dioxax = r11;
1447 plsc->dioxay = r21 * (lx / ly);
1448 plsc->dioxb = (1. - r11) * xx0 - r21 * yy0 * (lx / ly);
1449
1450 plsc->dioyax = r12 * (ly / lx);
1451 plsc->dioyay = r22;
1452 plsc->dioyb = (1. - r22) * yy0 - r12 * xx0 * (ly / lx);
1453 }
1454
1455 /*--------------------------------------------------------------------------*\
1456 * void plgdiori
1457 *
1458 * Get plot orientation
1459 \*--------------------------------------------------------------------------*/
1460
1461 void
c_plgdiori(PLFLT * p_rot)1462 c_plgdiori(PLFLT *p_rot)
1463 {
1464 *p_rot = plsc->diorot;
1465 }
1466
1467 /*--------------------------------------------------------------------------*\
1468 * void plsdimap
1469 *
1470 * Set up transformation from metafile coordinates. The size of the plot is
1471 * scaled so as to preserve aspect ratio. This isn't intended to be a
1472 * general-purpose facility just yet (not sure why the user would need it,
1473 * for one).
1474 \*--------------------------------------------------------------------------*/
1475
1476 void
c_plsdimap(PLINT dimxmin,PLINT dimxmax,PLINT dimymin,PLINT dimymax,PLFLT dimxpmm,PLFLT dimypmm)1477 c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
1478 PLFLT dimxpmm, PLFLT dimypmm)
1479 {
1480 plsetvar(plsc->dimxmin, dimxmin);
1481 plsetvar(plsc->dimxmax, dimxmax);
1482 plsetvar(plsc->dimymin, dimymin);
1483 plsetvar(plsc->dimymax, dimymax);
1484 plsetvar(plsc->dimxpmm, dimxpmm);
1485 plsetvar(plsc->dimypmm, dimypmm);
1486
1487 plsc->difilt |= PLDI_MAP;
1488 pldi_ini();
1489 }
1490
1491 /*--------------------------------------------------------------------------*\
1492 * void calc_dimap
1493 *
1494 * Set up transformation from metafile coordinates. The size of the plot is
1495 * scaled so as to preserve aspect ratio. This isn't intended to be a
1496 * general-purpose facility just yet (not sure why the user would need it,
1497 * for one).
1498 \*--------------------------------------------------------------------------*/
1499
1500 static void
calc_dimap(void)1501 calc_dimap(void) /* pmr: prototype */
1502 {
1503 PLFLT lx, ly;
1504 PLINT pxmin, pxmax, pymin, pymax;
1505 PLFLT dimxlen, dimylen, pxlen, pylen;
1506
1507 if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
1508 (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
1509 (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
1510 plsc->difilt &= ~PLDI_MAP;
1511 return;
1512 }
1513
1514 /* Set default aspect ratio */
1515
1516 lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
1517 ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
1518
1519 plsc->aspdev = lx / ly;
1520
1521 /* Build transformation to correct physical coordinates */
1522
1523 dimxlen = plsc->dimxmax - plsc->dimxmin;
1524 dimylen = plsc->dimymax - plsc->dimymin;
1525
1526 pxmin = plsc->phyxmi;
1527 pxmax = plsc->phyxma;
1528 pymin = plsc->phyymi;
1529 pymax = plsc->phyyma;
1530 pxlen = pxmax - pxmin;
1531 pylen = pymax - pymin;
1532
1533 plsc->dimxax = pxlen / dimxlen;
1534 plsc->dimyay = pylen / dimylen;
1535 plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
1536 plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
1537 }
1538
1539 /*--------------------------------------------------------------------------*\
1540 * void plflush()
1541 *
1542 * Flushes the output stream. Use sparingly, if at all.
1543 \*--------------------------------------------------------------------------*/
1544
1545 void
c_plflush(void)1546 c_plflush(void)
1547 {
1548 if (plsc->dev_flush) {
1549 (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
1550 PLESC_FLUSH, NULL );
1551 }
1552 else {
1553 if (plsc->OutFile != NULL)
1554 fflush(plsc->OutFile);
1555 }
1556 }
1557
1558 /*--------------------------------------------------------------------------*\
1559 * Startup routines.
1560 \*--------------------------------------------------------------------------*/
1561
1562 /*--------------------------------------------------------------------------*\
1563 * void pllib_init()
1564 *
1565 * Initialize library. Called internally by every startup routine.
1566 * Everything you want to always be initialized before plinit() is called
1567 * you should put here. E.g. dispatch table setup, rcfile read, etc.
1568 \*--------------------------------------------------------------------------*/
1569
1570 void
pllib_init(void)1571 pllib_init(void) /* pmr: prototype */
1572 {
1573 if (lib_initialized) return;
1574 lib_initialized = 1;
1575
1576 #ifdef ENABLE_DYNDRIVERS
1577 /* Create libltdl resources */
1578 lt_dlinit();
1579 #endif
1580
1581 /* Initialize the dispatch table with the info from the static drivers table
1582 and the available dynamic drivers. */
1583
1584 plInitDispatchTable();
1585 }
1586
1587 /*--------------------------------------------------------------------------*\
1588 * void plstar(nx, ny)
1589 *
1590 * Initialize PLplot, passing in the windows/page settings.
1591 \*--------------------------------------------------------------------------*/
1592
1593 void
c_plstar(PLINT nx,PLINT ny)1594 c_plstar(PLINT nx, PLINT ny)
1595 {
1596 pllib_init();
1597
1598 if (plsc->level != 0)
1599 plend1();
1600
1601 plssub(nx, ny);
1602
1603 c_plinit();
1604 }
1605
1606 /*--------------------------------------------------------------------------*\
1607 * void plstart(devname, nx, ny)
1608 *
1609 * Initialize PLplot, passing the device name and windows/page settings.
1610 \*--------------------------------------------------------------------------*/
1611
1612 void
c_plstart(const char * devname,PLINT nx,PLINT ny)1613 c_plstart(const char *devname, PLINT nx, PLINT ny)
1614 {
1615 pllib_init();
1616
1617 if (plsc->level != 0)
1618 plend1();
1619
1620 plssub(nx, ny);
1621 plsdev(devname);
1622
1623 c_plinit();
1624 }
1625
1626 /*--------------------------------------------------------------------------*\
1627 * void plinit()
1628 *
1629 * Initializes PLplot, using preset or default options.
1630 \*--------------------------------------------------------------------------*/
1631
1632 void
c_plinit(void)1633 c_plinit(void)
1634 {
1635 PLFLT def_arrow_x[6] = {-0.5, 0.5, 0.3, 0.5, 0.3, 0.5};
1636 PLFLT def_arrow_y[6] = {0.0, 0.0, 0.2, 0.0, -0.2, 0.0};
1637 PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
1638 PLINT mk = 0, sp = 0, inc = 0, del = 2000;
1639
1640 pllib_init();
1641
1642 if (plsc->level != 0)
1643 plend1();
1644
1645 /* Set stream number */
1646
1647 plsc->ipls = ipls;
1648
1649 /* Set up devices */
1650
1651 pllib_devinit();
1652
1653 /* Auxiliary stream setup */
1654
1655 plstrm_init();
1656
1657 /* Initialize device & first page */
1658
1659 plP_init();
1660 plP_bop();
1661 plsc->level = 1;
1662
1663 /* Calculate factor such that the character aspect ratio is preserved
1664 * when the overall aspect ratio is changed, i.e., if portrait mode is
1665 * requested (only honored for subset of drivers) or if the aspect ratio
1666 * is specified in any way, or if a 90 deg rotation occurs with
1667 * -freeaspect. */
1668
1669 /* Case where plsc->aspect has a value.... (e.g., -a aspect on the
1670 * command line or 2nd parameter of plsdidev specified) */
1671 if (plsc->aspect > 0.) {
1672 lx = plsc->phyxlen / plsc->xpmm;
1673 ly = plsc->phyylen / plsc->ypmm;
1674 aspect_old = lx / ly;
1675 aspect_new = plsc->aspect;
1676 plsc->caspfactor = sqrt(aspect_old/aspect_new);
1677 }
1678 /* Case of 90 deg rotations with -freeaspect (this is also how portraite
1679 * mode is implemented for the drivers that honor -portrait). */
1680 else if (plsc->freeaspect && ABS(cos(plsc->diorot * PI / 2.)) <= 1.e-5) {
1681 lx = plsc->phyxlen / plsc->xpmm;
1682 ly = plsc->phyylen / plsc->ypmm;
1683 aspect_old = lx / ly;
1684 aspect_new = ly / lx;
1685 plsc->caspfactor = sqrt(aspect_old/aspect_new);
1686 }
1687
1688 else
1689 plsc->caspfactor = 1.;
1690
1691 /* Load fonts */
1692
1693 plsc->cfont = 1;
1694 plfntld(initfont);
1695
1696 /* Set up subpages */
1697
1698 plP_subpInit();
1699
1700 /* Set up number of allowed digits before switching to scientific notation */
1701 /* The user can always change this */
1702
1703 if (plsc->xdigmax == 0)
1704 plsc->xdigmax = 4;
1705
1706 if (plsc->ydigmax == 0)
1707 plsc->ydigmax = 4;
1708
1709 if (plsc->zdigmax == 0)
1710 plsc->zdigmax = 3;
1711
1712 /* Switch to graphics mode and set color and arrow style*/
1713
1714 plgra();
1715 plcol(1);
1716
1717 plstyl(0, &mk, &sp);
1718 plpat(1, &inc, &del);
1719
1720 plsvect(def_arrow_x, def_arrow_y, 6, 0);
1721
1722 /* Set clip limits. */
1723
1724 plsc->clpxmi = plsc->phyxmi;
1725 plsc->clpxma = plsc->phyxma;
1726 plsc->clpymi = plsc->phyymi;
1727 plsc->clpyma = plsc->phyyma;
1728
1729 /* Page aspect ratio. */
1730
1731 lx = plsc->phyxlen / plsc->xpmm;
1732 ly = plsc->phyylen / plsc->ypmm;
1733 plsc->aspdev = lx / ly;
1734
1735 /* Initialize driver interface */
1736
1737 pldi_ini();
1738
1739 /* Apply compensating factor to original xpmm and ypmm so that
1740 * character aspect ratio is preserved when overall aspect ratio
1741 * is changed. This must appear here in the code because previous
1742 * code in this routine and in routines that it calls must use the original
1743 * values of xpmm and ypmm before the compensating factor is applied. */
1744
1745 plP_gpixmm(&xpmm_loc, &ypmm_loc);
1746 plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor);
1747 }
1748
1749 /*--------------------------------------------------------------------------*\
1750 * void plend()
1751 *
1752 * End a plotting session for all open streams.
1753 \*--------------------------------------------------------------------------*/
1754
1755 void
c_plend(void)1756 c_plend(void)
1757 {
1758 PLINT i;
1759
1760 if (lib_initialized == 0) return;
1761
1762 for (i = PL_NSTREAMS-1; i >= 0; i--) {
1763 if (pls[i] != NULL) {
1764 plsstrm(i);
1765 c_plend1();
1766 }
1767 }
1768 plfontrel();
1769 #ifdef ENABLE_DYNDRIVERS
1770 /* Release the libltdl resources */
1771 lt_dlexit();
1772 /* Free up memory allocated to the dispatch tables */
1773 for (i = 0; i < npldynamicdevices; i++) {
1774 free_mem(loadable_device_list[i].devnam);
1775 free_mem(loadable_device_list[i].description);
1776 free_mem(loadable_device_list[i].drvnam);
1777 free_mem(loadable_device_list[i].tag);
1778 }
1779 free_mem(loadable_device_list);
1780 for (i = 0; i < nloadabledrivers; i++) {
1781 free_mem(loadable_driver_list[i].drvnam);
1782 }
1783 free_mem(loadable_driver_list);
1784 for (i = nplstaticdevices; i < npldrivers; i++) {
1785 free_mem(dispatch_table[i]->pl_MenuStr);
1786 free_mem(dispatch_table[i]->pl_DevName);
1787 free_mem(dispatch_table[i]);
1788 }
1789 #endif
1790 for (i = 0; i < nplstaticdevices; i++) {
1791 free_mem(dispatch_table[i]);
1792 }
1793 free_mem(dispatch_table);
1794
1795 plP_FreeDrvOpts();
1796
1797 lib_initialized = 0;
1798 }
1799
1800 /*--------------------------------------------------------------------------*\
1801 * void plend1()
1802 *
1803 * End a plotting session for the current stream only. After the stream is
1804 * ended the memory associated with the stream's PLStream data structure is
1805 * freed (for stream > 0), and the stream counter is set to 0 (the default).
1806 \*--------------------------------------------------------------------------*/
1807
1808 void
c_plend1(void)1809 c_plend1(void)
1810 {
1811 if (plsc->level > 0) {
1812 plP_eop();
1813 plP_tidy();
1814 plsc->level = 0;
1815 }
1816 /* Move from plP_tidy because FileName may be set even if level == 0 */
1817 if (plsc->FileName)
1818 free_mem(plsc->FileName);
1819
1820 /* Free all malloc'ed stream memory */
1821
1822 free_mem(plsc->cmap0);
1823 free_mem(plsc->cmap1);
1824 free_mem(plsc->plwindow);
1825 free_mem(plsc->geometry);
1826 free_mem(plsc->dev);
1827 free_mem(plsc->BaseName);
1828 free_mem(plsc->Ext); /* pmr: added for EMBOSS */
1829 #ifndef BUFFERED_FILE
1830 free_mem(plsc->plbuf_buffer);
1831 #endif
1832 /* if (plsc->program) free_mem(plsc->program);*/ /* pmr: now const */
1833 if (plsc->server_name) free_mem(plsc->server_name);
1834 if (plsc->server_host) free_mem(plsc->server_host);
1835 if (plsc->server_port) free_mem(plsc->server_port);
1836 if (plsc->user) free_mem(plsc->user);
1837 if (plsc->plserver) free_mem(plsc->plserver);
1838 if (plsc->auto_path) free_mem(plsc->auto_path);
1839
1840 if (plsc->arrow_x) free_mem(plsc->arrow_x);
1841 if (plsc->arrow_y) free_mem(plsc->arrow_y);
1842
1843 /* Free malloc'ed stream if not in initial stream, else clear it out */
1844
1845 if (ipls > 0) {
1846 free_mem(plsc);
1847 pls[ipls] = NULL;
1848 plsstrm(0);
1849 }
1850 else {
1851 memset((char *) pls[ipls], 0, sizeof(PLStream));
1852 }
1853 }
1854
1855 /*--------------------------------------------------------------------------*\
1856 * void plsstrm
1857 *
1858 * Set stream number. If the data structure for a new stream is
1859 * unallocated, we allocate it here.
1860 \*--------------------------------------------------------------------------*/
1861
1862 void
c_plsstrm(PLINT strm)1863 c_plsstrm(PLINT strm)
1864 {
1865 if (strm < 0 || strm >= PL_NSTREAMS) {
1866 fprintf(stderr,
1867 "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
1868 (int) strm, PL_NSTREAMS);
1869 }
1870 else {
1871 ipls = strm;
1872 if (pls[ipls] == NULL) {
1873 pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
1874 if (pls[ipls] == NULL)
1875 plexit("plsstrm: Out of memory.");
1876
1877 memset((char *) pls[ipls], 0, sizeof(PLStream));
1878 }
1879 plsc = pls[ipls];
1880 plsc->ipls = ipls;
1881 }
1882 }
1883
1884 /*--------------------------------------------------------------------------*\
1885 * void plgstrm
1886 *
1887 * Get current stream number.
1888 \*--------------------------------------------------------------------------*/
1889
1890 void
c_plgstrm(PLINT * p_strm)1891 c_plgstrm(PLINT *p_strm)
1892 {
1893 *p_strm = ipls;
1894 }
1895
1896 /*--------------------------------------------------------------------------*\
1897 * void plmkstrm
1898 *
1899 * Creates a new stream and makes it the default. Differs from using
1900 * plsstrm(), in that a free stream number is found, and returned.
1901 *
1902 * Unfortunately, I /have/ to start at stream 1 and work upward, since
1903 * stream 0 is preallocated. One of the BIG flaws in the PLplot API is
1904 * that no initial, library-opening call is required. So stream 0 must be
1905 * preallocated, and there is no simple way of determining whether it is
1906 * already in use or not.
1907 \*--------------------------------------------------------------------------*/
1908
1909 void
c_plmkstrm(PLINT * p_strm)1910 c_plmkstrm(PLINT *p_strm)
1911 {
1912 int i;
1913
1914 for (i = 1; i < PL_NSTREAMS; i++) {
1915 if (pls[i] == NULL)
1916 break;
1917 }
1918
1919 if (i == PL_NSTREAMS) {
1920 fprintf(stderr, "plmkstrm: Cannot create new stream\n");
1921 *p_strm = -1;
1922 }
1923 else {
1924 *p_strm = i;
1925 plsstrm(i);
1926 }
1927 plstrm_init();
1928 }
1929
1930 /*--------------------------------------------------------------------------*\
1931 * void plstrm_init
1932 *
1933 * Does required startup initialization of a stream. Should be called right
1934 * after creating one (for allocating extra memory, etc). Users shouldn't
1935 * need to call this directly.
1936 *
1937 * This function can be called multiple times for a given stream, in which
1938 * case only the first call produces any effect. For streams >= 1, which
1939 * are created dynamically, this is called by the routine that allocates
1940 * the stream. Stream 0, which is preallocated, is much harder to deal with
1941 * because any of a number of different calls may be the first call to the
1942 * library. This is handled by just calling plstrm_init() from every
1943 * function that might be called first. Sucks, but it should work.
1944 \*--------------------------------------------------------------------------*/
1945
1946 void
plstrm_init(void)1947 plstrm_init(void)
1948 {
1949 if ( ! plsc->initialized) {
1950 plsc->initialized = 1;
1951
1952 if (plsc->cmap0 == NULL)
1953 plscmap0n(0);
1954
1955 if (plsc->cmap1 == NULL)
1956 plscmap1n(0);
1957 }
1958
1959 plsc->psdoc = NULL;
1960 }
1961
1962 /*--------------------------------------------------------------------------*\
1963 * pl_cpcolor
1964 *
1965 * Utility to copy one PLColor to another.
1966 \*--------------------------------------------------------------------------*/
1967
1968 void
pl_cpcolor(PLColor * to,PLColor * from)1969 pl_cpcolor(PLColor *to, PLColor *from)
1970 {
1971 to->r = from->r;
1972 to->g = from->g;
1973 to->b = from->b;
1974 }
1975
1976 /*--------------------------------------------------------------------------*\
1977 * void plcpstrm
1978 *
1979 * Copies state parameters from the reference stream to the current stream.
1980 * Tell driver interface to map device coordinates unless flags == 1.
1981 *
1982 * This function is used for making save files of selected plots (e.g.
1983 * from the TK driver). After initializing, you can get a copy of the
1984 * current plot to the specified device by switching to this stream and
1985 * issuing a plcpstrm() and a plreplot(), with calls to plbop() and
1986 * pleop() as appropriate. The plot buffer must have previously been
1987 * enabled (done automatically by some display drivers, such as X).
1988 \*--------------------------------------------------------------------------*/
1989
1990 void
c_plcpstrm(PLINT iplsr,PLINT flags)1991 c_plcpstrm(PLINT iplsr, PLINT flags)
1992 {
1993 int i;
1994 PLStream *plsr;
1995
1996 plsr = pls[iplsr];
1997 if (plsr == NULL) {
1998 fprintf(stderr, "plcpstrm: stream %d not in use\n", (int) iplsr);
1999 return;
2000 }
2001
2002 /* May be debugging */
2003
2004 plsc->debug = plsr->debug;
2005
2006 /* Plot buffer -- need to copy file pointer so that plreplot() works */
2007 /* This also prevents inadvertent writes into the plot buffer */
2008
2009 #ifdef BUFFERED_FILE
2010 plsc->plbufFile = plsr->plbufFile;
2011 #else
2012 plsc->plbuf_buffer = plsr->plbuf_buffer;
2013 plsc->plbuf_buffer_grow = plsr->plbuf_buffer_grow;
2014 plsc->plbuf_buffer_size = plsr->plbuf_buffer_size;
2015 plsc->plbuf_top = plsr->plbuf_top;
2016 plsc->plbuf_readpos = plsr->plbuf_readpos;
2017 #endif
2018
2019 /* Driver interface */
2020 /* Transformation must be recalculated in current driver coordinates */
2021
2022 if (plsr->difilt & PLDI_PLT)
2023 plsdiplt(plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax);
2024
2025 if (plsr->difilt & PLDI_DEV)
2026 plsdidev(plsr->mar, plsr->aspect, plsr->jx, plsr->jy);
2027
2028 if (plsr->difilt & PLDI_ORI)
2029 plsdiori(plsr->diorot);
2030
2031 /* Map device coordinates */
2032
2033 if ( ! (flags & 0x01)) {
2034 pldebug("plcpstrm", "mapping parameters: %d %d %d %d %f %f\n",
2035 plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
2036 plsr->xpmm, plsr->ypmm);
2037 plsdimap(plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
2038 plsr->xpmm, plsr->ypmm);
2039 }
2040
2041 /* current color */
2042
2043 pl_cpcolor(&plsc->curcolor, &plsr->curcolor);
2044
2045 /* cmap 0 */
2046
2047 plsc->icol0 = plsr->icol0;
2048 plsc->ncol0 = plsr->ncol0;
2049 if (plsc->cmap0 != NULL)
2050 free((void *) plsc->cmap0);
2051
2052 plsc->cmap0 = (PLColor *) calloc(1, plsc->ncol0 * sizeof(PLColor));
2053 for (i = 0; i < plsc->ncol0; i++)
2054 pl_cpcolor(&plsc->cmap0[i], &plsr->cmap0[i]);
2055
2056 /* cmap 1 */
2057
2058 plsc->icol1 = plsr->icol1;
2059 plsc->ncol1 = plsr->ncol1;
2060 if (plsc->cmap1 != NULL)
2061 free((void *) plsc->cmap1);
2062
2063 plsc->cmap1 = (PLColor *) calloc(1, plsc->ncol1 * sizeof(PLColor));
2064 for (i = 0; i < plsc->ncol1; i++)
2065 pl_cpcolor(&plsc->cmap1[i], &plsr->cmap1[i]);
2066
2067 /* Initialize if it hasn't been done yet. */
2068
2069 if (plsc->level == 0)
2070 plinit();
2071 }
2072
2073 /*--------------------------------------------------------------------------*\
2074 * pllib_devinit()
2075 *
2076 * Does preliminary setup of device driver.
2077 *
2078 * This function (previously plGetDev) used to be what is now shown as
2079 * plSelectDev below. However, the situation is a bit more complicated now in
2080 * the dynloadable drivers era. We now have to:
2081 *
2082 * 1) Make sure the dispatch table is initialized to the union of static
2083 * drivers and available dynamic drivers (done from pllib_init now).
2084 * 2) Allow the user to select the desired device.
2085 * 3) Initialize the dispatch table entries for the selected device, in the
2086 * case that it is a dynloadable driver that has not yet been loaded.
2087 *
2088 * Also made non-static, in order to allow some device calls to be made prior
2089 * to calling plinit(). E.g. plframe needs to tell the X driver to create its
2090 * internal data structure during widget construction time (using the escape
2091 * function), but doesn't call plinit() until the plframe is actually mapped.
2092 \*--------------------------------------------------------------------------*/
2093
2094 void
pllib_devinit(void)2095 pllib_devinit(void) /* pmr: prototype */
2096 {
2097 if (plsc->dev_initialized) return;
2098 plsc->dev_initialized = 1;
2099
2100 plSelectDev();
2101
2102 plLoadDriver();
2103
2104 /* offset by one since table is zero-based, but input list is not */
2105 plsc->dispatch_table = dispatch_table[plsc->device - 1];
2106 }
2107
plInBuildTree(void)2108 int PLDLLIMPEXP plInBuildTree(void) /* pmr: prototype */
2109 {
2110 static int inited = 0;
2111 static int inBuildTree = 0;
2112
2113 if (inited == 0) {
2114 char currdir[256];
2115
2116 /* AM: getcwd has a somewhat strange status on Windows, its proper
2117 name is _getcwd, this is a problem in the case of DLLs, like with
2118 the Java bindings.
2119 */
2120 #if defined(WIN32) && !defined(__BORLANDC__)
2121 #define getcwd _getcwd
2122 #endif
2123
2124 if (getcwd(currdir, 256) == NULL) {
2125 pldebug("plInBuildTree():", "Not enough buffer space");
2126 } else if (strncmp(BUILD_DIR, currdir, strlen(BUILD_DIR)) == 0)
2127 inBuildTree = 1;
2128 inited = 1;
2129 }
2130 return inBuildTree;
2131 }
2132
2133 #ifdef ENABLE_DYNDRIVERS
2134
2135 static char*
plGetDrvDir()2136 plGetDrvDir ()
2137 {
2138 char* drvdir;
2139
2140 /* Get drivers directory in PLPLOT_DRV_DIR or DRV_DIR,
2141 * on this order
2142 */
2143
2144 if (plInBuildTree() == 1) {
2145 drvdir = BUILD_DIR "/drivers";
2146 pldebug("plGetDrvDir", "Using %s as the driver directory.\n", drvdir);
2147 } else {
2148 pldebug("plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n");
2149 drvdir = getenv ("PLPLOT_DRV_DIR");
2150
2151 if (drvdir == NULL) {
2152 pldebug("plGetDrvDir",
2153 "Will use drivers dir: " DRV_DIR "\n");
2154 drvdir = DRV_DIR;
2155 }
2156 }
2157
2158 return drvdir;
2159 }
2160
2161 #endif
2162
2163
2164 /*--------------------------------------------------------------------------*\
2165 * void plInitDispatchTable()
2166 *
2167 * ...
2168 \*--------------------------------------------------------------------------*/
2169
plDispatchSequencer(const void * p1,const void * p2)2170 static int plDispatchSequencer( const void *p1, const void *p2 )
2171 {
2172 const PLDispatchTable* t1 = *(const PLDispatchTable * const *) p1;
2173 const PLDispatchTable* t2 = *(const PLDispatchTable * const *) p2;
2174
2175 /* printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n", */
2176 /* t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq ); */
2177
2178 return t1->pl_seq - t2->pl_seq;
2179 }
2180
2181 static void
plInitDispatchTable(void)2182 plInitDispatchTable(void) /* pmr: prototype */
2183 {
2184 int n;
2185
2186 #ifdef ENABLE_DYNDRIVERS
2187 char buf[300];
2188 char* drvdir;
2189 char *devnam, *devdesc, *devtype, *driver, *tag, *seqstr;
2190 int seq;
2191 int i, j, driver_found, done=0;
2192 FILE *fp_drvdb = NULL;
2193 DIR* dp_drvdir = NULL;
2194 struct dirent* entry;
2195 /* lt_dlhandle dlhand; */
2196
2197 /* Make sure driver counts are zeroed */
2198 npldynamicdevices = 0;
2199 nloadabledrivers = 0;
2200
2201 /* Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings
2202 will be stored */
2203 fp_drvdb = tmpfile ();
2204
2205 /* Open the drivers directory */
2206 drvdir = plGetDrvDir ();
2207 dp_drvdir = opendir (drvdir);
2208 if (dp_drvdir == NULL) {
2209 plabort ("plInitDispatchTable: Could not open drivers directory");
2210 return;
2211 }
2212
2213 /* Loop over each entry in the drivers directory */
2214
2215 pldebug ("plInitDispatchTable", "Scanning dyndrivers dir\n");
2216 while ((entry = readdir (dp_drvdir)) != NULL)
2217 {
2218 char* name = entry->d_name;
2219 int len = strlen (name) - 3;
2220
2221 pldebug ("plInitDispatchTable",
2222 "Consider file %s\n", name);
2223
2224 /* Only consider entries that have the ".rc" suffix */
2225 if ((len > 0) && (strcmp (name + len, ".rc") == 0)) {
2226 char path[300];
2227 char buf[300];
2228 FILE* fd;
2229
2230 /* Open the driver's info file */
2231 sprintf (path, "%s/%s", drvdir, name);
2232 fd = fopen (path, "r");
2233 if (fd == NULL) {
2234 sprintf (buf,
2235 "plInitDispatchTable: Could not open driver info file %s\n",
2236 name);
2237 plabort (buf);
2238 return;
2239 }
2240
2241 /* Each line in the <driver>.rc file corresponds to a specific device.
2242 * Write it to the drivers db file and take care of leading newline
2243 * character */
2244
2245 pldebug ("plInitDispatchTable",
2246 "Opened driver info file %s\n", name);
2247 while (fgets (buf, 300, fd) != NULL)
2248 {
2249 fprintf (fp_drvdb, "%s", buf);
2250 if ( buf [strlen (buf) - 1] != '\n' )
2251 fprintf (fp_drvdb, "\n");
2252 npldynamicdevices++;
2253 }
2254 fclose (fd);
2255 }
2256 }
2257
2258 /* Make sure that the temporary file containing the drivers database
2259 * is ready to read and close the directory handle */
2260 fflush (fp_drvdb);
2261 closedir (dp_drvdir);
2262
2263 #endif
2264
2265 /* Allocate space for the dispatch table. */
2266 dispatch_table = (PLDispatchTable **)
2267 malloc( (nplstaticdevices + npldynamicdevices) * sizeof(PLDispatchTable *) );
2268
2269 /* Initialize the dispatch table entries for the static devices by calling
2270 the dispatch table initialization function for each static device. This
2271 is the same function that would be called at load time for dynamic
2272 drivers. */
2273
2274 for( n=0; n < nplstaticdevices; n++ )
2275 {
2276 dispatch_table[n] = (PLDispatchTable *)malloc( sizeof(PLDispatchTable) );
2277
2278 (*static_device_initializers[n])( dispatch_table[n] );
2279 }
2280 npldrivers = nplstaticdevices;
2281
2282 #ifdef ENABLE_DYNDRIVERS
2283
2284 /* Allocate space for the device and driver specs. We may not use all of
2285 * these driver descriptors, but we obviously won't need more drivers than
2286 * devices... */
2287 loadable_device_list = malloc( npldynamicdevices * sizeof(PLLoadableDevice) );
2288 loadable_driver_list = malloc( npldynamicdevices * sizeof(PLLoadableDriver) );
2289
2290 rewind( fp_drvdb );
2291
2292 i = 0;
2293 done = !(i < npldynamicdevices);
2294 while( !done ) {
2295 char *p = fgets( buf, 300, fp_drvdb );
2296
2297 if (p == 0) {
2298 done = 1;
2299 continue;
2300 }
2301
2302 devnam = strtok( buf, ":" );
2303 devdesc = strtok( 0, ":" );
2304 devtype = strtok( 0, ":" );
2305 driver = strtok( 0, ":" );
2306 seqstr = strtok( 0, ":" );
2307 tag = strtok( 0, "\n" );
2308
2309 seq = atoi(seqstr);
2310
2311 n = npldrivers++;
2312
2313 dispatch_table[n] = malloc( sizeof(PLDispatchTable) );
2314
2315 /* Fill in the dispatch table entries. */
2316 dispatch_table[n]->pl_MenuStr = plstrdup(devdesc);
2317 dispatch_table[n]->pl_DevName = plstrdup(devnam);
2318 dispatch_table[n]->pl_type = atoi(devtype);
2319 dispatch_table[n]->pl_seq = seq;
2320 dispatch_table[n]->pl_init = 0;
2321 dispatch_table[n]->pl_line = 0;
2322 dispatch_table[n]->pl_polyline = 0;
2323 dispatch_table[n]->pl_eop = 0;
2324 dispatch_table[n]->pl_bop = 0;
2325 dispatch_table[n]->pl_tidy = 0;
2326 dispatch_table[n]->pl_state = 0;
2327 dispatch_table[n]->pl_esc = 0;
2328
2329 /* Add a record to the loadable device list */
2330 loadable_device_list[i].devnam = plstrdup(devnam);
2331 loadable_device_list[i].description = plstrdup(devdesc);
2332 loadable_device_list[i].drvnam = plstrdup(driver);
2333 loadable_device_list[i].tag = plstrdup(tag);
2334
2335 /* Now see if this driver has been seen before. If not, add a driver
2336 * entry for it. */
2337 driver_found = 0;
2338 for( j=0; j < nloadabledrivers; j++ )
2339 if (strcmp( driver, loadable_driver_list[j].drvnam) == 0)
2340 {
2341 driver_found = 1;
2342 break;
2343 }
2344
2345 if (!driver_found)
2346 {
2347 loadable_driver_list[nloadabledrivers].drvnam = plstrdup(driver);
2348 loadable_driver_list[nloadabledrivers].dlhand = 0;
2349 nloadabledrivers++;
2350 }
2351
2352 loadable_device_list[i].drvidx = j;
2353
2354 /* Get ready for next loadable device spec */
2355 i++;
2356 }
2357
2358 /* RML: close fp_drvdb */
2359 fclose (fp_drvdb);
2360
2361 #endif
2362
2363 /* Finally, we need to sort the list into presentation order, based on the
2364 sequence number in the dispatch ttable entries. */
2365
2366 qsort( dispatch_table, npldrivers, sizeof(PLDispatchTable*),
2367 plDispatchSequencer );
2368 }
2369
2370 /*--------------------------------------------------------------------------*\
2371 * void plSelectDev()
2372 *
2373 * If the user has not already specified the output device, or the
2374 * one specified is either: (a) not available, (b) "?", or (c) NULL, the
2375 * user is prompted for it.
2376 *
2377 * Prompting quits after 10 unsuccessful tries in case the user has
2378 * run the program in the background with insufficient input.
2379 \*--------------------------------------------------------------------------*/
2380
2381 static void
plSelectDev(void)2382 plSelectDev(void) /* pmr: prototype */
2383 {
2384 int dev, i, count, length;
2385 char response[80];
2386 int tlen;
2387
2388 /* Device name already specified. See if it is valid. */
2389
2390 if (*(plsc->DevName) != '\0' && *(plsc->DevName) != '?') {
2391 length = strlen(plsc->DevName);
2392 for (i = 0; i < npldrivers; i++) {
2393 if ((*plsc->DevName == *dispatch_table[i]->pl_DevName) &&
2394 (strncmp(plsc->DevName,
2395 dispatch_table[i]->pl_DevName, length) == 0))
2396 break;
2397 }
2398 if (i < npldrivers) {
2399 plsc->device = i + 1;
2400 return;
2401 }
2402 else {
2403 fprintf(stderr, "Requested device %s not available\n",
2404 plsc->DevName);
2405 }
2406 }
2407
2408 dev = 0;
2409 count = 0;
2410
2411 if (npldrivers == 1)
2412 dev = 1;
2413
2414 /* User hasn't specified it correctly yet, so we prompt */
2415
2416 while (dev < 1 || dev > npldrivers) {
2417 fprintf(stdout, "\nPlotting Options:\n");
2418 for (i = 0; i < npldrivers; i++) {
2419 fprintf(stdout, " <%2d> %-10s %s\n", i + 1,
2420 dispatch_table[i]->pl_DevName,
2421 dispatch_table[i]->pl_MenuStr);
2422 }
2423 if (ipls == 0)
2424 fprintf(stdout, "\nEnter device number or keyword: ");
2425 else
2426 fprintf(stdout, "\nEnter device number or keyword (stream %d): ",
2427 (int) ipls);
2428
2429 plio_fgets(response, sizeof(response), stdin);
2430
2431 /* First check to see if device keyword was entered. */
2432 /* Final "\n" in response messes things up, so ignore it. */
2433
2434 length = strlen(response);
2435 if(!length)
2436 {
2437 fprintf(stderr,"Error: empty response\n");
2438 exit(-1);
2439 }
2440
2441 tlen = length - 1;
2442 if (*(response + tlen) == '\n')
2443 length--;
2444
2445 for (i = 0; i < npldrivers; i++) {
2446 if ( ! strncmp(response, dispatch_table[i]->pl_DevName,
2447 (unsigned int) length))
2448 break;
2449 }
2450 if (i < npldrivers) {
2451 dev = i + 1;
2452 }
2453 else {
2454 if ((dev = atoi(response)) < 1) {
2455 fprintf(stdout, "\nInvalid device: %s", response);
2456 dev = 0;
2457 }
2458 }
2459 if (count++ > 10)
2460 plexit("plSelectDev: Too many tries.");
2461 }
2462 plsc->device = dev;
2463 strcpy(plsc->DevName, dispatch_table[dev - 1]->pl_DevName);
2464 }
2465
2466 /*--------------------------------------------------------------------------*\
2467 * void plLoadDriver()
2468 *
2469 * Make sure the selected driver is loaded. Static drivers are already
2470 * loaded, but if the user selected a dynamically loadable driver, we may
2471 * have to take care of that now.
2472 \*--------------------------------------------------------------------------*/
2473
2474 static void
plLoadDriver(void)2475 plLoadDriver(void)
2476 {
2477 #ifdef ENABLE_DYNDRIVERS
2478 int i, drvidx;
2479 char sym[60];
2480 char *tag;
2481
2482 int n=plsc->device - 1;
2483 PLDispatchTable *dev = dispatch_table[n];
2484 PLLoadableDriver *driver = 0;
2485
2486 /* If the dispatch table is already filled in, then either the device was
2487 * linked in statically, or else perhaps it was already loaded. In either
2488 * case, we have nothing left to do. */
2489 if (dev->pl_init)
2490 return;
2491
2492 pldebug("plLoadDriver", "Device not loaded!\n");
2493
2494 /* Now search through the list of loadable devices, looking for the record
2495 * that corresponds to the requested device. */
2496 for( i=0; i < npldynamicdevices; i++ )
2497 if (strcmp( dev->pl_DevName, loadable_device_list[i].devnam ) == 0)
2498 break;
2499
2500 /* If we couldn't find such a record, then there is some sort of internal
2501 * logic flaw since plSelectDev is supposed to only select a valid device.
2502 */
2503 if (i == npldynamicdevices) {
2504 fprintf( stderr, "No such device: %s.\n", dev->pl_DevName );
2505 plexit("plLoadDriver detected device logic screwup");
2506 }
2507
2508 /* Note the device tag, and the driver index. Note that a given driver could
2509 * supply multiple devices, each with a unique tag to distinguish the driver
2510 * entry points for the differnet supported devices. */
2511 tag = loadable_device_list[i].tag;
2512 drvidx = loadable_device_list[i].drvidx;
2513
2514 pldebug("plLoadDriver", "tag=%s, drvidx=%d\n", tag, drvidx );
2515
2516 driver = &loadable_driver_list[drvidx];
2517
2518 /* Load the driver if it hasn't been loaded yet. */
2519 if (!driver->dlhand)
2520 {
2521 char drvspec[ 400 ];
2522 sprintf( drvspec, "%s/%s", plGetDrvDir (), driver->drvnam );
2523
2524 pldebug("plLoadDriver", "Trying to load %s on %s\n",
2525 driver->drvnam, drvspec );
2526
2527 driver->dlhand = lt_dlopenext( drvspec);
2528 }
2529
2530 /* If it still isn't loaded, then we're doomed. */
2531 if (!driver->dlhand)
2532 {
2533 pldebug("plLoadDriver", "lt_dlopenext failed because of "
2534 "the following reason:\n%s\n", lt_dlerror ());
2535 fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam );
2536 plexit("Unable to load driver");
2537 }
2538
2539 /* Now we are ready to ask the driver's device dispatch init function to
2540 initialize the entries in the dispatch table. */
2541
2542 sprintf( sym, "plD_dispatch_init_%s", tag );
2543 {
2544 PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym );
2545 if (!dispatch_init)
2546 {
2547 fprintf( stderr,
2548 "Unable to locate dispatch table initialization function for driver: %s.\n",
2549 driver->drvnam );
2550 return;
2551 }
2552
2553 (*dispatch_init)( dev );
2554 }
2555 #endif
2556 }
2557
2558 /*--------------------------------------------------------------------------*\
2559 * void plfontld()
2560 *
2561 * Load specified font set.
2562 \*--------------------------------------------------------------------------*/
2563
2564 void
c_plfontld(PLINT ifont)2565 c_plfontld(PLINT ifont)
2566 {
2567 if (ifont != 0)
2568 ifont = 1;
2569
2570 if (plsc->level > 0)
2571 plfntld(ifont);
2572 else
2573 initfont = ifont;
2574 }
2575
2576 /*--------------------------------------------------------------------------*\
2577 * void plreplot()
2578 *
2579 * Replays contents of plot buffer to current device/file.
2580 \*--------------------------------------------------------------------------*/
2581
2582 void
c_plreplot(void)2583 c_plreplot(void)
2584 {
2585 #ifdef BUFFERED_FILE
2586 if (plsc->plbufFile != NULL) {
2587 #else
2588 if (plsc->plbuf_buffer != NULL) {
2589 #endif
2590 plRemakePlot(plsc);
2591 }
2592 else {
2593 plwarn("plreplot: plot buffer not available");
2594 }
2595 }
2596
2597 /*--------------------------------------------------------------------------*\
2598 * void plgFileDevs()
2599 *
2600 * Returns a list of file-oriented device names and their menu strings,
2601 * for use in a graphical interface. The caller must allocate enough
2602 * space for (*p_menustr) and (*p_devname) to hold a pointer for each
2603 * device -- 20 or so is plenty. E.g. char *menustr[20]. The size of
2604 * these arrays should be passed in *p_ndev, which, on exit, holds the
2605 * number of devices actually present.
2606 \*--------------------------------------------------------------------------*/
2607
2608 void /* pmr: const */
2609 plgFileDevs(const char ***p_menustr, const char ***p_devname, int *p_ndev)
2610 {
2611 plgdevlst(*p_menustr, *p_devname, p_ndev, 0);
2612 }
2613
2614 /*--------------------------------------------------------------------------*\
2615 * void plgDevs()
2616 *
2617 * Like plgFileDevs(), but returns names and menu strings for all devices.
2618 \*--------------------------------------------------------------------------*/
2619
2620 void /* pmr: const */
2621 plgDevs(const char ***p_menustr, const char ***p_devname, int *p_ndev)
2622 {
2623 plgdevlst(*p_menustr, *p_devname, p_ndev, -1);
2624 }
2625
2626 static void /* pmr: const */
2627 plgdevlst(const char **p_menustr, const char **p_devname, int *p_ndev, int type)
2628 {
2629 int i, j;
2630
2631 pllib_init();
2632
2633 for (i = j = 0; i < npldrivers; i++) {
2634 if (type < 0 || dispatch_table[i]->pl_type == type) {
2635 p_menustr[j] = dispatch_table[i]->pl_MenuStr;
2636 p_devname[j] = dispatch_table[i]->pl_DevName;
2637 if (++j + 1 >= *p_ndev) {
2638 plwarn("plgdevlst: too many devices");
2639 break;
2640 }
2641 }
2642 }
2643 p_menustr[j] = NULL;
2644 p_devname[j] = NULL;
2645 *p_ndev = j;
2646 }
2647
2648 /*--------------------------------------------------------------------------*\
2649 * Various external access routines.
2650 \*--------------------------------------------------------------------------*/
2651
2652 /* Get output device parameters. */
2653
2654 void
2655 c_plgpage(PLFLT *p_xp, PLFLT *p_yp,
2656 PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff)
2657 {
2658 *p_xp = plsc->xdpi;
2659 *p_yp = plsc->ydpi;
2660 *p_xleng = plsc->xlength;
2661 *p_yleng = plsc->ylength;
2662 *p_xoff = plsc->xoffset;
2663 *p_yoff = plsc->yoffset;
2664 }
2665
2666 /* Set output device parameters. Usually ignored by the driver. */
2667
2668 void
2669 c_plspage(PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff)
2670 {
2671 if (plsc->level > 0)
2672 plwarn("calling plspage() after plinit() may give unpredictable results");
2673
2674 if (xp)
2675 plsc->xdpi = xp;
2676 if (yp)
2677 plsc->ydpi = yp;
2678
2679 if (xleng)
2680 plsc->xlength = xleng;
2681 if (yleng)
2682 plsc->ylength = yleng;
2683
2684 if (xoff)
2685 plsc->xoffset = xoff;
2686 if (yoff)
2687 plsc->yoffset = yoff;
2688
2689 plsc->pageset = 1;
2690 }
2691
2692 /* Set the number of subwindows in x and y */
2693
2694 void
2695 c_plssub(PLINT nx, PLINT ny)
2696 {
2697 if (nx > 0)
2698 plsc->nsubx = nx;
2699 if (ny > 0)
2700 plsc->nsuby = ny;
2701
2702 /* Force a page advance */
2703
2704 if (plsc->level > 0) {
2705 plP_subpInit();
2706 /*AWI plP_eop();
2707 plP_bop();*/
2708 }
2709 }
2710
2711 /* Set the device (keyword) name */
2712
2713 void
2714 c_plsdev(const char *devname)
2715 {
2716 if (plsc->level > 0) {
2717 plwarn("plsdev: Must be called before plinit.");
2718 return;
2719 }
2720 if (devname != NULL) {
2721 strncpy(plsc->DevName, devname, sizeof(plsc->DevName) - 1);
2722 plsc->DevName[sizeof(plsc->DevName) - 1] = '\0';
2723 }
2724 }
2725
2726 /* Get the current device (keyword) name */
2727 /* Note: you MUST have allocated space for this (80 characters is safe) */
2728
2729 void
2730 c_plgdev(char *p_dev)
2731 {
2732 strcpy(p_dev, plsc->DevName);
2733 }
2734
2735 /* Set the memory area to be plotted (with the 'mem' driver) as the 'dev'
2736 member of the stream structure. Also set the number
2737 of pixels in the memory passed in in 'plotmem'.
2738 Plotmem is a block of memory maxy by maxx by 3 bytes long, say:
2739 480 x 640 x 3 (Y, X, RGB)
2740
2741 This memory will be freed by the user!
2742 */
2743
2744 void
2745 c_plsmem(PLINT maxx, PLINT maxy, void *plotmem)
2746 {
2747 plsc->dev = plotmem;
2748 plP_setphy (0, maxx, 0, maxy);
2749 }
2750
2751 /* Get the current stream pointer */
2752
2753 void
2754 plgpls(PLStream **p_pls)
2755 {
2756 *p_pls = plsc;
2757 }
2758
2759 /* Get the (current) run level.
2760 * Valid settings are:
2761 * 0 uninitialized
2762 * 1 initialized
2763 * 2 viewport defined
2764 * 3 world coords defined
2765 */
2766
2767 void
2768 c_plglevel(PLINT *p_level)
2769 {
2770 *p_level = plsc->level;
2771 }
2772
2773 /* Set the function pointer for the keyboard event handler */
2774
2775 void
2776 plsKeyEH(void (*KeyEH) (PLGraphicsIn *, void *, int *),
2777 void *KeyEH_data)
2778 {
2779 plsc->KeyEH = KeyEH;
2780 plsc->KeyEH_data = KeyEH_data;
2781 }
2782
2783 /* Set the function pointer for the (mouse) button event handler */
2784
2785 void
2786 plsButtonEH(void (*ButtonEH) (PLGraphicsIn *, void *, int *),
2787 void *ButtonEH_data)
2788 {
2789 plsc->ButtonEH = ButtonEH;
2790 plsc->ButtonEH_data = ButtonEH_data;
2791 }
2792
2793 /* Sets an optional user bop handler. */
2794
2795 void
2796 plsbopH(void (*handler) (void *, int *), void *handler_data)
2797 {
2798 plsc->bop_handler = handler;
2799 plsc->bop_data = handler_data;
2800 }
2801
2802 /* Sets an optional user eop handler. */
2803
2804 void
2805 plseopH(void (*handler) (void *, int *), void *handler_data)
2806 {
2807 plsc->eop_handler = handler;
2808 plsc->eop_data = handler_data;
2809 }
2810
2811 /* Set the variables to be used for storing error info */
2812
2813 void
2814 plsError(PLINT *errcode, char *errmsg)
2815 {
2816 if (errcode != NULL)
2817 plsc->errcode = errcode;
2818
2819 if (errmsg != NULL)
2820 plsc->errmsg = errmsg;
2821 }
2822
2823 /* Set orientation. Must be done before calling plinit. */
2824
2825 void
2826 c_plsori(PLINT ori)
2827 {
2828 plsdiori((PLFLT) ori);
2829 }
2830
2831 /*
2832 * Set pen width. Can be done any time, but before calling plinit is best
2833 * since otherwise it may be volatile (i.e. reset on next page advance).
2834 * If width < 0 or is unchanged by the call, nothing is done.
2835 */
2836
2837 void
2838 c_plwid(PLINT width)
2839 {
2840 if (width != plsc->width && width >= 0) {
2841 plsc->width = width;
2842
2843 if (plsc->level > 0) {
2844 if ( ! plsc->widthlock)
2845 plP_state(PLSTATE_WIDTH);
2846 }
2847 }
2848 }
2849
2850 /* Set the output file pointer */
2851
2852 void
2853 plgfile(FILE **p_file)
2854 {
2855 *p_file = plsc->OutFile;
2856 }
2857
2858 /* Get the output file pointer */
2859
2860 void
2861 plsfile(FILE *file)
2862 {
2863 plsc->OutFile = file;
2864 }
2865
2866 /* Get the (current) output file name. Must be preallocated to >=80 bytes */
2867 /* Beyond that, I truncate it. You have been warned. */
2868
2869 void
2870 c_plgfnam(char *fnam)
2871 {
2872 if (fnam == NULL) {
2873 plabort("filename string must be preallocated to >=80 bytes");
2874 return;
2875 }
2876
2877 *fnam = '\0';
2878 if (plsc->FileName != NULL) {
2879 strncpy(fnam, plsc->FileName, 79);
2880 fnam[79] = '\0';
2881 }
2882 }
2883
2884 /* Set the output file name. */
2885
2886 void
2887 c_plsfnam(const char *fnam)
2888 {
2889 plP_sfnam(plsc, fnam);
2890 }
2891
2892 void
2893 c_plxsfnam(const char *fnam, const char* ext)
2894 {
2895 plPX_sfnam(plsc, fnam, ext);
2896 }
2897
2898 /* Set the pause (on end-of-page) status */
2899
2900 void
2901 c_plspause(PLINT mypause) /* pmr: pause in unistd.h */
2902 {
2903 plsc->nopause = ! mypause;
2904 }
2905
2906 /* Set the floating point precision (in number of places) in numeric labels. */
2907
2908 void
2909 c_plprec(PLINT setp, PLINT prec)
2910 {
2911 plsc->setpre = setp;
2912 plsc->precis = prec;
2913 }
2914
2915 /* Get the floating point precision (in number of places) in numeric labels. */
2916
2917 void
2918 plP_gprec(PLINT *p_setp, PLINT *p_prec)
2919 {
2920 *p_setp = plsc->setpre;
2921 *p_prec = plsc->precis;
2922 }
2923
2924 /*
2925 * Set the escape character for text strings.
2926 * From C you can pass as a character, from Fortran it needs to be the decimal
2927 * ASCII value. Only selected characters are allowed to prevent the user from
2928 * shooting himself in the foot (a '\' isn't allowed since it conflicts with
2929 * C's use of backslash as a character escape).
2930 */
2931
2932 void
2933 c_plsesc(char esc)
2934 {
2935 switch (esc) {
2936 case '!': /* ASCII 33 */
2937 case '#': /* ASCII 35 */
2938 case '$': /* ASCII 36 */
2939 case '%': /* ASCII 37 */
2940 case '&': /* ASCII 38 */
2941 case '*': /* ASCII 42 */
2942 case '@': /* ASCII 64 */
2943 case '^': /* ASCII 94 */
2944 case '~': /* ASCII 126 */
2945 plsc->esc = esc;
2946 break;
2947
2948 default:
2949 plwarn("plsesc: Invalid escape character, ignoring.");
2950 }
2951 }
2952
2953 /* Get the escape character for text strings. */
2954
2955 void
2956 plgesc(unsigned char *p_esc)
2957 {
2958 if (plsc->esc == '\0')
2959 plsc->esc = '#';
2960
2961 *p_esc = plsc->esc;
2962 }
2963
2964 /* Set the FCI (font characterization integer) for unicode-enabled device
2965 * drivers.
2966 */
2967 void
2968 c_plsfci(PLUNICODE fci)
2969 {
2970 /* Always mark FCI as such. */
2971 plsc->fci = fci | PL_FCI_MARK;
2972 }
2973
2974 /* Get the FCI (font characterization integer) for unicode-enabled device
2975 * drivers.
2976 */
2977 void
2978 c_plgfci(PLUNICODE *pfci)
2979 {
2980 /* Always mark FCI as such. */
2981 *pfci = plsc->fci | PL_FCI_MARK;
2982 }
2983 /* Store hex digit value shifted to the left by hexdigit hexadecimal digits
2984 * into pre-existing FCI.
2985 */
2986 void
2987 plP_hex2fci(unsigned char hexdigit, unsigned char hexpower, PLUNICODE *pfci)
2988 {
2989 PLUNICODE mask;
2990 hexpower = hexpower & PL_FCI_HEXPOWER_MASK;
2991 mask = ~ (((PLUNICODE) PL_FCI_HEXDIGIT_MASK) << ((PLUNICODE) 4*hexpower));
2992 *pfci = *pfci & mask;
2993 mask = (((PLUNICODE) (hexdigit & PL_FCI_HEXDIGIT_MASK)) << (4*hexpower));
2994 *pfci = *pfci | mask;
2995 }
2996
2997 /* Retrieve hex digit value from FCI that is masked out and shifted to the
2998 * right by hexpower hexadecimal digits. */
2999 void
3000 plP_fci2hex(PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower)
3001 {
3002 PLUNICODE mask;
3003 hexpower = hexpower & PL_FCI_HEXPOWER_MASK;
3004 mask = (((PLUNICODE) PL_FCI_HEXPOWER_MASK) << ((PLUNICODE) (4*hexpower)));
3005 *phexdigit = (unsigned char) ((fci & mask) >>
3006 ((PLUNICODE) (4*hexpower)));
3007 }
3008
3009 /* Get the current library version number */
3010 /* Note: you MUST have allocated space for this (80 characters is safe) */
3011 void
3012 c_plgver(char *p_ver)
3013 {
3014 strcpy(p_ver, PLPLT_VERSION);
3015 }
3016
3017 /* Set inferior X window */
3018
3019 void
3020 plsxwin(PLINT window_id)
3021 {
3022 plsc->window_id = window_id;
3023 }
3024
3025 /*--------------------------------------------------------------------------*\
3026 * These set/get information for family files, and may be called prior
3027 * to plinit to set up the necessary parameters. Arguments:
3028 *
3029 * fam familying flag (boolean)
3030 * num member number
3031 * bmax maximum member size
3032 \*--------------------------------------------------------------------------*/
3033
3034 /* Get family file parameters */
3035
3036 void
3037 c_plgfam(PLINT *p_fam, PLINT *p_num, PLINT *p_bmax)
3038 {
3039 *p_fam = plsc->family;
3040 *p_num = plsc->member;
3041 *p_bmax = plsc->bytemax;
3042 }
3043
3044 /* Set family file parameters */
3045
3046 void
3047 c_plsfam(PLINT fam, PLINT num, PLINT bmax)
3048 {
3049 if (plsc->level > 0)
3050 plwarn("plsfam: Must be called before plinit.");
3051
3052 if (fam >= 0)
3053 plsc->family = fam;
3054 if (num >= 0)
3055 plsc->member = num;
3056 if (bmax >= 0)
3057 plsc->bytemax = bmax;
3058 }
3059
3060 /* Advance to the next family file on the next new page */
3061
3062 void
3063 c_plfamadv(void)
3064 {
3065 plsc->famadv = 1;
3066 }
3067
3068 /*--------------------------------------------------------------------------*\
3069 * Interface routines for axis labling parameters.
3070 * See pldtik.c for more info.
3071 \*--------------------------------------------------------------------------*/
3072
3073 /* Get x axis labeling parameters */
3074
3075 void
3076 c_plgxax(PLINT *p_digmax, PLINT *p_digits)
3077 {
3078 *p_digmax = plsc->xdigmax;
3079 *p_digits = plsc->xdigits;
3080 }
3081
3082 /* Set x axis labeling parameters */
3083
3084 void
3085 c_plsxax(PLINT digmax, PLINT digits)
3086 {
3087 plsc->xdigmax = digmax;
3088 plsc->xdigits = digits;
3089 }
3090
3091 /* Get y axis labeling parameters */
3092
3093 void
3094 c_plgyax(PLINT *p_digmax, PLINT *p_digits)
3095 {
3096 *p_digmax = plsc->ydigmax;
3097 *p_digits = plsc->ydigits;
3098 }
3099
3100 /* Set y axis labeling parameters */
3101
3102 void
3103 c_plsyax(PLINT digmax, PLINT digits)
3104 {
3105 plsc->ydigmax = digmax;
3106 plsc->ydigits = digits;
3107 }
3108
3109 /* Get z axis labeling parameters */
3110
3111 void
3112 c_plgzax(PLINT *p_digmax, PLINT *p_digits)
3113 {
3114 *p_digmax = plsc->zdigmax;
3115 *p_digits = plsc->zdigits;
3116 }
3117
3118 /* Set z axis labeling parameters */
3119
3120 void
3121 c_plszax(PLINT digmax, PLINT digits)
3122 {
3123 plsc->zdigmax = digmax;
3124 plsc->zdigits = digits;
3125 }
3126
3127 /* Get character default height and current (scaled) height */
3128
3129 void
3130 c_plgchr(PLFLT *p_def, PLFLT *p_ht)
3131 {
3132 *p_def = plsc->chrdef;
3133 *p_ht = plsc->chrht;
3134 }
3135
3136 /* Get viewport boundaries in normalized device coordinates */
3137
3138 void
3139 c_plgvpd(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
3140 {
3141 *p_xmin = plsc->vpdxmi;
3142 *p_xmax = plsc->vpdxma;
3143 *p_ymin = plsc->vpdymi;
3144 *p_ymax = plsc->vpdyma;
3145 }
3146
3147 /* Get viewport boundaries in world coordinates */
3148
3149 void
3150 c_plgvpw(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
3151 {
3152 *p_xmin = plsc->vpwxmi;
3153 *p_xmax = plsc->vpwxma;
3154 *p_ymin = plsc->vpwymi;
3155 *p_ymax = plsc->vpwyma;
3156 }
3157
3158 /*--------------------------------------------------------------------------*\
3159 * These should not be called by the user.
3160 \*--------------------------------------------------------------------------*/
3161
3162 /* Get x-y domain in world coordinates for 3d plots */
3163
3164 void
3165 plP_gdom(PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax)
3166 {
3167 *p_xmin = plsc->domxmi;
3168 *p_xmax = plsc->domxma;
3169 *p_ymin = plsc->domymi;
3170 *p_ymax = plsc->domyma;
3171 }
3172
3173 /* Get vertical (z) scale parameters for 3-d plot */
3174
3175 void
3176 plP_grange(PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax)
3177 {
3178 *p_zscl = plsc->zzscl;
3179 *p_zmin = plsc->ranmi;
3180 *p_zmax = plsc->ranma;
3181 }
3182
3183 /* Get parameters used in 3d plots */
3184
3185 void
3186 plP_gw3wc(PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz)
3187 {
3188 *p_dxx = plsc->cxx;
3189 *p_dxy = plsc->cxy;
3190 *p_dyx = plsc->cyx;
3191 *p_dyy = plsc->cyy;
3192 *p_dyz = plsc->cyz;
3193 }
3194
3195 /* Get clip boundaries in physical coordinates */
3196
3197 void
3198 plP_gclp(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
3199 {
3200 *p_ixmin = plsc->clpxmi;
3201 *p_ixmax = plsc->clpxma;
3202 *p_iymin = plsc->clpymi;
3203 *p_iymax = plsc->clpyma;
3204 }
3205
3206 /* Set clip boundaries in physical coordinates */
3207
3208 void
3209 plP_sclp(PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax)
3210 {
3211 plsc->clpxmi = ixmin;
3212 plsc->clpxma = ixmax;
3213 plsc->clpymi = iymin;
3214 plsc->clpyma = iymax;
3215 }
3216
3217 /* Get physical device limits in physical coordinates */
3218
3219 void
3220 plP_gphy(PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax)
3221 {
3222 *p_ixmin = plsc->phyxmi;
3223 *p_ixmax = plsc->phyxma;
3224 *p_iymin = plsc->phyymi;
3225 *p_iymax = plsc->phyyma;
3226 }
3227
3228 /* Get number of subpages on physical device and current subpage */
3229
3230 void
3231 plP_gsub(PLINT *p_nx, PLINT *p_ny, PLINT *p_cs)
3232 {
3233 *p_nx = plsc->nsubx;
3234 *p_ny = plsc->nsuby;
3235 *p_cs = plsc->cursub;
3236 }
3237
3238 /* Set number of subpages on physical device and current subpage */
3239
3240 void
3241 plP_ssub(PLINT nx, PLINT ny, PLINT cs)
3242 {
3243 plsc->nsubx = nx;
3244 plsc->nsuby = ny;
3245 plsc->cursub = cs;
3246 }
3247
3248 /* Get number of pixels to a millimeter */
3249
3250 void
3251 plP_gpixmm(PLFLT *p_x, PLFLT *p_y)
3252 {
3253 *p_x = plsc->xpmm;
3254 *p_y = plsc->ypmm;
3255 }
3256
3257 /* All the drivers call this to set physical pixels/mm. */
3258
3259 void
3260 plP_setpxl(PLFLT xpmm, PLFLT ypmm)
3261 {
3262 plsc->xpmm = xpmm;
3263 plsc->ypmm = ypmm;
3264 plsc->umx = 1000.0 / plsc->xpmm;
3265 plsc->umy = 1000.0 / plsc->ypmm;
3266 }
3267
3268 /* Sets up physical limits of plotting device. */
3269
3270 void
3271 plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
3272 {
3273 if (xmin > xmax || ymin > ymax)
3274 plexit("plP_setphy: device minima must not exceed maxima");
3275
3276 plsc->phyxmi = xmin;
3277 plsc->phyxma = xmax;
3278 plsc->phyymi = ymin;
3279 plsc->phyyma = ymax;
3280 plsc->phyxlen = xmax - xmin;
3281 plsc->phyylen = ymax - ymin;
3282 }
3283
3284 /*--------------------------------------------------------------------------*\
3285 * void c_plscompression()
3286 *
3287 * Set compression.
3288 * Has to be done before plinit.
3289 \*--------------------------------------------------------------------------*/
3290
3291 void
3292 c_plscompression(PLINT compression)
3293 {
3294 if (plsc->level <= 0)
3295 {
3296 plsc->dev_compression=compression;
3297 }
3298 }
3299
3300 /*--------------------------------------------------------------------------*\
3301 * void c_plgcompression()
3302 *
3303 * Get compression
3304 \*--------------------------------------------------------------------------*/
3305
3306 void
3307 c_plgcompression(PLINT *compression)
3308 {
3309 *compression = plsc->dev_compression;
3310 }
3311
3312
3313 /*--------------------------------------------------------------------------*\
3314 * void plP_getinitdriverlist()
3315 *
3316 * Check to see if a driver/stream has been initialised
3317 * Returns a space separated list of matches streams/drivers
3318 * If more than one stream uses the same device, then the device name
3319 * will be returned for each stream.
3320 * Caller must allocate enough memory for "names" to hold the answer.
3321 \*--------------------------------------------------------------------------*/
3322
3323 void
3324 plP_getinitdriverlist(char *names)
3325 {
3326 int i;
3327
3328 for (i=0;i<PL_NSTREAMS;++i)
3329 {
3330 if (pls[i]!=NULL)
3331 {
3332 if (i==0)
3333 strcpy(names,pls[i]->DevName);
3334 else
3335 {
3336 strcat(names," ");
3337 strcat(names,pls[i]->DevName);
3338 }
3339 }
3340 else
3341 break;
3342 }
3343 }
3344
3345
3346 /*--------------------------------------------------------------------------*\
3347 * PLINT plP_checkdriverinit()
3348 *
3349 * Checks from a list of given drivers which ones have been initialised
3350 * and returns the number of devices matching the list, or -1 if in error.
3351 * Effectively returns the number of streams matching the given stream.
3352 \*--------------------------------------------------------------------------*/
3353
3354 PLINT plP_checkdriverinit( char *names)
3355 {
3356 char *buff;
3357 char *tok=NULL;
3358 PLINT ret=0; /* set up return code to 0, the value if no devices match*/
3359
3360 buff=(char *)malloc((size_t) PL_NSTREAMS*8); /* Allocate enough memory for 8
3361 characters for each possible stream */
3362
3363 if (buff!=NULL)
3364 {
3365 memset(buff,0,PL_NSTREAMS*8); /* Make sure we clear it */
3366 plP_getinitdriverlist(buff); /* Get the list of initialised devices */
3367
3368 for (tok = strtok(buff, " ,"); /* Check each device against the "name" */
3369 tok; tok=strtok(0, " ,")) /* supplied to the subroutine */
3370 {
3371 if (strstr(names,tok)!=NULL) /* Check to see if the device has been initialised */
3372 {
3373 ret++; /* Bump the return code if it has */
3374 }
3375 }
3376 free(buff); /* Clear up that memory we allocated */
3377 }
3378 else
3379 ret=-1; /* Error flag */
3380
3381 return(ret);
3382 }
3383
3384
3385 /*--------------------------------------------------------------------------*\
3386 * plP_image
3387 *
3388 * Author: Alessandro Mirone, Nov 2001
3389 *
3390 *
3391 *
3392 \*--------------------------------------------------------------------------*/
3393
3394 void
3395 plP_image(short *x, short *y, unsigned short *z , PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT dy, unsigned short zmin, unsigned short zmax)
3396 {
3397 PLINT i, npts;
3398 short *myxscl, *myyscl;
3399 int plbuf_write;
3400
3401 plsc->page_status = DRAWING;
3402
3403 if (plsc->dev_fastimg == 0) {
3404 plimageslow(x, y, z, nx-1, ny-1,
3405 xmin, ymin, dx, dy, zmin, zmax);
3406 return ;
3407 }
3408
3409 if (plsc->plbuf_write) {
3410 IMG_DT img_dt;
3411
3412 img_dt.xmin=xmin;
3413 img_dt.ymin=ymin;
3414 img_dt.dx=dx;
3415 img_dt.dy=dy;
3416
3417 plsc->dev_ix = x;
3418 plsc->dev_iy = y;
3419 plsc->dev_z = z;
3420 plsc->dev_nptsX = nx;
3421 plsc->dev_nptsY = ny;
3422 plsc->dev_zmin = zmin;
3423 plsc->dev_zmax = zmax;
3424
3425 plbuf_esc(plsc, PLESC_IMAGE, &img_dt);
3426 }
3427
3428 /* avoid re-saving plot buffer while in plP_esc() */
3429 plbuf_write = plsc->plbuf_write;
3430 plsc->plbuf_write = 0;
3431
3432 npts = nx*ny;
3433 if (plsc->difilt) { /* isn't this odd? when replaying the plot buffer, e.g., when resizing the window, difilt() is caled again! the plot buffer should already contain the transformed data--it would save a lot of time! (and allow for differently oriented plots when in multiplot mode) */
3434 PLINT clpxmi, clpxma, clpymi, clpyma;
3435
3436 myxscl = (short *) malloc(nx*ny*sizeof(short));
3437 myyscl = (short *) malloc(nx*ny*sizeof(short));
3438 for (i = 0; i < npts; i++) {
3439 myxscl[i] = x[i];
3440 myyscl[i] = y[i];
3441 }
3442 sdifilt(myxscl, myyscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
3443 plsc->imclxmin = clpxmi;
3444 plsc->imclymin = clpymi;
3445 plsc->imclxmax = clpxma;
3446 plsc->imclymax = clpyma;
3447 grimage(myxscl, myyscl, z, nx, ny);
3448 free(myxscl);
3449 free(myyscl);
3450 } else {
3451 plsc->imclxmin = plsc->phyxmi;
3452 plsc->imclymin = plsc->phyymi;
3453 plsc->imclxmax = plsc->phyxma;
3454 plsc->imclymax = plsc->phyyma;
3455 grimage(x, y, z, nx, ny );
3456 }
3457 plsc->plbuf_write = plbuf_write;
3458 }
3459