PLplot: plcore.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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