/branches/mjl_fork_1/src/plcore.c
C | 2312 lines | 1360 code | 400 blank | 552 comment | 282 complexity | 6975587107950c6b97c6a3899daff82b MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /* $Id: plcore.c 6212 2005-04-27 06:44:27Z rlaboiss $
- Central dispatch facility for PLplot.
- Also contains the PLplot main data structures, external access
- routines, and initialization calls.
- This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
- Copyright (C) 2004 Joao Cardoso
- Copyright (C) 2004, 2005 Rafael Laboissiere
- Copyright (C) 2004 Andrew Ross
- Copyright (C) 2004 Andrew Roach
- Copyright (C) 2005 Alan W. Irwin
- Copyright (C) 2005 Thomas J. Duck
- This file is part of PLplot.
- PLplot is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Library Public License as published
- by the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- PLplot is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
- You should have received a copy of the GNU Library General Public License
- along with PLplot; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #define DEBUG
- #define NEED_PLDEBUG
- #include "plcore.h"
- #ifdef ENABLE_DYNDRIVERS
- #include <ltdl.h>
- #endif
- /*--------------------------------------------------------------------------*\
- * Driver Interface
- *
- * These routines are the low-level interface to the driver -- all calls to
- * driver functions must pass through here. For implementing driver-
- * specific functions, the escape function is provided. The command stream
- * gets duplicated to the plot buffer here.
- *
- * All functions that result in graphics actually being plotted (rather than
- * just a change of state) are filtered as necessary before being passed on.
- * The default settings do not require any filtering, i.e. PLplot physical
- * coordinates are the same as the device physical coordinates (currently
- * this can't be changed anyway), and a global view equal to the entire page
- * is used.
- *
- * The reason one wants to put view-specific filtering here is that if
- * enabled, the plot buffer should receive the unfiltered data stream. This
- * allows a specific view to be used from an interactive device (e.g. TCL/TK
- * driver) but be restored to the full view at any time merely by
- * reprocessing the contents of the plot buffer.
- *
- * The metafile, on the other hand, *should* be affected by changes in the
- * view, since this is a crucial editing capability. It is recommended that
- * the initial metafile be created without a restricted global view, and
- * modification of the view done on a per-plot basis as desired during
- * subsequent processing.
- *
- \*--------------------------------------------------------------------------*/
- enum {AT_BOP, DRAWING, AT_EOP};
- /* Initialize device. */
- /* The plot buffer must be called last. */
- /* The following array of chars is used both here and in plsym.c for
- * translating the Greek characters from the #g escape sequences into
- * the Hershey and Unicode codings
- */
- const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
- void
- plP_init(void)
- {
- plsc->page_status = AT_EOP;
- (*plsc->dispatch_table->pl_init) ((struct PLStream_struct *) plsc);
- if (plsc->plbuf_write)
- plbuf_init(plsc);
- }
- /* End of page */
- /* The plot buffer must be called first. */
- /* Ignore instruction if already at eop. */
- void
- plP_eop(void)
- {
- int skip_driver_eop = 0;
- if (plsc->page_status == AT_EOP)
- return;
- plsc->page_status = AT_EOP;
- if (plsc->plbuf_write)
- plbuf_eop(plsc);
- /* Call user eop handler if present. */
- if (plsc->eop_handler != NULL)
- (*plsc->eop_handler) (plsc->eop_data, &skip_driver_eop);
- if (!skip_driver_eop)
- (*plsc->dispatch_table->pl_eop) ((struct PLStream_struct *) plsc);
- }
- /* Set up new page. */
- /* The plot buffer must be called last. */
- /* Ignore if already at bop. */
- /* It's not actually necessary to be AT_EOP here, so don't check for it. */
- void
- plP_bop(void)
- {
- int skip_driver_bop = 0;
- plP_subpInit();
- if (plsc->page_status == AT_BOP)
- return;
- plsc->page_status = AT_BOP;
- plsc->nplwin = 0;
- /* Call user bop handler if present. */
- if (plsc->bop_handler != NULL)
- (*plsc->bop_handler) (plsc->bop_data, &skip_driver_bop);
- if (!skip_driver_bop)
- (*plsc->dispatch_table->pl_bop) ((struct PLStream_struct *) plsc);
- if (plsc->plbuf_write)
- plbuf_bop(plsc);
- }
- /* Tidy up device (flush buffers, close file, etc). */
- void
- plP_tidy(void)
- {
- if (plsc->tidy) {
- (*plsc->tidy) (plsc->tidy_data);
- plsc->tidy = NULL;
- plsc->tidy_data = NULL;
- }
- (*plsc->dispatch_table->pl_tidy) ((struct PLStream_struct *) plsc);
- if (plsc->plbuf_write)
- plbuf_tidy(plsc);
- plsc->OutFile = NULL;
- }
- /* Change state. */
- void
- plP_state(PLINT op)
- {
- (*plsc->dispatch_table->pl_state) ((struct PLStream_struct *) plsc, op);
- if (plsc->plbuf_write)
- plbuf_state(plsc, op);
- }
- /* Escape function, for driver-specific commands. */
- void
- plP_esc(PLINT op, void *ptr)
- {
- (*plsc->dispatch_table->pl_esc) ((struct PLStream_struct *) plsc, op, ptr);
- if (plsc->plbuf_write)
- plbuf_esc(plsc, op, ptr);
- }
- /* Set up plot window parameters. */
- /* The plot buffer must be called first */
- /* Some drivers (metafile, Tk) need access to this data */
- void
- plP_swin(PLWindow *plwin)
- {
- PLWindow *w;
- PLINT clpxmi, clpxma, clpymi, clpyma;
- /* Provide plot buffer with unfiltered window data */
- if (plsc->plbuf_write)
- plbuf_esc(plsc, PLESC_SWIN, (void *) plwin);
- w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
- w->dxmi = plwin->dxmi;
- w->dxma = plwin->dxma;
- w->dymi = plwin->dymi;
- w->dyma = plwin->dyma;
- if (plsc->difilt) {
- xscl[0] = plP_dcpcx(w->dxmi);
- xscl[1] = plP_dcpcx(w->dxma);
- yscl[0] = plP_dcpcy(w->dymi);
- yscl[1] = plP_dcpcy(w->dyma);
- difilt(xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma);
- w->dxmi = plP_pcdcx(xscl[0]);
- w->dxma = plP_pcdcx(xscl[1]);
- w->dymi = plP_pcdcy(yscl[0]);
- w->dyma = plP_pcdcy(yscl[1]);
- }
- w->wxmi = plwin->wxmi;
- w->wxma = plwin->wxma;
- w->wymi = plwin->wymi;
- w->wyma = plwin->wyma;
- /* If the driver wants to process swin commands, call it now */
- /* It must use the filtered data, which it can get from *plsc */
- if (plsc->dev_swin) {
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_SWIN, NULL );
- }
- }
- /*--------------------------------------------------------------------------*\
- * Drawing commands.
- \*--------------------------------------------------------------------------*/
- /* Draw line between two points */
- /* The plot buffer must be called first so it gets the unfiltered data */
- void
- plP_line(short *x, short *y)
- {
- PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
- plsc->page_status = DRAWING;
- if (plsc->plbuf_write)
- plbuf_line(plsc, x[0], y[0], x[1], y[1]);
- if (plsc->difilt) {
- for (i = 0; i < npts; i++) {
- xscl[i] = x[i];
- yscl[i] = y[i];
- }
- difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
- plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
- }
- else {
- grline(x, y, npts);
- }
- }
- /* Draw polyline */
- /* The plot buffer must be called first */
- void
- plP_polyline(short *x, short *y, PLINT npts)
- {
- PLINT i, clpxmi, clpxma, clpymi, clpyma;
- plsc->page_status = DRAWING;
- if (plsc->plbuf_write)
- plbuf_polyline(plsc, x, y, npts);
- if (plsc->difilt) {
- for (i = 0; i < npts; i++) {
- xscl[i] = x[i];
- yscl[i] = y[i];
- }
- difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
- plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
- grpolyline);
- }
- else {
- grpolyline(x, y, npts);
- }
- }
- /* Fill polygon */
- /* The plot buffer must be called first */
- /* Here if the desired area fill capability isn't present, we mock up */
- /* something in software */
- static int foo;
- void
- plP_fill(short *x, short *y, PLINT npts)
- {
- PLINT i, clpxmi, clpxma, clpymi, clpyma;
- plsc->page_status = DRAWING;
- if (plsc->plbuf_write) {
- plsc->dev_npts = npts;
- plsc->dev_x = x;
- plsc->dev_y = y;
- plbuf_esc(plsc, PLESC_FILL, NULL);
- }
- /* Account for driver ability to do fills */
- if (plsc->patt == 0 && ! plsc->dev_fill0) {
- if ( ! foo) {
- plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
- foo = 1;
- }
- plsc->patt = 8;
- plpsty(plsc->patt);
- }
- if (plsc->dev_fill1) {
- plsc->patt = -ABS(plsc->patt);
- }
- /* Perform fill. Here we MUST NOT allow the software fill to pass through the
- driver interface filtering twice, else we get the infamous 2*rotation for
- software fills on orientation swaps.
- */
- if (plsc->patt > 0)
- plfill_soft(x, y, npts);
- else {
- if (plsc->difilt) {
- for (i = 0; i < npts; i++) {
- xscl[i] = x[i];
- yscl[i] = y[i];
- }
- difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
- plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
- grfill);
- }
- else {
- grfill(x, y, npts);
- }
- }
- }
- /* Account for driver ability to draw text itself */
- /*
- #define DEBUG_TEXT
- */
- #define hex2dec( a ) isdigit(a) ? a - 48 : (toupper(a) - 65) + 10
- /*--------------------------------------------------------------------------*\
- * int text2num( char *text, char end, PLUNICODE *num)
- * char *text - pointer to the text to be parsed
- * char end - end character (i.e. ')' or ']' to stop parsing
- * PLUNICODE *num - pointer to an PLUNICODE to store the value
- *
- * Function takes a string, which can be either hex or decimal,
- * and converts it into an PLUNICODE, stopping at either a null,
- * or the character pointed to by 'end'. It is a bit brain-dead,
- * and probably should make more checks, but it works.
- \*--------------------------------------------------------------------------*/
- int text2num( const char *text, char end, PLUNICODE *num)
- {
- int base=10;
- unsigned short i=0;
- *num=0;
- if (text[1]=='x')
- {
- base=16;
- i=2;
- }
- while ((text[i]!=end)&&(text[i]!=0))
- {
- *num*=base;
- *num+=hex2dec(text[i]);
- i++;
- }
- return(i);
- }
- /*--------------------------------------------------------------------------*\
- * int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
- * char *text - pointer to the text to be parsed
- * unsigned char *hexdigit - pointer to hex value that is stored.
- * unsigned char *hexpower - pointer to hex power (left shift) that is stored.
- *
- * Function takes a pointer to a string, which is looked up in a table
- * to determine the corresponding FCI (font characterization integer)
- * hex digit value and hex power (left shift).
- * If the lookup succeeds, hexdigit and hexpower are set to the appropriate
- * values in the table, and the function returns the number of characters
- * in text that are consumed by the matching string in the table lookup.
- *
- * If the lookup fails, hexdigit is set to 0, hexpower is set to and
- * impossible value, and the function returns 0.
- \*--------------------------------------------------------------------------*/
- int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower)
- {
- typedef struct
- {
- char *ptext;
- unsigned char hexdigit;
- unsigned char hexpower;
- }
- TextLookupTable;
- /* This defines the various font control commands and the corresponding
- * hexdigit and hexpower in the FCI.
- */
- #define N_TextLookupTable 10
- const TextLookupTable lookup[N_TextLookupTable] = {
- {"<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY},
- {"<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY},
- {"<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY},
- {"<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY},
- {"<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY},
- {"<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE},
- {"<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE},
- {"<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE},
- {"<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT},
- {"<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT}
- };
- int i, length;
- for (i=0; i<N_TextLookupTable; i++) {
- length = strlen(lookup[i].ptext);
- if (! strncmp(text, lookup[i].ptext, length)) {
- *hexdigit = lookup[i].hexdigit;
- *hexpower = lookup[i].hexpower;
- return(length);
- }
- }
- *hexdigit = 0;
- *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
- return(0);
- }
- PLUNICODE unicode_buffer[1024];
- void
- plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
- PLINT refx, PLINT refy, const char *string)
- {
- if (plsc->dev_text) { /* Does the device render it's own text ? */
- EscText args;
- short len=0;
- char skip;
- unsigned short i,j, k;
- PLUNICODE code;
- char esc;
- int idx;
- args.base = base;
- args.just = just;
- args.xform = xform;
- args.x = x;
- args.y = y;
- args.refx = refx;
- args.refy = refy;
- if (plsc->dev_unicode) { /* Does the device also understand unicode ? */
- PLINT ig;
- PLUNICODE fci, fcisave;
- unsigned char hexdigit, hexpower;
- if (string!=NULL) { /* If the string isn't blank, then we will continue */
- len=strlen(string); /* this length is only used in the loop counter, we will work out the length of the unicode string as we go */
- plgesc(&esc);
-
- /* At this stage we will do some translations into unicode, like conversion to
- * Greek , and will save other translations such as superscript for the driver to
- * do later on. As we move through the string and do the translations, we will get
- * rid of the esc character sequence, just replacing it with unicode.
- */
-
- /* Obtain FCI (font characterization integer) for start of string. */
- plgfci(&fci);
- for (j=i=0;i<len;i++) { /* Walk through the strings, and convert some stuff to unicode on the fly */
- skip=0;
-
- if (string[i]==esc) {
- switch(string[i+1]) {
- case '(': /* hershey code */
- i+=2+text2num(&string[i+2],')',&code);
- idx=plhershey2unicode(code);
- /* momentarily switch to symbol font. */
- fcisave = fci;
- plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
- unicode_buffer[j++]= fci;
- unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
- /* if unicode_buffer[j-1] corresponds to the escape character
- * must unescape it by appending one more. This will probably
- * always be necessary since it is likely unicode_buffer
- * will always have to contain escape characters that are
- * interpreted by the device driver.
- */
- if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
- fci = fcisave;
- unicode_buffer[j]= fci;
- skip=1;
- break;
-
- case '[': /* unicode */
- i+=2+text2num(&string[i+2],']',&code);
- /* momentarily switch to symbol font. */
- fcisave = fci;
- plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
- unicode_buffer[j++]= fci;
- unicode_buffer[j++]=code;
- /* if unicode_buffer[j-1] corresponds to the escape character
- * must unescape it by appending one more. This will probably
- * always be necessary since it is likely unicode_buffer
- * will always have to contain escape characters that are
- * interpreted by the device driver.
- */
- if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
- fci = fcisave;
- unicode_buffer[j] = fci;
- skip=1;
- break;
-
- case '<': /* change font*/
- i+=2;
- if ('0' <= string[i] && string[i] <= '9' ) {
- i+=text2num(&string[i],'>', &code);
- if (code & PL_FCI_MARK) {
- /* code is a complete FCI (font characterization
- * integer): change FCI to this value.
- */
- fci = code;
- unicode_buffer[j]=fci;
- skip=1;
- }
- else {
- /* code is not complete FCI. Change
- * FCI with hex power in rightmost hex
- * digit and hex digit value in second rightmost
- * hex digit.
- */
- hexdigit = (code >> 4) & PL_FCI_HEXDIGIT_MASK;
- hexpower = code & PL_FCI_HEXPOWER_MASK;
- plP_hex2fci(hexdigit, hexpower, &fci);
- unicode_buffer[j]=fci;
- skip=1;
- }
- }
-
- else {
- /* align i on "<" because that is what text2fci
- * expects. */
- i--;
- i+=text2fci(&string[i], &hexdigit, &hexpower);
- if (hexpower < 7) {
- plP_hex2fci(hexdigit, hexpower, &fci);
- unicode_buffer[j]=fci;
- skip=1;
- }
- }
- break;
-
- case 'f': /* Deprecated Hershey-style font change*/
- case 'F': /* Deprecated Hershey-style font change*/
- /* We implement an approximate response here so that reasonable
- * results are obtained for unicode fonts, but this
- * method is deprecated and the #<nnn> or
- * #<command string> methods should be used instead
- * to change unicode fonts in mid-string.
- */
- fci = PL_FCI_MARK;
- if (string[i+2] == 'n') {
- /* medium, upright, sans-serif */
- plP_hex2fci(PL_FCI_SANS, PL_FCI_FAMILY, &fci);
- } else if (string[i+2] == 'r') {
- /* medium, upright, serif */
- plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
- } else if (string[i+2] == 'i') {
- /* medium, italic, serif */
- plP_hex2fci(PL_FCI_ITALIC, PL_FCI_STYLE, &fci);
- plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
- } else if (string[i+2] == 's') {
- /* medium, upright, script */
- plP_hex2fci(PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci);
- } else
- fci = PL_FCI_IMPOSSIBLE;
-
- if (fci != PL_FCI_IMPOSSIBLE){
- i+=2;
- unicode_buffer[j] = fci;
- skip = 1;
- }
- break;
-
- case 'g': /* Greek font */
- case 'G': /* Greek font */
- /* Get the index in the lookup table
- * 527 = upper case alpha displacement in Hershey Table
- * 627 = lower case alpha displacement in Hershey Table
- */
- /* momentarily switch to symbol font. */
- fcisave = fci;
- plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
- unicode_buffer[j++]= fci;
- ig = plP_strpos(plP_greek_mnemonic, string[i+2]);
- if (ig >= 0) {
- if (ig >= 24)
- ig = ig + 100 - 24;
- idx=plhershey2unicode(ig+527);
- unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
- i+=2;
- skip=1; /* skip is set if we have copied something into the unicode table */
- }
- else {
- /* Use "unknown" unicode character if string[i+2] is not in
- * the Greek array.*/
- unicode_buffer[j++]=(PLUNICODE)0x00;
- i+=2;
- skip=1; /* skip is set if we have copied something into the unicode table */
- }
- fci = fcisave;
- unicode_buffer[j]= fci;
- break;
-
- }
- }
-
- if (skip==0) {
- #ifdef HAVE_LIBUNICODE
- unicode_char_t unichar;
- char* ptr =
- unicode_get_utf8 (string + i, &unichar);
- if (ptr == NULL) {
- char buf[80];
- strncpy (buf, string, 30);
- sprintf (buf, "UTF-8 string is malformed: %s%s",
- buf, strlen (string) > 30 ? "[...]" : "");
- plabort (buf);
- }
- unicode_buffer [j] = (PLUNICODE) unichar;
- i += ptr - (string + i) - 1;
- #else
- unicode_buffer[j]=string[i];
- #endif
- /* Search for escesc (an unescaped escape) in the input string
- * and adjust unicode_buffer accordingly).
- */
- if (unicode_buffer[j] == esc && string[i+1] == esc) {
- i++;
- unicode_buffer[++j] = esc;
- }
- }
- j++;
- }
- if (j > 0) {
- args.unicode_array_len=j; /* Much easier to set the length than work it out later :-) */
- args.unicode_array=&unicode_buffer[0]; /* Get address of the unicode buffer (even though it is currently static) */
- args.string=NULL; /* Since we are using unicode, we want this to be NULL */
- } else
- /* Don't print anything, if there is no unicode to print! */
- return;
- }
- } else {
- args.string = string;
- }
- if (plsc->plbuf_write)
- plbuf_esc(plsc, PLESC_HAS_TEXT, &args);
- plP_esc(PLESC_HAS_TEXT, &args);
- #ifndef DEBUG_TEXT
- } else {
- #endif
- plstr(base, xform, refx, refy, string);
- }
- }
- static void
- grline(short *x, short *y, PLINT npts)
- {
- (*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
- x[0], y[0], x[1], y[1] );
- }
- static void
- grpolyline(short *x, short *y, PLINT npts)
- {
- (*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
- x, y, npts );
- }
- static void
- grfill(short *x, short *y, PLINT npts)
- {
- plsc->dev_npts = npts;
- plsc->dev_x = x;
- plsc->dev_y = y;
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_FILL, NULL );
- }
- /*--------------------------------------------------------------------------*\
- * void difilt
- *
- * Driver interface filter -- passes all coordinates through a variety
- * of filters. These include filters to change :
- *
- * - mapping of meta to physical coordinates
- * - plot orientation
- * - window into plot (zooms)
- * - window into device (i.e set margins)
- *
- * The filters are applied in the order specified above. Because the
- * orientation change comes first, subsequent window specifications affect
- * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
- * This is the only way that makes sense from a graphical interface
- * (e.g. TCL/TK driver).
- *
- * Where appropriate, the page clip limits are modified.
- \*--------------------------------------------------------------------------*/
- void
- difilt(PLINT *xscl, PLINT *yscl, PLINT npts,
- PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
- {
- PLINT i, x, y;
- /* Map meta coordinates to physical coordinates */
- if (plsc->difilt & PLDI_MAP) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
- yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
- }
- }
- /* Change orientation */
- if (plsc->difilt & PLDI_ORI) {
- for (i = 0; i < npts; i++) {
- x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
- y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
- xscl[i] = x;
- yscl[i] = y;
- }
- }
- /* Change window into plot space */
- if (plsc->difilt & PLDI_PLT) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
- yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
- }
- }
- /* Change window into device space and set clip limits */
- /* (this is the only filter that modifies them) */
- if (plsc->difilt & PLDI_DEV) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
- yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
- }
- *clpxmi = plsc->diclpxmi;
- *clpxma = plsc->diclpxma;
- *clpymi = plsc->diclpymi;
- *clpyma = plsc->diclpyma;
- }
- else {
- *clpxmi = plsc->phyxmi;
- *clpxma = plsc->phyxma;
- *clpymi = plsc->phyymi;
- *clpyma = plsc->phyyma;
- }
- }
- void
- sdifilt(short *xscl, short *yscl, PLINT npts,
- PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
- {
- int i;
- short x, y;
- /* Map meta coordinates to physical coordinates */
- if (plsc->difilt & PLDI_MAP) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
- yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
- }
- }
- /* Change orientation */
- if (plsc->difilt & PLDI_ORI) {
- for (i = 0; i < npts; i++) {
- x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
- y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
- xscl[i] = x;
- yscl[i] = y;
- }
- }
- /* Change window into plot space */
- if (plsc->difilt & PLDI_PLT) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
- yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
- }
- }
- /* Change window into device space and set clip limits */
- /* (this is the only filter that modifies them) */
- if (plsc->difilt & PLDI_DEV) {
- for (i = 0; i < npts; i++) {
- xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
- yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
- }
- *clpxmi = plsc->diclpxmi;
- *clpxma = plsc->diclpxma;
- *clpymi = plsc->diclpymi;
- *clpyma = plsc->diclpyma;
- }
- else {
- *clpxmi = plsc->phyxmi;
- *clpxma = plsc->phyxma;
- *clpymi = plsc->phyymi;
- *clpyma = plsc->phyyma;
- }
- }
- /*--------------------------------------------------------------------------*\
- * void pldi_ini
- *
- * Updates driver interface, making sure everything is in order.
- * Even if filter is not being used, the defaults need to be set up.
- \*--------------------------------------------------------------------------*/
- static void
- setdef_diplt()
- {
- plsc->dipxmin = 0.0;
- plsc->dipxmax = 1.0;
- plsc->dipymin = 0.0;
- plsc->dipymax = 1.0;
- }
- static void
- setdef_didev()
- {
- plsc->mar = 0.0;
- plsc->aspect = 0.0;
- plsc->jx = 0.0;
- plsc->jy = 0.0;
- }
- static void
- setdef_diori()
- {
- plsc->diorot = 0.;
- }
- static void
- pldi_ini(void)
- {
- if (plsc->level >= 1) {
- if (plsc->difilt & PLDI_MAP) /* Coordinate mapping */
- calc_dimap();
- if (plsc->difilt & PLDI_ORI) /* Orientation */
- calc_diori();
- else
- setdef_diori();
- if (plsc->difilt & PLDI_PLT) /* Plot window */
- calc_diplt();
- else
- setdef_diplt();
- if (plsc->difilt & PLDI_DEV) /* Device window */
- calc_didev();
- else
- setdef_didev();
- }
- }
- /*--------------------------------------------------------------------------*\
- * void pldid2pc
- *
- * Converts input values from relative device coordinates to relative plot
- * coordinates. This function must be called when selecting a plot window
- * from a display driver, since the coordinates chosen by the user are
- * necessarily device-specific.
- \*--------------------------------------------------------------------------*/
- void
- pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
- {
- PLFLT pxmin, pymin, pxmax, pymax;
- PLFLT sxmin, symin, sxmax, symax;
- PLFLT rxmin, rymin, rxmax, rymax;
- if (plsc->difilt & PLDI_DEV) {
- pldebug("pldid2pc",
- "Relative device coordinates (in): %f, %f, %f, %f\n",
- *xmin, *ymin, *xmax, *ymax);
- pxmin = plP_dcpcx(*xmin);
- pymin = plP_dcpcy(*ymin);
- pxmax = plP_dcpcx(*xmax);
- pymax = plP_dcpcy(*ymax);
- sxmin = (pxmin - plsc->didxb) / plsc->didxax;
- symin = (pymin - plsc->didyb) / plsc->didyay;
- sxmax = (pxmax - plsc->didxb) / plsc->didxax;
- symax = (pymax - plsc->didyb) / plsc->didyay;
- rxmin = plP_pcdcx(sxmin);
- rymin = plP_pcdcy(symin);
- rxmax = plP_pcdcx(sxmax);
- rymax = plP_pcdcy(symax);
- *xmin = (rxmin < 0) ? 0 : rxmin;
- *xmax = (rxmax > 1) ? 1 : rxmax;
- *ymin = (rymin < 0) ? 0 : rymin;
- *ymax = (rymax > 1) ? 1 : rymax;
- pldebug("pldid2pc",
- "Relative plot coordinates (out): %f, %f, %f, %f\n",
- rxmin, rymin, rxmax, rymax);
- }
- }
- /*--------------------------------------------------------------------------*\
- * void pldip2dc
- *
- * Converts input values from relative plot coordinates to relative
- * device coordinates.
- \*--------------------------------------------------------------------------*/
- void
- pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
- {
- PLFLT pxmin, pymin, pxmax, pymax;
- PLFLT sxmin, symin, sxmax, symax;
- PLFLT rxmin, rymin, rxmax, rymax;
- if (plsc->difilt & PLDI_DEV) {
- pldebug("pldip2pc",
- "Relative plot coordinates (in): %f, %f, %f, %f\n",
- *xmin, *ymin, *xmax, *ymax);
- pxmin = plP_dcpcx(*xmin);
- pymin = plP_dcpcy(*ymin);
- pxmax = plP_dcpcx(*xmax);
- pymax = plP_dcpcy(*ymax);
- sxmin = pxmin * plsc->didxax + plsc->didxb;
- symin = pymin * plsc->didyay + plsc->didyb;
- sxmax = pxmax * plsc->didxax + plsc->didxb;
- symax = pymax * plsc->didyay + plsc->didyb;
- rxmin = plP_pcdcx(sxmin);
- rymin = plP_pcdcy(symin);
- rxmax = plP_pcdcx(sxmax);
- rymax = plP_pcdcy(symax);
- *xmin = (rxmin < 0) ? 0 : rxmin;
- *xmax = (rxmax > 1) ? 1 : rxmax;
- *ymin = (rymin < 0) ? 0 : rymin;
- *ymax = (rymax > 1) ? 1 : rymax;
- pldebug("pldip2pc",
- "Relative device coordinates (out): %f, %f, %f, %f\n",
- rxmin, rymin, rxmax, rymax);
- }
- }
- /*--------------------------------------------------------------------------*\
- * void plsdiplt
- *
- * Set window into plot space
- \*--------------------------------------------------------------------------*/
- void
- c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
- {
- plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
- plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
- plsc->dipymin = (ymin < ymax) ? ymin : ymax;
- plsc->dipymax = (ymin < ymax) ? ymax : ymin;
- if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.) {
- plsc->difilt &= ~PLDI_PLT;
- return;
- }
- plsc->difilt |= PLDI_PLT;
- pldi_ini();
- }
- /*--------------------------------------------------------------------------*\
- * void plsdiplz
- *
- * Set window into plot space incrementally (zoom)
- \*--------------------------------------------------------------------------*/
- void
- c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
- {
- if (plsc->difilt & PLDI_PLT) {
- xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
- ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
- xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
- ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
- }
- plsdiplt(xmin, ymin, xmax, ymax);
- }
- /*--------------------------------------------------------------------------*\
- * void calc_diplt
- *
- * Calculate transformation coefficients to set window into plot space.
- *
- * Note: if driver has requested to handle these commands itself, we must
- * send the appropriate escape command. If the driver succeeds it will
- * cancel the filter operation. The command is deferred until this point
- * to ensure that the driver has been initialized.
- \*--------------------------------------------------------------------------*/
- static void
- calc_diplt(void)
- {
- PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
- if (plsc->dev_di) {
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_DI, NULL );
- }
- if ( ! (plsc->difilt & PLDI_PLT))
- return;
- pxmin = plP_dcpcx(plsc->dipxmin);
- pxmax = plP_dcpcx(plsc->dipxmax);
- pymin = plP_dcpcy(plsc->dipymin);
- pymax = plP_dcpcy(plsc->dipymax);
- pxlen = pxmax - pxmin;
- pylen = pymax - pymin;
- pxlen = MAX(1, pxlen);
- pylen = MAX(1, pylen);
- plsc->dipxax = plsc->phyxlen / (double) pxlen;
- plsc->dipyay = plsc->phyylen / (double) pylen;
- plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
- plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
- }
- /*--------------------------------------------------------------------------*\
- * void plgdiplt
- *
- * Retrieve current window into plot space
- \*--------------------------------------------------------------------------*/
- void
- c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
- {
- *p_xmin = plsc->dipxmin;
- *p_xmax = plsc->dipxmax;
- *p_ymin = plsc->dipymin;
- *p_ymax = plsc->dipymax;
- }
- /*--------------------------------------------------------------------------*\
- * void plsdidev
- *
- * Set window into device space using margin, aspect ratio, and
- * justification. If you want to just use the previous value for any of
- * these, just pass in the magic value PL_NOTSET.
- *
- * It is unlikely that one should ever need to change the aspect ratio
- * but it's in there for completeness.
- \*--------------------------------------------------------------------------*/
- void
- c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
- {
- plsetvar(plsc->mar, mar);
- plsetvar(plsc->aspect, aspect);
- plsetvar(plsc->jx, jx);
- plsetvar(plsc->jy, jy);
- if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
- ! (plsc->difilt & PLDI_ORI)) {
- plsc->difilt &= ~PLDI_DEV;
- return;
- }
- plsc->difilt |= PLDI_DEV;
- pldi_ini();
- }
- /*--------------------------------------------------------------------------*\
- * void calc_didev
- *
- * Calculate transformation coefficients to set window into device space.
- * Calculates relative window bounds and calls plsdidxy to finish the job.
- \*--------------------------------------------------------------------------*/
- static void
- calc_didev(void)
- {
- PLFLT lx, ly, aspect, aspdev;
- PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
- PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
- if (plsc->dev_di) {
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_DI, NULL );
- }
- if ( ! (plsc->difilt & PLDI_DEV))
- return;
- /* Calculate aspect ratio of physical device */
- lx = plsc->phyxlen / plsc->xpmm;
- ly = plsc->phyylen / plsc->ypmm;
- aspdev = lx / ly;
- if (plsc->difilt & PLDI_ORI)
- aspect = plsc->aspori;
- else
- aspect = plsc->aspect;
- if (aspect <= 0.)
- aspect = plsc->aspdev;
- /* Failsafe */
- plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
- plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
- plsc->jx = (plsc->jx > 0.5) ? 0.5 : plsc->jx;
- plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
- plsc->jy = (plsc->jy > 0.5) ? 0.5 : plsc->jy;
- plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
- /* Relative device coordinates that neutralize aspect ratio difference */
- xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
- ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
- xlen *= (1.0 - 2.*plsc->mar);
- ylen *= (1.0 - 2.*plsc->mar);
- xmin = (1. - xlen) * (0.5 + plsc->jx);
- xmax = xmin + xlen;
- ymin = (1. - ylen) * (0.5 + plsc->jy);
- ymax = ymin + ylen;
- /* Calculate transformation coefficients */
- pxmin = plP_dcpcx(xmin);
- pxmax = plP_dcpcx(xmax);
- pymin = plP_dcpcy(ymin);
- pymax = plP_dcpcy(ymax);
- pxlen = pxmax - pxmin;
- pylen = pymax - pymin;
- pxlen = MAX(1, pxlen);
- pylen = MAX(1, pylen);
- plsc->didxax = pxlen / (double) plsc->phyxlen;
- plsc->didyay = pylen / (double) plsc->phyylen;
- plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
- plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
- /* Set clip limits to conform to new page size */
- plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
- plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
- plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
- plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
- }
- /*--------------------------------------------------------------------------*\
- * void plgdidev
- *
- * Retrieve current window into device space
- \*--------------------------------------------------------------------------*/
- void
- c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
- {
- *p_mar = plsc->mar;
- *p_aspect = plsc->aspect;
- *p_jx = plsc->jx;
- *p_jy = plsc->jy;
- }
- /*--------------------------------------------------------------------------*\
- * void plsdiori
- *
- * Set plot orientation, specifying rotation in units of pi/2.
- \*--------------------------------------------------------------------------*/
- void
- c_plsdiori(PLFLT rot)
- {
- plsc->diorot = rot;
- if (rot == 0.) {
- plsc->difilt &= ~PLDI_ORI;
- pldi_ini();
- return;
- }
- plsc->difilt |= PLDI_ORI;
- pldi_ini();
- }
- /*--------------------------------------------------------------------------*\
- * void calc_diori
- *
- * Calculate transformation coefficients to arbitrarily orient plot.
- * Preserve aspect ratios so the output doesn't suck.
- \*--------------------------------------------------------------------------*/
- static void
- calc_diori(void)
- {
- PLFLT r11, r21, r12, r22, cost, sint;
- PLFLT x0, y0, lx, ly, aspect;
- if (plsc->dev_di) {
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_DI, NULL );
- }
- if ( ! (plsc->difilt & PLDI_ORI))
- return;
- /* Center point of rotation */
- x0 = (plsc->phyxma + plsc->phyxmi) / 2.;
- y0 = (plsc->phyyma + plsc->phyymi) / 2.;
- /* Rotation matrix */
- r11 = cos(plsc->diorot * PI / 2.);
- r21 = sin(plsc->diorot * PI / 2.);
- r12 = -r21;
- r22 = r11;
- cost = ABS(r11);
- sint = ABS(r21);
- /* Flip aspect ratio as necessary. Grungy but I don't see a better way */
- aspect = plsc->aspect;
- if (aspect == 0.)
- aspect = plsc->aspdev;
- if (plsc->freeaspect)
- plsc->aspori = aspect;
- else
- plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
- if ( ! (plsc->difilt & PLDI_DEV)) {
- plsc->difilt |= PLDI_DEV;
- setdef_didev();
- }
- calc_didev();
- /* Compute scale factors */
- lx = plsc->phyxlen;
- ly = plsc->phyylen;
- /* Transformation coefficients */
- plsc->dioxax = r11;
- plsc->dioxay = r21 * (lx / ly);
- plsc->dioxb = (1. - r11) * x0 - r21 * y0 * (lx / ly);
- plsc->dioyax = r12 * (ly / lx);
- plsc->dioyay = r22;
- plsc->dioyb = (1. - r22) * y0 - r12 * x0 * (ly / lx);
- }
- /*--------------------------------------------------------------------------*\
- * void plgdiori
- *
- * Get plot orientation
- \*--------------------------------------------------------------------------*/
- void
- c_plgdiori(PLFLT *p_rot)
- {
- *p_rot = plsc->diorot;
- }
- /*--------------------------------------------------------------------------*\
- * void plsdimap
- *
- * Set up transformation from metafile coordinates. The size of the plot is
- * scaled so as to preserve aspect ratio. This isn't intended to be a
- * general-purpose facility just yet (not sure why the user would need it,
- * for one).
- \*--------------------------------------------------------------------------*/
- void
- c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
- PLFLT dimxpmm, PLFLT dimypmm)
- {
- plsetvar(plsc->dimxmin, dimxmin);
- plsetvar(plsc->dimxmax, dimxmax);
- plsetvar(plsc->dimymin, dimymin);
- plsetvar(plsc->dimymax, dimymax);
- plsetvar(plsc->dimxpmm, dimxpmm);
- plsetvar(plsc->dimypmm, dimypmm);
- plsc->difilt |= PLDI_MAP;
- pldi_ini();
- }
- /*--------------------------------------------------------------------------*\
- * void calc_dimap
- *
- * Set up transformation from metafile coordinates. The size of the plot is
- * scaled so as to preserve aspect ratio. This isn't intended to be a
- * general-purpose facility just yet (not sure why the user would need it,
- * for one).
- \*--------------------------------------------------------------------------*/
- static void
- calc_dimap()
- {
- PLFLT lx, ly;
- PLINT pxmin, pxmax, pymin, pymax;
- PLFLT dimxlen, dimylen, pxlen, pylen;
- if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
- (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
- (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
- plsc->difilt &= ~PLDI_MAP;
- return;
- }
- /* Set default aspect ratio */
- lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
- ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
- plsc->aspdev = lx / ly;
- /* Build transformation to correct physical coordinates */
- dimxlen = plsc->dimxmax - plsc->dimxmin;
- dimylen = plsc->dimymax - plsc->dimymin;
- pxmin = plsc->phyxmi;
- pxmax = plsc->phyxma;
- pymin = plsc->phyymi;
- pymax = plsc->phyyma;
- pxlen = pxmax - pxmin;
- pylen = pymax - pymin;
- plsc->dimxax = pxlen / dimxlen;
- plsc->dimyay = pylen / dimylen;
- plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
- plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
- }
- /*--------------------------------------------------------------------------*\
- * void plflush()
- *
- * Flushes the output stream. Use sparingly, if at all.
- \*--------------------------------------------------------------------------*/
- void
- c_plflush(void)
- {
- if (plsc->dev_flush) {
- (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
- PLESC_FLUSH, NULL );
- }
- else {
- if (plsc->OutFile != NULL)
- fflush(plsc->OutFile);
- }
- }
- /*--------------------------------------------------------------------------*\
- * Startup routines.
- \*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*\
- * void pllib_init()
- *
- * Initialize library. Called internally by every startup routine.
- * Everything you want to always be initialized before plinit() is called
- * you should put here. E.g. dispatch table setup, rcfile read, etc.
- \*--------------------------------------------------------------------------*/
- void
- pllib_init()
- {
- if (lib_initialized) return;
- lib_initialized = 1;
- #ifdef ENABLE_DYNDRIVERS
- /* Create libltdl resources */
- lt_dlinit();
- #endif
- /* Initialize the dispatch table with the info from the static drivers table
- and the available dynamic drivers. */
- plInitDispatchTable();
- }
- /*--------------------------------------------------------------------------*\
- * void plstar(nx, ny)
- *
- * Initialize PLplot, passing in the windows/page settings.
- \*--------------------------------------------------------------------------*/
- void
- c_plstar(PLINT nx, PLINT ny)
- {
- pllib_init();
- if (plsc->level != 0)
- plend1();
- plssub(nx, ny);
- c_plinit();
- }
- /*--------------------------------------------------------------------------*\
- * void plstart(devname, nx, ny)
- *
- * Initialize PLplot, passing the device name and windows/page settings.
- \*--------------------------------------------------------------------------*/
- void
- c_plstart(const char *devname, PLINT nx, PLINT ny)
- {
- pllib_init();
- if (plsc->level != 0)
- plend1();
- plssub(nx, ny);
- plsdev(devname);
- c_plinit();
- }
- /*--------------------------------------------------------------------------*\
- * void plinit()
- *
- * Initializes PLplot, using preset or default options.
- \*--------------------------------------------------------------------------*/
- void
- c_plinit(void)
- {
- PLFLT def_arrow_x[6] = {-0.5, 0.5, 0.3, 0.5, 0.3, 0.5};
- PLFLT def_arrow_y[6] = {0.0, 0.0, 0.2, 0.0, -0.2, 0.0};
- PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
- PLINT mk = 0, sp = 0, inc = 0, del = 2000;
- pllib_init();
- if (plsc->level != 0)
- plend1();
- /* Set stream number */
- plsc->ipls = ipls;
- /* Set up devices */
- pllib_devinit();
- /* Auxiliary stream setup */
- plstrm_init();
- /* Initialize device & first page */
- plP_init();
- plP_bop();
- plsc->level = 1;
- /* Calculate factor such that the character aspect ratio is preserved
- * when the overall aspect ratio is changed, i.e., if portrait mode is
- * requested (only honored for subset of drivers) or if the aspect ratio
- * is specified in any way, or if a 90 deg rotation occurs with
- * -freeaspect. */
- /* Case where plsc->aspect has a value.... (e.g., -a aspect on the
- * command line or 2nd parameter of plsdidev specified) */
- if (plsc->aspect > 0.) {
- lx = plsc->phyxlen / plsc->xpmm;
- ly = plsc->phyylen / plsc->ypmm;
- aspect_old = lx / ly;
- aspect_new = plsc->aspect;
- plsc->caspfactor = sqrt(aspect_old/aspect_new);
- }
- /* Case of 90 deg rotations with -freeaspect (this is also how portraite
- * mode is implemented for the drivers that honor -portrait). */
- else if (plsc->freeaspect && ABS(cos(plsc->diorot * PI / 2.)) <= 1.e-5) {
- lx = plsc->phyxlen / plsc->xpmm;
- ly = plsc->phyylen / plsc->ypmm;
- aspect_old = lx / ly;
- aspect_new = ly / lx;
- plsc->caspfactor = sqrt(aspect_old/aspect_new);
- }
- else
- plsc->caspfactor = 1.;
- /* Load fonts */
- plsc->cfont = 1;
- plfntld(initfont);
- /* Set up subpages */
- plP_subpInit();
- /* Set up number of allowed digits before switching to scientific notation */
- /* The user can always change this */
- if (plsc->xdigmax == 0)
- plsc->xdigmax = 4;
- if (plsc->ydigmax == 0)
- plsc->ydigmax = 4;
- if (plsc->zdigmax == 0)
- plsc->zdigmax = 3;
- /* Switch to graphics mode and set color and arrow style*/
- plgra();
- plcol(1);
- plstyl(0, &mk, &sp);
- plpat(1, &inc, &del);
- plsvect(def_arrow_x, def_arrow_y, 6, 0);
- /* Set clip limits. */
- plsc->clpxmi = plsc->phyxmi;
- plsc->clpxma = plsc->phyxma;
- plsc->clpymi = plsc->phyymi;
- plsc->clpyma = plsc->phyyma;
- /* Page aspect ratio. */
- lx = plsc->phyxlen / plsc->xpmm;
- ly = plsc->phyylen / plsc->ypmm;
- plsc->aspdev = lx / ly;
- /* Initialize driver interface */
- pldi_ini();
- /* Apply compensating factor to original xpmm and ypmm so that
- * character aspect ratio is preserved when overall aspect ratio
- * is changed. This must appear here in the code because previous
- * code in this routine and in routines that it calls must use the original
- * values of xpmm and ypmm before the compensating factor is applied. */
- plP_gpixmm(&xpmm_loc, &ypmm_loc);
- plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor);
- }
- /*--------------------------------------------------------------------------*\
- * void plend()
- *
- * End a plotting session for all open streams.
- \*--------------------------------------------------------------------------*/
- void
- c_plend(void)
- {
- PLINT i;
- if (lib_initialized == 0) return;
- for (i = PL_NSTREAMS-1; i >= 0; i--) {
- if (pls[i] != NULL) {
- plsstrm(i);
- c_plend1();
- }
- }
- plfontrel();
- #ifdef ENABLE_DYNDRIVERS
- /* Release the libltdl resources */
- lt_dlexit();
- /* Free up memory allocated to the dispatch tables */
- for (i = 0; i < npldynamicdevices; i++) {
- free_mem(loadable_device_list[i].devnam);
- free_mem(loadable_device_list[i].description);
- free_mem(loadable_device_list[i].drvnam);
- free_mem(loadable_device_list[i].tag);
- }
- free_mem(loadable_device_list);
- for (i = 0; i < nloadabledrivers; i++) {
- free_mem(loadable_driver_list[i].drvnam);
- }
- free_mem(loadable_driver_list);
- for (i = nplstaticdevices; i < npldrivers; i++) {
- free_mem(dispatch_table[i]->pl_MenuStr);
- free_mem(dispatch_table[i]->pl_DevName);
- free_mem(dispatch_table[i]);
- }
- #endif
- for (i = 0; i < nplstaticdevices; i++) {
- free_mem(dispatch_table[i]);
- }
- free_mem(dispatch_table);
- plP_FreeDrvOpts();
- lib_initialized = 0;
- }
- /*--------------------------------------------------------------------------*\
- * void plend1()
- *
- * End a plotting session for the current stream only. After the stream is
- * ended the memory associated with the stream's PLStream data structure is
- * freed (for stream > 0), and the stream counter is set to 0 (the default).
- \*--------------------------------------------------------------------------*/
- void
- c_plend1(void)
- {
- if (plsc->level > 0) {
- plP_eop();
- plP_tidy();
- plsc->level = 0;
- }
- /* Move from plP_tidy because FileName may be set even if level == 0 */
- if (plsc->FileName)
- free_mem(plsc->FileName);
- /* Free all malloc'ed stream memory */
- free_mem(plsc->cmap0);
- free_mem(plsc->cmap1);
- free_mem(plsc->plwindow);
- free_mem(plsc->geometry);
- free_mem(plsc->dev);
- free_mem(plsc->BaseName);
- if (plsc->program) free_mem(plsc->program);
- if (plsc->server_name) free_mem(plsc->server_name);
- if (plsc->server_host) free_mem(plsc->server_host);
- if (plsc->server_port) free_mem(plsc->server_port);
- if (plsc->user) free_mem(plsc->user);
- if (plsc->plserver) free_mem(plsc->plserver);
- if (plsc->auto_path) free_mem(plsc->auto_path);
- if (plsc->arrow_x) free_mem(plsc->arrow_x);
- if (plsc->arrow_y) free_mem(plsc->arrow_y);
- /* Free malloc'ed stream if not in initial stream, else clear it out */
- if (ipls > 0) {
- free_mem(plsc);
- pls[ipls] = NULL;
- plsstrm(0);
- }
- else {
- memset((char *) pls[ipls], 0, sizeof(PLStream));
- }
- }
- /*--------------------------------------------------------------------------*\
- * void plsstrm
- *
- * Set stream number. If the data structure for a new stream is
- * unallocated, we allocate it here.
- \*--------------------------------------------------------------------------*/
- void
- c_plsstrm(PLINT strm)
- {
- if (strm < 0 || strm >= PL_NSTREAMS) {
- fprintf(stderr,
- "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
- (int) strm, PL_NSTREAMS);
- }
- else {
- ipls = strm;
- if (pls[ipls] == NULL) {
- pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
- if (pls[ipls] == NULL)
- plexit("plsstrm: Out of memory.");
- memset((char *) pls[ipls], 0, sizeof(PLStream));
- }
- plsc = pls[ipls];
- plsc->ipls = ipls;
- }
- }
- /*--------------------------------------------------------------------------*\
- * void plgstrm
- *
- * Get current stream number.
- \*--------------------------------------------------------------------------*/
- void
- c_plgstrm(PLINT *p_strm)
- {
- *p_strm = ipls;
- }
- /*--------------------------------------------------------------------------*\
- * void plmkstrm
- *
- * Creates a new stream and makes it the default. Differs from using
- * plsstrm(), in that a free stream number is found, and returned.
- *
- * Unfortunately, I /have/ to start at stream 1 and work upward, since
- * stream 0 is preallocated. One of the BIG flaws in the PLplot API is
- * that no initial, library-opening call is required. So stream 0 must be
- * preallocated, and there is no simple way of determining whether it is
- * already in use or not.
- \*--------------------------------------------------------------------------*/
- void
- c_plmkstrm(PLINT *p_strm)
- {
- int i;
- for (i = 1; i < PL_NSTREAMS; i++) {
- if (pls[i] == NULL)
- break;
- }
- if (i == PL_NSTREAMS) {
- fprintf(stderr, "plmkstrm: Cannot create new stream\n");
- *p_strm = -1;
- }
- else {
- *p_strm = i;
- plsstrm(i);
- }
- plstrm_…
Large files files are truncated, but you can click here to view the full file